From 705390bdcf625d7cb573c6d001569b68be0d9755 Mon Sep 17 00:00:00 2001 From: Tengda Wu Date: Wed, 16 Sep 2026 01:29:16 +0000 Subject: [PATCH] perf llvm: Fix arm64 adrp instruction disassembly mismatch with objdump The operands of 'adrp' instructions parsed by libllvm are currently represented as raw immediates rather than the "address " format used by objdump. This inconsistency causes arm64_mov__parse() to fail when parsing these instructions during post-processing. Example of the mismatch: Current: adrp x18, 8014 Objdump: adrp x18, ffff800081f5f000 Fix this by manually extracting the target address from the raw adrp instruction via symbol_lookup_callback(). The address is then converted to a specific symbol during symbol__disassemble_llvm() and formatted to match objdump's output, ensuring compatibility with existing parsers. Reviewed-by: Namhyung Kim Signed-off-by: Tengda Wu Reviewed-by: Ian Rogers Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/llvm.c | 52 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/llvm.c b/tools/perf/util/llvm.c index a0deb742a733..a78845689aa1 100644 --- a/tools/perf/util/llvm.c +++ b/tools/perf/util/llvm.c @@ -9,8 +9,10 @@ #include "symbol.h" #include #include +#include #include #include +#include #ifdef HAVE_LIBLLVM_SUPPORT #include "llvm-c-helpers.h" @@ -108,6 +110,16 @@ symbol_lookup_callback(void *disinfo, uint64_t value, storage->branch_addr = value; else if (*ref_type == LLVMDisassembler_ReferenceType_In_PCrel_Load) storage->pcrel_load_addr = value; + else if (*ref_type == LLVMDisassembler_ReferenceType_In_ARM64_ADRP) { + uint64_t adrp_imm; + + /* immhi (bits 23:5) and immlo (bits 30:29) */ + adrp_imm = ((value & 0x00ffffe0) >> 3) | ((value >> 29) & 0x3); + adrp_imm = sign_extend64(adrp_imm, 20); + + /* Calculate the target page address */ + storage->pcrel_load_addr = (address & ~0xfffULL) + (adrp_imm << 12); + } *ref_type = LLVMDisassembler_ReferenceType_InOut_None; return NULL; } @@ -228,12 +240,42 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym, } } if (storage.pcrel_load_addr != 0) { - char *name = llvm_name_for_data(dso, filename, + char *name; + + if (arch__is_arm64(args->arch)) { + /* + * For arm64, replace the immediate operand with + * the resolved address to match objdump's output. + * + * Example conversion: + * From: adrp x18, 8014 + * To: adrp x18, ffff800081f5f000 + */ + char *s = strchr(disasm_buf, ','); + + if (s == NULL) + goto err; + + s++; + *s = '\0'; + disasm_len = strlen(disasm_buf); + disasm_len += scnprintf(disasm_buf + disasm_len, + sizeof(disasm_buf) - disasm_len, + " %"PRIx64, storage.pcrel_load_addr); - disasm_len += scnprintf(disasm_buf + disasm_len, - sizeof(disasm_buf) - disasm_len, - " # %#"PRIx64, - storage.pcrel_load_addr); + } else { + /* + * For other archs, append the resolved address + * as an inline comment. + */ + disasm_len += scnprintf(disasm_buf + disasm_len, + sizeof(disasm_buf) - disasm_len, + " # %#"PRIx64, + storage.pcrel_load_addr); + } + + /* Append the resolved symbol name if available */ + name = llvm_name_for_data(dso, filename, storage.pcrel_load_addr); if (name) { disasm_len += scnprintf(disasm_buf + disasm_len, sizeof(disasm_buf) -