/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 320 | EmulationStateARM::EmulationStateARM() : m_vfp_regs(), m_memory() { |
24 | 320 | ClearPseudoRegisters(); |
25 | 320 | } |
26 | | |
27 | 320 | EmulationStateARM::~EmulationStateARM() = default; |
28 | | |
29 | | bool EmulationStateARM::StorePseudoRegisterValue(uint32_t reg_num, |
30 | 16.0k | uint64_t value) { |
31 | 16.0k | if (reg_num <= dwarf_cpsr) |
32 | 5.79k | m_gpr[reg_num - dwarf_r0] = (uint32_t)value; |
33 | 10.2k | else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31)) { |
34 | 10.1k | uint32_t idx = reg_num - dwarf_s0; |
35 | 10.1k | m_vfp_regs.s_regs[idx] = (uint32_t)value; |
36 | 10.1k | } else if (136 (dwarf_d0 <= reg_num)136 && (reg_num <= dwarf_d31)136 ) { |
37 | 136 | uint32_t idx = reg_num - dwarf_d0; |
38 | 136 | if (idx < 16) { |
39 | 72 | m_vfp_regs.s_regs[idx * 2] = (uint32_t)value; |
40 | 72 | m_vfp_regs.s_regs[idx * 2 + 1] = (uint32_t)(value >> 32); |
41 | 72 | } else |
42 | 64 | m_vfp_regs.d_regs[idx - 16] = value; |
43 | 136 | } else |
44 | 0 | return false; |
45 | | |
46 | 16.0k | return true; |
47 | 16.0k | } |
48 | | |
49 | | uint64_t EmulationStateARM::ReadPseudoRegisterValue(uint32_t reg_num, |
50 | 699 | bool &success) { |
51 | 699 | uint64_t value = 0; |
52 | 699 | success = true; |
53 | | |
54 | 699 | if (reg_num <= dwarf_cpsr) |
55 | 682 | value = m_gpr[reg_num - dwarf_r0]; |
56 | 17 | else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31)) { |
57 | 9 | uint32_t idx = reg_num - dwarf_s0; |
58 | 9 | value = m_vfp_regs.s_regs[idx]; |
59 | 9 | } else if (8 (dwarf_d0 <= reg_num)8 && (reg_num <= dwarf_d31)8 ) { |
60 | 8 | uint32_t idx = reg_num - dwarf_d0; |
61 | 8 | if (idx < 16) |
62 | 8 | value = (uint64_t)m_vfp_regs.s_regs[idx * 2] | |
63 | 8 | ((uint64_t)m_vfp_regs.s_regs[idx * 2 + 1] << 32); |
64 | 0 | else |
65 | 0 | value = m_vfp_regs.d_regs[idx - 16]; |
66 | 8 | } else |
67 | 0 | success = false; |
68 | | |
69 | 699 | return value; |
70 | 699 | } |
71 | | |
72 | 320 | void EmulationStateARM::ClearPseudoRegisters() { |
73 | 5.76k | for (int i = 0; i < 17; ++i5.44k ) |
74 | 5.44k | m_gpr[i] = 0; |
75 | | |
76 | 10.5k | for (int i = 0; i < 32; ++i10.2k ) |
77 | 10.2k | m_vfp_regs.s_regs[i] = 0; |
78 | | |
79 | 5.44k | for (int i = 0; i < 16; ++i5.12k ) |
80 | 5.12k | m_vfp_regs.d_regs[i] = 0; |
81 | 320 | } |
82 | | |
83 | 0 | void EmulationStateARM::ClearPseudoMemory() { m_memory.clear(); } |
84 | | |
85 | | bool EmulationStateARM::StoreToPseudoAddress(lldb::addr_t p_address, |
86 | 159 | uint32_t value) { |
87 | 159 | m_memory[p_address] = value; |
88 | 159 | return true; |
89 | 159 | } |
90 | | |
91 | | uint32_t EmulationStateARM::ReadFromPseudoAddress(lldb::addr_t p_address, |
92 | 81 | bool &success) { |
93 | 81 | std::map<lldb::addr_t, uint32_t>::iterator pos; |
94 | 81 | uint32_t ret_val = 0; |
95 | | |
96 | 81 | success = true; |
97 | 81 | pos = m_memory.find(p_address); |
98 | 81 | if (pos != m_memory.end()) |
99 | 81 | ret_val = pos->second; |
100 | 0 | else |
101 | 0 | success = false; |
102 | | |
103 | 81 | return ret_val; |
104 | 81 | } |
105 | | |
106 | | size_t EmulationStateARM::ReadPseudoMemory( |
107 | | EmulateInstruction *instruction, void *baton, |
108 | | const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst, |
109 | 73 | size_t length) { |
110 | 73 | if (!baton) |
111 | 0 | return 0; |
112 | | |
113 | 73 | bool success = true; |
114 | 73 | EmulationStateARM *pseudo_state = (EmulationStateARM *)baton; |
115 | 73 | if (length <= 4) { |
116 | 65 | uint32_t value = pseudo_state->ReadFromPseudoAddress(addr, success); |
117 | 65 | if (!success) |
118 | 0 | return 0; |
119 | | |
120 | 65 | if (endian::InlHostByteOrder() == lldb::eByteOrderBig) |
121 | 0 | value = llvm::byteswap<uint32_t>(value); |
122 | 65 | *((uint32_t *)dst) = value; |
123 | 65 | } else if (8 length == 88 ) { |
124 | 8 | uint32_t value1 = pseudo_state->ReadFromPseudoAddress(addr, success); |
125 | 8 | if (!success) |
126 | 0 | return 0; |
127 | | |
128 | 8 | uint32_t value2 = pseudo_state->ReadFromPseudoAddress(addr + 4, success); |
129 | 8 | if (!success) |
130 | 0 | return 0; |
131 | | |
132 | 8 | if (endian::InlHostByteOrder() == lldb::eByteOrderBig) { |
133 | 0 | value1 = llvm::byteswap<uint32_t>(value1); |
134 | 0 | value2 = llvm::byteswap<uint32_t>(value2); |
135 | 0 | } |
136 | 8 | ((uint32_t *)dst)[0] = value1; |
137 | 8 | ((uint32_t *)dst)[1] = value2; |
138 | 8 | } else |
139 | 0 | success = false; |
140 | | |
141 | 73 | if (success) |
142 | 73 | return length; |
143 | | |
144 | 0 | return 0; |
145 | 73 | } |
146 | | |
147 | | size_t EmulationStateARM::WritePseudoMemory( |
148 | | EmulateInstruction *instruction, void *baton, |
149 | | const EmulateInstruction::Context &context, lldb::addr_t addr, |
150 | 50 | const void *dst, size_t length) { |
151 | 50 | if (!baton) |
152 | 0 | return 0; |
153 | | |
154 | 50 | EmulationStateARM *pseudo_state = (EmulationStateARM *)baton; |
155 | | |
156 | 50 | if (length <= 4) { |
157 | 42 | uint32_t value; |
158 | 42 | memcpy (&value, dst, sizeof (uint32_t)); |
159 | 42 | if (endian::InlHostByteOrder() == lldb::eByteOrderBig) |
160 | 0 | value = llvm::byteswap<uint32_t>(value); |
161 | | |
162 | 42 | pseudo_state->StoreToPseudoAddress(addr, value); |
163 | 42 | return length; |
164 | 42 | } else if (8 length == 88 ) { |
165 | 8 | uint32_t value1; |
166 | 8 | uint32_t value2; |
167 | 8 | memcpy (&value1, dst, sizeof (uint32_t)); |
168 | 8 | memcpy(&value2, static_cast<const uint8_t *>(dst) + sizeof(uint32_t), |
169 | 8 | sizeof(uint32_t)); |
170 | 8 | if (endian::InlHostByteOrder() == lldb::eByteOrderBig) { |
171 | 0 | value1 = llvm::byteswap<uint32_t>(value1); |
172 | 0 | value2 = llvm::byteswap<uint32_t>(value2); |
173 | 0 | } |
174 | | |
175 | 8 | pseudo_state->StoreToPseudoAddress(addr, value1); |
176 | 8 | pseudo_state->StoreToPseudoAddress(addr + 4, value2); |
177 | 8 | return length; |
178 | 8 | } |
179 | | |
180 | 0 | return 0; |
181 | 50 | } |
182 | | |
183 | | bool EmulationStateARM::ReadPseudoRegister( |
184 | | EmulateInstruction *instruction, void *baton, |
185 | | const lldb_private::RegisterInfo *reg_info, |
186 | 699 | lldb_private::RegisterValue ®_value) { |
187 | 699 | if (!baton || !reg_info) |
188 | 0 | return false; |
189 | | |
190 | 699 | bool success = true; |
191 | 699 | EmulationStateARM *pseudo_state = (EmulationStateARM *)baton; |
192 | 699 | const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF]; |
193 | 699 | assert(dwarf_reg_num != LLDB_INVALID_REGNUM); |
194 | 699 | uint64_t reg_uval = |
195 | 699 | pseudo_state->ReadPseudoRegisterValue(dwarf_reg_num, success); |
196 | | |
197 | 699 | if (success) |
198 | 699 | success = reg_value.SetUInt(reg_uval, reg_info->byte_size); |
199 | 699 | return success; |
200 | 699 | } |
201 | | |
202 | | bool EmulationStateARM::WritePseudoRegister( |
203 | | EmulateInstruction *instruction, void *baton, |
204 | | const EmulateInstruction::Context &context, |
205 | | const lldb_private::RegisterInfo *reg_info, |
206 | 370 | const lldb_private::RegisterValue ®_value) { |
207 | 370 | if (!baton || !reg_info) |
208 | 0 | return false; |
209 | | |
210 | 370 | EmulationStateARM *pseudo_state = (EmulationStateARM *)baton; |
211 | 370 | const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF]; |
212 | 370 | assert(dwarf_reg_num != LLDB_INVALID_REGNUM); |
213 | 370 | return pseudo_state->StorePseudoRegisterValue(dwarf_reg_num, |
214 | 370 | reg_value.GetAsUInt64()); |
215 | 370 | } |
216 | | |
217 | | bool EmulationStateARM::CompareState(EmulationStateARM &other_state, |
218 | 160 | Stream &out_stream) { |
219 | 160 | bool match = true; |
220 | | |
221 | 2.88k | for (int i = 0; match && i < 17; ++i2.72k ) { |
222 | 2.72k | if (m_gpr[i] != other_state.m_gpr[i]) { |
223 | 0 | match = false; |
224 | 0 | out_stream.Printf("r%d: 0x%x != 0x%x\n", i, m_gpr[i], |
225 | 0 | other_state.m_gpr[i]); |
226 | 0 | } |
227 | 2.72k | } |
228 | | |
229 | 5.28k | for (int i = 0; match && i < 32; ++i5.12k ) { |
230 | 5.12k | if (m_vfp_regs.s_regs[i] != other_state.m_vfp_regs.s_regs[i]) { |
231 | 0 | match = false; |
232 | 0 | out_stream.Printf("s%d: 0x%x != 0x%x\n", i, m_vfp_regs.s_regs[i], |
233 | 0 | other_state.m_vfp_regs.s_regs[i]); |
234 | 0 | } |
235 | 5.12k | } |
236 | | |
237 | 2.72k | for (int i = 0; match && i < 16; ++i2.56k ) { |
238 | 2.56k | if (m_vfp_regs.d_regs[i] != other_state.m_vfp_regs.d_regs[i]) { |
239 | 0 | match = false; |
240 | 0 | out_stream.Printf("d%d: 0x%" PRIx64 " != 0x%" PRIx64 "\n", i + 16, |
241 | 0 | m_vfp_regs.d_regs[i], other_state.m_vfp_regs.d_regs[i]); |
242 | 0 | } |
243 | 2.56k | } |
244 | | |
245 | | // other_state is the expected state. If it has memory, check it. |
246 | 160 | if (!other_state.m_memory.empty() && m_memory != other_state.m_memory3 ) { |
247 | 0 | match = false; |
248 | 0 | out_stream.Printf("memory does not match\n"); |
249 | 0 | out_stream.Printf("got memory:\n"); |
250 | 0 | for (auto p : m_memory) |
251 | 0 | out_stream.Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second); |
252 | 0 | out_stream.Printf("expected memory:\n"); |
253 | 0 | for (auto p : other_state.m_memory) |
254 | 0 | out_stream.Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second); |
255 | 0 | } |
256 | | |
257 | 160 | return match; |
258 | 160 | } |
259 | | |
260 | | bool EmulationStateARM::LoadRegistersStateFromDictionary( |
261 | 960 | OptionValueDictionary *reg_dict, char kind, int first_reg, int num) { |
262 | 960 | StreamString sstr; |
263 | 16.3k | for (int i = 0; i < num; ++i15.3k ) { |
264 | 15.6k | sstr.Clear(); |
265 | 15.6k | sstr.Printf("%c%d", kind, i); |
266 | 15.6k | OptionValueSP value_sp = reg_dict->GetValueForKey(sstr.GetString()); |
267 | 15.6k | if (value_sp.get() == nullptr) |
268 | 320 | return false; |
269 | 15.3k | uint64_t reg_value = value_sp->GetValueAs<uint64_t>().value_or(0); |
270 | 15.3k | StorePseudoRegisterValue(first_reg + i, reg_value); |
271 | 15.3k | } |
272 | | |
273 | 640 | return true; |
274 | 960 | } |
275 | | |
276 | | bool EmulationStateARM::LoadStateFromDictionary( |
277 | 320 | OptionValueDictionary *test_data) { |
278 | 320 | static constexpr llvm::StringLiteral memory_key("memory"); |
279 | 320 | static constexpr llvm::StringLiteral registers_key("registers"); |
280 | | |
281 | 320 | if (!test_data) |
282 | 0 | return false; |
283 | | |
284 | 320 | OptionValueSP value_sp = test_data->GetValueForKey(memory_key); |
285 | | |
286 | | // Load memory, if present. |
287 | | |
288 | 320 | if (value_sp.get() != nullptr) { |
289 | 44 | static constexpr llvm::StringLiteral address_key("address"); |
290 | 44 | static constexpr llvm::StringLiteral data_key("data"); |
291 | 44 | uint64_t start_address = 0; |
292 | | |
293 | 44 | OptionValueDictionary *mem_dict = value_sp->GetAsDictionary(); |
294 | 44 | value_sp = mem_dict->GetValueForKey(address_key); |
295 | 44 | if (value_sp.get() == nullptr) |
296 | 0 | return false; |
297 | 44 | else |
298 | 44 | start_address = value_sp->GetValueAs<uint64_t>().value_or(0); |
299 | | |
300 | 44 | value_sp = mem_dict->GetValueForKey(data_key); |
301 | 44 | OptionValueArray *mem_array = value_sp->GetAsArray(); |
302 | 44 | if (!mem_array) |
303 | 0 | return false; |
304 | | |
305 | 44 | uint32_t num_elts = mem_array->GetSize(); |
306 | 44 | uint32_t address = (uint32_t)start_address; |
307 | | |
308 | 145 | for (uint32_t i = 0; i < num_elts; ++i101 ) { |
309 | 101 | value_sp = mem_array->GetValueAtIndex(i); |
310 | 101 | if (value_sp.get() == nullptr) |
311 | 0 | return false; |
312 | 101 | uint64_t value = value_sp->GetValueAs<uint64_t>().value_or(0); |
313 | 101 | StoreToPseudoAddress(address, value); |
314 | 101 | address = address + 4; |
315 | 101 | } |
316 | 44 | } |
317 | | |
318 | 320 | value_sp = test_data->GetValueForKey(registers_key); |
319 | 320 | if (value_sp.get() == nullptr) |
320 | 0 | return false; |
321 | | |
322 | | // Load General Registers |
323 | | |
324 | 320 | OptionValueDictionary *reg_dict = value_sp->GetAsDictionary(); |
325 | 320 | if (!LoadRegistersStateFromDictionary(reg_dict, 'r', dwarf_r0, 16)) |
326 | 0 | return false; |
327 | | |
328 | 320 | static constexpr llvm::StringLiteral cpsr_name("cpsr"); |
329 | 320 | value_sp = reg_dict->GetValueForKey(cpsr_name); |
330 | 320 | if (value_sp.get() == nullptr) |
331 | 0 | return false; |
332 | 320 | StorePseudoRegisterValue(dwarf_cpsr, |
333 | 320 | 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 | 320 | bool found_s_registers = |
340 | 320 | LoadRegistersStateFromDictionary(reg_dict, 's', dwarf_s0, 32); |
341 | 320 | bool found_d_registers = |
342 | 320 | LoadRegistersStateFromDictionary(reg_dict, 'd', dwarf_d0, 32); |
343 | | |
344 | 320 | return found_s_registers != found_d_registers; |
345 | 320 | } |