419 lines
12 KiB
C++
419 lines
12 KiB
C++
//===-- EmulationStateARM.cpp -----------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "EmulationStateARM.h"
|
|
|
|
#include "lldb/Core/RegisterValue.h"
|
|
#include "lldb/Core/Scalar.h"
|
|
#include "lldb/Interpreter/OptionValueArray.h"
|
|
#include "lldb/Interpreter/OptionValueDictionary.h"
|
|
#include "lldb/Target/StackFrame.h"
|
|
#include "lldb/Target/RegisterContext.h"
|
|
|
|
#include "Utility/ARM_DWARF_Registers.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
EmulationStateARM::EmulationStateARM () :
|
|
m_gpr (),
|
|
m_vfp_regs (),
|
|
m_memory ()
|
|
{
|
|
ClearPseudoRegisters();
|
|
}
|
|
|
|
EmulationStateARM::~EmulationStateARM ()
|
|
{
|
|
}
|
|
|
|
bool
|
|
EmulationStateARM::LoadPseudoRegistersFromFrame (StackFrame &frame)
|
|
{
|
|
RegisterContext *reg_ctx = frame.GetRegisterContext().get();
|
|
bool success = true;
|
|
uint32_t reg_num;
|
|
|
|
for (int i = dwarf_r0; i < dwarf_r0 + 17; ++i)
|
|
{
|
|
reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i);
|
|
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_num);
|
|
RegisterValue reg_value;
|
|
if (reg_ctx->ReadRegister (reg_info, reg_value))
|
|
{
|
|
m_gpr[i - dwarf_r0] = reg_value.GetAsUInt32();
|
|
}
|
|
else
|
|
success = false;
|
|
}
|
|
|
|
for (int i = dwarf_d0; i < dwarf_d0 + 32; ++i)
|
|
{
|
|
reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i);
|
|
RegisterValue reg_value;
|
|
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_num);
|
|
|
|
if (reg_ctx->ReadRegister (reg_info, reg_value))
|
|
{
|
|
uint64_t value = reg_value.GetAsUInt64();
|
|
uint32_t idx = i - dwarf_d0;
|
|
if (i < 16)
|
|
{
|
|
m_vfp_regs.s_regs[idx * 2] = (uint32_t)value;
|
|
m_vfp_regs.s_regs[idx * 2 + 1] = (uint32_t)(value >> 32);
|
|
}
|
|
else
|
|
m_vfp_regs.d_regs[idx - 16] = value;
|
|
}
|
|
else
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool
|
|
EmulationStateARM::StorePseudoRegisterValue (uint32_t reg_num, uint64_t value)
|
|
{
|
|
if ((dwarf_r0 <= reg_num) && (reg_num <= dwarf_cpsr))
|
|
m_gpr[reg_num - dwarf_r0] = (uint32_t) value;
|
|
else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31))
|
|
{
|
|
uint32_t idx = reg_num - dwarf_s0;
|
|
m_vfp_regs.s_regs[idx] = (uint32_t)value;
|
|
}
|
|
else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31))
|
|
{
|
|
uint32_t idx = reg_num - dwarf_d0;
|
|
if (idx < 16)
|
|
{
|
|
m_vfp_regs.s_regs[idx * 2] = (uint32_t)value;
|
|
m_vfp_regs.s_regs[idx * 2 + 1] = (uint32_t)(value >> 32);
|
|
}
|
|
else
|
|
m_vfp_regs.d_regs[idx - 16] = value;
|
|
}
|
|
else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
uint64_t
|
|
EmulationStateARM::ReadPseudoRegisterValue (uint32_t reg_num, bool &success)
|
|
{
|
|
uint64_t value = 0;
|
|
success = true;
|
|
|
|
if ((dwarf_r0 <= reg_num) && (reg_num <= dwarf_cpsr))
|
|
value = m_gpr[reg_num - dwarf_r0];
|
|
else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31))
|
|
{
|
|
uint32_t idx = reg_num - dwarf_s0;
|
|
value = m_vfp_regs.d_regs[idx];
|
|
}
|
|
else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31))
|
|
{
|
|
uint32_t idx = reg_num - dwarf_d0;
|
|
if (idx < 16)
|
|
value = (uint64_t)m_vfp_regs.s_regs[idx * 2] | ((uint64_t)m_vfp_regs.s_regs[idx * 2 + 1] >> 32);
|
|
else
|
|
value = m_vfp_regs.d_regs[idx - 16];
|
|
}
|
|
else
|
|
success = false;
|
|
|
|
return value;
|
|
}
|
|
|
|
void
|
|
EmulationStateARM::ClearPseudoRegisters ()
|
|
{
|
|
for (int i = 0; i < 17; ++i)
|
|
m_gpr[i] = 0;
|
|
|
|
for (int i = 0; i < 32; ++i)
|
|
m_vfp_regs.s_regs[i] = 0;
|
|
|
|
for (int i = 0; i < 16; ++i)
|
|
m_vfp_regs.d_regs[i] = 0;
|
|
}
|
|
|
|
void
|
|
EmulationStateARM::ClearPseudoMemory ()
|
|
{
|
|
m_memory.clear();
|
|
}
|
|
|
|
bool
|
|
EmulationStateARM::StoreToPseudoAddress (lldb::addr_t p_address, uint32_t value)
|
|
{
|
|
m_memory[p_address] = value;
|
|
return true;
|
|
}
|
|
|
|
uint32_t
|
|
EmulationStateARM::ReadFromPseudoAddress (lldb::addr_t p_address, bool &success)
|
|
{
|
|
std::map<lldb::addr_t,uint32_t>::iterator pos;
|
|
uint32_t ret_val = 0;
|
|
|
|
success = true;
|
|
pos = m_memory.find(p_address);
|
|
if (pos != m_memory.end())
|
|
ret_val = pos->second;
|
|
else
|
|
success = false;
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
size_t
|
|
EmulationStateARM::ReadPseudoMemory (EmulateInstruction *instruction,
|
|
void *baton,
|
|
const EmulateInstruction::Context &context,
|
|
lldb::addr_t addr,
|
|
void *dst,
|
|
size_t length)
|
|
{
|
|
if (!baton)
|
|
return 0;
|
|
|
|
bool success = true;
|
|
EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
|
|
if (length <= 4)
|
|
{
|
|
uint32_t value = pseudo_state->ReadFromPseudoAddress (addr, success);
|
|
if (!success)
|
|
return 0;
|
|
|
|
if (endian::InlHostByteOrder() == lldb::eByteOrderBig)
|
|
value = llvm::ByteSwap_32 (value);
|
|
*((uint32_t *) dst) = value;
|
|
}
|
|
else if (length == 8)
|
|
{
|
|
uint32_t value1 = pseudo_state->ReadFromPseudoAddress (addr, success);
|
|
if (!success)
|
|
return 0;
|
|
|
|
uint32_t value2 = pseudo_state->ReadFromPseudoAddress (addr + 4, success);
|
|
if (!success)
|
|
return 0;
|
|
|
|
if (endian::InlHostByteOrder() == lldb::eByteOrderBig)
|
|
{
|
|
value1 = llvm::ByteSwap_32 (value1);
|
|
value2 = llvm::ByteSwap_32 (value2);
|
|
}
|
|
((uint32_t *) dst)[0] = value1;
|
|
((uint32_t *) dst)[1] = value2;
|
|
}
|
|
else
|
|
success = false;
|
|
|
|
if (success)
|
|
return length;
|
|
|
|
return 0;
|
|
}
|
|
|
|
size_t
|
|
EmulationStateARM::WritePseudoMemory (EmulateInstruction *instruction,
|
|
void *baton,
|
|
const EmulateInstruction::Context &context,
|
|
lldb::addr_t addr,
|
|
const void *dst,
|
|
size_t length)
|
|
{
|
|
if (!baton)
|
|
return 0;
|
|
|
|
EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
|
|
|
|
if (length <= 4)
|
|
{
|
|
uint32_t value = *((const uint32_t *) dst);
|
|
if (endian::InlHostByteOrder() == lldb::eByteOrderBig)
|
|
value = llvm::ByteSwap_32 (value);
|
|
|
|
pseudo_state->StoreToPseudoAddress (addr, value);
|
|
return length;
|
|
}
|
|
else if (length == 8)
|
|
{
|
|
uint32_t value1 = ((const uint32_t *) dst)[0];
|
|
uint32_t value2 = ((const uint32_t *) dst)[1];
|
|
if (endian::InlHostByteOrder() == lldb::eByteOrderBig)
|
|
{
|
|
value1 = llvm::ByteSwap_32 (value1);
|
|
value2 = llvm::ByteSwap_32 (value2);
|
|
}
|
|
|
|
pseudo_state->StoreToPseudoAddress (addr, value1);
|
|
pseudo_state->StoreToPseudoAddress (addr + 4, value2);
|
|
return length;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
EmulationStateARM::ReadPseudoRegister (EmulateInstruction *instruction,
|
|
void *baton,
|
|
const lldb_private::RegisterInfo *reg_info,
|
|
lldb_private::RegisterValue ®_value)
|
|
{
|
|
if (!baton || !reg_info)
|
|
return false;
|
|
|
|
bool success = true;
|
|
EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
|
|
const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];
|
|
assert (dwarf_reg_num != LLDB_INVALID_REGNUM);
|
|
uint64_t reg_uval = pseudo_state->ReadPseudoRegisterValue (dwarf_reg_num, success);
|
|
|
|
if (success)
|
|
success = reg_value.SetUInt(reg_uval, reg_info->byte_size);
|
|
return success;
|
|
|
|
}
|
|
|
|
bool
|
|
EmulationStateARM::WritePseudoRegister (EmulateInstruction *instruction,
|
|
void *baton,
|
|
const EmulateInstruction::Context &context,
|
|
const lldb_private::RegisterInfo *reg_info,
|
|
const lldb_private::RegisterValue ®_value)
|
|
{
|
|
if (!baton || !reg_info)
|
|
return false;
|
|
|
|
EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
|
|
const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];
|
|
assert (dwarf_reg_num != LLDB_INVALID_REGNUM);
|
|
return pseudo_state->StorePseudoRegisterValue (dwarf_reg_num, reg_value.GetAsUInt64());
|
|
}
|
|
|
|
bool
|
|
EmulationStateARM::CompareState (EmulationStateARM &other_state)
|
|
{
|
|
bool match = true;
|
|
|
|
for (int i = 0; match && i < 17; ++i)
|
|
{
|
|
if (m_gpr[i] != other_state.m_gpr[i])
|
|
match = false;
|
|
}
|
|
|
|
for (int i = 0; match && i < 32; ++i)
|
|
{
|
|
if (m_vfp_regs.s_regs[i] != other_state.m_vfp_regs.s_regs[i])
|
|
match = false;
|
|
}
|
|
|
|
for (int i = 0; match && i < 16; ++i)
|
|
{
|
|
if (m_vfp_regs.d_regs[i] != other_state.m_vfp_regs.d_regs[i])
|
|
match = false;
|
|
}
|
|
|
|
return match;
|
|
}
|
|
|
|
bool
|
|
EmulationStateARM::LoadStateFromDictionary (OptionValueDictionary *test_data)
|
|
{
|
|
static ConstString memory_key ("memory");
|
|
static ConstString registers_key ("registers");
|
|
|
|
if (!test_data)
|
|
return false;
|
|
|
|
OptionValueSP value_sp = test_data->GetValueForKey (memory_key);
|
|
|
|
// Load memory, if present.
|
|
|
|
if (value_sp.get() != NULL)
|
|
{
|
|
static ConstString address_key ("address");
|
|
static ConstString data_key ("data");
|
|
uint64_t start_address = 0;
|
|
|
|
OptionValueDictionary *mem_dict = value_sp->GetAsDictionary();
|
|
value_sp = mem_dict->GetValueForKey (address_key);
|
|
if (value_sp.get() == NULL)
|
|
return false;
|
|
else
|
|
start_address = value_sp->GetUInt64Value ();
|
|
|
|
value_sp = mem_dict->GetValueForKey (data_key);
|
|
OptionValueArray *mem_array = value_sp->GetAsArray();
|
|
if (!mem_array)
|
|
return false;
|
|
|
|
uint32_t num_elts = mem_array->GetSize();
|
|
uint32_t address = (uint32_t) start_address;
|
|
|
|
for (uint32_t i = 0; i < num_elts; ++i)
|
|
{
|
|
value_sp = mem_array->GetValueAtIndex (i);
|
|
if (value_sp.get() == NULL)
|
|
return false;
|
|
uint64_t value = value_sp->GetUInt64Value();
|
|
StoreToPseudoAddress (address, value);
|
|
address = address + 4;
|
|
}
|
|
}
|
|
|
|
value_sp = test_data->GetValueForKey (registers_key);
|
|
if (value_sp.get() == NULL)
|
|
return false;
|
|
|
|
|
|
// Load General Registers
|
|
|
|
OptionValueDictionary *reg_dict = value_sp->GetAsDictionary ();
|
|
|
|
StreamString sstr;
|
|
for (int i = 0; i < 16; ++i)
|
|
{
|
|
sstr.Clear();
|
|
sstr.Printf ("r%d", i);
|
|
ConstString reg_name (sstr.GetData());
|
|
value_sp = reg_dict->GetValueForKey (reg_name);
|
|
if (value_sp.get() == NULL)
|
|
return false;
|
|
uint64_t reg_value = value_sp->GetUInt64Value();
|
|
StorePseudoRegisterValue (dwarf_r0 + i, reg_value);
|
|
}
|
|
|
|
static ConstString cpsr_name ("cpsr");
|
|
value_sp = reg_dict->GetValueForKey (cpsr_name);
|
|
if (value_sp.get() == NULL)
|
|
return false;
|
|
StorePseudoRegisterValue (dwarf_cpsr, value_sp->GetUInt64Value());
|
|
|
|
// Load s/d Registers
|
|
for (int i = 0; i < 32; ++i)
|
|
{
|
|
sstr.Clear();
|
|
sstr.Printf ("s%d", i);
|
|
ConstString reg_name (sstr.GetData());
|
|
value_sp = reg_dict->GetValueForKey (reg_name);
|
|
if (value_sp.get() == NULL)
|
|
return false;
|
|
uint64_t reg_value = value_sp->GetUInt64Value();
|
|
StorePseudoRegisterValue (dwarf_s0 + i, reg_value);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|