From f704ef44602fbf403e6722c7ed13f62d17e8cb20 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 19 Jan 2016 11:23:38 +0100 Subject: 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/arch/s390/util/unwind-libdw.c | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tools/perf/arch/s390/util/unwind-libdw.c (limited to 'tools/perf/arch/s390/util/unwind-libdw.c') 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); +} -- cgit From a9fc2db0a8abf51c81122799c5ae4808f2324b6d Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Wed, 8 Nov 2017 09:01:12 +0100 Subject: s390/perf: define common DWARF register string table Instead of defining DWARF register to string table in dwarf-regs-table.h and dwarf-regs.c, use a common table in dwarf-regs-table.h. Ensure that the DWARF register table is up-to-date with http://refspecs.linuxfoundation.org/ELF/zSeries/lzsabi0_s390/x1542.html. For unwinding with libdw, also ensure to correctly setup the DWARF register frame according to the register mappings. Currently, libdw supports up to 32 registers only. Suggested-by: Thomas Richter Signed-off-by: Hendrik Brueckner Reviewed-and-tested-by: Thomas Richter Signed-off-by: Martin Schwidefsky --- tools/perf/arch/s390/util/unwind-libdw.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'tools/perf/arch/s390/util/unwind-libdw.c') diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/arch/s390/util/unwind-libdw.c index 281bbb82402a..ba8d98b8b09e 100644 --- a/tools/perf/arch/s390/util/unwind-libdw.c +++ b/tools/perf/arch/s390/util/unwind-libdw.c @@ -1,21 +1,26 @@ +#include #include #include "../../util/unwind-libdw.h" #include "../../util/perf_regs.h" #include "../../util/event.h" +#include "dwarf-regs-table.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]; + Dwarf_Word dwarf_regs[ARRAY_SIZE(s390_dwarf_regs)]; #define REG(r) ({ \ Dwarf_Word val = 0; \ perf_reg_value(&val, user_regs, PERF_REG_S390_##r); \ val; \ }) - + /* + * For DWARF register mapping details, + * see also perf/arch/s390/include/dwarf-regs-table.h + */ dwarf_regs[0] = REG(R0); dwarf_regs[1] = REG(R1); dwarf_regs[2] = REG(R2); @@ -32,9 +37,9 @@ bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) 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); + dwarf_regs[64] = REG(MASK); + dwarf_regs[65] = REG(PC); - dwfl_thread_state_register_pc(thread, dwarf_regs[17]); + dwfl_thread_state_register_pc(thread, dwarf_regs[65]); return dwfl_thread_state_registers(thread, 0, 16, dwarf_regs); } -- cgit From de9954b75e992d26a67d83990e6219dcb6edc3bf Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Wed, 8 Nov 2017 09:17:38 +0100 Subject: s390/perf: add perf register support for floating-point registers For correct unwinding of user space processes, the floating-point register contents are required. For example, leaf functions might use fp registers to temporarily store the return address. Signed-off-by: Hendrik Brueckner Reviewed-and-tested-by: Thomas Richter Signed-off-by: Martin Schwidefsky --- tools/perf/arch/s390/util/unwind-libdw.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'tools/perf/arch/s390/util/unwind-libdw.c') diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/arch/s390/util/unwind-libdw.c index ba8d98b8b09e..387c698cdd1b 100644 --- a/tools/perf/arch/s390/util/unwind-libdw.c +++ b/tools/perf/arch/s390/util/unwind-libdw.c @@ -37,9 +37,27 @@ bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) dwarf_regs[13] = REG(R13); dwarf_regs[14] = REG(R14); dwarf_regs[15] = REG(R15); + + dwarf_regs[16] = REG(FP0); + dwarf_regs[17] = REG(FP2); + dwarf_regs[18] = REG(FP4); + dwarf_regs[19] = REG(FP6); + dwarf_regs[20] = REG(FP1); + dwarf_regs[21] = REG(FP3); + dwarf_regs[22] = REG(FP5); + dwarf_regs[23] = REG(FP7); + dwarf_regs[24] = REG(FP8); + dwarf_regs[25] = REG(FP10); + dwarf_regs[26] = REG(FP12); + dwarf_regs[27] = REG(FP14); + dwarf_regs[28] = REG(FP9); + dwarf_regs[29] = REG(FP11); + dwarf_regs[30] = REG(FP13); + dwarf_regs[31] = REG(FP15); + dwarf_regs[64] = REG(MASK); dwarf_regs[65] = REG(PC); dwfl_thread_state_register_pc(thread, dwarf_regs[65]); - return dwfl_thread_state_registers(thread, 0, 16, dwarf_regs); + return dwfl_thread_state_registers(thread, 0, 32, dwarf_regs); } -- cgit