summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp')
-rw-r--r--lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp468
1 files changed, 468 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp
new file mode 100644
index 00000000000..db2d561b24a
--- /dev/null
+++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp
@@ -0,0 +1,468 @@
+//===-- DisassemblerLLVM.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DisassemblerLLVM.h"
+
+#include "llvm-c/EnhancedDisassembly.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+
+#include <memory>
+#include <string>
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static
+int DataExtractorByteReader(uint8_t *byte, uint64_t address, void *arg)
+{
+ DataExtractor &extractor = *((DataExtractor *)arg);
+
+ if (extractor.ValidOffset(address))
+ {
+ *byte = *(extractor.GetDataStart() + address);
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+namespace {
+ struct RegisterReaderArg {
+ const lldb::addr_t instructionPointer;
+ const EDDisassemblerRef disassembler;
+
+ RegisterReaderArg(lldb::addr_t ip,
+ EDDisassemblerRef dis) :
+ instructionPointer(ip),
+ disassembler(dis)
+ {
+ }
+ };
+}
+
+static int IPRegisterReader(uint64_t *value, unsigned regID, void* arg)
+{
+ uint64_t instructionPointer = ((RegisterReaderArg*)arg)->instructionPointer;
+ EDDisassemblerRef disassembler = ((RegisterReaderArg*)arg)->disassembler;
+
+ if(EDRegisterIsProgramCounter(disassembler, regID)) {
+ *value = instructionPointer;
+ return 0;
+ }
+
+ return -1;
+}
+
+DisassemblerLLVM::Instruction::Instruction(EDDisassemblerRef disassembler) :
+ Disassembler::Instruction (),
+ m_disassembler (disassembler)
+{
+}
+
+DisassemblerLLVM::Instruction::~Instruction()
+{
+}
+
+static void
+PadString(Stream *s, const std::string &str, size_t width)
+{
+ int diff = width - str.length();
+
+ if (diff > 0)
+ s->Printf("%s%*.*s", str.c_str(), diff, diff, "");
+ else
+ s->Printf("%s ", str.c_str());
+}
+
+void
+DisassemblerLLVM::Instruction::Dump
+(
+ Stream *s,
+ lldb::addr_t base_address,
+ DataExtractor *bytes,
+ uint32_t bytes_offset,
+ const lldb_private::ExecutionContext exe_ctx,
+ bool raw
+)
+{
+ const size_t opcodeColumnWidth = 7;
+ const size_t operandColumnWidth = 25;
+
+ // If we have an address, print it out
+ if (base_address != LLDB_INVALID_ADDRESS)
+ s->Printf("0x%llx: ", base_address);
+
+ // If we are supposed to show bytes, "bytes" will be non-NULL.
+ if (bytes)
+ {
+ uint32_t bytes_dumped = bytes->Dump(s, bytes_offset, eFormatBytes, 1, EDInstByteSize(m_inst), UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0) - bytes_offset;
+ // Allow for 8 bytes of opcodes normally
+ const uint32_t default_num_opcode_bytes = 9;
+ if (bytes_dumped * 3 < (default_num_opcode_bytes*3))
+ {
+ uint32_t indent_level = (default_num_opcode_bytes*3) - (bytes_dumped * 3);
+ s->Printf("%*.*s", indent_level, indent_level, "");
+ }
+ }
+
+ int numTokens = EDNumTokens(m_inst);
+
+ int currentOpIndex = -1;
+
+ RegisterReaderArg rra(base_address + EDInstByteSize(m_inst), m_disassembler);
+
+ lldb_private::Process *process = exe_ctx.process;
+
+ bool printTokenized = false;
+
+ if (numTokens != -1)
+ {
+ printTokenized = true;
+
+ // Handle the opcode column.
+
+ StreamString opcode;
+
+ int tokenIndex = 0;
+
+ EDTokenRef token;
+ const char *tokenStr;
+
+ if (EDGetToken(&token, m_inst, tokenIndex))
+ printTokenized = false;
+
+ if (!printTokenized || !EDTokenIsOpcode(token))
+ printTokenized = false;
+
+ if (!printTokenized || EDGetTokenString(&tokenStr, token))
+ printTokenized = false;
+
+ // Put the token string into our opcode string
+ opcode.PutCString(tokenStr);
+
+ // If anything follows, it probably starts with some whitespace. Skip it.
+
+ tokenIndex++;
+
+ if (printTokenized && tokenIndex < numTokens)
+ {
+ if(!printTokenized || EDGetToken(&token, m_inst, tokenIndex))
+ printTokenized = false;
+
+ if(!printTokenized || !EDTokenIsWhitespace(token))
+ printTokenized = false;
+ }
+
+ tokenIndex++;
+
+ // Handle the operands and the comment.
+
+ StreamString operands;
+ StreamString comment;
+
+ if (printTokenized)
+ {
+ bool show_token;
+
+ for (; tokenIndex < numTokens; ++tokenIndex)
+ {
+ if (EDGetToken(&token, m_inst, tokenIndex))
+ return;
+
+ if (raw)
+ {
+ show_token = true;
+ }
+ else
+ {
+ int operandIndex = EDOperandIndexForToken(token);
+
+ if (operandIndex >= 0)
+ {
+ if (operandIndex != currentOpIndex)
+ {
+ show_token = true;
+
+ currentOpIndex = operandIndex;
+ EDOperandRef operand;
+
+ if (!EDGetOperand(&operand, m_inst, currentOpIndex))
+ {
+ if (EDOperandIsMemory(operand))
+ {
+ uint64_t operand_value;
+
+ if (!EDEvaluateOperand(&operand_value, operand, IPRegisterReader, &rra))
+ {
+ if (EDInstIsBranch(m_inst))
+ {
+ operands.Printf("0x%llx ", operand_value);
+ show_token = false;
+ }
+ else
+ {
+ // Put the address value into the comment
+ comment.Printf("0x%llx ", operand_value);
+ }
+
+ lldb_private::Address so_addr;
+ if (process)
+ {
+ if (process->ResolveLoadAddress(operand_value, so_addr))
+ {
+ so_addr.Dump(&comment, process, Address::DumpStyleResolvedDescription, Address::DumpStyleSectionNameOffset);
+ }
+ }
+ } // EDEvaluateOperand
+ } // EDOperandIsMemory
+ } // EDGetOperand
+ } // operandIndex != currentOpIndex
+ } // operandIndex >= 0
+ } // else(raw)
+
+ if (show_token)
+ {
+ if(EDGetTokenString(&tokenStr, token))
+ {
+ printTokenized = false;
+ break;
+ }
+
+ operands.PutCString(tokenStr);
+ }
+ } // for (tokenIndex)
+
+ if (printTokenized)
+ {
+ if (operands.GetString().empty())
+ {
+ s->PutCString(opcode.GetString().c_str());
+ }
+ else
+ {
+ PadString(s, opcode.GetString(), opcodeColumnWidth);
+
+ if (comment.GetString().empty())
+ {
+ s->PutCString(operands.GetString().c_str());
+ }
+ else
+ {
+ PadString(s, operands.GetString(), operandColumnWidth);
+
+ s->PutCString("; ");
+ s->PutCString(comment.GetString().c_str());
+ } // else (comment.GetString().empty())
+ } // else (operands.GetString().empty())
+ } // printTokenized
+ } // for (tokenIndex)
+ } // numTokens != -1
+
+ if (!printTokenized)
+ {
+ const char *str;
+
+ if (EDGetInstString(&str, m_inst))
+ return;
+ else
+ s->PutCString(str);
+ }
+}
+
+bool
+DisassemblerLLVM::Instruction::DoesBranch() const
+{
+ return EDInstIsBranch(m_inst);
+}
+
+size_t
+DisassemblerLLVM::Instruction::GetByteSize() const
+{
+ return EDInstByteSize(m_inst);
+}
+
+size_t
+DisassemblerLLVM::Instruction::Extract(const DataExtractor &data, uint32_t data_offset)
+{
+ if (EDCreateInsts(&m_inst, 1, m_disassembler, DataExtractorByteReader, data_offset, (void*)(&data)))
+ return EDInstByteSize(m_inst);
+ else
+ return 0;
+}
+
+static inline const char *
+TripleForCPU(cpu_type_t cpuType)
+{
+ switch (cpuType)
+ {
+ default:
+ return NULL;
+ case CPU_TYPE_X86:
+ return "i386-unknown-unknown";
+ case CPU_TYPE_X86_64:
+ return "x86_64-unknown-unknown";
+ }
+}
+
+static inline EDAssemblySyntax_t
+SyntaxForCPU(cpu_type_t cpuType)
+{
+ switch (cpuType)
+ {
+ default:
+ return (EDAssemblySyntax_t)0; // default
+ case CPU_TYPE_X86:
+ case CPU_TYPE_X86_64:
+ return kEDAssemblySyntaxX86ATT;
+ }
+}
+
+Disassembler *
+DisassemblerLLVM::CreateInstance(const ArchSpec &arch)
+{
+ cpu_type_t cpuType = arch.GetCPUType();
+
+ if (TripleForCPU(cpuType))
+ return new DisassemblerLLVM(arch);
+ else
+ return NULL;
+}
+
+DisassemblerLLVM::DisassemblerLLVM(const ArchSpec &arch) :
+ Disassembler(arch)
+{
+ cpu_type_t cpuType = arch.GetCPUType();
+
+ const char *triple = TripleForCPU(cpuType);
+ assert(triple && "Unhandled CPU type!");
+
+ EDAssemblySyntax_t syntax = SyntaxForCPU(cpuType);
+
+ assert(!EDGetDisassembler(&m_disassembler, triple, syntax) && "No disassembler created!");
+}
+
+DisassemblerLLVM::~DisassemblerLLVM()
+{
+}
+
+size_t
+DisassemblerLLVM::ParseInstructions
+(
+ const DataExtractor& data,
+ uint32_t data_offset,
+ uint32_t num_instructions,
+ lldb::addr_t base_addr
+)
+{
+ size_t total_inst_byte_size = 0;
+
+ m_instruction_list.Clear();
+
+ while (data.ValidOffset(data_offset) && num_instructions)
+ {
+ Instruction::shared_ptr inst_sp (new Instruction(m_disassembler));
+
+ size_t inst_byte_size = inst_sp->Extract(data, data_offset);
+
+ if (inst_byte_size == 0)
+ break;
+
+ m_instruction_list.AppendInstruction(inst_sp);
+
+ total_inst_byte_size += inst_byte_size;
+ data_offset += inst_byte_size;
+ num_instructions--;
+ }
+
+ return total_inst_byte_size;
+}
+
+void
+DisassemblerLLVM::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DisassemblerLLVM::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+DisassemblerLLVM::GetPluginNameStatic()
+{
+ return "disassembler.llvm";
+}
+
+const char *
+DisassemblerLLVM::GetPluginDescriptionStatic()
+{
+ return "Disassembler that uses LLVM opcode tables to disassemble i386 and x86_64.";
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+DisassemblerLLVM::GetPluginName()
+{
+ return "DisassemblerLLVM";
+}
+
+const char *
+DisassemblerLLVM::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DisassemblerLLVM::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+DisassemblerLLVM::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+DisassemblerLLVM::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+DisassemblerLLVM::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
+
OpenPOWER on IntegriCloud