diff options
Diffstat (limited to 'source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp')
-rw-r--r-- | source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp | 236 |
1 files changed, 155 insertions, 81 deletions
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp index d20219f6d1eb..6d124b689341 100644 --- a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp @@ -7,8 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "DisassemblerLLVMC.h" - +// C Includes +// C++ Includes +// Project includes #include "llvm-c/Disassembler.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" @@ -25,6 +26,8 @@ #include "llvm/Support/TargetSelect.h" #include "llvm/ADT/SmallString.h" +// Other libraries and framework includes +#include "DisassemblerLLVMC.h" #include "lldb/Core/Address.h" #include "lldb/Core/DataExtractor.h" @@ -52,18 +55,16 @@ public: Instruction (address, addr_class), m_disasm_sp (disasm.shared_from_this()), m_does_branch (eLazyBoolCalculate), + m_has_delay_slot (eLazyBoolCalculate), m_is_valid (false), m_using_file_addr (false) { } - virtual - ~InstructionLLVMC () - { - } + ~InstructionLLVMC() override = default; - virtual bool - DoesBranch () + bool + DoesBranch() override { if (m_does_branch == eLazyBoolCalculate) { @@ -99,6 +100,43 @@ public: return m_does_branch == eLazyBoolYes; } + bool + HasDelaySlot() override + { + if (m_has_delay_slot == eLazyBoolCalculate) + { + GetDisassemblerLLVMC().Lock(this, NULL); + DataExtractor data; + if (m_opcode.GetData(data)) + { + bool is_alternate_isa; + lldb::addr_t pc = m_address.GetFileAddress(); + + DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa); + const uint8_t *opcode_data = data.GetDataStart(); + const size_t opcode_data_len = data.GetByteSize(); + llvm::MCInst inst; + const size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data, + opcode_data_len, + pc, + inst); + // if we didn't understand the instruction, say it doesn't have a delay slot... + if (inst_size == 0) + m_has_delay_slot = eLazyBoolNo; + else + { + const bool has_delay_slot = mc_disasm_ptr->HasDelaySlot(inst); + if (has_delay_slot) + m_has_delay_slot = eLazyBoolYes; + else + m_has_delay_slot = eLazyBoolNo; + } + } + GetDisassemblerLLVMC().Unlock(); + } + return m_has_delay_slot == eLazyBoolYes; + } + DisassemblerLLVMC::LLVMCDisassembler * GetDisasmToUse (bool &is_alternate_isa) { @@ -117,10 +155,10 @@ public: return llvm_disasm.m_disasm_ap.get(); } - virtual size_t - Decode (const lldb_private::Disassembler &disassembler, - const lldb_private::DataExtractor &data, - lldb::offset_t data_offset) + size_t + Decode(const lldb_private::Disassembler &disassembler, + const lldb_private::DataExtractor &data, + lldb::offset_t data_offset) override { // All we have to do is read the opcode which can be easy for some // architectures @@ -234,15 +272,16 @@ public: } } - virtual void - CalculateMnemonicOperandsAndComment (const lldb_private::ExecutionContext *exe_ctx) + void + CalculateMnemonicOperandsAndComment(const lldb_private::ExecutionContext *exe_ctx) override { DataExtractor data; const AddressClass address_class = GetAddressClass (); if (m_opcode.GetData(data)) { - char out_string[512]; + std::string out_string; + std::string comment_string; DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC(); @@ -293,7 +332,12 @@ public: if (inst_size > 0) { mc_disasm_ptr->SetStyle(use_hex_immediates, hex_style); - mc_disasm_ptr->PrintMCInst(inst, out_string, sizeof(out_string)); + mc_disasm_ptr->PrintMCInst(inst, out_string, comment_string); + + if (!comment_string.empty()) + { + AppendComment(comment_string); + } } llvm_disasm.Unlock(); @@ -375,10 +419,10 @@ public: RegularExpression::Match matches(3); - if (s_regex.Execute(out_string, &matches)) + if (s_regex.Execute(out_string.c_str(), &matches)) { - matches.GetMatchAtIndex(out_string, 1, m_opcode_name); - matches.GetMatchAtIndex(out_string, 2, m_mnemonics); + matches.GetMatchAtIndex(out_string.c_str(), 1, m_opcode_name); + matches.GetMatchAtIndex(out_string.c_str(), 2, m_mnemonics); } } } @@ -409,12 +453,11 @@ protected: DisassemblerSP m_disasm_sp; // for ownership LazyBool m_does_branch; + LazyBool m_has_delay_slot; bool m_is_valid; bool m_using_file_addr; }; - - DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, const char *cpu, const char *features_str, unsigned flavor, DisassemblerLLVMC &owner): m_is_valid(true) { @@ -482,9 +525,7 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, con m_is_valid = false; } -DisassemblerLLVMC::LLVMCDisassembler::~LLVMCDisassembler() -{ -} +DisassemblerLLVMC::LLVMCDisassembler::~LLVMCDisassembler() = default; uint64_t DisassemblerLLVMC::LLVMCDisassembler::GetMCInst (const uint8_t *opcode_data, @@ -508,22 +549,25 @@ DisassemblerLLVMC::LLVMCDisassembler::GetMCInst (const uint8_t *opcode_data, return 0; } -uint64_t +void DisassemblerLLVMC::LLVMCDisassembler::PrintMCInst (llvm::MCInst &mc_inst, - char *dst, - size_t dst_len) + std::string &inst_string, + std::string &comments_string) { - llvm::StringRef unused_annotations; - llvm::SmallString<64> inst_string; - llvm::raw_svector_ostream inst_stream(inst_string); - m_instr_printer_ap->printInst (&mc_inst, inst_stream, unused_annotations, - *m_subtarget_info_ap); - inst_stream.flush(); - const size_t output_size = std::min(dst_len - 1, inst_string.size()); - std::memcpy(dst, inst_string.data(), output_size); - dst[output_size] = '\0'; - - return output_size; + llvm::raw_string_ostream inst_stream(inst_string); + llvm::raw_string_ostream comments_stream(comments_string); + + m_instr_printer_ap->setCommentStream(comments_stream); + m_instr_printer_ap->printInst (&mc_inst, inst_stream, llvm::StringRef(), *m_subtarget_info_ap); + m_instr_printer_ap->setCommentStream(llvm::nulls()); + comments_stream.flush(); + + static std::string g_newlines("\r\n"); + + for (size_t newline_pos = 0; (newline_pos = comments_string.find_first_of(g_newlines, newline_pos)) != comments_string.npos; /**/) + { + comments_string.replace(comments_string.begin() + newline_pos, comments_string.begin() + newline_pos + 1, 1, ' '); + } } void @@ -544,35 +588,9 @@ DisassemblerLLVMC::LLVMCDisassembler::CanBranch (llvm::MCInst &mc_inst) } bool -DisassemblerLLVMC::FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, const char *flavor) +DisassemblerLLVMC::LLVMCDisassembler::HasDelaySlot (llvm::MCInst &mc_inst) { - llvm::Triple triple = arch.GetTriple(); - if (flavor == NULL || strcmp (flavor, "default") == 0) - return true; - - if (triple.getArch() == llvm::Triple::x86 || triple.getArch() == llvm::Triple::x86_64) - { - if (strcmp (flavor, "intel") == 0 || strcmp (flavor, "att") == 0) - return true; - else - return false; - } - else - return false; -} - - -Disassembler * -DisassemblerLLVMC::CreateInstance (const ArchSpec &arch, const char *flavor) -{ - if (arch.GetTriple().getArch() != llvm::Triple::UnknownArch) - { - std::unique_ptr<DisassemblerLLVMC> disasm_ap (new DisassemblerLLVMC(arch, flavor)); - - if (disasm_ap.get() && disasm_ap->IsValid()) - return disasm_ap.release(); - } - return NULL; + return m_instr_info_ap->get(mc_inst.getOpcode()).hasDelaySlot(); } DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_string) : @@ -586,13 +604,12 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s m_flavor.assign("default"); } - const char *triple = arch.GetTriple().getTriple().c_str(); unsigned flavor = ~0U; + llvm::Triple triple = arch.GetTriple(); // So far the only supported flavor is "intel" on x86. The base class will set this // correctly coming in. - if (arch.GetTriple().getArch() == llvm::Triple::x86 - || arch.GetTriple().getArch() == llvm::Triple::x86_64) + if (triple.getArch() == llvm::Triple::x86 || triple.getArch() == llvm::Triple::x86_64) { if (m_flavor == "intel") { @@ -605,7 +622,7 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s } ArchSpec thumb_arch(arch); - if (arch.GetTriple().getArch() == llvm::Triple::arm) + if (triple.getArch() == llvm::Triple::arm) { std::string thumb_arch_name (thumb_arch.GetTriple().getArchName().str()); // Replace "arm" with "thumb" so we get all thumb variants correct @@ -621,18 +638,29 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s thumb_arch.GetTriple().setArchName(llvm::StringRef(thumb_arch_name.c_str())); } + // If no sub architecture specified then use the most recent arm architecture so the + // disassembler will return all instruction. Without it we will see a lot of unknow opcode + // in case the code uses instructions which are not available in the oldest arm version + // (used when no sub architecture is specified) + if (triple.getArch() == llvm::Triple::arm && triple.getSubArch() == llvm::Triple::NoSubArch) + triple.setArchName("armv8.1a"); + + const char *triple_str = triple.getTriple().c_str(); + + // v. https://en.wikipedia.org/wiki/ARM_Cortex-M#Silicon_customization + // // Cortex-M3 devices (e.g. armv7m) can only execute thumb (T2) instructions, // so hardcode the primary disassembler to thumb mode. Same for Cortex-M4 (armv7em). // // Handle the Cortex-M0 (armv6m) the same; the ISA is a subset of the T and T32 // instructions defined in ARMv7-A. - if (arch.GetTriple().getArch() == llvm::Triple::arm + if ((triple.getArch() == llvm::Triple::arm || triple.getArch() == llvm::Triple::thumb) && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m || arch.GetCore() == ArchSpec::Core::eCore_arm_armv7em || arch.GetCore() == ArchSpec::Core::eCore_arm_armv6m)) { - triple = thumb_arch.GetTriple().getTriple().c_str(); + triple_str = thumb_arch.GetTriple().getTriple().c_str(); } const char *cpu = ""; @@ -674,8 +702,8 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s } std::string features_str = ""; - if (arch.GetTriple().getArch() == llvm::Triple::mips || arch.GetTriple().getArch() == llvm::Triple::mipsel - || arch.GetTriple().getArch() == llvm::Triple::mips64 || arch.GetTriple().getArch() == llvm::Triple::mips64el) + if (triple.getArch() == llvm::Triple::mips || triple.getArch() == llvm::Triple::mipsel + || triple.getArch() == llvm::Triple::mips64 || triple.getArch() == llvm::Triple::mips64el) { uint32_t arch_flags = arch.GetFlags (); if (arch_flags & ArchSpec::eMIPSAse_msa) @@ -684,13 +712,9 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s features_str += "+dsp,"; if (arch_flags & ArchSpec::eMIPSAse_dspr2) features_str += "+dspr2,"; - if (arch_flags & ArchSpec::eMIPSAse_mips16) - features_str += "+mips16,"; - if (arch_flags & ArchSpec::eMIPSAse_micromips) - features_str += "+micromips,"; } - m_disasm_ap.reset (new LLVMCDisassembler(triple, cpu, features_str.c_str(), flavor, *this)); + m_disasm_ap.reset (new LLVMCDisassembler(triple_str, cpu, features_str.c_str(), flavor, *this)); if (!m_disasm_ap->IsValid()) { // We use m_disasm_ap.get() to tell whether we are valid or not, so if this isn't good for some reason, @@ -698,8 +722,10 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s m_disasm_ap.reset(); } + llvm::Triple::ArchType llvm_arch = triple.getArch(); + // For arm CPUs that can execute arm or thumb instructions, also create a thumb instruction disassembler. - if (arch.GetTriple().getArch() == llvm::Triple::arm) + if (llvm_arch == llvm::Triple::arm) { std::string thumb_triple(thumb_arch.GetTriple().getTriple()); m_alternate_disasm_ap.reset(new LLVMCDisassembler(thumb_triple.c_str(), "", "", flavor, *this)); @@ -709,10 +735,40 @@ DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_s m_alternate_disasm_ap.reset(); } } + else if (llvm_arch == llvm::Triple::mips + || llvm_arch == llvm::Triple::mipsel + || llvm_arch == llvm::Triple::mips64 + || llvm_arch == llvm::Triple::mips64el) + { + /* Create alternate disassembler for MIPS16 and microMIPS */ + uint32_t arch_flags = arch.GetFlags (); + if (arch_flags & ArchSpec::eMIPSAse_mips16) + features_str += "+mips16,"; + else if (arch_flags & ArchSpec::eMIPSAse_micromips) + features_str += "+micromips,"; + + m_alternate_disasm_ap.reset(new LLVMCDisassembler (triple_str, cpu, features_str.c_str(), flavor, *this)); + if (!m_alternate_disasm_ap->IsValid()) + { + m_disasm_ap.reset(); + m_alternate_disasm_ap.reset(); + } + } } -DisassemblerLLVMC::~DisassemblerLLVMC() +DisassemblerLLVMC::~DisassemblerLLVMC() = default; + +Disassembler * +DisassemblerLLVMC::CreateInstance (const ArchSpec &arch, const char *flavor) { + if (arch.GetTriple().getArch() != llvm::Triple::UnknownArch) + { + std::unique_ptr<DisassemblerLLVMC> disasm_ap (new DisassemblerLLVMC(arch, flavor)); + + if (disasm_ap.get() && disasm_ap->IsValid()) + return disasm_ap.release(); + } + return NULL; } size_t @@ -817,6 +873,24 @@ const char *DisassemblerLLVMC::SymbolLookupCallback (void *disassembler, name); } +bool +DisassemblerLLVMC::FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, const char *flavor) +{ + llvm::Triple triple = arch.GetTriple(); + if (flavor == NULL || strcmp (flavor, "default") == 0) + return true; + + if (triple.getArch() == llvm::Triple::x86 || triple.getArch() == llvm::Triple::x86_64) + { + if (strcmp (flavor, "intel") == 0 || strcmp (flavor, "att") == 0) + return true; + else + return false; + } + else + return false; +} + int DisassemblerLLVMC::OpInfo (uint64_t PC, uint64_t Offset, uint64_t Size, |