Files
llvm/lldb/source/Core/EmulateInstruction.cpp
Greg Clayton 31f1d2f535 Moved all code from ArchDefaultUnwindPlan and ArchVolatileRegs into their
respective ABI plugins as they were plug-ins that supplied ABI specfic info.

Also hookep up the UnwindAssemblyInstEmulation so that it can generate the
unwind plans for ARM.

Changed the way ABI plug-ins are handed out when you get an instance from
the plug-in manager. They used to return pointers that would be mananged
individually by each client that requested them, but now they are handed out
as shared pointers since there is no state in the ABI objects, they can be
shared.

llvm-svn: 131193
2011-05-11 18:39:18 +00:00

682 lines
21 KiB
C++

//===-- EmulateInstruction.h ------------------------------------*- 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/EmulateInstruction.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
using namespace lldb;
using namespace lldb_private;
EmulateInstruction*
EmulateInstruction::FindPlugin (const ArchSpec &arch, InstructionType supported_inst_type, const char *plugin_name)
{
EmulateInstructionCreateInstance create_callback = NULL;
if (plugin_name)
{
create_callback = PluginManager::GetEmulateInstructionCreateCallbackForPluginName (plugin_name);
if (create_callback)
{
EmulateInstruction *emulate_insn_ptr = create_callback(arch, supported_inst_type);
if (emulate_insn_ptr)
return emulate_insn_ptr;
}
}
else
{
for (uint32_t idx = 0; (create_callback = PluginManager::GetEmulateInstructionCreateCallbackAtIndex(idx)) != NULL; ++idx)
{
EmulateInstruction *emulate_insn_ptr = create_callback(arch, supported_inst_type);
if (emulate_insn_ptr)
return emulate_insn_ptr;
}
}
return NULL;
}
EmulateInstruction::EmulateInstruction (const ArchSpec &arch) :
m_arch (arch),
m_baton (NULL),
m_read_mem_callback (&ReadMemoryDefault),
m_write_mem_callback (&WriteMemoryDefault),
m_read_reg_callback (&ReadRegisterDefault),
m_write_reg_callback (&WriteRegisterDefault),
m_addr (LLDB_INVALID_ADDRESS)
{
::memset (&m_opcode, 0, sizeof (m_opcode));
}
bool
EmulateInstruction::ReadRegister (const RegisterInfo *reg_info, RegisterValue& reg_value)
{
if (m_read_reg_callback)
return m_read_reg_callback (this, m_baton, reg_info, reg_value);
return false;
}
bool
EmulateInstruction::ReadRegister (uint32_t reg_kind, uint32_t reg_num, RegisterValue& reg_value)
{
RegisterInfo reg_info;
if (GetRegisterInfo(reg_kind, reg_num, reg_info))
return ReadRegister (&reg_info, reg_value);
return false;
}
uint64_t
EmulateInstruction::ReadRegisterUnsigned (uint32_t reg_kind,
uint32_t reg_num,
uint64_t fail_value,
bool *success_ptr)
{
RegisterValue reg_value;
if (ReadRegister (reg_kind, reg_num, reg_value))
return reg_value.GetAsUInt64(fail_value, success_ptr);
if (success_ptr)
*success_ptr = false;
return fail_value;
}
uint64_t
EmulateInstruction::ReadRegisterUnsigned (const RegisterInfo *reg_info,
uint64_t fail_value,
bool *success_ptr)
{
RegisterValue reg_value;
if (ReadRegister (reg_info, reg_value))
return reg_value.GetAsUInt64(fail_value, success_ptr);
if (success_ptr)
*success_ptr = false;
return fail_value;
}
bool
EmulateInstruction::WriteRegister (const Context &context,
const RegisterInfo *reg_info,
const RegisterValue& reg_value)
{
if (m_write_reg_callback)
return m_write_reg_callback (this, m_baton, context, reg_info, reg_value);
return false;
}
bool
EmulateInstruction::WriteRegister (const Context &context,
uint32_t reg_kind,
uint32_t reg_num,
const RegisterValue& reg_value)
{
RegisterInfo reg_info;
if (GetRegisterInfo(reg_kind, reg_num, reg_info))
return WriteRegister (context, &reg_info, reg_value);
return false;
}
bool
EmulateInstruction::WriteRegisterUnsigned (const Context &context,
uint32_t reg_kind,
uint32_t reg_num,
uint64_t uint_value)
{
RegisterInfo reg_info;
if (GetRegisterInfo(reg_kind, reg_num, reg_info))
{
RegisterValue reg_value;
if (reg_value.SetUInt(uint_value, reg_info.byte_size))
return WriteRegister (context, &reg_info, reg_value);
}
return false;
}
bool
EmulateInstruction::WriteRegisterUnsigned (const Context &context,
const RegisterInfo *reg_info,
uint64_t uint_value)
{
if (reg_info)
{
RegisterValue reg_value;
if (reg_value.SetUInt(uint_value, reg_info->byte_size))
return WriteRegister (context, reg_info, reg_value);
}
return false;
}
size_t
EmulateInstruction::ReadMemory (const Context &context,
lldb::addr_t addr,
void *dst,
size_t dst_len)
{
if (m_read_mem_callback)
return m_read_mem_callback (this, m_baton, context, addr, dst, dst_len) == dst_len;
return false;
}
uint64_t
EmulateInstruction::ReadMemoryUnsigned (const Context &context, lldb::addr_t addr, size_t byte_size, uint64_t fail_value, bool *success_ptr)
{
uint64_t uval64 = 0;
bool success = false;
if (byte_size <= 8)
{
uint8_t buf[sizeof(uint64_t)];
size_t bytes_read = m_read_mem_callback (this, m_baton, context, addr, buf, byte_size);
if (bytes_read == byte_size)
{
uint32_t offset = 0;
DataExtractor data (buf, byte_size, GetByteOrder(), GetAddressByteSize());
uval64 = data.GetMaxU64 (&offset, byte_size);
success = true;
}
}
if (success_ptr)
*success_ptr = success;
if (!success)
uval64 = fail_value;
return uval64;
}
bool
EmulateInstruction::WriteMemoryUnsigned (const Context &context,
lldb::addr_t addr,
uint64_t uval,
size_t uval_byte_size)
{
StreamString strm(Stream::eBinary, GetAddressByteSize(), GetByteOrder());
strm.PutMaxHex64 (uval, uval_byte_size);
size_t bytes_written = m_write_mem_callback (this, m_baton, context, addr, strm.GetData(), uval_byte_size);
if (bytes_written == uval_byte_size)
return true;
return false;
}
bool
EmulateInstruction::WriteMemory (const Context &context,
lldb::addr_t addr,
const void *src,
size_t src_len)
{
if (m_write_mem_callback)
return m_write_mem_callback (this, m_baton, context, addr, src, src_len) == src_len;
return false;
}
void
EmulateInstruction::SetBaton (void *baton)
{
m_baton = baton;
}
void
EmulateInstruction::SetCallbacks (ReadMemoryCallback read_mem_callback,
WriteMemoryCallback write_mem_callback,
ReadRegisterCallback read_reg_callback,
WriteRegisterCallback write_reg_callback)
{
m_read_mem_callback = read_mem_callback;
m_write_mem_callback = write_mem_callback;
m_read_reg_callback = read_reg_callback;
m_write_reg_callback = write_reg_callback;
}
void
EmulateInstruction::SetReadMemCallback (ReadMemoryCallback read_mem_callback)
{
m_read_mem_callback = read_mem_callback;
}
void
EmulateInstruction::SetWriteMemCallback (WriteMemoryCallback write_mem_callback)
{
m_write_mem_callback = write_mem_callback;
}
void
EmulateInstruction::SetReadRegCallback (ReadRegisterCallback read_reg_callback)
{
m_read_reg_callback = read_reg_callback;
}
void
EmulateInstruction::SetWriteRegCallback (WriteRegisterCallback write_reg_callback)
{
m_write_reg_callback = write_reg_callback;
}
//
// Read & Write Memory and Registers callback functions.
//
size_t
EmulateInstruction::ReadMemoryFrame (EmulateInstruction *instruction,
void *baton,
const Context &context,
lldb::addr_t addr,
void *dst,
size_t length)
{
if (!baton)
return 0;
StackFrame *frame = (StackFrame *) baton;
DataBufferSP data_sp (new DataBufferHeap (length, '\0'));
Error error;
size_t bytes_read = frame->GetThread().GetProcess().ReadMemory (addr, data_sp->GetBytes(), data_sp->GetByteSize(),
error);
if (bytes_read > 0)
((DataBufferHeap *) data_sp.get())->CopyData (dst, length);
return bytes_read;
}
size_t
EmulateInstruction::WriteMemoryFrame (EmulateInstruction *instruction,
void *baton,
const Context &context,
lldb::addr_t addr,
const void *dst,
size_t length)
{
if (!baton)
return 0;
StackFrame *frame = (StackFrame *) baton;
lldb::DataBufferSP data_sp (new DataBufferHeap (dst, length));
if (data_sp)
{
length = data_sp->GetByteSize();
if (length > 0)
{
Error error;
size_t bytes_written = frame->GetThread().GetProcess().WriteMemory (addr, data_sp->GetBytes(), length,
error);
return bytes_written;
}
}
return 0;
}
bool
EmulateInstruction::ReadRegisterFrame (EmulateInstruction *instruction,
void *baton,
const RegisterInfo *reg_info,
RegisterValue &reg_value)
{
if (!baton)
return false;
StackFrame *frame = (StackFrame *) baton;
return frame->GetRegisterContext()->ReadRegister (reg_info, reg_value);
}
bool
EmulateInstruction::WriteRegisterFrame (EmulateInstruction *instruction,
void *baton,
const Context &context,
const RegisterInfo *reg_info,
const RegisterValue &reg_value)
{
if (!baton)
return false;
StackFrame *frame = (StackFrame *) baton;
return frame->GetRegisterContext()->WriteRegister (reg_info, reg_value);
}
size_t
EmulateInstruction::ReadMemoryDefault (EmulateInstruction *instruction,
void *baton,
const Context &context,
lldb::addr_t addr,
void *dst,
size_t length)
{
StreamFile strm (stdout, false);
strm.Printf (" Read from Memory (address = 0x%llx, length = %zu, context = ", addr, length);
context.Dump (strm, instruction);
strm.EOL();
*((uint64_t *) dst) = 0xdeadbeef;
return length;
}
size_t
EmulateInstruction::WriteMemoryDefault (EmulateInstruction *instruction,
void *baton,
const Context &context,
lldb::addr_t addr,
const void *dst,
size_t length)
{
StreamFile strm (stdout, false);
strm.Printf (" Write to Memory (address = 0x%llx, length = %zu, context = ", addr, length);
context.Dump (strm, instruction);
strm.EOL();
return length;
}
bool
EmulateInstruction::ReadRegisterDefault (EmulateInstruction *instruction,
void *baton,
const RegisterInfo *reg_info,
RegisterValue &reg_value)
{
StreamFile strm (stdout, false);
strm.Printf (" Read Register (%s)\n", reg_info->name);
uint32_t reg_kind, reg_num;
if (GetBestRegisterKindAndNumber (reg_info, reg_kind, reg_num))
reg_value.SetUInt64((uint64_t)reg_kind << 24 | reg_num);
else
reg_value.SetUInt64(0);
return true;
}
bool
EmulateInstruction::WriteRegisterDefault (EmulateInstruction *instruction,
void *baton,
const Context &context,
const RegisterInfo *reg_info,
const RegisterValue &reg_value)
{
StreamFile strm (stdout, false);
strm.Printf (" Write to Register (name = %s, value = " , reg_info->name);
reg_value.Dump(&strm, reg_info, false);
strm.PutCString (", context = ");
context.Dump (strm, instruction);
strm.EOL();
return true;
}
void
EmulateInstruction::Context::Dump (Stream &strm,
EmulateInstruction *instruction) const
{
switch (type)
{
case eContextReadOpcode:
strm.PutCString ("reading opcode");
break;
case eContextImmediate:
strm.PutCString ("immediate");
break;
case eContextPushRegisterOnStack:
strm.PutCString ("push register");
break;
case eContextPopRegisterOffStack:
strm.PutCString ("pop register");
break;
case eContextAdjustStackPointer:
strm.PutCString ("adjust sp");
break;
case eContextAdjustBaseRegister:
strm.PutCString ("adjusting (writing value back to) a base register");
break;
case eContextRegisterPlusOffset:
strm.PutCString ("register + offset");
break;
case eContextRegisterStore:
strm.PutCString ("store register");
break;
case eContextRegisterLoad:
strm.PutCString ("load register");
break;
case eContextRelativeBranchImmediate:
strm.PutCString ("relative branch immediate");
break;
case eContextAbsoluteBranchRegister:
strm.PutCString ("absolute branch register");
break;
case eContextSupervisorCall:
strm.PutCString ("supervisor call");
break;
case eContextTableBranchReadMemory:
strm.PutCString ("table branch read memory");
break;
case eContextWriteRegisterRandomBits:
strm.PutCString ("write random bits to a register");
break;
case eContextWriteMemoryRandomBits:
strm.PutCString ("write random bits to a memory address");
break;
case eContextArithmetic:
strm.PutCString ("arithmetic");
break;
case eContextReturnFromException:
strm.PutCString ("return from exception");
break;
default:
strm.PutCString ("unrecognized context.");
break;
}
switch (info_type)
{
case eInfoTypeRegisterPlusOffset:
{
strm.Printf (" (reg_plus_offset = %s%+lld)",
info.RegisterPlusOffset.reg.name,
info.RegisterPlusOffset.signed_offset);
}
break;
case eInfoTypeRegisterPlusIndirectOffset:
{
strm.Printf (" (reg_plus_reg = %s + %s)",
info.RegisterPlusIndirectOffset.base_reg.name,
info.RegisterPlusIndirectOffset.offset_reg.name);
}
break;
case eInfoTypeRegisterToRegisterPlusOffset:
{
strm.Printf (" (base_and_imm_offset = %s%+lld, data_reg = %s)",
info.RegisterToRegisterPlusOffset.base_reg.name,
info.RegisterToRegisterPlusOffset.offset,
info.RegisterToRegisterPlusOffset.data_reg.name);
}
break;
case eInfoTypeRegisterToRegisterPlusIndirectOffset:
{
strm.Printf (" (base_and_reg_offset = %s + %s, data_reg = %s)",
info.RegisterToRegisterPlusIndirectOffset.base_reg.name,
info.RegisterToRegisterPlusIndirectOffset.offset_reg.name,
info.RegisterToRegisterPlusIndirectOffset.data_reg.name);
}
break;
case eInfoTypeRegisterRegisterOperands:
{
strm.Printf (" (register to register binary op: %s and %s)",
info.RegisterRegisterOperands.operand1.name,
info.RegisterRegisterOperands.operand2.name);
}
break;
case eInfoTypeOffset:
strm.Printf (" (signed_offset = %+lld)", info.signed_offset);
break;
case eInfoTypeRegister:
strm.Printf (" (reg = %s)", info.reg.name);
break;
case eInfoTypeImmediate:
strm.Printf (" (unsigned_immediate = %llu (0x%16.16llx))",
info.unsigned_immediate,
info.unsigned_immediate);
break;
case eInfoTypeImmediateSigned:
strm.Printf (" (signed_immediate = %+lld (0x%16.16llx))",
info.signed_immediate,
info.signed_immediate);
break;
case eInfoTypeAddress:
strm.Printf (" (address = 0x%llx)", info.address);
break;
case eInfoTypeISAAndImmediate:
strm.Printf (" (isa = %u, unsigned_immediate = %u (0x%8.8x))",
info.ISAAndImmediate.isa,
info.ISAAndImmediate.unsigned_data32,
info.ISAAndImmediate.unsigned_data32);
break;
case eInfoTypeISAAndImmediateSigned:
strm.Printf (" (isa = %u, signed_immediate = %i (0x%8.8x))",
info.ISAAndImmediateSigned.isa,
info.ISAAndImmediateSigned.signed_data32,
info.ISAAndImmediateSigned.signed_data32);
break;
case eInfoTypeISA:
strm.Printf (" (isa = %u)", info.isa);
break;
case eInfoTypeNoArgs:
break;
default:
strm.Printf (" (unknown <info_type>)");
break;
}
}
bool
EmulateInstruction::SetInstruction (const Opcode &opcode, const Address &inst_addr, Target *target)
{
m_opcode = opcode;
m_addr = LLDB_INVALID_ADDRESS;
if (inst_addr.IsValid())
{
if (target)
m_addr = inst_addr.GetLoadAddress (target);
if (m_addr == LLDB_INVALID_ADDRESS)
m_addr = inst_addr.GetFileAddress ();
}
return true;
}
bool
EmulateInstruction::GetBestRegisterKindAndNumber (const RegisterInfo *reg_info,
uint32_t &reg_kind,
uint32_t &reg_num)
{
// Generic and DWARF should be the two most popular register kinds when
// emulating instructions since they are the most platform agnostic...
reg_num = reg_info->kinds[eRegisterKindGeneric];
if (reg_num != LLDB_INVALID_REGNUM)
{
reg_kind = eRegisterKindGeneric;
return true;
}
reg_num = reg_info->kinds[eRegisterKindDWARF];
if (reg_num != LLDB_INVALID_REGNUM)
{
reg_kind = eRegisterKindDWARF;
return true;
}
reg_num = reg_info->kinds[eRegisterKindLLDB];
if (reg_num != LLDB_INVALID_REGNUM)
{
reg_kind = eRegisterKindLLDB;
return true;
}
reg_num = reg_info->kinds[eRegisterKindGCC];
if (reg_num != LLDB_INVALID_REGNUM)
{
reg_kind = eRegisterKindGCC;
return true;
}
reg_num = reg_info->kinds[eRegisterKindGDB];
if (reg_num != LLDB_INVALID_REGNUM)
{
reg_kind = eRegisterKindGDB;
return true;
}
return false;
}
uint32_t
EmulateInstruction::GetInternalRegisterNumber (RegisterContext *reg_ctx, const RegisterInfo &reg_info)
{
uint32_t reg_kind, reg_num;
if (reg_ctx && GetBestRegisterKindAndNumber (&reg_info, reg_kind, reg_num))
return reg_ctx->ConvertRegisterKindToRegisterNumber (reg_kind, reg_num);
return LLDB_INVALID_REGNUM;
}
bool
EmulateInstruction::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
{
unwind_plan.Clear();
return false;
}