diff options
Diffstat (limited to 'lldb/source/Core/Disassembler.cpp')
-rw-r--r-- | lldb/source/Core/Disassembler.cpp | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp new file mode 100644 index 00000000000..570ff726225 --- /dev/null +++ b/lldb/source/Core/Disassembler.cpp @@ -0,0 +1,299 @@ +//===-- Disassembler.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/Disassembler.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Timer.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" + +#define DEFAULT_DISASM_BYTE_SIZE 32 + +using namespace lldb; +using namespace lldb_private; + + +Disassembler* +Disassembler::FindPlugin (const ArchSpec &arch) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "Disassembler::FindPlugin (arch = %s)", + arch.AsCString()); + + std::auto_ptr<Disassembler> disassembler_ap; + DisassemblerCreateInstance create_callback; + for (uint32_t idx = 0; (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(idx)) != NULL; ++idx) + { + disassembler_ap.reset (create_callback(arch)); + + if (disassembler_ap.get()) + return disassembler_ap.release(); + } + return NULL; +} + +bool +Disassembler::Disassemble +( + const ArchSpec &arch, + const ExecutionContext &exe_ctx, + uint32_t mixed_context_lines, + Stream &strm +) +{ + Disassembler *disassembler = Disassembler::FindPlugin(arch); + + if (disassembler) + { + lldb::addr_t addr = LLDB_INVALID_ADDRESS; + size_t byte_size = 0; + if (exe_ctx.frame) + { + SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); + if (sc.function) + { + addr = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(exe_ctx.process); + if (addr != LLDB_INVALID_ADDRESS) + byte_size = sc.function->GetAddressRange().GetByteSize(); + } + else if (sc.symbol && sc.symbol->GetAddressRangePtr()) + { + addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(exe_ctx.process); + if (addr != LLDB_INVALID_ADDRESS) + { + byte_size = sc.symbol->GetAddressRangePtr()->GetByteSize(); + if (byte_size == 0) + byte_size = DEFAULT_DISASM_BYTE_SIZE; + } + } + else + { + addr = exe_ctx.frame->GetPC().GetLoadAddress(exe_ctx.process); + if (addr != LLDB_INVALID_ADDRESS) + byte_size = DEFAULT_DISASM_BYTE_SIZE; + } + } + + if (byte_size) + { + DataExtractor data; + size_t bytes_disassembled = disassembler->ParseInstructions (&exe_ctx, eAddressTypeLoad, addr, byte_size, data); + if (bytes_disassembled == 0) + { + return false; + } + else + { + // We got some things disassembled... + size_t num_instructions = disassembler->GetInstructionList().GetSize(); + uint32_t offset = 0; + SymbolContext sc; + SymbolContext prev_sc; + AddressRange sc_range; + if (mixed_context_lines) + strm.IndentMore (); + + for (size_t i=0; i<num_instructions; ++i) + { + Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i); + if (inst) + { + lldb::addr_t curr_addr = addr + offset; + if (mixed_context_lines) + { + if (!sc_range.ContainsLoadAddress (curr_addr, exe_ctx.process)) + { + prev_sc = sc; + Address curr_so_addr; + Process *process = exe_ctx.process; + if (process && process->ResolveLoadAddress (curr_addr, curr_so_addr)) + { + if (curr_so_addr.GetSection()) + { + Module *module = curr_so_addr.GetSection()->GetModule(); + uint32_t resolved_mask = module->ResolveSymbolContextForAddress(curr_so_addr, eSymbolContextEverything, sc); + if (resolved_mask) + { + sc.GetAddressRange (eSymbolContextEverything, sc_range); + if (sc != prev_sc) + { + if (offset != 0) + strm.EOL(); + + sc.DumpStopContext(&strm, process, curr_so_addr); + + if (sc.comp_unit && sc.line_entry.IsValid()) + { + Debugger::GetSharedInstance().GetSourceManager().DisplaySourceLinesWithLineNumbers ( + sc.line_entry.file, + sc.line_entry.line, + mixed_context_lines, + mixed_context_lines, + mixed_context_lines ? "->" : "", + &strm); + } + } + } + } + } + } + } + if (mixed_context_lines) + strm.IndentMore (); + strm.Indent(); + size_t inst_byte_size = inst->GetByteSize(); + //inst->Dump(&strm, curr_addr, &data, offset); // Do dump opcode bytes + inst->Dump(&strm, curr_addr, NULL, offset, exe_ctx, false); // Don't dump opcode bytes + strm.EOL(); + offset += inst_byte_size; + if (mixed_context_lines) + strm.IndentLess (); + } + else + { + break; + } + } + if (mixed_context_lines) + strm.IndentLess (); + + } + } + return true; + } + return false; +} + +Disassembler::Instruction::Instruction() +{ +} + +Disassembler::Instruction::~Instruction() +{ +} + + +Disassembler::InstructionList::InstructionList() : + m_instructions() +{ +} + +Disassembler::InstructionList::~InstructionList() +{ +} + +size_t +Disassembler::InstructionList::GetSize() const +{ + return m_instructions.size(); +} + + +Disassembler::Instruction * +Disassembler::InstructionList::GetInstructionAtIndex (uint32_t idx) +{ + if (idx < m_instructions.size()) + return m_instructions[idx].get(); + return NULL; +} + +const Disassembler::Instruction * +Disassembler::InstructionList::GetInstructionAtIndex (uint32_t idx) const +{ + if (idx < m_instructions.size()) + return m_instructions[idx].get(); + return NULL; +} + +void +Disassembler::InstructionList::Clear() +{ + m_instructions.clear(); +} + +void +Disassembler::InstructionList::AppendInstruction (Instruction::shared_ptr &inst_sp) +{ + if (inst_sp) + m_instructions.push_back(inst_sp); +} + + +size_t +Disassembler::ParseInstructions +( + const ExecutionContext *exe_ctx, + lldb::AddressType addr_type, + lldb::addr_t addr, + size_t byte_size, + DataExtractor& data +) +{ + Process *process = exe_ctx->process; + + if (process == NULL) + return 0; + + DataBufferSP data_sp(new DataBufferHeap (byte_size, '\0')); + + Error error; + if (process->GetTarget().ReadMemory (addr_type, addr, data_sp->GetBytes(), data_sp->GetByteSize(), error, NULL)) + { + data.SetData(data_sp); + data.SetByteOrder(process->GetByteOrder()); + data.SetAddressByteSize(process->GetAddressByteSize()); + return ParseInstructions (data, 0, UINT32_MAX, addr); + } + + return 0; +} + +//---------------------------------------------------------------------- +// Disassembler copy constructor +//---------------------------------------------------------------------- +Disassembler::Disassembler(const ArchSpec& arch) : + m_arch (arch), + m_instruction_list(), + m_base_addr(LLDB_INVALID_ADDRESS) +{ + +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +Disassembler::~Disassembler() +{ +} + +Disassembler::InstructionList & +Disassembler::GetInstructionList () +{ + return m_instruction_list; +} + +const Disassembler::InstructionList & +Disassembler::GetInstructionList () const +{ + return m_instruction_list; +} |