forked from OSchip/llvm-project
300 lines
9.6 KiB
C++
300 lines
9.6 KiB
C++
//===-- 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;
|
|
}
|