LLDB mainline
EmulationStateARM.cpp
Go to the documentation of this file.
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
16#include "lldb/Utility/Scalar.h"
17
19
20using namespace lldb;
21using namespace lldb_private;
22
23EmulationStateARM::EmulationStateARM() : m_vfp_regs(), m_memory() {
25}
26
28
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
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
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
84
86 uint32_t value) {
87 m_memory[p_address] = value;
88 return true;
89}
90
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 else
101 success = false;
102
103 return ret_val;
104}
105
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
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
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 } else
139 success = false;
140
141 if (success)
142 return length;
143
144 return 0;
145}
146
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));
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));
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
184 EmulateInstruction *instruction, void *baton,
185 const lldb_private::RegisterInfo *reg_info,
186 lldb_private::RegisterValue &reg_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
203 EmulateInstruction *instruction, void *baton,
204 const EmulateInstruction::Context &context,
205 const lldb_private::RegisterInfo *reg_info,
206 const lldb_private::RegisterValue &reg_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
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
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
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 else
298 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 Registers
323
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;
333 value_sp->GetValueAs<uint64_t>().value_or(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, '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}
@ dwarf_r0
@ dwarf_s0
@ dwarf_s31
@ dwarf_cpsr
@ dwarf_d0
@ dwarf_d31
static bool ReadPseudoRegister(lldb_private::EmulateInstruction *instruction, void *baton, const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &reg_value)
static size_t ReadPseudoMemory(lldb_private::EmulateInstruction *instruction, void *baton, const lldb_private::EmulateInstruction::Context &context, lldb::addr_t addr, void *dst, size_t length)
virtual ~EmulationStateARM()
struct EmulationStateARM::_sd_regs m_vfp_regs
bool StorePseudoRegisterValue(uint32_t reg_num, uint64_t value)
static bool WritePseudoRegister(lldb_private::EmulateInstruction *instruction, void *baton, const lldb_private::EmulateInstruction::Context &context, const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &reg_value)
static size_t WritePseudoMemory(lldb_private::EmulateInstruction *instruction, void *baton, const lldb_private::EmulateInstruction::Context &context, lldb::addr_t addr, const void *dst, size_t length)
std::map< lldb::addr_t, uint32_t > m_memory
bool StoreToPseudoAddress(lldb::addr_t p_address, uint32_t value)
uint64_t ReadPseudoRegisterValue(uint32_t reg_num, bool &success)
bool LoadRegistersStateFromDictionary(lldb_private::OptionValueDictionary *reg_dict, char kind, int first_reg, int num)
bool LoadStateFromDictionary(lldb_private::OptionValueDictionary *test_data)
bool CompareState(EmulationStateARM &other_state, lldb_private::Stream &out_stream)
uint32_t ReadFromPseudoAddress(lldb::addr_t p_address, bool &success)
"lldb/Core/EmulateInstruction.h" A class that allows emulation of CPU opcodes.
lldb::OptionValueSP GetValueAtIndex(size_t idx) const
lldb::OptionValueSP GetValueForKey(llvm::StringRef key) const
OptionValueDictionary * GetAsDictionary()
OptionValueArray * GetAsArray()
bool SetUInt(uint64_t uint, uint32_t byte_size)
uint64_t GetAsUInt64(uint64_t fail_value=UINT64_MAX, bool *success_ptr=nullptr) const
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:134
#define LLDB_INVALID_REGNUM
Definition: lldb-defines.h:87
lldb::ByteOrder InlHostByteOrder()
Definition: Endian.h:25
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Definition: SBAddress.h:15
uint64_t addr_t
Definition: lldb-types.h:79
std::shared_ptr< lldb_private::OptionValue > OptionValueSP
Definition: lldb-forward.h:376
@ eRegisterKindDWARF
the register numbers seen DWARF
Every register is described in detail including its name, alternate name (optional),...
uint32_t byte_size
Size in bytes of the register.
uint32_t kinds[lldb::kNumRegisterKinds]
Holds all of the various register numbers for all register kinds.