From f704ef44602fbf403e6722c7ed13f62d17e8cb20 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 19 Jan 2016 11:23:38 +0100 Subject: [PATCH] s390/perf: add support for perf_regs and libdw With support for perf_regs and libdw, you can record and report call graphs for user space programs. Simply invoke perf with the --call-graph=dwarf command line option. Signed-off-by: Heiko Carstens [brueckner: added dwfl_thread_state_register_pc() call] Signed-off-by: Hendrik Brueckner Reviewed-and-tested-by: Thomas Richter Signed-off-by: Martin Schwidefsky --- tools/perf/Makefile.config | 6 ++- tools/perf/arch/s390/include/perf_regs.h | 63 ++++++++++++++++++++++++ tools/perf/arch/s390/util/Build | 1 + tools/perf/arch/s390/util/dwarf-regs.c | 4 ++ tools/perf/arch/s390/util/unwind-libdw.c | 40 +++++++++++++++ 5 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 tools/perf/arch/s390/include/perf_regs.h create mode 100644 tools/perf/arch/s390/util/unwind-libdw.c diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 63f534a0902f..ed65e82f034e 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -53,6 +53,10 @@ ifeq ($(SRCARCH),arm64) LIBUNWIND_LIBS = -lunwind -lunwind-aarch64 endif +ifeq ($(ARCH),s390) + NO_PERF_REGS := 0 +endif + ifeq ($(NO_PERF_REGS),0) $(call detected,CONFIG_PERF_REGS) endif @@ -61,7 +65,7 @@ endif # Disable it on all other architectures in case libdw unwind # support is detected in system. Add supported architectures # to the check. -ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc)) +ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc s390)) NO_LIBDW_DWARF_UNWIND := 1 endif diff --git a/tools/perf/arch/s390/include/perf_regs.h b/tools/perf/arch/s390/include/perf_regs.h new file mode 100644 index 000000000000..ac4b8c8c49e2 --- /dev/null +++ b/tools/perf/arch/s390/include/perf_regs.h @@ -0,0 +1,63 @@ +#ifndef ARCH_PERF_REGS_H +#define ARCH_PERF_REGS_H + +#include +#include +#include <../../../../arch/s390/include/uapi/asm/perf_regs.h> + +void perf_regs_load(u64 *regs); + +#define PERF_REGS_MASK ((1ULL << PERF_REG_S390_MAX) - 1) +#define PERF_REGS_MAX PERF_REG_S390_MAX +#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64 + +#define PERF_REG_IP PERF_REG_S390_PC +#define PERF_REG_SP PERF_REG_S390_R15 + +static inline const char *perf_reg_name(int id) +{ + switch (id) { + case PERF_REG_S390_R0: + return "R0"; + case PERF_REG_S390_R1: + return "R1"; + case PERF_REG_S390_R2: + return "R2"; + case PERF_REG_S390_R3: + return "R3"; + case PERF_REG_S390_R4: + return "R4"; + case PERF_REG_S390_R5: + return "R5"; + case PERF_REG_S390_R6: + return "R6"; + case PERF_REG_S390_R7: + return "R7"; + case PERF_REG_S390_R8: + return "R8"; + case PERF_REG_S390_R9: + return "R9"; + case PERF_REG_S390_R10: + return "R10"; + case PERF_REG_S390_R11: + return "R11"; + case PERF_REG_S390_R12: + return "R12"; + case PERF_REG_S390_R13: + return "R13"; + case PERF_REG_S390_R14: + return "R14"; + case PERF_REG_S390_R15: + return "R15"; + case PERF_REG_S390_MASK: + return "MASK"; + case PERF_REG_S390_PC: + return "PC"; + default: + return NULL; + } + + return NULL; +} + +#endif /* ARCH_PERF_REGS_H */ diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build index 397084382b23..4a233683c684 100644 --- a/tools/perf/arch/s390/util/Build +++ b/tools/perf/arch/s390/util/Build @@ -2,6 +2,7 @@ libperf-y += header.o libperf-y += kvm-stat.o libperf-$(CONFIG_DWARF) += dwarf-regs.o +libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-y += machine.o diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c index 0dff5b2ed1e5..0cd7cba5d6ee 100644 --- a/tools/perf/arch/s390/util/dwarf-regs.c +++ b/tools/perf/arch/s390/util/dwarf-regs.c @@ -19,5 +19,9 @@ static const char *gpr_names[NUM_GPRS] = { const char *get_arch_regstr(unsigned int n) { + if (n == 64) + return "mask"; + if (n == 65) + return "pc"; return (n >= NUM_GPRS) ? NULL : gpr_names[n]; } diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/arch/s390/util/unwind-libdw.c new file mode 100644 index 000000000000..281bbb82402a --- /dev/null +++ b/tools/perf/arch/s390/util/unwind-libdw.c @@ -0,0 +1,40 @@ +#include +#include "../../util/unwind-libdw.h" +#include "../../util/perf_regs.h" +#include "../../util/event.h" + + +bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) +{ + struct unwind_info *ui = arg; + struct regs_dump *user_regs = &ui->sample->user_regs; + Dwarf_Word dwarf_regs[PERF_REG_S390_MAX]; + +#define REG(r) ({ \ + Dwarf_Word val = 0; \ + perf_reg_value(&val, user_regs, PERF_REG_S390_##r); \ + val; \ +}) + + dwarf_regs[0] = REG(R0); + dwarf_regs[1] = REG(R1); + dwarf_regs[2] = REG(R2); + dwarf_regs[3] = REG(R3); + dwarf_regs[4] = REG(R4); + dwarf_regs[5] = REG(R5); + dwarf_regs[6] = REG(R6); + dwarf_regs[7] = REG(R7); + dwarf_regs[8] = REG(R8); + dwarf_regs[9] = REG(R9); + dwarf_regs[10] = REG(R10); + dwarf_regs[11] = REG(R11); + dwarf_regs[12] = REG(R12); + dwarf_regs[13] = REG(R13); + dwarf_regs[14] = REG(R14); + dwarf_regs[15] = REG(R15); + dwarf_regs[16] = REG(MASK); + dwarf_regs[17] = REG(PC); + + dwfl_thread_state_register_pc(thread, dwarf_regs[17]); + return dwfl_thread_state_registers(thread, 0, 16, dwarf_regs); +} -- GitLab