346 lines · cpp
1//===-- EmulationStateARM.cpp ---------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "EmulationStateARM.h"10 11#include "lldb/Interpreter/OptionValueArray.h"12#include "lldb/Interpreter/OptionValueDictionary.h"13#include "lldb/Target/RegisterContext.h"14#include "lldb/Target/StackFrame.h"15#include "lldb/Utility/RegisterValue.h"16#include "lldb/Utility/Scalar.h"17 18#include "Utility/ARM_DWARF_Registers.h"19 20using namespace lldb;21using namespace lldb_private;22 23EmulationStateARM::EmulationStateARM() : m_vfp_regs(), m_memory() {24 ClearPseudoRegisters();25}26 27EmulationStateARM::~EmulationStateARM() = default;28 29bool EmulationStateARM::StorePseudoRegisterValue(uint32_t reg_num,30 uint64_t value) {31 if (reg_num <= dwarf_cpsr)32 m_gpr[reg_num - dwarf_r0] = (uint32_t)value;33 else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31)) {34 uint32_t idx = reg_num - dwarf_s0;35 m_vfp_regs.s_regs[idx] = (uint32_t)value;36 } else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31)) {37 uint32_t idx = reg_num - dwarf_d0;38 if (idx < 16) {39 m_vfp_regs.s_regs[idx * 2] = (uint32_t)value;40 m_vfp_regs.s_regs[idx * 2 + 1] = (uint32_t)(value >> 32);41 } else42 m_vfp_regs.d_regs[idx - 16] = value;43 } else44 return false;45 46 return true;47}48 49uint64_t EmulationStateARM::ReadPseudoRegisterValue(uint32_t reg_num,50 bool &success) {51 uint64_t value = 0;52 success = true;53 54 if (reg_num <= dwarf_cpsr)55 value = m_gpr[reg_num - dwarf_r0];56 else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31)) {57 uint32_t idx = reg_num - dwarf_s0;58 value = m_vfp_regs.s_regs[idx];59 } else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31)) {60 uint32_t idx = reg_num - dwarf_d0;61 if (idx < 16)62 value = (uint64_t)m_vfp_regs.s_regs[idx * 2] |63 ((uint64_t)m_vfp_regs.s_regs[idx * 2 + 1] << 32);64 else65 value = m_vfp_regs.d_regs[idx - 16];66 } else67 success = false;68 69 return value;70}71 72void EmulationStateARM::ClearPseudoRegisters() {73 for (int i = 0; i < 17; ++i)74 m_gpr[i] = 0;75 76 for (int i = 0; i < 32; ++i)77 m_vfp_regs.s_regs[i] = 0;78 79 for (int i = 0; i < 16; ++i)80 m_vfp_regs.d_regs[i] = 0;81}82 83void EmulationStateARM::ClearPseudoMemory() { m_memory.clear(); }84 85bool EmulationStateARM::StoreToPseudoAddress(lldb::addr_t p_address,86 uint32_t value) {87 m_memory[p_address] = value;88 return true;89}90 91uint32_t EmulationStateARM::ReadFromPseudoAddress(lldb::addr_t p_address,92 bool &success) {93 std::map<lldb::addr_t, uint32_t>::iterator pos;94 uint32_t ret_val = 0;95 96 success = true;97 pos = m_memory.find(p_address);98 if (pos != m_memory.end())99 ret_val = pos->second;100 else101 success = false;102 103 return ret_val;104}105 106size_t EmulationStateARM::ReadPseudoMemory(107 EmulateInstruction *instruction, void *baton,108 const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst,109 size_t length) {110 if (!baton)111 return 0;112 113 bool success = true;114 EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;115 if (length <= 4) {116 uint32_t value = pseudo_state->ReadFromPseudoAddress(addr, success);117 if (!success)118 return 0;119 120 if (endian::InlHostByteOrder() == lldb::eByteOrderBig)121 value = llvm::byteswap<uint32_t>(value);122 *((uint32_t *)dst) = value;123 } else if (length == 8) {124 uint32_t value1 = pseudo_state->ReadFromPseudoAddress(addr, success);125 if (!success)126 return 0;127 128 uint32_t value2 = pseudo_state->ReadFromPseudoAddress(addr + 4, success);129 if (!success)130 return 0;131 132 if (endian::InlHostByteOrder() == lldb::eByteOrderBig) {133 value1 = llvm::byteswap<uint32_t>(value1);134 value2 = llvm::byteswap<uint32_t>(value2);135 }136 ((uint32_t *)dst)[0] = value1;137 ((uint32_t *)dst)[1] = value2;138 } else139 success = false;140 141 if (success)142 return length;143 144 return 0;145}146 147size_t EmulationStateARM::WritePseudoMemory(148 EmulateInstruction *instruction, void *baton,149 const EmulateInstruction::Context &context, lldb::addr_t addr,150 const void *dst, size_t length) {151 if (!baton)152 return 0;153 154 EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;155 156 if (length <= 4) {157 uint32_t value;158 memcpy (&value, dst, sizeof (uint32_t));159 if (endian::InlHostByteOrder() == lldb::eByteOrderBig)160 value = llvm::byteswap<uint32_t>(value);161 162 pseudo_state->StoreToPseudoAddress(addr, value);163 return length;164 } else if (length == 8) {165 uint32_t value1;166 uint32_t value2;167 memcpy (&value1, dst, sizeof (uint32_t));168 memcpy(&value2, static_cast<const uint8_t *>(dst) + sizeof(uint32_t),169 sizeof(uint32_t));170 if (endian::InlHostByteOrder() == lldb::eByteOrderBig) {171 value1 = llvm::byteswap<uint32_t>(value1);172 value2 = llvm::byteswap<uint32_t>(value2);173 }174 175 pseudo_state->StoreToPseudoAddress(addr, value1);176 pseudo_state->StoreToPseudoAddress(addr + 4, value2);177 return length;178 }179 180 return 0;181}182 183bool EmulationStateARM::ReadPseudoRegister(184 EmulateInstruction *instruction, void *baton,185 const lldb_private::RegisterInfo *reg_info,186 lldb_private::RegisterValue ®_value) {187 if (!baton || !reg_info)188 return false;189 190 bool success = true;191 EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;192 const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];193 assert(dwarf_reg_num != LLDB_INVALID_REGNUM);194 uint64_t reg_uval =195 pseudo_state->ReadPseudoRegisterValue(dwarf_reg_num, success);196 197 if (success)198 success = reg_value.SetUInt(reg_uval, reg_info->byte_size);199 return success;200}201 202bool EmulationStateARM::WritePseudoRegister(203 EmulateInstruction *instruction, void *baton,204 const EmulateInstruction::Context &context,205 const lldb_private::RegisterInfo *reg_info,206 const lldb_private::RegisterValue ®_value) {207 if (!baton || !reg_info)208 return false;209 210 EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;211 const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];212 assert(dwarf_reg_num != LLDB_INVALID_REGNUM);213 return pseudo_state->StorePseudoRegisterValue(dwarf_reg_num,214 reg_value.GetAsUInt64());215}216 217bool EmulationStateARM::CompareState(EmulationStateARM &other_state,218 Stream &out_stream) {219 bool match = true;220 221 for (int i = 0; match && i < 17; ++i) {222 if (m_gpr[i] != other_state.m_gpr[i]) {223 match = false;224 out_stream.Printf("r%d: 0x%x != 0x%x\n", i, m_gpr[i],225 other_state.m_gpr[i]);226 }227 }228 229 for (int i = 0; match && i < 32; ++i) {230 if (m_vfp_regs.s_regs[i] != other_state.m_vfp_regs.s_regs[i]) {231 match = false;232 out_stream.Printf("s%d: 0x%x != 0x%x\n", i, m_vfp_regs.s_regs[i],233 other_state.m_vfp_regs.s_regs[i]);234 }235 }236 237 for (int i = 0; match && i < 16; ++i) {238 if (m_vfp_regs.d_regs[i] != other_state.m_vfp_regs.d_regs[i]) {239 match = false;240 out_stream.Printf("d%d: 0x%" PRIx64 " != 0x%" PRIx64 "\n", i + 16,241 m_vfp_regs.d_regs[i], other_state.m_vfp_regs.d_regs[i]);242 }243 }244 245 // other_state is the expected state. If it has memory, check it.246 if (!other_state.m_memory.empty() && m_memory != other_state.m_memory) {247 match = false;248 out_stream.Printf("memory does not match\n");249 out_stream.Printf("got memory:\n");250 for (auto p : m_memory)251 out_stream.Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second);252 out_stream.Printf("expected memory:\n");253 for (auto p : other_state.m_memory)254 out_stream.Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second);255 }256 257 return match;258}259 260bool EmulationStateARM::LoadRegistersStateFromDictionary(261 OptionValueDictionary *reg_dict, char kind, int first_reg, int num) {262 StreamString sstr;263 for (int i = 0; i < num; ++i) {264 sstr.Clear();265 sstr.Printf("%c%d", kind, i);266 OptionValueSP value_sp = reg_dict->GetValueForKey(sstr.GetString());267 if (value_sp.get() == nullptr)268 return false;269 uint64_t reg_value = value_sp->GetValueAs<uint64_t>().value_or(0);270 StorePseudoRegisterValue(first_reg + i, reg_value);271 }272 273 return true;274}275 276bool EmulationStateARM::LoadStateFromDictionary(277 OptionValueDictionary *test_data) {278 static constexpr llvm::StringLiteral memory_key("memory");279 static constexpr llvm::StringLiteral registers_key("registers");280 281 if (!test_data)282 return false;283 284 OptionValueSP value_sp = test_data->GetValueForKey(memory_key);285 286 // Load memory, if present.287 288 if (value_sp.get() != nullptr) {289 static constexpr llvm::StringLiteral address_key("address");290 static constexpr llvm::StringLiteral data_key("data");291 uint64_t start_address = 0;292 293 OptionValueDictionary *mem_dict = value_sp->GetAsDictionary();294 value_sp = mem_dict->GetValueForKey(address_key);295 if (value_sp.get() == nullptr)296 return false;297 else298 start_address = value_sp->GetValueAs<uint64_t>().value_or(0);299 300 value_sp = mem_dict->GetValueForKey(data_key);301 OptionValueArray *mem_array = value_sp->GetAsArray();302 if (!mem_array)303 return false;304 305 uint32_t num_elts = mem_array->GetSize();306 uint32_t address = (uint32_t)start_address;307 308 for (uint32_t i = 0; i < num_elts; ++i) {309 value_sp = mem_array->GetValueAtIndex(i);310 if (value_sp.get() == nullptr)311 return false;312 uint64_t value = value_sp->GetValueAs<uint64_t>().value_or(0);313 StoreToPseudoAddress(address, value);314 address = address + 4;315 }316 }317 318 value_sp = test_data->GetValueForKey(registers_key);319 if (value_sp.get() == nullptr)320 return false;321 322 // Load General Registers323 324 OptionValueDictionary *reg_dict = value_sp->GetAsDictionary();325 if (!LoadRegistersStateFromDictionary(reg_dict, 'r', dwarf_r0, 16))326 return false;327 328 static constexpr llvm::StringLiteral cpsr_name("cpsr");329 value_sp = reg_dict->GetValueForKey(cpsr_name);330 if (value_sp.get() == nullptr)331 return false;332 StorePseudoRegisterValue(dwarf_cpsr,333 value_sp->GetValueAs<uint64_t>().value_or(0));334 335 // Load s/d Registers336 // To prevent you giving both types in a state and overwriting337 // one or the other, we'll expect to get either all S registers,338 // or all D registers. Not a mix of the two.339 bool found_s_registers =340 LoadRegistersStateFromDictionary(reg_dict, 's', dwarf_s0, 32);341 bool found_d_registers =342 LoadRegistersStateFromDictionary(reg_dict, 'd', dwarf_d0, 32);343 344 return found_s_registers != found_d_registers;345}346