Re: [PATCH v4 01/23] perf capstone: Fix arm64 jump/adrp disassembly mismatch with objdump
Shuai Xue <[email protected]>
| Newsgroups | org.kernel.vger.linux-perf-users,dev.linux.lists.llvm,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 8/8/26 8:23 PM, Tengda Wu wrote: > The jump and adrp instructions parsed by libcapstone currently lack > symbolic representation and use a '#' prefix for addresses. This > format is inconsistent with objdump's output, which causes subsequent > parsing in jump__parse() and arm64_mov__parse() to fail. > > Example mismatch: > Current: b #0xffff8000800114c8 > Fix: b ffff8000800114c8 <el0t_64_sync+0x108> > > Current: adrp x18, #0xffff800081f5f000 > Fix: adrp x18, ffff800081f5f000 <this_cpu_vector> > > Fix this by implementing extended formatting for these arm64 > instructions during symbol__disassemble_capstone(). This ensures > the output matches objdump's expected style, including the raw > address and the associated <symbol+offset> suffix. > > Signed-off-by: Tengda Wu <[email protected]> > --- > tools/perf/util/capstone.c | 136 +++++++++++++++++++++++++++++++++---- > tools/perf/util/disasm.c | 5 ++ > tools/perf/util/disasm.h | 1 + > 3 files changed, 130 insertions(+), 12 deletions(-) > > diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c > index 74213daf8786..fb8a2bc5558f 100644 > --- a/tools/perf/util/capstone.c > +++ b/tools/perf/util/capstone.c > @@ -3,6 +3,7 @@ > > #include <errno.h> > #include <inttypes.h> > +#include <stdlib.h> > #include <string.h> > > #include <dlfcn.h> > @@ -31,6 +32,10 @@ > #define CS_MODE_RISCVC 4 > #endif > > +#if CS_VERSION_MAJOR < 4 > +#define ARM64_GRP_BRANCH_RELATIVE 7 Please add a comment explaining where '7' comes from (CS_GRP_BRANCH_RELATIVE in capstone v3), otherwise it reads like an arbitrary magic number. > +#endif > + > #ifdef LIBCAPSTONE_DLOPEN > static void *perf_cs_dll_handle(void) > { > @@ -225,6 +230,12 @@ static int capstone_init(uint16_t e_machine, csh *cs_handle, bool is64, bool is_ > * on x86 by investigating instruction details. > */ > perf_cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON); > + } else if (arch == CS_ARCH_ARM64) { > + /* > + * Same as x86: arm64 needs instruction details to resolve > + * symbolic addresses. > + */ > + perf_cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON); > } > > return 0; > @@ -299,10 +310,6 @@ static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t len, > struct map *map = args->ms->map; > struct symbol *sym; > > - /* TODO: support more architectures */ > - if (!arch__is_x86(args->arch)) > - return; > - > if (insn->detail == NULL) > return; > > @@ -354,6 +361,116 @@ static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t len, > } > } > > +static int print_default_format(struct cs_insn *insn, char *buf, size_t len) > +{ > + return scnprintf(buf, len, " %-7s %s", > + insn->mnemonic, insn->op_str); > +} > + > +static void format_capstone_insn_x86(struct cs_insn *insn, char *buf, > + size_t len, struct annotate_args *args, > + u64 addr) > +{ > + int printed; > + > + printed = print_default_format(insn, buf, len); > + buf += printed; > + len -= printed; > + > + print_capstone_detail(insn, buf, len, args, addr); > +} > + > +static bool is_pc_relative_insn(struct cs_insn *insn) > +{ > + int i; > + > + if (insn->id == ARM64_INS_ADR || insn->id == ARM64_INS_ADRP) > + return true; > + > + if (insn->detail == NULL) > + return false; > + > + for (i = 0; i < insn->detail->groups_count; i++) { > + if (insn->detail->groups[i] == ARM64_GRP_JUMP || > + insn->detail->groups[i] == ARM64_GRP_CALL || > + insn->detail->groups[i] == ARM64_GRP_BRANCH_RELATIVE) > + return true; > + } > + > + return false; > +} > + > +static void format_capstone_insn_arm64(struct cs_insn *insn, char *buf, > + size_t len, struct annotate_args *args) > +{ > + struct map *map = args->ms->map; > + struct symbol *sym; > + char *last_imm, *endptr; > + u64 orig_addr, addr; > + struct map *found_map = NULL; > + > + print_default_format(insn, buf, len); > + /* > + * Adjust instructions to keep the existing behavior with objdump. > + * > + * Example conversion: > + * From: b #0xffff8000800114c8 > + * To: b ffff8000800114c8 <el0t_64_sync+0x108> > + */ > + if (is_pc_relative_insn(insn)) { > + /* Extract last immediate value as address */ > + last_imm = strrchr(buf, '#'); > + if (!last_imm) > + return; > + > + orig_addr = strtoull(last_imm + 1, &endptr, 16); > + if (endptr == last_imm + 1) > + return; > + > + addr = map__objdump_2mem(map, orig_addr); > + > + /* Relocate map that contains the address */ > + if (dso__kernel(map__dso(map))) { > + found_map = maps__find(map__kmaps(map), addr); > + if (found_map == NULL) > + return; > + map = found_map; > + } > + > + /* Convert it to map-relative address for search */ > + addr = map__map_ip(map, addr); > + > + sym = map__find_symbol(map, addr); > + if (sym == NULL) { > + map__put(found_map); > + return; > + } > + > + /* Symbolize the resolved address */ > + len = len - (last_imm - buf); > + if (addr == sym->start) { > + scnprintf(last_imm, len, "%"PRIx64" <%s>", > + orig_addr, sym->name); > + } else { > + scnprintf(last_imm, len, "%"PRIx64" <%s+%#"PRIx64">", > + orig_addr, sym->name, addr - sym->start); > + } > + map__put(found_map); This whole sequence (objdump_2mem -> kmaps relocation -> map_ip -> find_symbol -> scnprintf the "<sym+off>" string) is almost identical to what print_capstone_detail() does for x86 RIP-relative operands. Could you factor out a common helper so the two paths don't diverge over time? Thanks. Shuai