perf tools: Support MIPS unwinding and dwarf-regs

Map perf APIs (perf_reg_name/get_arch_regstr/unwind__arch_reg_id) with
MIPS specific registers.

[ayan@wavecomp.com: repick this patch for unwinding userstack backtrace
by perf and libunwind on MIPS based CPU.]

[yangtiezhu@loongson.cn: Add sample_reg_masks[] to fix build error,
silence some checkpatch errors and warnings, and also separate the
original patches into two parts (MIPS kernel and perf tools) to merge
easily.]

The original patches:

https://lore.kernel.org/patchwork/patch/1126521/
https://lore.kernel.org/patchwork/patch/1126520/

Committer notes:

Do it as __perf_reg_name() to cope with:

  067012974c ("perf tools: Fix arm64 build error with gcc-11")

Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Archer Yan <ayan@wavecomp.com>
Cc: David Daney <david.daney@cavium.com>
Cc: Jianlin Lv <Jianlin.Lv@arm.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Juxin Gao <gaojuxin@loongson.cn>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Xuefeng Li <lixuefeng@loongson.cn>
Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: linux-mips@vger.kernel.org
Link: http://lore.kernel.org/lkml/1612409724-3516-3-git-send-email-yangtiezhu@loongson.cn
Signed-off-by: Archer Yan <ayan@wavecomp.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Tiezhu Yang 2021-02-04 11:35:23 +08:00 committed by Arnaldo Carvalho de Melo
parent 84b7725536
commit b5f184fbdb
9 changed files with 197 additions and 0 deletions

View File

@ -87,6 +87,12 @@ ifeq ($(ARCH),s390)
CFLAGS += -fPIC -I$(OUTPUT)arch/s390/include/generated
endif
ifeq ($(ARCH),mips)
NO_PERF_REGS := 0
CFLAGS += -I../../arch/mips/include/uapi -I../../arch/mips/include/generated/uapi
LIBUNWIND_LIBS = -lunwind -lunwind-mips
endif
ifeq ($(NO_PERF_REGS),0)
$(call detected,CONFIG_PERF_REGS)
endif

View File

@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif

View File

@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* dwarf-regs-table.h : Mapping of DWARF debug register numbers into
* register names.
*
* Copyright (C) 2013 Cavium, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifdef DEFINE_DWARF_REGSTR_TABLE
#undef REG_DWARFNUM_NAME
#define REG_DWARFNUM_NAME(reg, idx) [idx] = "$" #reg
static const char * const mips_regstr_tbl[] = {
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
"$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19",
"$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "%29",
"$30", "$31",
REG_DWARFNUM_NAME(hi, 64),
REG_DWARFNUM_NAME(lo, 65),
};
#endif

View File

@ -0,0 +1,84 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef ARCH_PERF_REGS_H
#define ARCH_PERF_REGS_H
#include <stdlib.h>
#include <linux/types.h>
#include <asm/perf_regs.h>
#define PERF_REGS_MAX PERF_REG_MIPS_MAX
#define PERF_REG_IP PERF_REG_MIPS_PC
#define PERF_REG_SP PERF_REG_MIPS_R29
#define PERF_REGS_MASK ((1ULL << PERF_REG_MIPS_MAX) - 1)
static inline const char *__perf_reg_name(int id)
{
switch (id) {
case PERF_REG_MIPS_PC:
return "PC";
case PERF_REG_MIPS_R1:
return "$1";
case PERF_REG_MIPS_R2:
return "$2";
case PERF_REG_MIPS_R3:
return "$3";
case PERF_REG_MIPS_R4:
return "$4";
case PERF_REG_MIPS_R5:
return "$5";
case PERF_REG_MIPS_R6:
return "$6";
case PERF_REG_MIPS_R7:
return "$7";
case PERF_REG_MIPS_R8:
return "$8";
case PERF_REG_MIPS_R9:
return "$9";
case PERF_REG_MIPS_R10:
return "$10";
case PERF_REG_MIPS_R11:
return "$11";
case PERF_REG_MIPS_R12:
return "$12";
case PERF_REG_MIPS_R13:
return "$13";
case PERF_REG_MIPS_R14:
return "$14";
case PERF_REG_MIPS_R15:
return "$15";
case PERF_REG_MIPS_R16:
return "$16";
case PERF_REG_MIPS_R17:
return "$17";
case PERF_REG_MIPS_R18:
return "$18";
case PERF_REG_MIPS_R19:
return "$19";
case PERF_REG_MIPS_R20:
return "$20";
case PERF_REG_MIPS_R21:
return "$21";
case PERF_REG_MIPS_R22:
return "$22";
case PERF_REG_MIPS_R23:
return "$23";
case PERF_REG_MIPS_R24:
return "$24";
case PERF_REG_MIPS_R25:
return "$25";
case PERF_REG_MIPS_R28:
return "$28";
case PERF_REG_MIPS_R29:
return "$29";
case PERF_REG_MIPS_R30:
return "$30";
case PERF_REG_MIPS_R31:
return "$31";
default:
break;
}
return NULL;
}
#endif /* ARCH_PERF_REGS_H */

View File

@ -0,0 +1,3 @@
perf-y += perf_regs.o
perf-$(CONFIG_DWARF) += dwarf-regs.o
perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o

View File

@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0
/*
* dwarf-regs.c : Mapping of DWARF debug register numbers into register names.
*
* Copyright (C) 2013 Cavium, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <stdio.h>
#include <dwarf-regs.h>
static const char *mips_gpr_names[32] = {
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
"$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19",
"$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29",
"$30", "$31"
};
const char *get_arch_regstr(unsigned int n)
{
if (n < 32)
return mips_gpr_names[n];
if (n == 64)
return "hi";
if (n == 65)
return "lo";
return NULL;
}

View File

@ -0,0 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include "../../util/perf_regs.h"
const struct sample_reg sample_reg_masks[] = {
SMPL_REG_END
};

View File

@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <libunwind.h>
#include "perf_regs.h"
#include "../../util/unwind.h"
#include "util/debug.h"
int libunwind__arch_reg_id(int regnum)
{
switch (regnum) {
case UNW_MIPS_R1 ... UNW_MIPS_R25:
return regnum - UNW_MIPS_R1 + PERF_REG_MIPS_R1;
case UNW_MIPS_R28 ... UNW_MIPS_R31:
return regnum - UNW_MIPS_R28 + PERF_REG_MIPS_R28;
case UNW_MIPS_PC:
return PERF_REG_MIPS_PC;
default:
pr_err("unwind: invalid reg id %d\n", regnum);
return -EINVAL;
}
}

View File

@ -24,6 +24,7 @@
#include "../arch/s390/include/dwarf-regs-table.h"
#include "../arch/sparc/include/dwarf-regs-table.h"
#include "../arch/xtensa/include/dwarf-regs-table.h"
#include "../arch/mips/include/dwarf-regs-table.h"
#define __get_dwarf_regstr(tbl, n) (((n) < ARRAY_SIZE(tbl)) ? (tbl)[(n)] : NULL)
@ -53,6 +54,8 @@ const char *get_dwarf_regstr(unsigned int n, unsigned int machine)
return __get_dwarf_regstr(sparc_regstr_tbl, n);
case EM_XTENSA:
return __get_dwarf_regstr(xtensa_regstr_tbl, n);
case EM_MIPS:
return __get_dwarf_regstr(mips_regstr_tbl, n);
default:
pr_err("ELF MACHINE %x is not supported.\n", machine);
}