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
23using namespace lldb;
24using namespace lldb_private;
25using 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
67enum {
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
171static 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
184static 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
198static 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
348constexpr size_t k_num_reg_infos = std::size(g_reg_infos);
349
350// ARM general purpose registers.
351const 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};
371const 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
457constexpr size_t k_num_gpr_regs = std::size(g_gpr_regnums) - 1;
458constexpr size_t k_num_fpu_regs = std::size(g_fpu_regnums) - 1;
459
460static 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
465constexpr size_t k_num_reg_sets = std::size(g_reg_sets);
466
467RegisterContextMinidump_ARM::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
481size_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).
487size_t RegisterContextMinidump_ARM::GetRegisterCount() {
488 return GetRegisterCountStatic();
489}
490
491// Used for unit testing so we can verify register info is filled in.
492const RegisterInfo *
493RegisterContextMinidump_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
508const RegisterInfo *
509RegisterContextMinidump_ARM::GetRegisterInfoAtIndex(size_t reg) {
510 return GetRegisterInfoAtIndexStatic(reg, apple: m_apple);
511}
512
513size_t RegisterContextMinidump_ARM::GetRegisterSetCount() {
514 return k_num_reg_sets;
515}
516
517const 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
523const 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
529bool RegisterContextMinidump_ARM::ReadRegister(const RegisterInfo *reg_info,
530 RegisterValue &reg_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
538bool RegisterContextMinidump_ARM::WriteRegister(const RegisterInfo *,
539 const RegisterValue &) {
540 return false;
541}
542
543uint32_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

source code of lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp