for eh_frame and stabs register numberings. This is not complete but it's a step in the right direction. It's almost entirely mechanical. lldb informally uses "gcc register numbering" to mean eh_frame. Why? Probably because there's a notorious bug with gcc on i386 darwin where the register numbers in eh_frame were incorrect. In all other cases, eh_frame register numbering is identical to dwarf. lldb informally uses "gdb register numbering" to mean stabs. There are no official definitions of stabs register numbers for different architectures, so the implementations of gdb and gcc are the de facto reference source. There were some incorrect uses of these register number types in lldb already. I fixed the ones that I saw as I made this change. This commit changes all references to "gcc" and "gdb" register numbers in lldb to "eh_frame" and "stabs" to make it clear what is actually being represented. lldb cannot parse the stabs debug format, and given that no one is using stabs any more, it is unlikely that it ever will. A more comprehensive cleanup would remove the stabs register numbers altogether - it's unnecessary cruft / complication to all of our register structures. In ProcessGDBRemote, when we get register definitions from the gdb-remote stub, we expect to see "gcc:" (qRegisterInfo) or "gcc_regnum" (qXfer:features:read: packet to get xml payload). This patch changes ProcessGDBRemote to also accept "ehframe:" and "ehframe_regnum" from these remotes. I did not change GDBRemoteCommunicationServerLLGS or debugserver to send these new packets. I don't know what kind of interoperability constraints we might be working under. At some point in the future we should transition to using the more descriptive names. Throughout lldb we're still using enum names like "gcc_r0" and "gdb_r0", for eh_frame and stabs register numberings. These should be cleaned up eventually too. The sources link cleanly on macosx native with xcode build. I don't think we'll see problems on other platforms but please let me know if I broke anyone. llvm-svn: 245141
673 lines
21 KiB
C++
673 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/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)
|
|
{
|
|
ConstString const_plugin_name (plugin_name);
|
|
create_callback = PluginManager::GetEmulateInstructionCreateCallbackForPluginName (const_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 (lldb::RegisterKind reg_kind, uint32_t reg_num, RegisterValue& reg_value)
|
|
{
|
|
RegisterInfo reg_info;
|
|
if (GetRegisterInfo(reg_kind, reg_num, reg_info))
|
|
return ReadRegister (®_info, reg_value);
|
|
return false;
|
|
}
|
|
|
|
uint64_t
|
|
EmulateInstruction::ReadRegisterUnsigned (lldb::RegisterKind 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,
|
|
lldb::RegisterKind reg_kind,
|
|
uint32_t reg_num,
|
|
const RegisterValue& reg_value)
|
|
{
|
|
RegisterInfo reg_info;
|
|
if (GetRegisterInfo(reg_kind, reg_num, reg_info))
|
|
return WriteRegister (context, ®_info, reg_value);
|
|
return false;
|
|
}
|
|
|
|
|
|
bool
|
|
EmulateInstruction::WriteRegisterUnsigned (const Context &context,
|
|
lldb::RegisterKind 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, ®_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)
|
|
{
|
|
lldb::offset_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 dst_len)
|
|
{
|
|
if (!baton || dst == NULL || dst_len == 0)
|
|
return 0;
|
|
|
|
StackFrame *frame = (StackFrame *) baton;
|
|
|
|
ProcessSP process_sp (frame->CalculateProcess());
|
|
if (process_sp)
|
|
{
|
|
Error error;
|
|
return process_sp->ReadMemory (addr, dst, dst_len, error);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
size_t
|
|
EmulateInstruction::WriteMemoryFrame (EmulateInstruction *instruction,
|
|
void *baton,
|
|
const Context &context,
|
|
lldb::addr_t addr,
|
|
const void *src,
|
|
size_t src_len)
|
|
{
|
|
if (!baton || src == NULL || src_len == 0)
|
|
return 0;
|
|
|
|
StackFrame *frame = (StackFrame *) baton;
|
|
|
|
ProcessSP process_sp (frame->CalculateProcess());
|
|
if (process_sp)
|
|
{
|
|
Error error;
|
|
return process_sp->WriteMemory (addr, src, src_len, error);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
EmulateInstruction::ReadRegisterFrame (EmulateInstruction *instruction,
|
|
void *baton,
|
|
const RegisterInfo *reg_info,
|
|
RegisterValue ®_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 ®_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%" PRIx64 ", length = %" PRIu64 ", context = ", addr, (uint64_t)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%" PRIx64 ", length = %" PRIu64 ", context = ", addr, (uint64_t)length);
|
|
context.Dump (strm, instruction);
|
|
strm.EOL();
|
|
return length;
|
|
}
|
|
|
|
bool
|
|
EmulateInstruction::ReadRegisterDefault (EmulateInstruction *instruction,
|
|
void *baton,
|
|
const RegisterInfo *reg_info,
|
|
RegisterValue ®_value)
|
|
{
|
|
StreamFile strm (stdout, false);
|
|
strm.Printf (" Read Register (%s)\n", reg_info->name);
|
|
lldb::RegisterKind reg_kind;
|
|
uint32_t 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 ®_value)
|
|
{
|
|
StreamFile strm (stdout, false);
|
|
strm.Printf (" Write to Register (name = %s, value = " , reg_info->name);
|
|
reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
|
|
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 eContextSetFramePointer:
|
|
strm.PutCString ("set frame pointer");
|
|
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%+" PRId64 ")",
|
|
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%+" PRId64 ", 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 = %+" PRId64 ")", info.signed_offset);
|
|
break;
|
|
|
|
case eInfoTypeRegister:
|
|
strm.Printf (" (reg = %s)", info.reg.name);
|
|
break;
|
|
|
|
case eInfoTypeImmediate:
|
|
strm.Printf (" (unsigned_immediate = %" PRIu64 " (0x%16.16" PRIx64 "))",
|
|
info.unsigned_immediate,
|
|
info.unsigned_immediate);
|
|
break;
|
|
|
|
case eInfoTypeImmediateSigned:
|
|
strm.Printf (" (signed_immediate = %+" PRId64 " (0x%16.16" PRIx64 "))",
|
|
info.signed_immediate,
|
|
info.signed_immediate);
|
|
break;
|
|
|
|
case eInfoTypeAddress:
|
|
strm.Printf (" (address = 0x%" PRIx64 ")", 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;
|
|
}
|
|
}
|
|
|
|
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,
|
|
lldb::RegisterKind ®_kind,
|
|
uint32_t ®_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[eRegisterKindEHFrame];
|
|
if (reg_num != LLDB_INVALID_REGNUM)
|
|
{
|
|
reg_kind = eRegisterKindEHFrame;
|
|
return true;
|
|
}
|
|
|
|
reg_num = reg_info->kinds[eRegisterKindStabs];
|
|
if (reg_num != LLDB_INVALID_REGNUM)
|
|
{
|
|
reg_kind = eRegisterKindStabs;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
uint32_t
|
|
EmulateInstruction::GetInternalRegisterNumber (RegisterContext *reg_ctx, const RegisterInfo ®_info)
|
|
{
|
|
lldb::RegisterKind reg_kind;
|
|
uint32_t reg_num;
|
|
if (reg_ctx && GetBestRegisterKindAndNumber (®_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;
|
|
}
|
|
|
|
|