//===-- 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/Scalar.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_context = frame.GetRegisterContext().get(); Scalar value; uint64_t reg_value64; uint32_t reg_value32; bool success = true; for (int i = dwarf_r0; i < dwarf_r0 + 17; ++i) { uint32_t internal_reg_num = reg_context->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i); if (reg_context->ReadRegisterValue (internal_reg_num, value)) { reg_value32 = (uint32_t) value.GetRawBits64 (0); m_gpr[i - dwarf_r0] = reg_value32; } else success = false; } for (int i = dwarf_s0; i < dwarf_s0 + 32; ++i) { uint32_t internal_reg_num = reg_context->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i); if (reg_context->ReadRegisterValue (internal_reg_num, value)) { uint32_t idx = i - dwarf_s0; reg_value32 = (uint32_t) value.GetRawBits64 (0); m_vfp_regs.sd_regs[idx / 2].s_reg[idx % 2] = reg_value32; } else success = false; } for (int i = dwarf_d0; i < dwarf_d0 + 32; ++i) { uint32_t internal_reg_num = reg_context->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i); if (reg_context->ReadRegisterValue (internal_reg_num, value)) { uint32_t idx = i - dwarf_d0; reg_value64 = value.GetRawBits64 (0); if (i < 16) m_vfp_regs.sd_regs[idx].d_reg = reg_value64; else m_vfp_regs.d_regs[idx - 16] = reg_value64; } 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.sd_regs[idx / 2].s_reg[idx % 2] = (uint32_t) value; } else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31)) { if ((reg_num - dwarf_d0) < 16) { m_vfp_regs.sd_regs[reg_num - dwarf_d0].d_reg = value; } else m_vfp_regs.d_regs[reg_num - dwarf_d16] = 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.sd_regs[idx / 2].s_reg[idx % 2]; } else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31)) { if ((reg_num - dwarf_d0) < 16) value = m_vfp_regs.sd_regs[reg_num - dwarf_d0].d_reg; else value = m_vfp_regs.d_regs[reg_num - dwarf_d16]; } else success = false; return value; } void EmulationStateARM::ClearPseudoRegisters () { for (int i = 0; i < 17; ++i) m_gpr[i] = 0; for (int i = 0; i < 16; ++i) m_vfp_regs.sd_regs[i].d_reg = 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, uint64_t value, uint32_t size) { if (size > 8) return false; if (size <= 4) m_memory[p_address] = value; else if (size == 8) { m_memory[p_address] = (value << 32) >> 32; m_memory[p_address + 4] = value << 32; } return true; } uint32_t EmulationStateARM::ReadFromPseudoAddress (lldb::addr_t p_address, uint32_t size, bool &success) { std::map::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 (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, length, success); if (!success) return 0; *((uint32_t *) dst) = value; } else if (length == 8) { uint32_t value1 = pseudo_state->ReadFromPseudoAddress (addr, 4, success); if (!success) return 0; uint32_t value2 = pseudo_state->ReadFromPseudoAddress (addr + 4, 4, success); if (!success) return 0; uint64_t value64 = value2; value64 = (value64 << 32) | value1; *((uint64_t *) dst) = value64; } else success = false; if (success) return length; return 0; } size_t EmulationStateARM::WritePseudoMemory (void *baton, const EmulateInstruction::Context &context, lldb::addr_t addr, const void *dst, size_t length) { if (!baton) return 0; bool success; EmulationStateARM *pseudo_state = (EmulationStateARM *) baton; uint64_t value = *((uint64_t *) dst); success = pseudo_state->StoreToPseudoAddress (addr, value, length); if (success) return length; return 0; } bool EmulationStateARM::ReadPseudoRegister (void *baton, uint32_t reg_kind, uint32_t reg_num, uint64_t ®_value) { if (!baton) return false; bool success = true; EmulationStateARM *pseudo_state = (EmulationStateARM *) baton; if (reg_kind == eRegisterKindGeneric) { switch (reg_num) { case LLDB_REGNUM_GENERIC_PC: reg_num = dwarf_pc; break; case LLDB_REGNUM_GENERIC_SP: reg_num = dwarf_sp; break; case LLDB_REGNUM_GENERIC_FLAGS: reg_num = dwarf_cpsr; break; case LLDB_REGNUM_GENERIC_RA: reg_num = dwarf_lr; break; default: break; } } reg_value = pseudo_state->ReadPseudoRegisterValue (reg_num, success); return success; } bool EmulationStateARM::WritePseudoRegister (void *baton, const EmulateInstruction::Context &context, uint32_t reg_kind, uint32_t reg_num, uint64_t reg_value) { if (!baton) return false; if (reg_kind == eRegisterKindGeneric) { switch (reg_num) { case LLDB_REGNUM_GENERIC_PC: reg_num = dwarf_pc; break; case LLDB_REGNUM_GENERIC_SP: reg_num = dwarf_sp; break; case LLDB_REGNUM_GENERIC_FLAGS: reg_num = dwarf_cpsr; break; case LLDB_REGNUM_GENERIC_RA: reg_num = dwarf_lr; break; default: break; } } EmulationStateARM *pseudo_state = (EmulationStateARM *) baton; return pseudo_state->StorePseudoRegisterValue (reg_num, reg_value); } 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 < 16; ++i) { if (m_vfp_regs.sd_regs[i].s_reg[0] != other_state.m_vfp_regs.sd_regs[i].s_reg[0]) match = false; if (m_vfp_regs.sd_regs[i].s_reg[1] != other_state.m_vfp_regs.sd_regs[i].s_reg[1]) match = false; } for (int i = 0; match && i < 32; ++i) { if (i < 16) { if (m_vfp_regs.sd_regs[i].d_reg != other_state.m_vfp_regs.sd_regs[i].d_reg) match = false; } else { if (m_vfp_regs.d_regs[i - 16] != other_state.m_vfp_regs.d_regs[i - 16]) 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->GetAsDictionaryValue(); 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->GetAsArrayValue(); if (!mem_array) return false; uint32_t num_elts = mem_array->GetSize(); uint32_t address = (uint32_t) start_address; for (int 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, 4); 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->GetAsDictionaryValue (); 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; }