1 | //===-- RegisterContextMinidump_ARM.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 "RegisterContextMinidump_ARM.h" |
10 | |
11 | #include "Utility/ARM_DWARF_Registers.h" |
12 | #include "Utility/ARM_ehframe_Registers.h" |
13 | #include "lldb/Utility/RegisterValue.h" |
14 | #include "lldb/Utility/DataExtractor.h" |
15 | #include "lldb/Utility/LLDBAssert.h" |
16 | #include "lldb/lldb-enumerations.h" |
17 | |
18 | // C includes |
19 | #include <cassert> |
20 | |
21 | // C++ includes |
22 | |
23 | using namespace lldb; |
24 | using namespace lldb_private; |
25 | using namespace minidump; |
26 | |
27 | #define INV LLDB_INVALID_REGNUM |
28 | #define OFFSET(r) (offsetof(RegisterContextMinidump_ARM::Context, r)) |
29 | |
30 | #define DEF_R(i) \ |
31 | { \ |
32 | "r" #i, nullptr, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \ |
33 | {ehframe_r##i, dwarf_r##i, INV, INV, reg_r##i}, nullptr, nullptr, \ |
34 | nullptr, \ |
35 | } |
36 | |
37 | #define DEF_R_ARG(i, n) \ |
38 | { \ |
39 | "r" #i, "arg" #n, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \ |
40 | {ehframe_r##i, dwarf_r##i, LLDB_REGNUM_GENERIC_ARG1 + i, INV, \ |
41 | reg_r##i}, \ |
42 | nullptr, nullptr, nullptr, \ |
43 | } |
44 | |
45 | #define DEF_D(i) \ |
46 | { \ |
47 | "d" #i, nullptr, 8, OFFSET(d) + i * 8, eEncodingVector, \ |
48 | eFormatVectorOfUInt8, {dwarf_d##i, dwarf_d##i, INV, INV, reg_d##i}, \ |
49 | nullptr, nullptr, nullptr, \ |
50 | } |
51 | |
52 | #define DEF_S(i) \ |
53 | { \ |
54 | "s" #i, nullptr, 4, OFFSET(s) + i * 4, eEncodingIEEE754, eFormatFloat, \ |
55 | {dwarf_s##i, dwarf_s##i, INV, INV, reg_s##i}, nullptr, nullptr, \ |
56 | nullptr, \ |
57 | } |
58 | |
59 | #define DEF_Q(i) \ |
60 | { \ |
61 | "q" #i, nullptr, 16, OFFSET(q) + i * 16, eEncodingVector, \ |
62 | eFormatVectorOfUInt8, {dwarf_q##i, dwarf_q##i, INV, INV, reg_q##i}, \ |
63 | nullptr, nullptr, nullptr, \ |
64 | } |
65 | |
66 | // Zero based LLDB register numbers for this register context |
67 | enum { |
68 | // General Purpose Registers |
69 | reg_r0, |
70 | reg_r1, |
71 | reg_r2, |
72 | reg_r3, |
73 | reg_r4, |
74 | reg_r5, |
75 | reg_r6, |
76 | reg_r7, |
77 | reg_r8, |
78 | reg_r9, |
79 | reg_r10, |
80 | reg_r11, |
81 | reg_r12, |
82 | reg_sp, |
83 | reg_lr, |
84 | reg_pc, |
85 | reg_cpsr, |
86 | // Floating Point Registers |
87 | reg_fpscr, |
88 | reg_d0, |
89 | reg_d1, |
90 | reg_d2, |
91 | reg_d3, |
92 | reg_d4, |
93 | reg_d5, |
94 | reg_d6, |
95 | reg_d7, |
96 | reg_d8, |
97 | reg_d9, |
98 | reg_d10, |
99 | reg_d11, |
100 | reg_d12, |
101 | reg_d13, |
102 | reg_d14, |
103 | reg_d15, |
104 | reg_d16, |
105 | reg_d17, |
106 | reg_d18, |
107 | reg_d19, |
108 | reg_d20, |
109 | reg_d21, |
110 | reg_d22, |
111 | reg_d23, |
112 | reg_d24, |
113 | reg_d25, |
114 | reg_d26, |
115 | reg_d27, |
116 | reg_d28, |
117 | reg_d29, |
118 | reg_d30, |
119 | reg_d31, |
120 | reg_s0, |
121 | reg_s1, |
122 | reg_s2, |
123 | reg_s3, |
124 | reg_s4, |
125 | reg_s5, |
126 | reg_s6, |
127 | reg_s7, |
128 | reg_s8, |
129 | reg_s9, |
130 | reg_s10, |
131 | reg_s11, |
132 | reg_s12, |
133 | reg_s13, |
134 | reg_s14, |
135 | reg_s15, |
136 | reg_s16, |
137 | reg_s17, |
138 | reg_s18, |
139 | reg_s19, |
140 | reg_s20, |
141 | reg_s21, |
142 | reg_s22, |
143 | reg_s23, |
144 | reg_s24, |
145 | reg_s25, |
146 | reg_s26, |
147 | reg_s27, |
148 | reg_s28, |
149 | reg_s29, |
150 | reg_s30, |
151 | reg_s31, |
152 | reg_q0, |
153 | reg_q1, |
154 | reg_q2, |
155 | reg_q3, |
156 | reg_q4, |
157 | reg_q5, |
158 | reg_q6, |
159 | reg_q7, |
160 | reg_q8, |
161 | reg_q9, |
162 | reg_q10, |
163 | reg_q11, |
164 | reg_q12, |
165 | reg_q13, |
166 | reg_q14, |
167 | reg_q15, |
168 | k_num_regs |
169 | }; |
170 | |
171 | static RegisterInfo g_reg_info_apple_fp = { |
172 | .name: "fp" , |
173 | .alt_name: "r7" , |
174 | .byte_size: 4, |
175 | OFFSET(r) + 7 * 4, |
176 | .encoding: eEncodingUint, |
177 | .format: eFormatHex, |
178 | .kinds: {ehframe_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, INV, reg_r7}, |
179 | .value_regs: nullptr, |
180 | .invalidate_regs: nullptr, |
181 | .flags_type: nullptr, |
182 | }; |
183 | |
184 | static RegisterInfo g_reg_info_fp = { |
185 | .name: "fp" , |
186 | .alt_name: "r11" , |
187 | .byte_size: 4, |
188 | OFFSET(r) + 11 * 4, |
189 | .encoding: eEncodingUint, |
190 | .format: eFormatHex, |
191 | .kinds: {ehframe_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, INV, reg_r11}, |
192 | .value_regs: nullptr, |
193 | .invalidate_regs: nullptr, |
194 | .flags_type: nullptr, |
195 | }; |
196 | |
197 | // Register info definitions for this register context |
198 | static RegisterInfo g_reg_infos[] = { |
199 | DEF_R_ARG(0, 1), |
200 | DEF_R_ARG(1, 2), |
201 | DEF_R_ARG(2, 3), |
202 | DEF_R_ARG(3, 4), |
203 | DEF_R(4), |
204 | DEF_R(5), |
205 | DEF_R(6), |
206 | DEF_R(7), |
207 | DEF_R(8), |
208 | DEF_R(9), |
209 | DEF_R(10), |
210 | DEF_R(11), |
211 | DEF_R(12), |
212 | {.name: "sp" , |
213 | .alt_name: "r13" , |
214 | .byte_size: 4, |
215 | OFFSET(r) + 13 * 4, |
216 | .encoding: eEncodingUint, |
217 | .format: eFormatHex, |
218 | .kinds: {ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, INV, reg_sp}, |
219 | .value_regs: nullptr, |
220 | .invalidate_regs: nullptr, |
221 | .flags_type: nullptr, |
222 | }, |
223 | {.name: "lr" , |
224 | .alt_name: "r14" , |
225 | .byte_size: 4, |
226 | OFFSET(r) + 14 * 4, |
227 | .encoding: eEncodingUint, |
228 | .format: eFormatHex, |
229 | .kinds: {ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, INV, reg_lr}, |
230 | .value_regs: nullptr, |
231 | .invalidate_regs: nullptr, |
232 | .flags_type: nullptr, |
233 | }, |
234 | {.name: "pc" , |
235 | .alt_name: "r15" , |
236 | .byte_size: 4, |
237 | OFFSET(r) + 15 * 4, |
238 | .encoding: eEncodingUint, |
239 | .format: eFormatHex, |
240 | .kinds: {ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc}, |
241 | .value_regs: nullptr, |
242 | .invalidate_regs: nullptr, |
243 | .flags_type: nullptr, |
244 | }, |
245 | {.name: "cpsr" , |
246 | .alt_name: "psr" , |
247 | .byte_size: 4, |
248 | OFFSET(cpsr), |
249 | .encoding: eEncodingUint, |
250 | .format: eFormatHex, |
251 | .kinds: {ehframe_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr}, |
252 | .value_regs: nullptr, |
253 | .invalidate_regs: nullptr, |
254 | .flags_type: nullptr, |
255 | }, |
256 | {.name: "fpscr" , |
257 | .alt_name: nullptr, |
258 | .byte_size: 8, |
259 | OFFSET(fpscr), |
260 | .encoding: eEncodingUint, |
261 | .format: eFormatHex, |
262 | .kinds: {INV, INV, INV, INV, reg_fpscr}, |
263 | .value_regs: nullptr, |
264 | .invalidate_regs: nullptr, |
265 | .flags_type: nullptr, |
266 | }, |
267 | DEF_D(0), |
268 | DEF_D(1), |
269 | DEF_D(2), |
270 | DEF_D(3), |
271 | DEF_D(4), |
272 | DEF_D(5), |
273 | DEF_D(6), |
274 | DEF_D(7), |
275 | DEF_D(8), |
276 | DEF_D(9), |
277 | DEF_D(10), |
278 | DEF_D(11), |
279 | DEF_D(12), |
280 | DEF_D(13), |
281 | DEF_D(14), |
282 | DEF_D(15), |
283 | DEF_D(16), |
284 | DEF_D(17), |
285 | DEF_D(18), |
286 | DEF_D(19), |
287 | DEF_D(20), |
288 | DEF_D(21), |
289 | DEF_D(22), |
290 | DEF_D(23), |
291 | DEF_D(24), |
292 | DEF_D(25), |
293 | DEF_D(26), |
294 | DEF_D(27), |
295 | DEF_D(28), |
296 | DEF_D(29), |
297 | DEF_D(30), |
298 | DEF_D(31), |
299 | DEF_S(0), |
300 | DEF_S(1), |
301 | DEF_S(2), |
302 | DEF_S(3), |
303 | DEF_S(4), |
304 | DEF_S(5), |
305 | DEF_S(6), |
306 | DEF_S(7), |
307 | DEF_S(8), |
308 | DEF_S(9), |
309 | DEF_S(10), |
310 | DEF_S(11), |
311 | DEF_S(12), |
312 | DEF_S(13), |
313 | DEF_S(14), |
314 | DEF_S(15), |
315 | DEF_S(16), |
316 | DEF_S(17), |
317 | DEF_S(18), |
318 | DEF_S(19), |
319 | DEF_S(20), |
320 | DEF_S(21), |
321 | DEF_S(22), |
322 | DEF_S(23), |
323 | DEF_S(24), |
324 | DEF_S(25), |
325 | DEF_S(26), |
326 | DEF_S(27), |
327 | DEF_S(28), |
328 | DEF_S(29), |
329 | DEF_S(30), |
330 | DEF_S(31), |
331 | DEF_Q(0), |
332 | DEF_Q(1), |
333 | DEF_Q(2), |
334 | DEF_Q(3), |
335 | DEF_Q(4), |
336 | DEF_Q(5), |
337 | DEF_Q(6), |
338 | DEF_Q(7), |
339 | DEF_Q(8), |
340 | DEF_Q(9), |
341 | DEF_Q(10), |
342 | DEF_Q(11), |
343 | DEF_Q(12), |
344 | DEF_Q(13), |
345 | DEF_Q(14), |
346 | DEF_Q(15)}; |
347 | |
348 | constexpr size_t k_num_reg_infos = std::size(g_reg_infos); |
349 | |
350 | // ARM general purpose registers. |
351 | const uint32_t g_gpr_regnums[] = { |
352 | reg_r0, |
353 | reg_r1, |
354 | reg_r2, |
355 | reg_r3, |
356 | reg_r4, |
357 | reg_r5, |
358 | reg_r6, |
359 | reg_r7, |
360 | reg_r8, |
361 | reg_r9, |
362 | reg_r10, |
363 | reg_r11, |
364 | reg_r12, |
365 | reg_sp, |
366 | reg_lr, |
367 | reg_pc, |
368 | reg_cpsr, |
369 | LLDB_INVALID_REGNUM // register sets need to end with this flag |
370 | }; |
371 | const uint32_t g_fpu_regnums[] = { |
372 | reg_fpscr, |
373 | reg_d0, |
374 | reg_d1, |
375 | reg_d2, |
376 | reg_d3, |
377 | reg_d4, |
378 | reg_d5, |
379 | reg_d6, |
380 | reg_d7, |
381 | reg_d8, |
382 | reg_d9, |
383 | reg_d10, |
384 | reg_d11, |
385 | reg_d12, |
386 | reg_d13, |
387 | reg_d14, |
388 | reg_d15, |
389 | reg_d16, |
390 | reg_d17, |
391 | reg_d18, |
392 | reg_d19, |
393 | reg_d20, |
394 | reg_d21, |
395 | reg_d22, |
396 | reg_d23, |
397 | reg_d24, |
398 | reg_d25, |
399 | reg_d26, |
400 | reg_d27, |
401 | reg_d28, |
402 | reg_d29, |
403 | reg_d30, |
404 | reg_d31, |
405 | reg_s0, |
406 | reg_s1, |
407 | reg_s2, |
408 | reg_s3, |
409 | reg_s4, |
410 | reg_s5, |
411 | reg_s6, |
412 | reg_s7, |
413 | reg_s8, |
414 | reg_s9, |
415 | reg_s10, |
416 | reg_s11, |
417 | reg_s12, |
418 | reg_s13, |
419 | reg_s14, |
420 | reg_s15, |
421 | reg_s16, |
422 | reg_s17, |
423 | reg_s18, |
424 | reg_s19, |
425 | reg_s20, |
426 | reg_s21, |
427 | reg_s22, |
428 | reg_s23, |
429 | reg_s24, |
430 | reg_s25, |
431 | reg_s26, |
432 | reg_s27, |
433 | reg_s28, |
434 | reg_s29, |
435 | reg_s30, |
436 | reg_s31, |
437 | reg_q0, |
438 | reg_q1, |
439 | reg_q2, |
440 | reg_q3, |
441 | reg_q4, |
442 | reg_q5, |
443 | reg_q6, |
444 | reg_q7, |
445 | reg_q8, |
446 | reg_q9, |
447 | reg_q10, |
448 | reg_q11, |
449 | reg_q12, |
450 | reg_q13, |
451 | reg_q14, |
452 | reg_q15, |
453 | LLDB_INVALID_REGNUM // register sets need to end with this flag |
454 | }; |
455 | |
456 | // Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1 |
457 | constexpr size_t k_num_gpr_regs = std::size(g_gpr_regnums) - 1; |
458 | constexpr size_t k_num_fpu_regs = std::size(g_fpu_regnums) - 1; |
459 | |
460 | static RegisterSet g_reg_sets[] = { |
461 | {.name: "General Purpose Registers" , .short_name: "gpr" , .num_registers: k_num_gpr_regs, .registers: g_gpr_regnums}, |
462 | {.name: "Floating Point Registers" , .short_name: "fpu" , .num_registers: k_num_fpu_regs, .registers: g_fpu_regnums}, |
463 | }; |
464 | |
465 | constexpr size_t k_num_reg_sets = std::size(g_reg_sets); |
466 | |
467 | RegisterContextMinidump_ARM::( |
468 | lldb_private::Thread &thread, const DataExtractor &data, bool apple) |
469 | : RegisterContext(thread, 0), m_apple(apple) { |
470 | lldb::offset_t offset = 0; |
471 | m_regs.context_flags = data.GetU32(offset_ptr: &offset); |
472 | for (unsigned i = 0; i < std::size(m_regs.r); ++i) |
473 | m_regs.r[i] = data.GetU32(offset_ptr: &offset); |
474 | m_regs.cpsr = data.GetU32(offset_ptr: &offset); |
475 | m_regs.fpscr = data.GetU64(offset_ptr: &offset); |
476 | for (unsigned i = 0; i < std::size(m_regs.d); ++i) |
477 | m_regs.d[i] = data.GetU64(offset_ptr: &offset); |
478 | lldbassert(k_num_regs == k_num_reg_infos); |
479 | } |
480 | |
481 | size_t RegisterContextMinidump_ARM::GetRegisterCountStatic() { |
482 | return k_num_regs; |
483 | } |
484 | |
485 | // Used for unit testing so we can verify register info is filled in for |
486 | // all register flavors (DWARF, EH Frame, generic, etc). |
487 | size_t RegisterContextMinidump_ARM::GetRegisterCount() { |
488 | return GetRegisterCountStatic(); |
489 | } |
490 | |
491 | // Used for unit testing so we can verify register info is filled in. |
492 | const RegisterInfo * |
493 | RegisterContextMinidump_ARM::GetRegisterInfoAtIndexStatic(size_t reg, |
494 | bool apple) { |
495 | if (reg < k_num_reg_infos) { |
496 | if (apple) { |
497 | if (reg == reg_r7) |
498 | return &g_reg_info_apple_fp; |
499 | } else { |
500 | if (reg == reg_r11) |
501 | return &g_reg_info_fp; |
502 | } |
503 | return &g_reg_infos[reg]; |
504 | } |
505 | return nullptr; |
506 | } |
507 | |
508 | const RegisterInfo * |
509 | RegisterContextMinidump_ARM::GetRegisterInfoAtIndex(size_t reg) { |
510 | return GetRegisterInfoAtIndexStatic(reg, apple: m_apple); |
511 | } |
512 | |
513 | size_t RegisterContextMinidump_ARM::GetRegisterSetCount() { |
514 | return k_num_reg_sets; |
515 | } |
516 | |
517 | const RegisterSet *RegisterContextMinidump_ARM::GetRegisterSet(size_t set) { |
518 | if (set < k_num_reg_sets) |
519 | return &g_reg_sets[set]; |
520 | return nullptr; |
521 | } |
522 | |
523 | const char *RegisterContextMinidump_ARM::GetRegisterName(unsigned reg) { |
524 | if (reg < k_num_reg_infos) |
525 | return g_reg_infos[reg].name; |
526 | return nullptr; |
527 | } |
528 | |
529 | bool RegisterContextMinidump_ARM::ReadRegister(const RegisterInfo *reg_info, |
530 | RegisterValue ®_value) { |
531 | Status error; |
532 | reg_value.SetFromMemoryData( |
533 | reg_info: *reg_info, src: (const uint8_t *)&m_regs + reg_info->byte_offset, |
534 | src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle, error); |
535 | return error.Success(); |
536 | } |
537 | |
538 | bool RegisterContextMinidump_ARM::WriteRegister(const RegisterInfo *, |
539 | const RegisterValue &) { |
540 | return false; |
541 | } |
542 | |
543 | uint32_t RegisterContextMinidump_ARM::ConvertRegisterKindToRegisterNumber( |
544 | lldb::RegisterKind kind, uint32_t num) { |
545 | for (size_t i = 0; i < k_num_regs; ++i) { |
546 | if (g_reg_infos[i].kinds[kind] == num) |
547 | return i; |
548 | } |
549 | return LLDB_INVALID_REGNUM; |
550 | } |
551 | |