summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Disassembler/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Disassembler/llvm')
-rw-r--r--lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp566
-rw-r--r--lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h1
2 files changed, 567 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
index 4d24cf1ab6d..61a57ef3fcd 100644
--- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
@@ -31,6 +31,7 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Stream.h"
#include "lldb/Symbol/SymbolContext.h"
@@ -56,6 +57,7 @@ public:
m_disasm_wp (std::static_pointer_cast<DisassemblerLLVMC>(disasm.shared_from_this())),
m_does_branch (eLazyBoolCalculate),
m_has_delay_slot (eLazyBoolCalculate),
+ m_is_call (eLazyBoolCalculate),
m_is_valid (false),
m_using_file_addr (false)
{
@@ -467,11 +469,569 @@ public:
{
return m_disasm_wp.lock();
}
+
+ static llvm::StringRef::const_iterator
+ ConsumeWhitespace(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ while (osi != ose)
+ {
+ switch (*osi) {
+ default:
+ return osi;
+ case ' ': case '\t':
+ break;
+ }
+ ++osi;
+ }
+
+ return osi;
+ }
+
+ static std::pair<bool, llvm::StringRef::const_iterator>
+ ConsumeChar(llvm::StringRef::const_iterator osi, const char c, llvm::StringRef::const_iterator ose)
+ {
+ bool found = false;
+
+ osi = ConsumeWhitespace(osi, ose);
+ if (osi != ose && *osi == c)
+ {
+ found = true;
+ ++osi;
+ }
+
+ return std::make_pair(found, osi);
+ }
+
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseRegisterName(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ Operand ret;
+ ret.m_type = Operand::Type::Register;
+ std::string str;
+
+ osi = ConsumeWhitespace(osi, ose);
+
+ while (osi != ose)
+ {
+ if (*osi >= '0' && *osi <= '9')
+ {
+ if (str.empty())
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ else
+ {
+ str.push_back(*osi);
+ }
+ }
+ else if (*osi >= 'a' && *osi <= 'z')
+ {
+ str.push_back(*osi);
+ }
+ else
+ {
+ switch (*osi)
+ {
+ default:
+ if (str.empty())
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ else
+ {
+ ret.m_register = ConstString(str);
+ return std::make_pair(ret, osi);
+ }
+ case '%':
+ if (!str.empty())
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ break;
+ }
+ }
+ ++osi;
+ }
+
+ ret.m_register = ConstString(str);
+ return std::make_pair(ret, osi);
+ }
+
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseImmediate(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ Operand ret;
+ ret.m_type = Operand::Type::Immediate;
+ std::string str;
+ bool is_hex = false;
+
+ osi = ConsumeWhitespace(osi, ose);
+
+ while (osi != ose)
+ {
+ if (*osi >= '0' && *osi <= '9')
+ {
+ str.push_back(*osi);
+ }
+ else if (*osi >= 'a' && *osi <= 'f')
+ {
+ if (is_hex)
+ {
+ str.push_back(*osi);
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ }
+ else
+ {
+ switch (*osi)
+ {
+ default:
+ if (str.empty())
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ else
+ {
+ ret.m_immediate = std::stoull(str, nullptr, 0);
+ return std::make_pair(ret, osi);
+ }
+ case 'x':
+ if (!str.compare("0"))
+ {
+ is_hex = true;
+ str.push_back(*osi);
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ break;
+ case '#': case '$':
+ if (!str.empty())
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ break;
+ case '-':
+ if (str.empty())
+ {
+ ret.m_negative = true;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+ }
+ }
+ ++osi;
+ }
+
+ ret.m_immediate = std::stoull(str, nullptr, 0);
+ return std::make_pair(ret, osi);
+ }
+
+ // -0x5(%rax,%rax,2)
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseIntelIndexedAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator = ParseImmediate(osi, ose);
+ if (offset_and_iterator.first.IsValid())
+ {
+ osi = offset_and_iterator.second;
+ }
+
+ bool found = false;
+ std::tie(found, osi) = ConsumeChar(osi, '(', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+ if (base_and_iterator.first.IsValid())
+ {
+ osi = base_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ',', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> index_and_iterator = ParseRegisterName(osi, ose);
+ if (index_and_iterator.first.IsValid())
+ {
+ osi = index_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ',', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> multiplier_and_iterator = ParseImmediate(osi, ose);
+ if (index_and_iterator.first.IsValid())
+ {
+ osi = index_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ')', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ Operand product;
+ product.m_type = Operand::Type::Product;
+ product.m_children.push_back(index_and_iterator.first);
+ product.m_children.push_back(multiplier_and_iterator.first);
+
+ Operand index;
+ index.m_type = Operand::Type::Sum;
+ index.m_children.push_back(base_and_iterator.first);
+ index.m_children.push_back(product);
+
+ if (offset_and_iterator.first.IsValid())
+ {
+ Operand offset;
+ offset.m_type = Operand::Type::Sum;
+ offset.m_children.push_back(offset_and_iterator.first);
+ offset.m_children.push_back(index);
+
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(offset);
+ return std::make_pair(deref, osi);
+ }
+ else
+ {
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(index);
+ return std::make_pair(deref, osi);
+ }
+ }
+
+ // -0x10(%rbp)
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseIntelDerefAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator = ParseImmediate(osi, ose);
+ if (offset_and_iterator.first.IsValid())
+ {
+ osi = offset_and_iterator.second;
+ }
+
+ bool found = false;
+ std::tie(found, osi) = ConsumeChar(osi, '(', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+ if (base_and_iterator.first.IsValid())
+ {
+ osi = base_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ')', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ if (offset_and_iterator.first.IsValid())
+ {
+ Operand offset;
+ offset.m_type = Operand::Type::Sum;
+ offset.m_children.push_back(offset_and_iterator.first);
+ offset.m_children.push_back(base_and_iterator.first);
+
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(offset);
+ return std::make_pair(deref, osi);
+ }
+ else
+ {
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(base_and_iterator.first);
+ return std::make_pair(deref, osi);
+ }
+ }
+
+ // [sp, #8]!
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseARMOffsetAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ bool found = false;
+ std::tie(found, osi) = ConsumeChar(osi, '[', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+ if (base_and_iterator.first.IsValid())
+ {
+ osi = base_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ',', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator = ParseImmediate(osi, ose);
+ if (offset_and_iterator.first.IsValid())
+ {
+ osi = offset_and_iterator.second;
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ']', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ Operand offset;
+ offset.m_type = Operand::Type::Sum;
+ offset.m_children.push_back(offset_and_iterator.first);
+ offset.m_children.push_back(base_and_iterator.first);
+
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(offset);
+ return std::make_pair(deref, osi);
+ }
+
+ // [sp]
+ static std::pair<Operand, llvm::StringRef::const_iterator>
+ ParseARMDerefAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+ {
+ bool found = false;
+ std::tie(found, osi) = ConsumeChar(osi, '[', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+ if (base_and_iterator.first.IsValid())
+ {
+ osi = base_and_iterator.second;
+ }
+ else
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ std::tie(found, osi) = ConsumeChar(osi, ']', ose);
+ if (!found)
+ {
+ return std::make_pair(Operand(), osi);
+ }
+
+ Operand deref;
+ deref.m_type = Operand::Type::Dereference;
+ deref.m_children.push_back(base_and_iterator.first);
+ return std::make_pair(deref, osi);
+ }
+
+ static void
+ DumpOperand(const Operand &op, Stream &s)
+ {
+ switch (op.m_type)
+ {
+ case Operand::Type::Dereference:
+ s.PutCString("*");
+ DumpOperand(op.m_children[0], s);
+ break;
+ case Operand::Type::Immediate:
+ if (op.m_negative)
+ {
+ s.PutCString("-");
+ }
+ s.PutCString(std::to_string(op.m_immediate).c_str());
+ break;
+ case Operand::Type::Invalid:
+ s.PutCString("Invalid");
+ break;
+ case Operand::Type::Product:
+ s.PutCString("(");
+ DumpOperand(op.m_children[0], s);
+ s.PutCString("*");
+ DumpOperand(op.m_children[1], s);
+ s.PutCString(")");
+ break;
+ case Operand::Type::Register:
+ s.PutCString(op.m_register.AsCString());
+ break;
+ case Operand::Type::Sum:
+ s.PutCString("(");
+ DumpOperand(op.m_children[0], s);
+ s.PutCString("+");
+ DumpOperand(op.m_children[1], s);
+ s.PutCString(")");
+ break;
+ }
+ }
+
+ bool
+ ParseOperands (llvm::SmallVectorImpl<Instruction::Operand> &operands) override
+ {
+ const char *operands_string = GetOperands(nullptr);
+
+ if (!operands_string)
+ {
+ return false;
+ }
+
+ llvm::StringRef operands_ref(operands_string);
+
+ llvm::StringRef::const_iterator osi = operands_ref.begin();
+ llvm::StringRef::const_iterator ose = operands_ref.end();
+
+ while (osi != ose)
+ {
+ Operand operand;
+ llvm::StringRef::const_iterator iter;
+
+ if ((std::tie(operand, iter) = ParseIntelIndexedAccess(osi, ose), operand.IsValid()) ||
+ (std::tie(operand, iter) = ParseIntelDerefAccess(osi, ose), operand.IsValid()) ||
+ (std::tie(operand, iter) = ParseARMOffsetAccess(osi, ose), operand.IsValid()) ||
+ (std::tie(operand, iter) = ParseARMDerefAccess(osi, ose), operand.IsValid()) ||
+ (std::tie(operand, iter) = ParseRegisterName(osi, ose), operand.IsValid()) ||
+ (std::tie(operand, iter) = ParseImmediate(osi, ose), operand.IsValid()))
+ {
+ osi = iter;
+ operands.push_back(operand);
+ }
+ else
+ {
+ return false;
+ }
+
+ std::pair<bool, llvm::StringRef::const_iterator> found_and_iter = ConsumeChar(osi, ',', ose);
+ if (found_and_iter.first)
+ {
+ osi = found_and_iter.second;
+ }
+
+ osi = ConsumeWhitespace(osi, ose);
+ }
+
+ DisassemblerSP disasm_sp = m_disasm_wp.lock();
+
+ if (disasm_sp && operands.size() > 1)
+ {
+ // TODO tie this into the MC Disassembler's notion of clobbers.
+ switch (disasm_sp->GetArchitecture().GetMachine())
+ {
+ default:
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ operands[operands.size() - 1].m_clobbered = true;
+ break;
+ case llvm::Triple::arm:
+ operands[0].m_clobbered = true;
+ break;
+ }
+ }
+
+ if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS))
+ {
+ StreamString ss;
+
+ ss.Printf("[%s] expands to %zu operands:\n", operands_string, operands.size());
+ for (const Operand &operand : operands) {
+ ss.PutCString(" ");
+ DumpOperand(operand, ss);
+ ss.PutCString("\n");
+ }
+
+ log->PutCString(ss.GetData());
+ }
+
+ return true;
+ }
+
+ bool
+ IsCall () override
+ {
+ if (m_is_call == eLazyBoolCalculate)
+ {
+ std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler());
+ if (disasm_sp)
+ {
+ disasm_sp->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 (inst_size == 0)
+ {
+ m_is_call = eLazyBoolNo;
+ }
+ else
+ {
+ if (mc_disasm_ptr->IsCall(inst))
+ m_is_call = eLazyBoolYes;
+ else
+ m_is_call = eLazyBoolNo;
+ }
+ }
+ disasm_sp->Unlock();
+ }
+ }
+ return m_is_call == eLazyBoolYes;
+ }
+
protected:
std::weak_ptr<DisassemblerLLVMC> m_disasm_wp;
LazyBool m_does_branch;
LazyBool m_has_delay_slot;
+ LazyBool m_is_call;
bool m_is_valid;
bool m_using_file_addr;
};
@@ -611,6 +1171,12 @@ DisassemblerLLVMC::LLVMCDisassembler::HasDelaySlot (llvm::MCInst &mc_inst)
return m_instr_info_ap->get(mc_inst.getOpcode()).hasDelaySlot();
}
+bool
+DisassemblerLLVMC::LLVMCDisassembler::IsCall (llvm::MCInst &mc_inst)
+{
+ return m_instr_info_ap->get(mc_inst.getOpcode()).isCall();
+}
+
DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_string) :
Disassembler(arch, flavor_string),
m_exe_ctx (NULL),
diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
index e8f09a4d3ab..f2f54d39399 100644
--- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
+++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
@@ -55,6 +55,7 @@ class DisassemblerLLVMC : public lldb_private::Disassembler
void SetStyle (bool use_hex_immed, HexImmediateStyle hex_style);
bool CanBranch (llvm::MCInst &mc_inst);
bool HasDelaySlot (llvm::MCInst &mc_inst);
+ bool IsCall (llvm::MCInst &mc_inst);
bool IsValid()
{
return m_is_valid;
OpenPOWER on IntegriCloud