summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp')
-rw-r--r--lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp100
1 files changed, 88 insertions, 12 deletions
diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
index 7cd505d0ed29..2cf32bdd3800 100644
--- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
@@ -21,9 +21,9 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ScopedPrinter.h"
-#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "lldb/Core/Address.h"
@@ -61,6 +61,8 @@ public:
bool CanBranch(llvm::MCInst &mc_inst) const;
bool HasDelaySlot(llvm::MCInst &mc_inst) const;
bool IsCall(llvm::MCInst &mc_inst) const;
+ bool IsLoad(llvm::MCInst &mc_inst) const;
+ bool IsAuthenticated(llvm::MCInst &mc_inst) const;
private:
MCDisasmInstance(std::unique_ptr<llvm::MCInstrInfo> &&instr_info_up,
@@ -102,6 +104,16 @@ public:
return m_has_delay_slot;
}
+ bool IsLoad() override {
+ VisitInstruction();
+ return m_is_load;
+ }
+
+ bool IsAuthenticated() override {
+ VisitInstruction();
+ return m_is_authenticated;
+ }
+
DisassemblerLLVMC::MCDisasmInstance *GetDisasmToUse(bool &is_alternate_isa) {
DisassemblerScope disasm(*this);
return GetDisasmToUse(is_alternate_isa, disasm);
@@ -817,9 +829,13 @@ protected:
// - Might branch
// - Does not have a delay slot
// - Is not a call
+ // - Is not a load
+ // - Is not an authenticated instruction
bool m_does_branch = true;
bool m_has_delay_slot = false;
bool m_is_call = false;
+ bool m_is_load = false;
+ bool m_is_authenticated = false;
void VisitInstruction() {
if (m_has_visited_instruction)
@@ -849,6 +865,8 @@ protected:
m_does_branch = mc_disasm_ptr->CanBranch(inst);
m_has_delay_slot = mc_disasm_ptr->HasDelaySlot(inst);
m_is_call = mc_disasm_ptr->IsCall(inst);
+ m_is_load = mc_disasm_ptr->IsLoad(inst);
+ m_is_authenticated = mc_disasm_ptr->IsAuthenticated(inst);
}
private:
@@ -1027,10 +1045,32 @@ bool DisassemblerLLVMC::MCDisasmInstance::IsCall(llvm::MCInst &mc_inst) const {
return m_instr_info_up->get(mc_inst.getOpcode()).isCall();
}
+bool DisassemblerLLVMC::MCDisasmInstance::IsLoad(llvm::MCInst &mc_inst) const {
+ return m_instr_info_up->get(mc_inst.getOpcode()).mayLoad();
+}
+
+bool DisassemblerLLVMC::MCDisasmInstance::IsAuthenticated(
+ llvm::MCInst &mc_inst) const {
+ auto InstrDesc = m_instr_info_up->get(mc_inst.getOpcode());
+
+ // Treat software auth traps (brk 0xc470 + aut key, where 0x70 == 'p', 0xc4
+ // == 'a' + 'c') as authenticated instructions for reporting purposes, in
+ // addition to the standard authenticated instructions specified in ARMv8.3.
+ bool IsBrkC47x = false;
+ if (InstrDesc.isTrap() && mc_inst.getNumOperands() == 1) {
+ const llvm::MCOperand &Op0 = mc_inst.getOperand(0);
+ if (Op0.isImm() && Op0.getImm() >= 0xc470 && Op0.getImm() <= 0xc474)
+ IsBrkC47x = true;
+ }
+
+ return InstrDesc.isAuthenticated() || IsBrkC47x;
+}
+
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");
}
@@ -1255,11 +1295,6 @@ void DisassemblerLLVMC::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
-ConstString DisassemblerLLVMC::GetPluginNameStatic() {
- static ConstString g_name("llvm-mc");
- return g_name;
-}
-
int DisassemblerLLVMC::OpInfoCallback(void *disassembler, uint64_t pc,
uint64_t offset, uint64_t size,
int tag_type, void *tag_bug) {
@@ -1310,6 +1345,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,12 +1446,13 @@ 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;
}
-
-// PluginInterface protocol
-ConstString DisassemblerLLVMC::GetPluginName() { return GetPluginNameStatic(); }
-
-uint32_t DisassemblerLLVMC::GetPluginVersion() { return 1; }