Re: [PATCH v4 01/23] perf capstone: Fix arm64 jump/adrp disassembly mismatch with objdump
From: Tengda Wu
Date: Mon Aug 10 2026 - 22:30:42 EST
Hi Shuai, thank you for your time.
On 2026/8/10 21:08, Shuai Xue wrote:
>
>
> 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 <wutengda@xxxxxxxxxxxxxxx>
>> ---
>> 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.
>
Um, this was done following Namhyung's approach. That said, adding a
comment would certainly make this definition clearer -- will add it.
Also, I couldn't find CS_GRP_BRANCH_RELATIVE in v3. From what I can see,
it was originally introduced in v4, together with ARM64_GRP_BRANCH_RELATIVE
(see https://github.com/capstone-engine/capstone/commit/a09a81813c83).
So the comment might look something like this:
#define ARM64_GRP_BRANCH_RELATIVE 7 /* = CS_GRP_BRANCH_RELATIVE */
Is this acceptable?
Thanks,
Tengda
>> +#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