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

perf script: Support 32bit code under 64bit OS with capstone

Use the DSO to resolve whether an IP is 32bit or 64bit and use that to
configure capstone to the correct mode. This allows to correctly
disassemble 32bit code under a 64bit OS.

% cat > loop.c
volatile int var;
int main(void)
{
int i;
for (i = 0; i < 100000; i++)
var++;
}
% gcc -m32 -o loop loop.c
% perf record -e cycles:u ./loop
% perf script -F +disasm
loop 82665 1833176.618023: 1 cycles:u: f7eed500 _start+0x0 (/usr/lib/ld-linux.so.2) movl %esp, %eax
loop 82665 1833176.618029: 1 cycles:u: f7eed500 _start+0x0 (/usr/lib/ld-linux.so.2) movl %esp, %eax
loop 82665 1833176.618031: 7 cycles:u: f7eed500 _start+0x0 (/usr/lib/ld-linux.so.2) movl %esp, %eax
loop 82665 1833176.618034: 91 cycles:u: f7eed500 _start+0x0 (/usr/lib/ld-linux.so.2) movl %esp, %eax
loop 82665 1833176.618036: 1242 cycles:u: f7eed500 _start+0x0 (/usr/lib/ld-linux.so.2) movl %esp, %eax

Reviewed-by: Adrian Hunter <adrian.hunter@intel.com>
Acked-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Link: https://lore.kernel.org/r/20240401210925.209671-2-ak@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Andi Kleen and committed by
Arnaldo Carvalho de Melo
38ab6013 c2f3d7df

+28 -10
+5 -4
tools/perf/builtin-script.c
··· 1517 1517 static int perf_sample__fprintf_insn(struct perf_sample *sample, 1518 1518 struct perf_event_attr *attr, 1519 1519 struct thread *thread, 1520 - struct machine *machine, FILE *fp) 1520 + struct machine *machine, FILE *fp, 1521 + struct addr_location *al) 1521 1522 { 1522 1523 int printed = 0; 1523 1524 ··· 1532 1531 } 1533 1532 if (PRINT_FIELD(DISASM) && sample->insn_len) { 1534 1533 printed += fprintf(fp, "\t\t"); 1535 - printed += sample__fprintf_insn_asm(sample, thread, machine, fp); 1534 + printed += sample__fprintf_insn_asm(sample, thread, machine, fp, al); 1536 1535 } 1537 1536 if (PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN)) 1538 1537 printed += perf_sample__fprintf_brstackinsn(sample, thread, attr, machine, fp); ··· 1607 1606 if (print_srcline_last) 1608 1607 printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); 1609 1608 1610 - printed += perf_sample__fprintf_insn(sample, attr, thread, machine, fp); 1609 + printed += perf_sample__fprintf_insn(sample, attr, thread, machine, fp, al); 1611 1610 printed += fprintf(fp, "\n"); 1612 1611 if (PRINT_FIELD(SRCCODE)) { 1613 1612 int ret = map__fprintf_srccode(al->map, al->addr, stdout, ··· 2260 2259 2261 2260 if (evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) 2262 2261 perf_sample__fprintf_bpf_output(sample, fp); 2263 - perf_sample__fprintf_insn(sample, attr, thread, machine, fp); 2262 + perf_sample__fprintf_insn(sample, attr, thread, machine, fp, al); 2264 2263 2265 2264 if (PRINT_FIELD(PHYS_ADDR)) 2266 2265 fprintf(fp, "%16" PRIx64, sample->phys_addr);
+22 -5
tools/perf/util/print_insn.c
··· 12 12 #include "machine.h" 13 13 #include "thread.h" 14 14 #include "print_insn.h" 15 + #include "map.h" 16 + #include "dso.h" 15 17 16 18 size_t sample__fprintf_insn_raw(struct perf_sample *sample, FILE *fp) 17 19 { ··· 30 28 #ifdef HAVE_LIBCAPSTONE_SUPPORT 31 29 #include <capstone/capstone.h> 32 30 33 - static int capstone_init(struct machine *machine, csh *cs_handle) 31 + static int capstone_init(struct machine *machine, csh *cs_handle, bool is64) 34 32 { 35 33 cs_arch arch; 36 34 cs_mode mode; 37 35 38 - if (machine__is(machine, "x86_64")) { 36 + if (machine__is(machine, "x86_64") && is64) { 39 37 arch = CS_ARCH_X86; 40 38 mode = CS_MODE_64; 41 39 } else if (machine__normalized_is(machine, "x86")) { ··· 95 93 return printed; 96 94 } 97 95 96 + static bool is64bitip(struct machine *machine, struct addr_location *al) 97 + { 98 + const struct dso *dso = al->map ? map__dso(al->map) : NULL; 99 + 100 + if (dso) 101 + return dso->is_64_bit; 102 + 103 + return machine__is(machine, "x86_64") || 104 + machine__normalized_is(machine, "arm64") || 105 + machine__normalized_is(machine, "s390"); 106 + } 107 + 98 108 size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread, 99 - struct machine *machine, FILE *fp) 109 + struct machine *machine, FILE *fp, 110 + struct addr_location *al) 100 111 { 101 112 csh cs_handle; 102 113 cs_insn *insn; 103 114 size_t count; 104 115 size_t printed = 0; 105 116 int ret; 117 + bool is64bit = is64bitip(machine, al); 106 118 107 119 /* TODO: Try to initiate capstone only once but need a proper place. */ 108 - ret = capstone_init(machine, &cs_handle); 120 + ret = capstone_init(machine, &cs_handle, is64bit); 109 121 if (ret < 0) { 110 122 /* fallback */ 111 123 return sample__fprintf_insn_raw(sample, fp); ··· 144 128 size_t sample__fprintf_insn_asm(struct perf_sample *sample __maybe_unused, 145 129 struct thread *thread __maybe_unused, 146 130 struct machine *machine __maybe_unused, 147 - FILE *fp __maybe_unused) 131 + FILE *fp __maybe_unused, 132 + struct addr_location *al __maybe_unused) 148 133 { 149 134 return 0; 150 135 }
+1 -1
tools/perf/util/print_insn.h
··· 10 10 struct machine; 11 11 12 12 size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread, 13 - struct machine *machine, FILE *fp); 13 + struct machine *machine, FILE *fp, struct addr_location *al); 14 14 size_t sample__fprintf_insn_raw(struct perf_sample *sample, FILE *fp); 15 15 16 16 #endif /* PERF_PRINT_INSN_H */