summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Disassembler
diff options
context:
space:
mode:
authorJason Molenda <jason@molenda.com>2021-08-12 14:29:30 -0700
committerJason Molenda <jason@molenda.com>2021-08-12 14:44:17 -0700
commit7150b562081ffb2ec5406edfa579b16d3ec20d90 (patch)
tree02ec3a53c5a64138b6b3ed64a110e8a1992b9d5e /lldb/source/Plugins/Disassembler
parent8930af45c35b5224d3b90c8408957f6b7bfa1be0 (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.cpp49
-rw-r--r--lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h7
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,