xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- EmulationStateARM.cpp ---------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "EmulationStateARM.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/Interpreter/OptionValueArray.h"
12061da546Spatrick #include "lldb/Interpreter/OptionValueDictionary.h"
13061da546Spatrick #include "lldb/Target/RegisterContext.h"
14061da546Spatrick #include "lldb/Target/StackFrame.h"
15061da546Spatrick #include "lldb/Utility/RegisterValue.h"
16061da546Spatrick #include "lldb/Utility/Scalar.h"
17061da546Spatrick 
18061da546Spatrick #include "Utility/ARM_DWARF_Registers.h"
19061da546Spatrick 
20061da546Spatrick using namespace lldb;
21061da546Spatrick using namespace lldb_private;
22061da546Spatrick 
EmulationStateARM()23be691f3bSpatrick EmulationStateARM::EmulationStateARM() : m_vfp_regs(), m_memory() {
24061da546Spatrick   ClearPseudoRegisters();
25061da546Spatrick }
26061da546Spatrick 
27be691f3bSpatrick EmulationStateARM::~EmulationStateARM() = default;
28061da546Spatrick 
StorePseudoRegisterValue(uint32_t reg_num,uint64_t value)29061da546Spatrick bool EmulationStateARM::StorePseudoRegisterValue(uint32_t reg_num,
30061da546Spatrick                                                  uint64_t value) {
31061da546Spatrick   if (reg_num <= dwarf_cpsr)
32061da546Spatrick     m_gpr[reg_num - dwarf_r0] = (uint32_t)value;
33061da546Spatrick   else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31)) {
34061da546Spatrick     uint32_t idx = reg_num - dwarf_s0;
35061da546Spatrick     m_vfp_regs.s_regs[idx] = (uint32_t)value;
36061da546Spatrick   } else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31)) {
37061da546Spatrick     uint32_t idx = reg_num - dwarf_d0;
38061da546Spatrick     if (idx < 16) {
39061da546Spatrick       m_vfp_regs.s_regs[idx * 2] = (uint32_t)value;
40061da546Spatrick       m_vfp_regs.s_regs[idx * 2 + 1] = (uint32_t)(value >> 32);
41061da546Spatrick     } else
42061da546Spatrick       m_vfp_regs.d_regs[idx - 16] = value;
43061da546Spatrick   } else
44061da546Spatrick     return false;
45061da546Spatrick 
46061da546Spatrick   return true;
47061da546Spatrick }
48061da546Spatrick 
ReadPseudoRegisterValue(uint32_t reg_num,bool & success)49061da546Spatrick uint64_t EmulationStateARM::ReadPseudoRegisterValue(uint32_t reg_num,
50061da546Spatrick                                                     bool &success) {
51061da546Spatrick   uint64_t value = 0;
52061da546Spatrick   success = true;
53061da546Spatrick 
54061da546Spatrick   if (reg_num <= dwarf_cpsr)
55061da546Spatrick     value = m_gpr[reg_num - dwarf_r0];
56061da546Spatrick   else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31)) {
57061da546Spatrick     uint32_t idx = reg_num - dwarf_s0;
58*f6aab3d8Srobert     value = m_vfp_regs.s_regs[idx];
59061da546Spatrick   } else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31)) {
60061da546Spatrick     uint32_t idx = reg_num - dwarf_d0;
61061da546Spatrick     if (idx < 16)
62061da546Spatrick       value = (uint64_t)m_vfp_regs.s_regs[idx * 2] |
63*f6aab3d8Srobert               ((uint64_t)m_vfp_regs.s_regs[idx * 2 + 1] << 32);
64061da546Spatrick     else
65061da546Spatrick       value = m_vfp_regs.d_regs[idx - 16];
66061da546Spatrick   } else
67061da546Spatrick     success = false;
68061da546Spatrick 
69061da546Spatrick   return value;
70061da546Spatrick }
71061da546Spatrick 
ClearPseudoRegisters()72061da546Spatrick void EmulationStateARM::ClearPseudoRegisters() {
73061da546Spatrick   for (int i = 0; i < 17; ++i)
74061da546Spatrick     m_gpr[i] = 0;
75061da546Spatrick 
76061da546Spatrick   for (int i = 0; i < 32; ++i)
77061da546Spatrick     m_vfp_regs.s_regs[i] = 0;
78061da546Spatrick 
79061da546Spatrick   for (int i = 0; i < 16; ++i)
80061da546Spatrick     m_vfp_regs.d_regs[i] = 0;
81061da546Spatrick }
82061da546Spatrick 
ClearPseudoMemory()83061da546Spatrick void EmulationStateARM::ClearPseudoMemory() { m_memory.clear(); }
84061da546Spatrick 
StoreToPseudoAddress(lldb::addr_t p_address,uint32_t value)85061da546Spatrick bool EmulationStateARM::StoreToPseudoAddress(lldb::addr_t p_address,
86061da546Spatrick                                              uint32_t value) {
87061da546Spatrick   m_memory[p_address] = value;
88061da546Spatrick   return true;
89061da546Spatrick }
90061da546Spatrick 
ReadFromPseudoAddress(lldb::addr_t p_address,bool & success)91061da546Spatrick uint32_t EmulationStateARM::ReadFromPseudoAddress(lldb::addr_t p_address,
92061da546Spatrick                                                   bool &success) {
93061da546Spatrick   std::map<lldb::addr_t, uint32_t>::iterator pos;
94061da546Spatrick   uint32_t ret_val = 0;
95061da546Spatrick 
96061da546Spatrick   success = true;
97061da546Spatrick   pos = m_memory.find(p_address);
98061da546Spatrick   if (pos != m_memory.end())
99061da546Spatrick     ret_val = pos->second;
100061da546Spatrick   else
101061da546Spatrick     success = false;
102061da546Spatrick 
103061da546Spatrick   return ret_val;
104061da546Spatrick }
105061da546Spatrick 
ReadPseudoMemory(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,void * dst,size_t length)106061da546Spatrick size_t EmulationStateARM::ReadPseudoMemory(
107061da546Spatrick     EmulateInstruction *instruction, void *baton,
108061da546Spatrick     const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst,
109061da546Spatrick     size_t length) {
110061da546Spatrick   if (!baton)
111061da546Spatrick     return 0;
112061da546Spatrick 
113061da546Spatrick   bool success = true;
114061da546Spatrick   EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;
115061da546Spatrick   if (length <= 4) {
116061da546Spatrick     uint32_t value = pseudo_state->ReadFromPseudoAddress(addr, success);
117061da546Spatrick     if (!success)
118061da546Spatrick       return 0;
119061da546Spatrick 
120061da546Spatrick     if (endian::InlHostByteOrder() == lldb::eByteOrderBig)
121061da546Spatrick       value = llvm::ByteSwap_32(value);
122061da546Spatrick     *((uint32_t *)dst) = value;
123061da546Spatrick   } else if (length == 8) {
124061da546Spatrick     uint32_t value1 = pseudo_state->ReadFromPseudoAddress(addr, success);
125061da546Spatrick     if (!success)
126061da546Spatrick       return 0;
127061da546Spatrick 
128061da546Spatrick     uint32_t value2 = pseudo_state->ReadFromPseudoAddress(addr + 4, success);
129061da546Spatrick     if (!success)
130061da546Spatrick       return 0;
131061da546Spatrick 
132061da546Spatrick     if (endian::InlHostByteOrder() == lldb::eByteOrderBig) {
133061da546Spatrick       value1 = llvm::ByteSwap_32(value1);
134061da546Spatrick       value2 = llvm::ByteSwap_32(value2);
135061da546Spatrick     }
136061da546Spatrick     ((uint32_t *)dst)[0] = value1;
137061da546Spatrick     ((uint32_t *)dst)[1] = value2;
138061da546Spatrick   } else
139061da546Spatrick     success = false;
140061da546Spatrick 
141061da546Spatrick   if (success)
142061da546Spatrick     return length;
143061da546Spatrick 
144061da546Spatrick   return 0;
145061da546Spatrick }
146061da546Spatrick 
WritePseudoMemory(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,const void * dst,size_t length)147061da546Spatrick size_t EmulationStateARM::WritePseudoMemory(
148061da546Spatrick     EmulateInstruction *instruction, void *baton,
149061da546Spatrick     const EmulateInstruction::Context &context, lldb::addr_t addr,
150061da546Spatrick     const void *dst, size_t length) {
151061da546Spatrick   if (!baton)
152061da546Spatrick     return 0;
153061da546Spatrick 
154061da546Spatrick   EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;
155061da546Spatrick 
156061da546Spatrick   if (length <= 4) {
157061da546Spatrick     uint32_t value;
158061da546Spatrick     memcpy (&value, dst, sizeof (uint32_t));
159061da546Spatrick     if (endian::InlHostByteOrder() == lldb::eByteOrderBig)
160061da546Spatrick       value = llvm::ByteSwap_32(value);
161061da546Spatrick 
162061da546Spatrick     pseudo_state->StoreToPseudoAddress(addr, value);
163061da546Spatrick     return length;
164061da546Spatrick   } else if (length == 8) {
165061da546Spatrick     uint32_t value1;
166061da546Spatrick     uint32_t value2;
167061da546Spatrick     memcpy (&value1, dst, sizeof (uint32_t));
168061da546Spatrick     memcpy(&value2, static_cast<const uint8_t *>(dst) + sizeof(uint32_t),
169061da546Spatrick            sizeof(uint32_t));
170061da546Spatrick     if (endian::InlHostByteOrder() == lldb::eByteOrderBig) {
171061da546Spatrick       value1 = llvm::ByteSwap_32(value1);
172061da546Spatrick       value2 = llvm::ByteSwap_32(value2);
173061da546Spatrick     }
174061da546Spatrick 
175061da546Spatrick     pseudo_state->StoreToPseudoAddress(addr, value1);
176061da546Spatrick     pseudo_state->StoreToPseudoAddress(addr + 4, value2);
177061da546Spatrick     return length;
178061da546Spatrick   }
179061da546Spatrick 
180061da546Spatrick   return 0;
181061da546Spatrick }
182061da546Spatrick 
ReadPseudoRegister(EmulateInstruction * instruction,void * baton,const lldb_private::RegisterInfo * reg_info,lldb_private::RegisterValue & reg_value)183061da546Spatrick bool EmulationStateARM::ReadPseudoRegister(
184061da546Spatrick     EmulateInstruction *instruction, void *baton,
185061da546Spatrick     const lldb_private::RegisterInfo *reg_info,
186061da546Spatrick     lldb_private::RegisterValue &reg_value) {
187061da546Spatrick   if (!baton || !reg_info)
188061da546Spatrick     return false;
189061da546Spatrick 
190061da546Spatrick   bool success = true;
191061da546Spatrick   EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;
192061da546Spatrick   const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];
193061da546Spatrick   assert(dwarf_reg_num != LLDB_INVALID_REGNUM);
194061da546Spatrick   uint64_t reg_uval =
195061da546Spatrick       pseudo_state->ReadPseudoRegisterValue(dwarf_reg_num, success);
196061da546Spatrick 
197061da546Spatrick   if (success)
198061da546Spatrick     success = reg_value.SetUInt(reg_uval, reg_info->byte_size);
199061da546Spatrick   return success;
200061da546Spatrick }
201061da546Spatrick 
WritePseudoRegister(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,const lldb_private::RegisterInfo * reg_info,const lldb_private::RegisterValue & reg_value)202061da546Spatrick bool EmulationStateARM::WritePseudoRegister(
203061da546Spatrick     EmulateInstruction *instruction, void *baton,
204061da546Spatrick     const EmulateInstruction::Context &context,
205061da546Spatrick     const lldb_private::RegisterInfo *reg_info,
206061da546Spatrick     const lldb_private::RegisterValue &reg_value) {
207061da546Spatrick   if (!baton || !reg_info)
208061da546Spatrick     return false;
209061da546Spatrick 
210061da546Spatrick   EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;
211061da546Spatrick   const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];
212061da546Spatrick   assert(dwarf_reg_num != LLDB_INVALID_REGNUM);
213061da546Spatrick   return pseudo_state->StorePseudoRegisterValue(dwarf_reg_num,
214061da546Spatrick                                                 reg_value.GetAsUInt64());
215061da546Spatrick }
216061da546Spatrick 
CompareState(EmulationStateARM & other_state,Stream * out_stream)217*f6aab3d8Srobert bool EmulationStateARM::CompareState(EmulationStateARM &other_state,
218*f6aab3d8Srobert                                      Stream *out_stream) {
219061da546Spatrick   bool match = true;
220061da546Spatrick 
221061da546Spatrick   for (int i = 0; match && i < 17; ++i) {
222*f6aab3d8Srobert     if (m_gpr[i] != other_state.m_gpr[i]) {
223061da546Spatrick       match = false;
224*f6aab3d8Srobert       out_stream->Printf("r%d: 0x%x != 0x%x\n", i, m_gpr[i],
225*f6aab3d8Srobert                          other_state.m_gpr[i]);
226*f6aab3d8Srobert     }
227061da546Spatrick   }
228061da546Spatrick 
229061da546Spatrick   for (int i = 0; match && i < 32; ++i) {
230*f6aab3d8Srobert     if (m_vfp_regs.s_regs[i] != other_state.m_vfp_regs.s_regs[i]) {
231061da546Spatrick       match = false;
232*f6aab3d8Srobert       out_stream->Printf("s%d: 0x%x != 0x%x\n", i, m_vfp_regs.s_regs[i],
233*f6aab3d8Srobert                          other_state.m_vfp_regs.s_regs[i]);
234*f6aab3d8Srobert     }
235061da546Spatrick   }
236061da546Spatrick 
237061da546Spatrick   for (int i = 0; match && i < 16; ++i) {
238*f6aab3d8Srobert     if (m_vfp_regs.d_regs[i] != other_state.m_vfp_regs.d_regs[i]) {
239061da546Spatrick       match = false;
240*f6aab3d8Srobert       out_stream->Printf("d%d: 0x%" PRIx64 " != 0x%" PRIx64 "\n", i + 16,
241*f6aab3d8Srobert                          m_vfp_regs.d_regs[i],
242*f6aab3d8Srobert                          other_state.m_vfp_regs.d_regs[i]);
243*f6aab3d8Srobert     }
244*f6aab3d8Srobert   }
245*f6aab3d8Srobert 
246*f6aab3d8Srobert   // other_state is the expected state. If it has memory, check it.
247*f6aab3d8Srobert   if (!other_state.m_memory.empty() && m_memory != other_state.m_memory) {
248*f6aab3d8Srobert     match = false;
249*f6aab3d8Srobert     out_stream->Printf("memory does not match\n");
250*f6aab3d8Srobert     out_stream->Printf("got memory:\n");
251*f6aab3d8Srobert     for (auto p : m_memory)
252*f6aab3d8Srobert       out_stream->Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second);
253*f6aab3d8Srobert     out_stream->Printf("expected memory:\n");
254*f6aab3d8Srobert     for (auto p : other_state.m_memory)
255*f6aab3d8Srobert       out_stream->Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second);
256061da546Spatrick   }
257061da546Spatrick 
258061da546Spatrick   return match;
259061da546Spatrick }
260061da546Spatrick 
LoadRegistersStateFromDictionary(OptionValueDictionary * reg_dict,char kind,int first_reg,int num)261*f6aab3d8Srobert bool EmulationStateARM::LoadRegistersStateFromDictionary(
262*f6aab3d8Srobert     OptionValueDictionary *reg_dict, char kind, int first_reg, int num) {
263*f6aab3d8Srobert   StreamString sstr;
264*f6aab3d8Srobert   for (int i = 0; i < num; ++i) {
265*f6aab3d8Srobert     sstr.Clear();
266*f6aab3d8Srobert     sstr.Printf("%c%d", kind, i);
267*f6aab3d8Srobert     OptionValueSP value_sp =
268*f6aab3d8Srobert         reg_dict->GetValueForKey(ConstString(sstr.GetString()));
269*f6aab3d8Srobert     if (value_sp.get() == nullptr)
270*f6aab3d8Srobert       return false;
271*f6aab3d8Srobert     uint64_t reg_value = value_sp->GetUInt64Value();
272*f6aab3d8Srobert     StorePseudoRegisterValue(first_reg + i, reg_value);
273*f6aab3d8Srobert   }
274*f6aab3d8Srobert 
275*f6aab3d8Srobert   return true;
276*f6aab3d8Srobert }
277*f6aab3d8Srobert 
LoadStateFromDictionary(OptionValueDictionary * test_data)278061da546Spatrick bool EmulationStateARM::LoadStateFromDictionary(
279061da546Spatrick     OptionValueDictionary *test_data) {
280061da546Spatrick   static ConstString memory_key("memory");
281061da546Spatrick   static ConstString registers_key("registers");
282061da546Spatrick 
283061da546Spatrick   if (!test_data)
284061da546Spatrick     return false;
285061da546Spatrick 
286061da546Spatrick   OptionValueSP value_sp = test_data->GetValueForKey(memory_key);
287061da546Spatrick 
288061da546Spatrick   // Load memory, if present.
289061da546Spatrick 
290061da546Spatrick   if (value_sp.get() != nullptr) {
291061da546Spatrick     static ConstString address_key("address");
292061da546Spatrick     static ConstString data_key("data");
293061da546Spatrick     uint64_t start_address = 0;
294061da546Spatrick 
295061da546Spatrick     OptionValueDictionary *mem_dict = value_sp->GetAsDictionary();
296061da546Spatrick     value_sp = mem_dict->GetValueForKey(address_key);
297061da546Spatrick     if (value_sp.get() == nullptr)
298061da546Spatrick       return false;
299061da546Spatrick     else
300061da546Spatrick       start_address = value_sp->GetUInt64Value();
301061da546Spatrick 
302061da546Spatrick     value_sp = mem_dict->GetValueForKey(data_key);
303061da546Spatrick     OptionValueArray *mem_array = value_sp->GetAsArray();
304061da546Spatrick     if (!mem_array)
305061da546Spatrick       return false;
306061da546Spatrick 
307061da546Spatrick     uint32_t num_elts = mem_array->GetSize();
308061da546Spatrick     uint32_t address = (uint32_t)start_address;
309061da546Spatrick 
310061da546Spatrick     for (uint32_t i = 0; i < num_elts; ++i) {
311061da546Spatrick       value_sp = mem_array->GetValueAtIndex(i);
312061da546Spatrick       if (value_sp.get() == nullptr)
313061da546Spatrick         return false;
314061da546Spatrick       uint64_t value = value_sp->GetUInt64Value();
315061da546Spatrick       StoreToPseudoAddress(address, value);
316061da546Spatrick       address = address + 4;
317061da546Spatrick     }
318061da546Spatrick   }
319061da546Spatrick 
320061da546Spatrick   value_sp = test_data->GetValueForKey(registers_key);
321061da546Spatrick   if (value_sp.get() == nullptr)
322061da546Spatrick     return false;
323061da546Spatrick 
324061da546Spatrick   // Load General Registers
325061da546Spatrick 
326061da546Spatrick   OptionValueDictionary *reg_dict = value_sp->GetAsDictionary();
327*f6aab3d8Srobert   if (!LoadRegistersStateFromDictionary(reg_dict, 'r', dwarf_r0, 16))
328061da546Spatrick     return false;
329061da546Spatrick 
330061da546Spatrick   static ConstString cpsr_name("cpsr");
331061da546Spatrick   value_sp = reg_dict->GetValueForKey(cpsr_name);
332061da546Spatrick   if (value_sp.get() == nullptr)
333061da546Spatrick     return false;
334061da546Spatrick   StorePseudoRegisterValue(dwarf_cpsr, value_sp->GetUInt64Value());
335061da546Spatrick 
336061da546Spatrick   // Load s/d Registers
337*f6aab3d8Srobert   // To prevent you giving both types in a state and overwriting
338*f6aab3d8Srobert   // one or the other, we'll expect to get either all S registers,
339*f6aab3d8Srobert   // or all D registers. Not a mix of the two.
340*f6aab3d8Srobert   bool found_s_registers =
341*f6aab3d8Srobert       LoadRegistersStateFromDictionary(reg_dict, 's', dwarf_s0, 32);
342*f6aab3d8Srobert   bool found_d_registers =
343*f6aab3d8Srobert       LoadRegistersStateFromDictionary(reg_dict, 'd', dwarf_d0, 32);
344061da546Spatrick 
345*f6aab3d8Srobert   return found_s_registers != found_d_registers;
346061da546Spatrick }
347