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-exception |
6 | // |
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 | |
20 | using namespace lldb; |
21 | using namespace lldb_private; |
22 | |
23 | EmulationStateARM::EmulationStateARM() : m_vfp_regs(), m_memory() { |
24 | ClearPseudoRegisters(); |
25 | } |
26 | |
27 | EmulationStateARM::~EmulationStateARM() = default; |
28 | |
29 | bool 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 | } else |
42 | m_vfp_regs.d_regs[idx - 16] = value; |
43 | } else |
44 | return false; |
45 | |
46 | return true; |
47 | } |
48 | |
49 | uint64_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 | else |
65 | value = m_vfp_regs.d_regs[idx - 16]; |
66 | } else |
67 | success = false; |
68 | |
69 | return value; |
70 | } |
71 | |
72 | void 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 | |
83 | void EmulationStateARM::ClearPseudoMemory() { m_memory.clear(); } |
84 | |
85 | bool EmulationStateARM::StoreToPseudoAddress(lldb::addr_t p_address, |
86 | uint32_t value) { |
87 | m_memory[p_address] = value; |
88 | return true; |
89 | } |
90 | |
91 | uint32_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(x: p_address); |
98 | if (pos != m_memory.end()) |
99 | ret_val = pos->second; |
100 | else |
101 | success = false; |
102 | |
103 | return ret_val; |
104 | } |
105 | |
106 | size_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(p_address: addr, success); |
117 | if (!success) |
118 | return 0; |
119 | |
120 | if (endian::InlHostByteOrder() == lldb::eByteOrderBig) |
121 | value = llvm::byteswap<uint32_t>(V: value); |
122 | *((uint32_t *)dst) = value; |
123 | } else if (length == 8) { |
124 | uint32_t value1 = pseudo_state->ReadFromPseudoAddress(p_address: addr, success); |
125 | if (!success) |
126 | return 0; |
127 | |
128 | uint32_t value2 = pseudo_state->ReadFromPseudoAddress(p_address: addr + 4, success); |
129 | if (!success) |
130 | return 0; |
131 | |
132 | if (endian::InlHostByteOrder() == lldb::eByteOrderBig) { |
133 | value1 = llvm::byteswap<uint32_t>(V: value1); |
134 | value2 = llvm::byteswap<uint32_t>(V: value2); |
135 | } |
136 | ((uint32_t *)dst)[0] = value1; |
137 | ((uint32_t *)dst)[1] = value2; |
138 | } else |
139 | success = false; |
140 | |
141 | if (success) |
142 | return length; |
143 | |
144 | return 0; |
145 | } |
146 | |
147 | size_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 (dest: &value, src: dst, n: sizeof (uint32_t)); |
159 | if (endian::InlHostByteOrder() == lldb::eByteOrderBig) |
160 | value = llvm::byteswap<uint32_t>(V: value); |
161 | |
162 | pseudo_state->StoreToPseudoAddress(p_address: addr, value); |
163 | return length; |
164 | } else if (length == 8) { |
165 | uint32_t value1; |
166 | uint32_t value2; |
167 | memcpy (dest: &value1, src: dst, n: sizeof (uint32_t)); |
168 | memcpy(dest: &value2, src: static_cast<const uint8_t *>(dst) + sizeof(uint32_t), |
169 | n: sizeof(uint32_t)); |
170 | if (endian::InlHostByteOrder() == lldb::eByteOrderBig) { |
171 | value1 = llvm::byteswap<uint32_t>(V: value1); |
172 | value2 = llvm::byteswap<uint32_t>(V: value2); |
173 | } |
174 | |
175 | pseudo_state->StoreToPseudoAddress(p_address: addr, value: value1); |
176 | pseudo_state->StoreToPseudoAddress(p_address: addr + 4, value: value2); |
177 | return length; |
178 | } |
179 | |
180 | return 0; |
181 | } |
182 | |
183 | bool 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(reg_num: dwarf_reg_num, success); |
196 | |
197 | if (success) |
198 | success = reg_value.SetUInt(uint: reg_uval, byte_size: reg_info->byte_size); |
199 | return success; |
200 | } |
201 | |
202 | bool 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(reg_num: dwarf_reg_num, |
214 | value: reg_value.GetAsUInt64()); |
215 | } |
216 | |
217 | bool 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(format: "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(format: "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(format: "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(format: "memory does not match\n" ); |
249 | out_stream.Printf(format: "got memory:\n" ); |
250 | for (auto p : m_memory) |
251 | out_stream.Printf(format: "0x%08" PRIx64 ": 0x%08x\n" , p.first, p.second); |
252 | out_stream.Printf(format: "expected memory:\n" ); |
253 | for (auto p : other_state.m_memory) |
254 | out_stream.Printf(format: "0x%08" PRIx64 ": 0x%08x\n" , p.first, p.second); |
255 | } |
256 | |
257 | return match; |
258 | } |
259 | |
260 | bool EmulationStateARM::( |
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(format: "%c%d" , kind, i); |
266 | OptionValueSP value_sp = reg_dict->GetValueForKey(key: sstr.GetString()); |
267 | if (value_sp.get() == nullptr) |
268 | return false; |
269 | uint64_t reg_value = value_sp->GetValueAs<uint64_t>().value_or(u: 0); |
270 | StorePseudoRegisterValue(reg_num: first_reg + i, value: reg_value); |
271 | } |
272 | |
273 | return true; |
274 | } |
275 | |
276 | bool 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(key: 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(key: address_key); |
295 | if (value_sp.get() == nullptr) |
296 | return false; |
297 | else |
298 | start_address = value_sp->GetValueAs<uint64_t>().value_or(u: 0); |
299 | |
300 | value_sp = mem_dict->GetValueForKey(key: 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(idx: i); |
310 | if (value_sp.get() == nullptr) |
311 | return false; |
312 | uint64_t value = value_sp->GetValueAs<uint64_t>().value_or(u: 0); |
313 | StoreToPseudoAddress(p_address: address, value); |
314 | address = address + 4; |
315 | } |
316 | } |
317 | |
318 | value_sp = test_data->GetValueForKey(key: registers_key); |
319 | if (value_sp.get() == nullptr) |
320 | return false; |
321 | |
322 | // Load General Registers |
323 | |
324 | OptionValueDictionary *reg_dict = value_sp->GetAsDictionary(); |
325 | if (!LoadRegistersStateFromDictionary(reg_dict, kind: 'r', first_reg: dwarf_r0, num: 16)) |
326 | return false; |
327 | |
328 | static constexpr llvm::StringLiteral cpsr_name("cpsr" ); |
329 | value_sp = reg_dict->GetValueForKey(key: cpsr_name); |
330 | if (value_sp.get() == nullptr) |
331 | return false; |
332 | StorePseudoRegisterValue(reg_num: dwarf_cpsr, |
333 | value: value_sp->GetValueAs<uint64_t>().value_or(u: 0)); |
334 | |
335 | // Load s/d Registers |
336 | // To prevent you giving both types in a state and overwriting |
337 | // 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, kind: 's', first_reg: dwarf_s0, num: 32); |
341 | bool found_d_registers = |
342 | LoadRegistersStateFromDictionary(reg_dict, kind: 'd', first_reg: dwarf_d0, num: 32); |
343 | |
344 | return found_s_registers != found_d_registers; |
345 | } |
346 | |