[PATCH v4 02/23] perf llvm: Fix arm64 adrp instruction disassembly mismatch with objdump
Tengda Wu <[email protected]>
| Newsgroups | dev.linux.lists.llvm,org.kernel.vger.linux-kernel,org.kernel.vger.linux-perf-users |
|---|---|
| Message-ID | <[email protected]> |
The operands of 'adrp' instructions parsed by libllvm are currently represented as raw immediates rather than the "address <symbol+offset>" 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 Fix: adrp x18, ffff800081f5f000 <this_cpu_vector> 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. Signed-off-by: Tengda Wu <[email protected]> --- tools/perf/util/llvm.c | 50 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/llvm.c b/tools/perf/util/llvm.c index a0deb742a733..6b53b283205a 100644 --- a/tools/perf/util/llvm.c +++ b/tools/perf/util/llvm.c @@ -9,8 +9,10 @@ #include "symbol.h" #include <errno.h> #include <fcntl.h> +#include <string.h> #include <unistd.h> #include <linux/zalloc.h> +#include <linux/bitops.h> #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; } @@ -230,10 +242,40 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym, if (storage.pcrel_load_addr != 0) { char *name = llvm_name_for_data(dso, filename, storage.pcrel_load_addr); - disasm_len += scnprintf(disasm_buf + disasm_len, - sizeof(disasm_buf) - disasm_len, - " # %#"PRIx64, - storage.pcrel_load_addr); + + 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); + } 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 */ if (name) { disasm_len += scnprintf(disasm_buf + disasm_len, sizeof(disasm_buf) - -- 2.34.1