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

perf probe: Support probing on offline cross-arch binary

Support probing on offline cross-architecture binary by adding getting
the target machine arch from ELF and choose correct register string for
the machine.

Here is an example:
-----
$ perf probe --vmlinux=./vmlinux-arm --definition 'do_sys_open $params'
p:probe/do_sys_open do_sys_open+0 dfd=%r5:s32 filename=%r1:u32 flags=%r6:s32 mode=%r3:u16
-----

Here, we can get probe/do_sys_open from above and append it to to the target
machine's tracing/kprobe_events file in the tracefs mountput, usually
/sys/kernel/debug/tracing/kprobe_events (or /sys/kernel/tracing/kprobe_events).

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/147214229717.23638.6440579792548044658.stgit@devbox
[ Add definition for EM_AARCH64 to fix the build on at least centos 6, debian 7 & ubuntu 12.04.5 ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Masami Hiramatsu and committed by
Arnaldo Carvalho de Melo
293d5b43 428aff82

+205 -11
+9
tools/perf/arch/arm/include/dwarf-regs-table.h
··· 1 + #ifdef DEFINE_DWARF_REGSTR_TABLE 2 + /* This is included in perf/util/dwarf-regs.c */ 3 + 4 + static const char * const arm_regstr_tbl[] = { 5 + "%r0", "%r1", "%r2", "%r3", "%r4", 6 + "%r5", "%r6", "%r7", "%r8", "%r9", "%r10", 7 + "%fp", "%ip", "%sp", "%lr", "%pc", 8 + }; 9 + #endif
+13
tools/perf/arch/arm64/include/dwarf-regs-table.h
··· 1 + #ifdef DEFINE_DWARF_REGSTR_TABLE 2 + /* This is included in perf/util/dwarf-regs.c */ 3 + 4 + static const char * const aarch64_regstr_tbl[] = { 5 + "%r0", "%r1", "%r2", "%r3", "%r4", 6 + "%r5", "%r6", "%r7", "%r8", "%r9", 7 + "%r10", "%r11", "%r12", "%r13", "%r14", 8 + "%r15", "%r16", "%r17", "%r18", "%r19", 9 + "%r20", "%r21", "%r22", "%r23", "%r24", 10 + "%r25", "%r26", "%r27", "%r28", "%r29", 11 + "%lr", "%sp", 12 + }; 13 + #endif
+27
tools/perf/arch/powerpc/include/dwarf-regs-table.h
··· 1 + #ifdef DEFINE_DWARF_REGSTR_TABLE 2 + /* This is included in perf/util/dwarf-regs.c */ 3 + 4 + /* 5 + * Reference: 6 + * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html 7 + * http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf 8 + */ 9 + #define REG_DWARFNUM_NAME(reg, idx) [idx] = "%" #reg 10 + 11 + static const char * const powerpc_regstr_tbl[] = { 12 + "%gpr0", "%gpr1", "%gpr2", "%gpr3", "%gpr4", 13 + "%gpr5", "%gpr6", "%gpr7", "%gpr8", "%gpr9", 14 + "%gpr10", "%gpr11", "%gpr12", "%gpr13", "%gpr14", 15 + "%gpr15", "%gpr16", "%gpr17", "%gpr18", "%gpr19", 16 + "%gpr20", "%gpr21", "%gpr22", "%gpr23", "%gpr24", 17 + "%gpr25", "%gpr26", "%gpr27", "%gpr28", "%gpr29", 18 + "%gpr30", "%gpr31", 19 + REG_DWARFNUM_NAME(msr, 66), 20 + REG_DWARFNUM_NAME(ctr, 109), 21 + REG_DWARFNUM_NAME(link, 108), 22 + REG_DWARFNUM_NAME(xer, 101), 23 + REG_DWARFNUM_NAME(dar, 119), 24 + REG_DWARFNUM_NAME(dsisr, 118), 25 + }; 26 + 27 + #endif
+8
tools/perf/arch/s390/include/dwarf-regs-table.h
··· 1 + #ifdef DEFINE_DWARF_REGSTR_TABLE 2 + /* This is included in perf/util/dwarf-regs.c */ 3 + 4 + static const char * const s390_regstr_tbl[] = { 5 + "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", 6 + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", 7 + }; 8 + #endif
+25
tools/perf/arch/sh/include/dwarf-regs-table.h
··· 1 + #ifdef DEFINE_DWARF_REGSTR_TABLE 2 + /* This is included in perf/util/dwarf-regs.c */ 3 + 4 + const char * const sh_regstr_tbl[] = { 5 + "r0", 6 + "r1", 7 + "r2", 8 + "r3", 9 + "r4", 10 + "r5", 11 + "r6", 12 + "r7", 13 + "r8", 14 + "r9", 15 + "r10", 16 + "r11", 17 + "r12", 18 + "r13", 19 + "r14", 20 + "r15", 21 + "pc", 22 + "pr", 23 + }; 24 + 25 + #endif
+18
tools/perf/arch/sparc/include/dwarf-regs-table.h
··· 1 + #ifdef DEFINE_DWARF_REGSTR_TABLE 2 + /* This is included in perf/util/dwarf-regs.c */ 3 + 4 + static const char * const sparc_regstr_tbl[] = { 5 + "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", 6 + "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7", 7 + "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", 8 + "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7", 9 + "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", 10 + "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15", 11 + "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23", 12 + "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31", 13 + "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39", 14 + "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47", 15 + "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55", 16 + "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63", 17 + }; 18 + #endif
+14
tools/perf/arch/x86/include/dwarf-regs-table.h
··· 1 + #ifdef DEFINE_DWARF_REGSTR_TABLE 2 + /* This is included in perf/util/dwarf-regs.c */ 3 + 4 + static const char * const x86_32_regstr_tbl[] = { 5 + "%ax", "%cx", "%dx", "%bx", "$stack",/* Stack address instead of %sp */ 6 + "%bp", "%si", "%di", 7 + }; 8 + 9 + static const char * const x86_64_regstr_tbl[] = { 10 + "%ax", "dx", "%cx", "%bx", "%si", "%di", 11 + "%bp", "%sp", "%r8", "%r9", "%r10", "%r11", 12 + "%r12", "%r13", "%r14", "%r15", 13 + }; 14 + #endif
+8
tools/perf/arch/xtensa/include/dwarf-regs-table.h
··· 1 + #ifdef DEFINE_DWARF_REGSTR_TABLE 2 + /* This is included in perf/util/dwarf-regs.c */ 3 + 4 + static const char * const xtensa_regstr_tbl[] = { 5 + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", 6 + "a8", "a9", "a10", "a11", "a12", "a13", "a14", "a15", 7 + }; 8 + #endif
+1
tools/perf/util/Build
··· 98 98 99 99 libperf-$(CONFIG_DWARF) += probe-finder.o 100 100 libperf-$(CONFIG_DWARF) += dwarf-aux.o 101 + libperf-$(CONFIG_DWARF) += dwarf-regs.o 101 102 102 103 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o 103 104 libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o
+59
tools/perf/util/dwarf-regs.c
··· 1 + /* 2 + * dwarf-regs.c : Mapping of DWARF debug register numbers into register names. 3 + * 4 + * Written by: Masami Hiramatsu <mhiramat@kernel.org> 5 + */ 6 + 7 + #include <util.h> 8 + #include <debug.h> 9 + #include <dwarf-regs.h> 10 + #include <elf.h> 11 + 12 + #ifndef EM_AARCH64 13 + #define EM_AARCH64 183 /* ARM 64 bit */ 14 + #endif 15 + 16 + /* Define const char * {arch}_register_tbl[] */ 17 + #define DEFINE_DWARF_REGSTR_TABLE 18 + #include "../arch/x86/include/dwarf-regs-table.h" 19 + #include "../arch/arm/include/dwarf-regs-table.h" 20 + #include "../arch/arm64/include/dwarf-regs-table.h" 21 + #include "../arch/sh/include/dwarf-regs-table.h" 22 + #include "../arch/powerpc/include/dwarf-regs-table.h" 23 + #include "../arch/s390/include/dwarf-regs-table.h" 24 + #include "../arch/sparc/include/dwarf-regs-table.h" 25 + #include "../arch/xtensa/include/dwarf-regs-table.h" 26 + 27 + #define __get_dwarf_regstr(tbl, n) (((n) < ARRAY_SIZE(tbl)) ? (tbl)[(n)] : NULL) 28 + 29 + /* Return architecture dependent register string (for kprobe-tracer) */ 30 + const char *get_dwarf_regstr(unsigned int n, unsigned int machine) 31 + { 32 + switch (machine) { 33 + case EM_NONE: /* Generic arch - use host arch */ 34 + return get_arch_regstr(n); 35 + case EM_386: 36 + return __get_dwarf_regstr(x86_32_regstr_tbl, n); 37 + case EM_X86_64: 38 + return __get_dwarf_regstr(x86_64_regstr_tbl, n); 39 + case EM_ARM: 40 + return __get_dwarf_regstr(arm_regstr_tbl, n); 41 + case EM_AARCH64: 42 + return __get_dwarf_regstr(aarch64_regstr_tbl, n); 43 + case EM_SH: 44 + return __get_dwarf_regstr(sh_regstr_tbl, n); 45 + case EM_S390: 46 + return __get_dwarf_regstr(s390_regstr_tbl, n); 47 + case EM_PPC: 48 + case EM_PPC64: 49 + return __get_dwarf_regstr(powerpc_regstr_tbl, n); 50 + case EM_SPARC: 51 + case EM_SPARCV9: 52 + return __get_dwarf_regstr(sparc_regstr_tbl, n); 53 + case EM_XTENSA: 54 + return __get_dwarf_regstr(xtensa_regstr_tbl, n); 55 + default: 56 + pr_err("ELF MACHINE %x is not supported.\n", machine); 57 + } 58 + return NULL; 59 + }
+6
tools/perf/util/include/dwarf-regs.h
··· 3 3 4 4 #ifdef HAVE_DWARF_SUPPORT 5 5 const char *get_arch_regstr(unsigned int n); 6 + /* 7 + * get_dwarf_regstr - Returns ftrace register string from DWARF regnum 8 + * n: DWARF register number 9 + * machine: ELF machine signature (EM_*) 10 + */ 11 + const char *get_dwarf_regstr(unsigned int n, unsigned int machine); 6 12 #endif 7 13 8 14 #ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
+16 -11
tools/perf/util/probe-finder.c
··· 171 171 */ 172 172 static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 173 173 Dwarf_Op *fb_ops, Dwarf_Die *sp_die, 174 + unsigned int machine, 174 175 struct probe_trace_arg *tvar) 175 176 { 176 177 Dwarf_Attribute attr; ··· 267 266 if (!tvar) 268 267 return ret2; 269 268 270 - regs = get_arch_regstr(regn); 269 + regs = get_dwarf_regstr(regn, machine); 271 270 if (!regs) { 272 271 /* This should be a bug in DWARF or this tool */ 273 272 pr_warning("Mapping for the register number %u " ··· 544 543 dwarf_diename(vr_die)); 545 544 546 545 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 547 - &pf->sp_die, pf->tvar); 546 + &pf->sp_die, pf->machine, pf->tvar); 548 547 if (ret == -ENOENT || ret == -EINVAL) { 549 548 pr_err("Failed to find the location of the '%s' variable at this address.\n" 550 549 " Perhaps it has been optimized out.\n" ··· 1107 1106 struct probe_finder *pf) 1108 1107 { 1109 1108 int ret = 0; 1110 - 1111 - #if _ELFUTILS_PREREQ(0, 142) 1112 1109 Elf *elf; 1113 1110 GElf_Ehdr ehdr; 1114 - GElf_Shdr shdr; 1115 1111 1116 1112 if (pf->cfi_eh || pf->cfi_dbg) 1117 1113 return debuginfo__find_probe_location(dbg, pf); ··· 1121 1123 if (gelf_getehdr(elf, &ehdr) == NULL) 1122 1124 return -EINVAL; 1123 1125 1124 - if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && 1125 - shdr.sh_type == SHT_PROGBITS) 1126 - pf->cfi_eh = dwarf_getcfi_elf(elf); 1126 + pf->machine = ehdr.e_machine; 1127 1127 1128 - pf->cfi_dbg = dwarf_getcfi(dbg->dbg); 1128 + #if _ELFUTILS_PREREQ(0, 142) 1129 + do { 1130 + GElf_Shdr shdr; 1131 + 1132 + if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && 1133 + shdr.sh_type == SHT_PROGBITS) 1134 + pf->cfi_eh = dwarf_getcfi_elf(elf); 1135 + 1136 + pf->cfi_dbg = dwarf_getcfi(dbg->dbg); 1137 + } while (0); 1129 1138 #endif 1130 1139 1131 1140 ret = debuginfo__find_probe_location(dbg, pf); ··· 1160 1155 (tag == DW_TAG_variable && vf->vars)) { 1161 1156 if (convert_variable_location(die_mem, vf->pf->addr, 1162 1157 vf->pf->fb_ops, &pf->sp_die, 1163 - NULL) == 0) { 1158 + pf->machine, NULL) == 0) { 1164 1159 vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); 1165 1160 if (vf->args[vf->nargs].var == NULL) { 1166 1161 vf->ret = -ENOMEM; ··· 1323 1318 tag == DW_TAG_variable) { 1324 1319 ret = convert_variable_location(die_mem, af->pf.addr, 1325 1320 af->pf.fb_ops, &af->pf.sp_die, 1326 - NULL); 1321 + af->pf.machine, NULL); 1327 1322 if (ret == 0 || ret == -ERANGE) { 1328 1323 int ret2; 1329 1324 bool externs = !af->child;
+1
tools/perf/util/probe-finder.h
··· 80 80 Dwarf_CFI *cfi_dbg; 81 81 #endif 82 82 Dwarf_Op *fb_ops; /* Frame base attribute */ 83 + unsigned int machine; /* Target machine arch */ 83 84 struct perf_probe_arg *pvar; /* Current target variable */ 84 85 struct probe_trace_arg *tvar; /* Current result variable */ 85 86 };