summaryrefslogtreecommitdiffstats
path: root/lldb/source/Core/Disassembler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Core/Disassembler.cpp')
-rw-r--r--lldb/source/Core/Disassembler.cpp299
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;
+}
OpenPOWER on IntegriCloud