Fix a memory leak in InstructionLLVMC where it held onto a strong reference to the DisassemblerLLVMC which in turn had a vector of InstructionSP causing the strong cycle. This is fixed now.

Rules are as follows for internal code using lldb::DisassemblerSP and lldb::InstructionSP:
1 - The disassembler needs to stay around as long as instructions do as the Instruction subclass now has a weak pointer to the disassembler
2 - The public API has been fixed so that if you get a SBInstruction, it will hold onto a strong reference to the disassembler in a new InstructionImpl class

This will keep code like like: 

inst = lldb.target.ReadInstructions(frame.GetPCAddress(), 1).GetInstructionAtIndex(0)
inst.GetMnemonic()

Working as expected (not the SBInstructionList() that was returned by SBTarget.ReadInstructions() is gone, but "inst" has a strong reference inside of it to the disassembler and the instruction.
                                                     
All code inside the LLDB shared library was verified to correctly hold onto the disassembler instance in all places.

<rdar://problem/24585496>

llvm-svn: 272069
This commit is contained in:
Greg Clayton 2016-06-07 22:56:40 +00:00
parent cef4360ac4
commit 4a9d83a55e
4 changed files with 398 additions and 304 deletions

View File

@ -18,6 +18,8 @@
// There's a lot to be fixed here, but need to wait for underlying insn implementation
// to be revised & settle down first.
class InstructionImpl;
namespace lldb {
class LLDB_API SBInstruction
@ -81,14 +83,17 @@ public:
protected:
friend class SBInstructionList;
SBInstruction (const lldb::InstructionSP &inst_sp);
SBInstruction(const lldb::DisassemblerSP &disasm_sp, const lldb::InstructionSP &inst_sp);
void
SetOpaque (const lldb::InstructionSP &inst_sp);
SetOpaque(const lldb::DisassemblerSP &disasm_sp, const lldb::InstructionSP& inst_sp);
lldb::InstructionSP
GetOpaque();
private:
lldb::InstructionSP m_opaque_sp;
std::shared_ptr<InstructionImpl> m_opaque_sp;
};

View File

@ -26,15 +26,63 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
//----------------------------------------------------------------------
// We recently fixed a leak in one of the Instruction subclasses where
// the instruction will only hold a weak reference to the disassembler
// to avoid a cycle that was keeping both objects alive (leak) and we
// need the InstructionImpl class to make sure our public API behaves
// as users would expect. Calls in our public API allow clients to do
// things like:
//
// 1 lldb::SBInstruction inst;
// 2 inst = target.ReadInstructions(pc, 1).GetInstructionAtIndex(0)
// 3 if (inst.DoesBranch())
// 4 ...
//
// There was a temporary lldb::DisassemblerSP object created in the
// SBInstructionList that was returned by lldb.target.ReadInstructions()
// that will go away after line 2 but the "inst" object should be able
// to still answer questions about itself. So we make sure that any
// SBInstruction objects that are given out have a strong reference to
// the disassembler and the instruction so that the object can live and
// successfully respond to all queries.
//----------------------------------------------------------------------
class InstructionImpl
{
public:
InstructionImpl (const lldb::DisassemblerSP &disasm_sp, const lldb::InstructionSP& inst_sp) :
m_disasm_sp(disasm_sp),
m_inst_sp(inst_sp)
{
}
lldb::InstructionSP
GetSP() const
{
return m_inst_sp;
}
bool
IsValid() const
{
return (bool)m_inst_sp;
}
protected:
lldb::DisassemblerSP m_disasm_sp; // Can be empty/invalid
lldb::InstructionSP m_inst_sp;
};
using namespace lldb;
using namespace lldb_private;
SBInstruction::SBInstruction ()
SBInstruction::SBInstruction() :
m_opaque_sp()
{
}
SBInstruction::SBInstruction (const lldb::InstructionSP& inst_sp) :
m_opaque_sp (inst_sp)
SBInstruction::SBInstruction(const lldb::DisassemblerSP &disasm_sp, const lldb::InstructionSP& inst_sp) :
m_opaque_sp(new InstructionImpl(disasm_sp, inst_sp))
{
}
@ -58,22 +106,24 @@ SBInstruction::~SBInstruction ()
bool
SBInstruction::IsValid()
{
return (m_opaque_sp.get() != NULL);
return m_opaque_sp && m_opaque_sp->IsValid();
}
SBAddress
SBInstruction::GetAddress()
{
SBAddress sb_addr;
if (m_opaque_sp && m_opaque_sp->GetAddress().IsValid())
sb_addr.SetAddress(&m_opaque_sp->GetAddress());
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp && inst_sp->GetAddress().IsValid())
sb_addr.SetAddress(&inst_sp->GetAddress());
return sb_addr;
}
const char *
SBInstruction::GetMnemonic(SBTarget target)
{
if (m_opaque_sp)
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
{
ExecutionContext exe_ctx;
TargetSP target_sp (target.GetSP());
@ -85,7 +135,7 @@ SBInstruction::GetMnemonic(SBTarget target)
target_sp->CalculateExecutionContext (exe_ctx);
exe_ctx.SetProcessSP(target_sp->GetProcessSP());
}
return m_opaque_sp->GetMnemonic(&exe_ctx);
return inst_sp->GetMnemonic(&exe_ctx);
}
return NULL;
}
@ -93,7 +143,8 @@ SBInstruction::GetMnemonic(SBTarget target)
const char *
SBInstruction::GetOperands(SBTarget target)
{
if (m_opaque_sp)
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
{
ExecutionContext exe_ctx;
TargetSP target_sp (target.GetSP());
@ -105,7 +156,7 @@ SBInstruction::GetOperands(SBTarget target)
target_sp->CalculateExecutionContext (exe_ctx);
exe_ctx.SetProcessSP(target_sp->GetProcessSP());
}
return m_opaque_sp->GetOperands(&exe_ctx);
return inst_sp->GetOperands(&exe_ctx);
}
return NULL;
}
@ -113,7 +164,8 @@ SBInstruction::GetOperands(SBTarget target)
const char *
SBInstruction::GetComment(SBTarget target)
{
if (m_opaque_sp)
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
{
ExecutionContext exe_ctx;
TargetSP target_sp (target.GetSP());
@ -125,7 +177,7 @@ SBInstruction::GetComment(SBTarget target)
target_sp->CalculateExecutionContext (exe_ctx);
exe_ctx.SetProcessSP(target_sp->GetProcessSP());
}
return m_opaque_sp->GetComment(&exe_ctx);
return inst_sp->GetComment(&exe_ctx);
}
return NULL;
}
@ -133,8 +185,9 @@ SBInstruction::GetComment(SBTarget target)
size_t
SBInstruction::GetByteSize ()
{
if (m_opaque_sp)
return m_opaque_sp->GetOpcode().GetByteSize();
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
return inst_sp->GetOpcode().GetByteSize();
return 0;
}
@ -142,10 +195,11 @@ SBData
SBInstruction::GetData (SBTarget target)
{
lldb::SBData sb_data;
if (m_opaque_sp)
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
{
DataExtractorSP data_extractor_sp (new DataExtractor());
if (m_opaque_sp->GetData (*data_extractor_sp))
if (inst_sp->GetData (*data_extractor_sp))
{
sb_data.SetOpaque (data_extractor_sp);
}
@ -158,32 +212,44 @@ SBInstruction::GetData (SBTarget target)
bool
SBInstruction::DoesBranch ()
{
if (m_opaque_sp)
return m_opaque_sp->DoesBranch ();
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
return inst_sp->DoesBranch ();
return false;
}
bool
SBInstruction::HasDelaySlot ()
{
if (m_opaque_sp)
return m_opaque_sp->HasDelaySlot ();
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
return inst_sp->HasDelaySlot ();
return false;
}
void
SBInstruction::SetOpaque (const lldb::InstructionSP &inst_sp)
lldb::InstructionSP
SBInstruction::GetOpaque ()
{
m_opaque_sp = inst_sp;
if (m_opaque_sp)
return m_opaque_sp->GetSP();
else
return lldb::InstructionSP();
}
void
SBInstruction::SetOpaque (const lldb::DisassemblerSP &disasm_sp, const lldb::InstructionSP& inst_sp)
{
m_opaque_sp.reset(new InstructionImpl(disasm_sp, inst_sp));
}
bool
SBInstruction::GetDescription (lldb::SBStream &s)
{
if (m_opaque_sp)
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
{
SymbolContext sc;
const Address &addr = m_opaque_sp->GetAddress();
const Address &addr = inst_sp->GetAddress();
ModuleSP module_sp (addr.GetModule());
if (module_sp)
module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
@ -191,7 +257,7 @@ SBInstruction::GetDescription (lldb::SBStream &s)
// didn't have a stream already created, one will get created...
FormatEntity::Entry format;
FormatEntity::Parse("${addr}: ", format);
m_opaque_sp->Dump (&s.ref(), 0, true, false, NULL, &sc, NULL, &format, 0);
inst_sp->Dump (&s.ref(), 0, true, false, NULL, &sc, NULL, &format, 0);
return true;
}
return false;
@ -203,24 +269,26 @@ SBInstruction::Print (FILE *out)
if (out == NULL)
return;
if (m_opaque_sp)
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
{
SymbolContext sc;
const Address &addr = m_opaque_sp->GetAddress();
const Address &addr = inst_sp->GetAddress();
ModuleSP module_sp (addr.GetModule());
if (module_sp)
module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
StreamFile out_stream (out, false);
FormatEntity::Entry format;
FormatEntity::Parse("${addr}: ", format);
m_opaque_sp->Dump (&out_stream, 0, true, false, NULL, &sc, NULL, &format, 0);
inst_sp->Dump (&out_stream, 0, true, false, NULL, &sc, NULL, &format, 0);
}
}
bool
SBInstruction::EmulateWithFrame (lldb::SBFrame &frame, uint32_t evaluate_options)
{
if (m_opaque_sp)
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
{
lldb::StackFrameSP frame_sp (frame.GetFrameSP());
@ -231,13 +299,13 @@ SBInstruction::EmulateWithFrame (lldb::SBFrame &frame, uint32_t evaluate_options
lldb_private::Target *target = exe_ctx.GetTargetPtr();
lldb_private::ArchSpec arch = target->GetArchitecture();
return m_opaque_sp->Emulate (arch,
evaluate_options,
(void *) frame_sp.get(),
&lldb_private::EmulateInstruction::ReadMemoryFrame,
&lldb_private::EmulateInstruction::WriteMemoryFrame,
&lldb_private::EmulateInstruction::ReadRegisterFrame,
&lldb_private::EmulateInstruction::WriteRegisterFrame);
return inst_sp->Emulate(arch,
evaluate_options,
(void *) frame_sp.get(),
&lldb_private::EmulateInstruction::ReadMemoryFrame,
&lldb_private::EmulateInstruction::WriteMemoryFrame,
&lldb_private::EmulateInstruction::ReadRegisterFrame,
&lldb_private::EmulateInstruction::WriteRegisterFrame);
}
}
return false;
@ -246,29 +314,32 @@ SBInstruction::EmulateWithFrame (lldb::SBFrame &frame, uint32_t evaluate_options
bool
SBInstruction::DumpEmulation (const char *triple)
{
if (m_opaque_sp && triple)
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp && triple)
{
lldb_private::ArchSpec arch (triple, NULL);
return m_opaque_sp->DumpEmulation (arch);
return inst_sp->DumpEmulation (arch);
}
return false;
}
bool
SBInstruction::TestEmulation (lldb::SBStream &output_stream, const char *test_file)
SBInstruction::TestEmulation (lldb::SBStream &output_stream, const char *test_file)
{
if (!m_opaque_sp.get())
m_opaque_sp.reset (new PseudoInstruction());
return m_opaque_sp->TestEmulation (output_stream.get(), test_file);
if (!m_opaque_sp)
SetOpaque(lldb::DisassemblerSP(), lldb::InstructionSP(new PseudoInstruction()));
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
return inst_sp->TestEmulation (output_stream.get(), test_file);
return false;
}
lldb::AddressClass
SBInstruction::GetAddressClass ()
{
if (m_opaque_sp.get())
return m_opaque_sp->GetAddressClass();
lldb::InstructionSP inst_sp(GetOpaque());
if (inst_sp)
return inst_sp->GetAddressClass();
return eAddressClassInvalid;
}

View File

@ -61,7 +61,7 @@ SBInstructionList::GetInstructionAtIndex (uint32_t idx)
{
SBInstruction inst;
if (m_opaque_sp && idx < m_opaque_sp->GetInstructionList().GetSize())
inst.SetOpaque (m_opaque_sp->GetInstructionList().GetInstructionAtIndex (idx));
inst.SetOpaque (m_opaque_sp, m_opaque_sp->GetInstructionList().GetInstructionAtIndex (idx));
return inst;
}

View File

@ -53,7 +53,7 @@ public:
const lldb_private::Address &address,
AddressClass addr_class) :
Instruction (address, addr_class),
m_disasm_sp (disasm.shared_from_this()),
m_disasm_wp (std::static_pointer_cast<DisassemblerLLVMC>(disasm.shared_from_this())),
m_does_branch (eLazyBoolCalculate),
m_has_delay_slot (eLazyBoolCalculate),
m_is_valid (false),
@ -68,34 +68,38 @@ public:
{
if (m_does_branch == eLazyBoolCalculate)
{
GetDisassemblerLLVMC().Lock(this, NULL);
DataExtractor data;
if (m_opcode.GetData(data))
std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler());
if (disasm_sp)
{
bool is_alternate_isa;
lldb::addr_t pc = m_address.GetFileAddress();
DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
const uint8_t *opcode_data = data.GetDataStart();
const size_t opcode_data_len = data.GetByteSize();
llvm::MCInst inst;
const size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
opcode_data_len,
pc,
inst);
// Be conservative, if we didn't understand the instruction, say it might branch...
if (inst_size == 0)
m_does_branch = eLazyBoolYes;
else
disasm_sp->Lock(this, NULL);
DataExtractor data;
if (m_opcode.GetData(data))
{
const bool can_branch = mc_disasm_ptr->CanBranch(inst);
if (can_branch)
bool is_alternate_isa;
lldb::addr_t pc = m_address.GetFileAddress();
DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
const uint8_t *opcode_data = data.GetDataStart();
const size_t opcode_data_len = data.GetByteSize();
llvm::MCInst inst;
const size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
opcode_data_len,
pc,
inst);
// Be conservative, if we didn't understand the instruction, say it might branch...
if (inst_size == 0)
m_does_branch = eLazyBoolYes;
else
m_does_branch = eLazyBoolNo;
{
const bool can_branch = mc_disasm_ptr->CanBranch(inst);
if (can_branch)
m_does_branch = eLazyBoolYes;
else
m_does_branch = eLazyBoolNo;
}
}
disasm_sp->Unlock();
}
GetDisassemblerLLVMC().Unlock();
}
return m_does_branch == eLazyBoolYes;
}
@ -105,34 +109,38 @@ public:
{
if (m_has_delay_slot == eLazyBoolCalculate)
{
GetDisassemblerLLVMC().Lock(this, NULL);
DataExtractor data;
if (m_opcode.GetData(data))
std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler());
if (disasm_sp)
{
bool is_alternate_isa;
lldb::addr_t pc = m_address.GetFileAddress();
DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
const uint8_t *opcode_data = data.GetDataStart();
const size_t opcode_data_len = data.GetByteSize();
llvm::MCInst inst;
const size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
opcode_data_len,
pc,
inst);
// if we didn't understand the instruction, say it doesn't have a delay slot...
if (inst_size == 0)
m_has_delay_slot = eLazyBoolNo;
else
disasm_sp->Lock(this, NULL);
DataExtractor data;
if (m_opcode.GetData(data))
{
const bool has_delay_slot = mc_disasm_ptr->HasDelaySlot(inst);
if (has_delay_slot)
m_has_delay_slot = eLazyBoolYes;
else
bool is_alternate_isa;
lldb::addr_t pc = m_address.GetFileAddress();
DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
const uint8_t *opcode_data = data.GetDataStart();
const size_t opcode_data_len = data.GetByteSize();
llvm::MCInst inst;
const size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
opcode_data_len,
pc,
inst);
// if we didn't understand the instruction, say it doesn't have a delay slot...
if (inst_size == 0)
m_has_delay_slot = eLazyBoolNo;
else
{
const bool has_delay_slot = mc_disasm_ptr->HasDelaySlot(inst);
if (has_delay_slot)
m_has_delay_slot = eLazyBoolYes;
else
m_has_delay_slot = eLazyBoolNo;
}
}
disasm_sp->Unlock();
}
GetDisassemblerLLVMC().Unlock();
}
return m_has_delay_slot == eLazyBoolYes;
}
@ -141,18 +149,22 @@ public:
GetDisasmToUse (bool &is_alternate_isa)
{
is_alternate_isa = false;
DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC();
if (llvm_disasm.m_alternate_disasm_ap.get() != NULL)
std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler());
if (disasm_sp)
{
const AddressClass address_class = GetAddressClass ();
if (address_class == eAddressClassCodeAlternateISA)
if (disasm_sp->m_alternate_disasm_ap.get() != NULL)
{
is_alternate_isa = true;
return llvm_disasm.m_alternate_disasm_ap.get();
const AddressClass address_class = GetAddressClass ();
if (address_class == eAddressClassCodeAlternateISA)
{
is_alternate_isa = true;
return disasm_sp->m_alternate_disasm_ap.get();
}
}
return disasm_sp->m_disasm_ap.get();
}
return llvm_disasm.m_disasm_ap.get();
return nullptr;
}
size_t
@ -163,101 +175,105 @@ public:
// All we have to do is read the opcode which can be easy for some
// architectures
bool got_op = false;
DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC();
const ArchSpec &arch = llvm_disasm.GetArchitecture();
const lldb::ByteOrder byte_order = data.GetByteOrder();
const uint32_t min_op_byte_size = arch.GetMinimumOpcodeByteSize();
const uint32_t max_op_byte_size = arch.GetMaximumOpcodeByteSize();
if (min_op_byte_size == max_op_byte_size)
std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler());
if (disasm_sp)
{
// Fixed size instructions, just read that amount of data.
if (!data.ValidOffsetForDataOfSize(data_offset, min_op_byte_size))
return false;
const ArchSpec &arch = disasm_sp->GetArchitecture();
const lldb::ByteOrder byte_order = data.GetByteOrder();
switch (min_op_byte_size)
const uint32_t min_op_byte_size = arch.GetMinimumOpcodeByteSize();
const uint32_t max_op_byte_size = arch.GetMaximumOpcodeByteSize();
if (min_op_byte_size == max_op_byte_size)
{
case 1:
m_opcode.SetOpcode8 (data.GetU8 (&data_offset), byte_order);
got_op = true;
break;
// Fixed size instructions, just read that amount of data.
if (!data.ValidOffsetForDataOfSize(data_offset, min_op_byte_size))
return false;
case 2:
m_opcode.SetOpcode16 (data.GetU16 (&data_offset), byte_order);
got_op = true;
break;
case 4:
m_opcode.SetOpcode32 (data.GetU32 (&data_offset), byte_order);
got_op = true;
break;
case 8:
m_opcode.SetOpcode64 (data.GetU64 (&data_offset), byte_order);
got_op = true;
break;
default:
m_opcode.SetOpcodeBytes(data.PeekData(data_offset, min_op_byte_size), min_op_byte_size);
got_op = true;
break;
}
}
if (!got_op)
{
bool is_alternate_isa = false;
DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
const llvm::Triple::ArchType machine = arch.GetMachine();
if (machine == llvm::Triple::arm || machine == llvm::Triple::thumb)
{
if (machine == llvm::Triple::thumb || is_alternate_isa)
switch (min_op_byte_size)
{
uint32_t thumb_opcode = data.GetU16(&data_offset);
if ((thumb_opcode & 0xe000) != 0xe000 || ((thumb_opcode & 0x1800u) == 0))
case 1:
m_opcode.SetOpcode8 (data.GetU8 (&data_offset), byte_order);
got_op = true;
break;
case 2:
m_opcode.SetOpcode16 (data.GetU16 (&data_offset), byte_order);
got_op = true;
break;
case 4:
m_opcode.SetOpcode32 (data.GetU32 (&data_offset), byte_order);
got_op = true;
break;
case 8:
m_opcode.SetOpcode64 (data.GetU64 (&data_offset), byte_order);
got_op = true;
break;
default:
m_opcode.SetOpcodeBytes(data.PeekData(data_offset, min_op_byte_size), min_op_byte_size);
got_op = true;
break;
}
}
if (!got_op)
{
bool is_alternate_isa = false;
DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
const llvm::Triple::ArchType machine = arch.GetMachine();
if (machine == llvm::Triple::arm || machine == llvm::Triple::thumb)
{
if (machine == llvm::Triple::thumb || is_alternate_isa)
{
m_opcode.SetOpcode16 (thumb_opcode, byte_order);
m_is_valid = true;
uint32_t thumb_opcode = data.GetU16(&data_offset);
if ((thumb_opcode & 0xe000) != 0xe000 || ((thumb_opcode & 0x1800u) == 0))
{
m_opcode.SetOpcode16 (thumb_opcode, byte_order);
m_is_valid = true;
}
else
{
thumb_opcode <<= 16;
thumb_opcode |= data.GetU16(&data_offset);
m_opcode.SetOpcode16_2 (thumb_opcode, byte_order);
m_is_valid = true;
}
}
else
{
thumb_opcode <<= 16;
thumb_opcode |= data.GetU16(&data_offset);
m_opcode.SetOpcode16_2 (thumb_opcode, byte_order);
m_opcode.SetOpcode32 (data.GetU32(&data_offset), byte_order);
m_is_valid = true;
}
}
else
{
m_opcode.SetOpcode32 (data.GetU32(&data_offset), byte_order);
m_is_valid = true;
}
}
else
{
// The opcode isn't evenly sized, so we need to actually use the llvm
// disassembler to parse it and get the size.
uint8_t *opcode_data = const_cast<uint8_t *>(data.PeekData (data_offset, 1));
const size_t opcode_data_len = data.BytesLeft(data_offset);
const addr_t pc = m_address.GetFileAddress();
llvm::MCInst inst;
// The opcode isn't evenly sized, so we need to actually use the llvm
// disassembler to parse it and get the size.
uint8_t *opcode_data = const_cast<uint8_t *>(data.PeekData (data_offset, 1));
const size_t opcode_data_len = data.BytesLeft(data_offset);
const addr_t pc = m_address.GetFileAddress();
llvm::MCInst inst;
llvm_disasm.Lock(this, NULL);
const size_t inst_size = mc_disasm_ptr->GetMCInst(opcode_data,
opcode_data_len,
pc,
inst);
llvm_disasm.Unlock();
if (inst_size == 0)
m_opcode.Clear();
else
{
m_opcode.SetOpcodeBytes(opcode_data, inst_size);
m_is_valid = true;
disasm_sp->Lock(this, NULL);
const size_t inst_size = mc_disasm_ptr->GetMCInst(opcode_data,
opcode_data_len,
pc,
inst);
disasm_sp->Unlock();
if (inst_size == 0)
m_opcode.Clear();
else
{
m_opcode.SetOpcodeBytes(opcode_data, inst_size);
m_is_valid = true;
}
}
}
return m_opcode.GetByteSize();
}
return m_opcode.GetByteSize();
return 0;
}
void
@ -283,146 +299,148 @@ public:
std::string out_string;
std::string comment_string;
DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC();
DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr;
if (address_class == eAddressClassCodeAlternateISA)
mc_disasm_ptr = llvm_disasm.m_alternate_disasm_ap.get();
else
mc_disasm_ptr = llvm_disasm.m_disasm_ap.get();
lldb::addr_t pc = m_address.GetFileAddress();
m_using_file_addr = true;
const bool data_from_file = GetDisassemblerLLVMC().m_data_from_file;
bool use_hex_immediates = true;
Disassembler::HexImmediateStyle hex_style = Disassembler::eHexStyleC;
if (exe_ctx)
std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler());
if (disasm_sp)
{
Target *target = exe_ctx->GetTargetPtr();
if (target)
{
use_hex_immediates = target->GetUseHexImmediates();
hex_style = target->GetHexImmediateStyle();
DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr;
if (!data_from_file)
if (address_class == eAddressClassCodeAlternateISA)
mc_disasm_ptr = disasm_sp->m_alternate_disasm_ap.get();
else
mc_disasm_ptr = disasm_sp->m_disasm_ap.get();
lldb::addr_t pc = m_address.GetFileAddress();
m_using_file_addr = true;
const bool data_from_file = disasm_sp->m_data_from_file;
bool use_hex_immediates = true;
Disassembler::HexImmediateStyle hex_style = Disassembler::eHexStyleC;
if (exe_ctx)
{
Target *target = exe_ctx->GetTargetPtr();
if (target)
{
const lldb::addr_t load_addr = m_address.GetLoadAddress(target);
if (load_addr != LLDB_INVALID_ADDRESS)
use_hex_immediates = target->GetUseHexImmediates();
hex_style = target->GetHexImmediateStyle();
if (!data_from_file)
{
pc = load_addr;
m_using_file_addr = false;
const lldb::addr_t load_addr = m_address.GetLoadAddress(target);
if (load_addr != LLDB_INVALID_ADDRESS)
{
pc = load_addr;
m_using_file_addr = false;
}
}
}
}
}
llvm_disasm.Lock(this, exe_ctx);
disasm_sp->Lock(this, exe_ctx);
const uint8_t *opcode_data = data.GetDataStart();
const size_t opcode_data_len = data.GetByteSize();
llvm::MCInst inst;
size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
opcode_data_len,
pc,
inst);
const uint8_t *opcode_data = data.GetDataStart();
const size_t opcode_data_len = data.GetByteSize();
llvm::MCInst inst;
size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
opcode_data_len,
pc,
inst);
if (inst_size > 0)
{
mc_disasm_ptr->SetStyle(use_hex_immediates, hex_style);
mc_disasm_ptr->PrintMCInst(inst, out_string, comment_string);
if (!comment_string.empty())
if (inst_size > 0)
{
AppendComment(comment_string);
mc_disasm_ptr->SetStyle(use_hex_immediates, hex_style);
mc_disasm_ptr->PrintMCInst(inst, out_string, comment_string);
if (!comment_string.empty())
{
AppendComment(comment_string);
}
}
}
llvm_disasm.Unlock();
disasm_sp->Unlock();
if (inst_size == 0)
{
m_comment.assign ("unknown opcode");
inst_size = m_opcode.GetByteSize();
StreamString mnemonic_strm;
lldb::offset_t offset = 0;
lldb::ByteOrder byte_order = data.GetByteOrder();
switch (inst_size)
if (inst_size == 0)
{
case 1:
{
const uint8_t uval8 = data.GetU8 (&offset);
m_opcode.SetOpcode8 (uval8, byte_order);
m_opcode_name.assign (".byte");
mnemonic_strm.Printf("0x%2.2x", uval8);
}
break;
case 2:
{
const uint16_t uval16 = data.GetU16(&offset);
m_opcode.SetOpcode16(uval16, byte_order);
m_opcode_name.assign (".short");
mnemonic_strm.Printf("0x%4.4x", uval16);
}
break;
case 4:
{
const uint32_t uval32 = data.GetU32(&offset);
m_opcode.SetOpcode32(uval32, byte_order);
m_opcode_name.assign (".long");
mnemonic_strm.Printf("0x%8.8x", uval32);
}
break;
case 8:
{
const uint64_t uval64 = data.GetU64(&offset);
m_opcode.SetOpcode64(uval64, byte_order);
m_opcode_name.assign (".quad");
mnemonic_strm.Printf("0x%16.16" PRIx64, uval64);
}
break;
default:
if (inst_size == 0)
return;
else
{
const uint8_t *bytes = data.PeekData(offset, inst_size);
if (bytes == NULL)
m_comment.assign ("unknown opcode");
inst_size = m_opcode.GetByteSize();
StreamString mnemonic_strm;
lldb::offset_t offset = 0;
lldb::ByteOrder byte_order = data.GetByteOrder();
switch (inst_size)
{
case 1:
{
const uint8_t uval8 = data.GetU8 (&offset);
m_opcode.SetOpcode8 (uval8, byte_order);
m_opcode_name.assign (".byte");
mnemonic_strm.Printf("0x%2.2x", uval8);
}
break;
case 2:
{
const uint16_t uval16 = data.GetU16(&offset);
m_opcode.SetOpcode16(uval16, byte_order);
m_opcode_name.assign (".short");
mnemonic_strm.Printf("0x%4.4x", uval16);
}
break;
case 4:
{
const uint32_t uval32 = data.GetU32(&offset);
m_opcode.SetOpcode32(uval32, byte_order);
m_opcode_name.assign (".long");
mnemonic_strm.Printf("0x%8.8x", uval32);
}
break;
case 8:
{
const uint64_t uval64 = data.GetU64(&offset);
m_opcode.SetOpcode64(uval64, byte_order);
m_opcode_name.assign (".quad");
mnemonic_strm.Printf("0x%16.16" PRIx64, uval64);
}
break;
default:
if (inst_size == 0)
return;
m_opcode_name.assign (".byte");
m_opcode.SetOpcodeBytes(bytes, inst_size);
mnemonic_strm.Printf("0x%2.2x", bytes[0]);
for (uint32_t i=1; i<inst_size; ++i)
mnemonic_strm.Printf(" 0x%2.2x", bytes[i]);
}
break;
else
{
const uint8_t *bytes = data.PeekData(offset, inst_size);
if (bytes == NULL)
return;
m_opcode_name.assign (".byte");
m_opcode.SetOpcodeBytes(bytes, inst_size);
mnemonic_strm.Printf("0x%2.2x", bytes[0]);
for (uint32_t i=1; i<inst_size; ++i)
mnemonic_strm.Printf(" 0x%2.2x", bytes[i]);
}
break;
}
m_mnemonics.swap(mnemonic_strm.GetString());
return;
}
m_mnemonics.swap(mnemonic_strm.GetString());
return;
}
else
{
if (m_does_branch == eLazyBoolCalculate)
else
{
const bool can_branch = mc_disasm_ptr->CanBranch(inst);
if (can_branch)
m_does_branch = eLazyBoolYes;
else
m_does_branch = eLazyBoolNo;
if (m_does_branch == eLazyBoolCalculate)
{
const bool can_branch = mc_disasm_ptr->CanBranch(inst);
if (can_branch)
m_does_branch = eLazyBoolYes;
else
m_does_branch = eLazyBoolNo;
}
}
}
static RegularExpression s_regex("[ \t]*([^ ^\t]+)[ \t]*([^ ^\t].*)?");
static RegularExpression s_regex("[ \t]*([^ ^\t]+)[ \t]*([^ ^\t].*)?");
RegularExpression::Match matches(3);
RegularExpression::Match matches(3);
if (s_regex.Execute(out_string.c_str(), &matches))
{
matches.GetMatchAtIndex(out_string.c_str(), 1, m_opcode_name);
matches.GetMatchAtIndex(out_string.c_str(), 2, m_mnemonics);
if (s_regex.Execute(out_string.c_str(), &matches))
{
matches.GetMatchAtIndex(out_string.c_str(), 1, m_opcode_name);
matches.GetMatchAtIndex(out_string.c_str(), 2, m_mnemonics);
}
}
}
}
@ -444,14 +462,14 @@ public:
return m_opcode.GetByteSize();
}
DisassemblerLLVMC &
GetDisassemblerLLVMC ()
std::shared_ptr<DisassemblerLLVMC>
GetDisassembler ()
{
return *(DisassemblerLLVMC *)m_disasm_sp.get();
return m_disasm_wp.lock();
}
protected:
DisassemblerSP m_disasm_sp; // for ownership
std::weak_ptr<DisassemblerLLVMC> m_disasm_wp;
LazyBool m_does_branch;
LazyBool m_has_delay_slot;
bool m_is_valid;