diff options
Diffstat (limited to 'lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp')
-rw-r--r-- | lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp | 468 |
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; +} + |