diff options
| author | Jason Molenda <jason@molenda.com> | 2021-08-12 14:29:30 -0700 |
|---|---|---|
| committer | Jason Molenda <jason@molenda.com> | 2021-08-12 14:44:17 -0700 |
| commit | 7150b562081ffb2ec5406edfa579b16d3ec20d90 (patch) | |
| tree | 02ec3a53c5a64138b6b3ed64a110e8a1992b9d5e /lldb/source/Plugins/Disassembler | |
| parent | 8930af45c35b5224d3b90c8408957f6b7bfa1be0 (diff) | |
Symbolicate aarch64 adrp+add pc-relative addr in disass
On aarch64 a two instruction sequence is used to calculate a
pc-relative address, add some state to the DisassemblerLLVMC
symbolicator so it can track the necessary data across the
two instructions and compute the address being calculated.
Differential Revision: https://reviews.llvm.org/D107213
rdar://49119253
Diffstat (limited to 'lldb/source/Plugins/Disassembler')
| -rw-r--r-- | lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp | 49 | ||||
| -rw-r--r-- | lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h | 7 |
2 files changed, 55 insertions, 1 deletions
diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp index 7cd505d0ed29..24998e96af6f 100644 --- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp +++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp @@ -1030,7 +1030,8 @@ bool DisassemblerLLVMC::MCDisasmInstance::IsCall(llvm::MCInst &mc_inst) const { DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, const char *flavor_string) : Disassembler(arch, flavor_string), m_exe_ctx(nullptr), m_inst(nullptr), - m_data_from_file(false) { + m_data_from_file(false), m_adrp_address(LLDB_INVALID_ADDRESS), + m_adrp_insn() { if (!FlavorValidForArchSpec(arch, m_flavor.c_str())) { m_flavor.assign("default"); } @@ -1310,6 +1311,46 @@ const char *DisassemblerLLVMC::SymbolLookup(uint64_t value, uint64_t *type_ptr, Target *target = m_exe_ctx ? m_exe_ctx->GetTargetPtr() : nullptr; Address value_so_addr; Address pc_so_addr; + if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64 || + target->GetArchitecture().GetMachine() == llvm::Triple::aarch64_be || + target->GetArchitecture().GetMachine() == llvm::Triple::aarch64_32) { + if (*type_ptr == LLVMDisassembler_ReferenceType_In_ARM64_ADRP) { + m_adrp_address = pc; + m_adrp_insn = value; + *name = nullptr; + *type_ptr = LLVMDisassembler_ReferenceType_InOut_None; + return nullptr; + } + // If this instruction is an ADD and + // the previous instruction was an ADRP and + // the ADRP's register and this ADD's register are the same, + // then this is a pc-relative address calculation. + if (*type_ptr == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri && + m_adrp_insn.hasValue() && m_adrp_address == pc - 4 && + (m_adrp_insn.getValue() & 0x1f) == ((value >> 5) & 0x1f)) { + uint32_t addxri_inst; + uint64_t adrp_imm, addxri_imm; + // Get immlo and immhi bits, OR them together to get the ADRP imm + // value. + adrp_imm = ((m_adrp_insn.getValue() & 0x00ffffe0) >> 3) | + ((m_adrp_insn.getValue() >> 29) & 0x3); + // if high bit of immhi after right-shifting set, sign extend + if (adrp_imm & (1ULL << 20)) + adrp_imm |= ~((1ULL << 21) - 1); + + addxri_inst = value; + addxri_imm = (addxri_inst >> 10) & 0xfff; + // check if 'sh' bit is set, shift imm value up if so + // (this would make no sense, ADRP already gave us this part) + if ((addxri_inst >> (12 + 5 + 5)) & 1) + addxri_imm <<= 12; + value = (m_adrp_address & 0xfffffffffffff000LL) + (adrp_imm << 12) + + addxri_imm; + } + m_adrp_address = LLDB_INVALID_ADDRESS; + m_adrp_insn.reset(); + } + if (m_inst->UsingFileAddress()) { ModuleSP module_sp(m_inst->GetAddress().GetModule()); if (module_sp) { @@ -1371,6 +1412,12 @@ const char *DisassemblerLLVMC::SymbolLookup(uint64_t value, uint64_t *type_ptr, } } + // TODO: llvm-objdump sets the type_ptr to the + // LLVMDisassembler_ReferenceType_Out_* values + // based on where value_so_addr is pointing, with + // Mach-O specific augmentations in MachODump.cpp. e.g. + // see what AArch64ExternalSymbolizer::tryAddingSymbolicOperand + // handles. *type_ptr = LLVMDisassembler_ReferenceType_InOut_None; *name = nullptr; return nullptr; diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h index 9b3741bdd18f..91ddaabc8671 100644 --- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h +++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h @@ -16,6 +16,7 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/PluginManager.h" +#include "llvm/ADT/Optional.h" class InstructionLLVMC; @@ -73,6 +74,12 @@ protected: InstructionLLVMC *m_inst; std::mutex m_mutex; bool m_data_from_file; + // Save the AArch64 ADRP instruction word and address it was at, + // in case the next instruction is an ADD to the same register; + // this is a pc-relative address calculation and we need both + // parts to calculate the symbolication. + lldb::addr_t m_adrp_address; + llvm::Optional<uint32_t> m_adrp_insn; // Since we need to make two actual MC Disassemblers for ARM (ARM & THUMB), // and there's a bit of goo to set up and own in the MC disassembler world, |
