Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
39644 views
//===-- EmulationStateARM.cpp ---------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "EmulationStateARM.h"910#include "lldb/Interpreter/OptionValueArray.h"11#include "lldb/Interpreter/OptionValueDictionary.h"12#include "lldb/Target/RegisterContext.h"13#include "lldb/Target/StackFrame.h"14#include "lldb/Utility/RegisterValue.h"15#include "lldb/Utility/Scalar.h"1617#include "Utility/ARM_DWARF_Registers.h"1819using namespace lldb;20using namespace lldb_private;2122EmulationStateARM::EmulationStateARM() : m_vfp_regs(), m_memory() {23ClearPseudoRegisters();24}2526EmulationStateARM::~EmulationStateARM() = default;2728bool EmulationStateARM::StorePseudoRegisterValue(uint32_t reg_num,29uint64_t value) {30if (reg_num <= dwarf_cpsr)31m_gpr[reg_num - dwarf_r0] = (uint32_t)value;32else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31)) {33uint32_t idx = reg_num - dwarf_s0;34m_vfp_regs.s_regs[idx] = (uint32_t)value;35} else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31)) {36uint32_t idx = reg_num - dwarf_d0;37if (idx < 16) {38m_vfp_regs.s_regs[idx * 2] = (uint32_t)value;39m_vfp_regs.s_regs[idx * 2 + 1] = (uint32_t)(value >> 32);40} else41m_vfp_regs.d_regs[idx - 16] = value;42} else43return false;4445return true;46}4748uint64_t EmulationStateARM::ReadPseudoRegisterValue(uint32_t reg_num,49bool &success) {50uint64_t value = 0;51success = true;5253if (reg_num <= dwarf_cpsr)54value = m_gpr[reg_num - dwarf_r0];55else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31)) {56uint32_t idx = reg_num - dwarf_s0;57value = m_vfp_regs.s_regs[idx];58} else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31)) {59uint32_t idx = reg_num - dwarf_d0;60if (idx < 16)61value = (uint64_t)m_vfp_regs.s_regs[idx * 2] |62((uint64_t)m_vfp_regs.s_regs[idx * 2 + 1] << 32);63else64value = m_vfp_regs.d_regs[idx - 16];65} else66success = false;6768return value;69}7071void EmulationStateARM::ClearPseudoRegisters() {72for (int i = 0; i < 17; ++i)73m_gpr[i] = 0;7475for (int i = 0; i < 32; ++i)76m_vfp_regs.s_regs[i] = 0;7778for (int i = 0; i < 16; ++i)79m_vfp_regs.d_regs[i] = 0;80}8182void EmulationStateARM::ClearPseudoMemory() { m_memory.clear(); }8384bool EmulationStateARM::StoreToPseudoAddress(lldb::addr_t p_address,85uint32_t value) {86m_memory[p_address] = value;87return true;88}8990uint32_t EmulationStateARM::ReadFromPseudoAddress(lldb::addr_t p_address,91bool &success) {92std::map<lldb::addr_t, uint32_t>::iterator pos;93uint32_t ret_val = 0;9495success = true;96pos = m_memory.find(p_address);97if (pos != m_memory.end())98ret_val = pos->second;99else100success = false;101102return ret_val;103}104105size_t EmulationStateARM::ReadPseudoMemory(106EmulateInstruction *instruction, void *baton,107const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst,108size_t length) {109if (!baton)110return 0;111112bool success = true;113EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;114if (length <= 4) {115uint32_t value = pseudo_state->ReadFromPseudoAddress(addr, success);116if (!success)117return 0;118119if (endian::InlHostByteOrder() == lldb::eByteOrderBig)120value = llvm::byteswap<uint32_t>(value);121*((uint32_t *)dst) = value;122} else if (length == 8) {123uint32_t value1 = pseudo_state->ReadFromPseudoAddress(addr, success);124if (!success)125return 0;126127uint32_t value2 = pseudo_state->ReadFromPseudoAddress(addr + 4, success);128if (!success)129return 0;130131if (endian::InlHostByteOrder() == lldb::eByteOrderBig) {132value1 = llvm::byteswap<uint32_t>(value1);133value2 = llvm::byteswap<uint32_t>(value2);134}135((uint32_t *)dst)[0] = value1;136((uint32_t *)dst)[1] = value2;137} else138success = false;139140if (success)141return length;142143return 0;144}145146size_t EmulationStateARM::WritePseudoMemory(147EmulateInstruction *instruction, void *baton,148const EmulateInstruction::Context &context, lldb::addr_t addr,149const void *dst, size_t length) {150if (!baton)151return 0;152153EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;154155if (length <= 4) {156uint32_t value;157memcpy (&value, dst, sizeof (uint32_t));158if (endian::InlHostByteOrder() == lldb::eByteOrderBig)159value = llvm::byteswap<uint32_t>(value);160161pseudo_state->StoreToPseudoAddress(addr, value);162return length;163} else if (length == 8) {164uint32_t value1;165uint32_t value2;166memcpy (&value1, dst, sizeof (uint32_t));167memcpy(&value2, static_cast<const uint8_t *>(dst) + sizeof(uint32_t),168sizeof(uint32_t));169if (endian::InlHostByteOrder() == lldb::eByteOrderBig) {170value1 = llvm::byteswap<uint32_t>(value1);171value2 = llvm::byteswap<uint32_t>(value2);172}173174pseudo_state->StoreToPseudoAddress(addr, value1);175pseudo_state->StoreToPseudoAddress(addr + 4, value2);176return length;177}178179return 0;180}181182bool EmulationStateARM::ReadPseudoRegister(183EmulateInstruction *instruction, void *baton,184const lldb_private::RegisterInfo *reg_info,185lldb_private::RegisterValue ®_value) {186if (!baton || !reg_info)187return false;188189bool success = true;190EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;191const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];192assert(dwarf_reg_num != LLDB_INVALID_REGNUM);193uint64_t reg_uval =194pseudo_state->ReadPseudoRegisterValue(dwarf_reg_num, success);195196if (success)197success = reg_value.SetUInt(reg_uval, reg_info->byte_size);198return success;199}200201bool EmulationStateARM::WritePseudoRegister(202EmulateInstruction *instruction, void *baton,203const EmulateInstruction::Context &context,204const lldb_private::RegisterInfo *reg_info,205const lldb_private::RegisterValue ®_value) {206if (!baton || !reg_info)207return false;208209EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;210const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];211assert(dwarf_reg_num != LLDB_INVALID_REGNUM);212return pseudo_state->StorePseudoRegisterValue(dwarf_reg_num,213reg_value.GetAsUInt64());214}215216bool EmulationStateARM::CompareState(EmulationStateARM &other_state,217Stream &out_stream) {218bool match = true;219220for (int i = 0; match && i < 17; ++i) {221if (m_gpr[i] != other_state.m_gpr[i]) {222match = false;223out_stream.Printf("r%d: 0x%x != 0x%x\n", i, m_gpr[i],224other_state.m_gpr[i]);225}226}227228for (int i = 0; match && i < 32; ++i) {229if (m_vfp_regs.s_regs[i] != other_state.m_vfp_regs.s_regs[i]) {230match = false;231out_stream.Printf("s%d: 0x%x != 0x%x\n", i, m_vfp_regs.s_regs[i],232other_state.m_vfp_regs.s_regs[i]);233}234}235236for (int i = 0; match && i < 16; ++i) {237if (m_vfp_regs.d_regs[i] != other_state.m_vfp_regs.d_regs[i]) {238match = false;239out_stream.Printf("d%d: 0x%" PRIx64 " != 0x%" PRIx64 "\n", i + 16,240m_vfp_regs.d_regs[i], other_state.m_vfp_regs.d_regs[i]);241}242}243244// other_state is the expected state. If it has memory, check it.245if (!other_state.m_memory.empty() && m_memory != other_state.m_memory) {246match = false;247out_stream.Printf("memory does not match\n");248out_stream.Printf("got memory:\n");249for (auto p : m_memory)250out_stream.Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second);251out_stream.Printf("expected memory:\n");252for (auto p : other_state.m_memory)253out_stream.Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second);254}255256return match;257}258259bool EmulationStateARM::LoadRegistersStateFromDictionary(260OptionValueDictionary *reg_dict, char kind, int first_reg, int num) {261StreamString sstr;262for (int i = 0; i < num; ++i) {263sstr.Clear();264sstr.Printf("%c%d", kind, i);265OptionValueSP value_sp = reg_dict->GetValueForKey(sstr.GetString());266if (value_sp.get() == nullptr)267return false;268uint64_t reg_value = value_sp->GetValueAs<uint64_t>().value_or(0);269StorePseudoRegisterValue(first_reg + i, reg_value);270}271272return true;273}274275bool EmulationStateARM::LoadStateFromDictionary(276OptionValueDictionary *test_data) {277static constexpr llvm::StringLiteral memory_key("memory");278static constexpr llvm::StringLiteral registers_key("registers");279280if (!test_data)281return false;282283OptionValueSP value_sp = test_data->GetValueForKey(memory_key);284285// Load memory, if present.286287if (value_sp.get() != nullptr) {288static constexpr llvm::StringLiteral address_key("address");289static constexpr llvm::StringLiteral data_key("data");290uint64_t start_address = 0;291292OptionValueDictionary *mem_dict = value_sp->GetAsDictionary();293value_sp = mem_dict->GetValueForKey(address_key);294if (value_sp.get() == nullptr)295return false;296else297start_address = value_sp->GetValueAs<uint64_t>().value_or(0);298299value_sp = mem_dict->GetValueForKey(data_key);300OptionValueArray *mem_array = value_sp->GetAsArray();301if (!mem_array)302return false;303304uint32_t num_elts = mem_array->GetSize();305uint32_t address = (uint32_t)start_address;306307for (uint32_t i = 0; i < num_elts; ++i) {308value_sp = mem_array->GetValueAtIndex(i);309if (value_sp.get() == nullptr)310return false;311uint64_t value = value_sp->GetValueAs<uint64_t>().value_or(0);312StoreToPseudoAddress(address, value);313address = address + 4;314}315}316317value_sp = test_data->GetValueForKey(registers_key);318if (value_sp.get() == nullptr)319return false;320321// Load General Registers322323OptionValueDictionary *reg_dict = value_sp->GetAsDictionary();324if (!LoadRegistersStateFromDictionary(reg_dict, 'r', dwarf_r0, 16))325return false;326327static constexpr llvm::StringLiteral cpsr_name("cpsr");328value_sp = reg_dict->GetValueForKey(cpsr_name);329if (value_sp.get() == nullptr)330return false;331StorePseudoRegisterValue(dwarf_cpsr,332value_sp->GetValueAs<uint64_t>().value_or(0));333334// Load s/d Registers335// To prevent you giving both types in a state and overwriting336// one or the other, we'll expect to get either all S registers,337// or all D registers. Not a mix of the two.338bool found_s_registers =339LoadRegistersStateFromDictionary(reg_dict, 's', dwarf_s0, 32);340bool found_d_registers =341LoadRegistersStateFromDictionary(reg_dict, 'd', dwarf_d0, 32);342343return found_s_registers != found_d_registers;344}345346347