Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools arm64: Add libdw DWARF post unwind support for ARM64

Based on prior work:

https://lkml.org/lkml/2014/5/6/395

and on how other arches add libdw unwind support. Includes support for
running the unwind test, e.g., on a system with only elfutils' libdw
0.170, the test now runs, and successfully:

$ ./perf test unwind
56: Test dwarf unwind : Ok

Originally-by: Jean Pihet <jean.pihet@linaro.org>
Reported-by: Christian Hansen <chansen3@cisco.com>
Signed-off-by: Kim Phillips <kim.phillips@arm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20180308211030.4ee4a0d6ff6dc5cda1b567d4@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Kim Phillips and committed by
Arnaldo Carvalho de Melo
744e9a91 03d9fcb7

+92 -1
+1 -1
tools/perf/Makefile.config
··· 75 75 # Disable it on all other architectures in case libdw unwind 76 76 # support is detected in system. Add supported architectures 77 77 # to the check. 78 - ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc s390)) 78 + ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc s390)) 79 79 NO_LIBDW_DWARF_UNWIND := 1 80 80 endif 81 81
+12
tools/perf/arch/arm64/include/arch-tests.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef ARCH_TESTS_H 3 + #define ARCH_TESTS_H 4 + 5 + #ifdef HAVE_DWARF_UNWIND_SUPPORT 6 + struct thread; 7 + struct perf_sample; 8 + #endif 9 + 10 + extern struct test arch_tests[]; 11 + 12 + #endif
+2
tools/perf/arch/arm64/tests/Build
··· 1 1 libperf-y += regs_load.o 2 2 libperf-y += dwarf-unwind.o 3 + 4 + libperf-y += arch-tests.o
+16
tools/perf/arch/arm64/tests/arch-tests.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <string.h> 3 + #include "tests/tests.h" 4 + #include "arch-tests.h" 5 + 6 + struct test arch_tests[] = { 7 + #ifdef HAVE_DWARF_UNWIND_SUPPORT 8 + { 9 + .desc = "DWARF unwind", 10 + .func = test__dwarf_unwind, 11 + }, 12 + #endif 13 + { 14 + .func = NULL, 15 + }, 16 + };
+1
tools/perf/arch/arm64/util/Build
··· 2 2 libperf-y += sym-handling.o 3 3 libperf-$(CONFIG_DWARF) += dwarf-regs.o 4 4 libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o 5 + libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o 5 6 6 7 libperf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o \ 7 8 ../../arm/util/auxtrace.o \
+60
tools/perf/arch/arm64/util/unwind-libdw.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <elfutils/libdwfl.h> 3 + #include "../../util/unwind-libdw.h" 4 + #include "../../util/perf_regs.h" 5 + #include "../../util/event.h" 6 + 7 + bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) 8 + { 9 + struct unwind_info *ui = arg; 10 + struct regs_dump *user_regs = &ui->sample->user_regs; 11 + Dwarf_Word dwarf_regs[PERF_REG_ARM64_MAX], dwarf_pc; 12 + 13 + #define REG(r) ({ \ 14 + Dwarf_Word val = 0; \ 15 + perf_reg_value(&val, user_regs, PERF_REG_ARM64_##r); \ 16 + val; \ 17 + }) 18 + 19 + dwarf_regs[0] = REG(X0); 20 + dwarf_regs[1] = REG(X1); 21 + dwarf_regs[2] = REG(X2); 22 + dwarf_regs[3] = REG(X3); 23 + dwarf_regs[4] = REG(X4); 24 + dwarf_regs[5] = REG(X5); 25 + dwarf_regs[6] = REG(X6); 26 + dwarf_regs[7] = REG(X7); 27 + dwarf_regs[8] = REG(X8); 28 + dwarf_regs[9] = REG(X9); 29 + dwarf_regs[10] = REG(X10); 30 + dwarf_regs[11] = REG(X11); 31 + dwarf_regs[12] = REG(X12); 32 + dwarf_regs[13] = REG(X13); 33 + dwarf_regs[14] = REG(X14); 34 + dwarf_regs[15] = REG(X15); 35 + dwarf_regs[16] = REG(X16); 36 + dwarf_regs[17] = REG(X17); 37 + dwarf_regs[18] = REG(X18); 38 + dwarf_regs[19] = REG(X19); 39 + dwarf_regs[20] = REG(X20); 40 + dwarf_regs[21] = REG(X21); 41 + dwarf_regs[22] = REG(X22); 42 + dwarf_regs[23] = REG(X23); 43 + dwarf_regs[24] = REG(X24); 44 + dwarf_regs[25] = REG(X25); 45 + dwarf_regs[26] = REG(X26); 46 + dwarf_regs[27] = REG(X27); 47 + dwarf_regs[28] = REG(X28); 48 + dwarf_regs[29] = REG(X29); 49 + dwarf_regs[30] = REG(LR); 50 + dwarf_regs[31] = REG(SP); 51 + 52 + if (!dwfl_thread_state_registers(thread, 0, PERF_REG_ARM64_MAX, 53 + dwarf_regs)) 54 + return false; 55 + 56 + dwarf_pc = REG(PC); 57 + dwfl_thread_state_register_pc(thread, dwarf_pc); 58 + 59 + return true; 60 + }