1 //===-- RegisterContextMinidump_ARM.cpp -----------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "RegisterContextMinidump_ARM.h"
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"
24 using namespace lldb_private
;
25 using namespace minidump
;
27 #define INV LLDB_INVALID_REGNUM
28 #define OFFSET(r) (offsetof(RegisterContextMinidump_ARM::Context, r))
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, \
37 #define DEF_R_ARG(i, n) \
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, \
42 nullptr, nullptr, nullptr, \
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, \
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, \
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, \
66 // Zero based LLDB register numbers for this register context
68 // General Purpose Registers
86 // Floating Point Registers
171 static RegisterInfo g_reg_info_apple_fp
= {
178 {ehframe_r7
, dwarf_r7
, LLDB_REGNUM_GENERIC_FP
, INV
, reg_r7
},
184 static RegisterInfo g_reg_info_fp
= {
191 {ehframe_r11
, dwarf_r11
, LLDB_REGNUM_GENERIC_FP
, INV
, reg_r11
},
197 // Register info definitions for this register context
198 static RegisterInfo g_reg_infos
[] = {
218 {ehframe_sp
, dwarf_sp
, LLDB_REGNUM_GENERIC_SP
, INV
, reg_sp
},
229 {ehframe_lr
, dwarf_lr
, LLDB_REGNUM_GENERIC_RA
, INV
, reg_lr
},
240 {ehframe_pc
, dwarf_pc
, LLDB_REGNUM_GENERIC_PC
, INV
, reg_pc
},
251 {ehframe_cpsr
, dwarf_cpsr
, LLDB_REGNUM_GENERIC_FLAGS
, INV
, reg_cpsr
},
262 {INV
, INV
, INV
, INV
, reg_fpscr
},
348 constexpr size_t k_num_reg_infos
= std::size(g_reg_infos
);
350 // ARM general purpose registers.
351 const uint32_t g_gpr_regnums
[] = {
369 LLDB_INVALID_REGNUM
// register sets need to end with this flag
371 const uint32_t g_fpu_regnums
[] = {
453 LLDB_INVALID_REGNUM
// register sets need to end with this flag
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;
460 static RegisterSet g_reg_sets
[] = {
461 {"General Purpose Registers", "gpr", k_num_gpr_regs
, g_gpr_regnums
},
462 {"Floating Point Registers", "fpu", k_num_fpu_regs
, g_fpu_regnums
},
465 constexpr size_t k_num_reg_sets
= std::size(g_reg_sets
);
467 RegisterContextMinidump_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
);
472 for (unsigned i
= 0; i
< std::size(m_regs
.r
); ++i
)
473 m_regs
.r
[i
] = data
.GetU32(&offset
);
474 m_regs
.cpsr
= data
.GetU32(&offset
);
475 m_regs
.fpscr
= data
.GetU64(&offset
);
476 for (unsigned i
= 0; i
< std::size(m_regs
.d
); ++i
)
477 m_regs
.d
[i
] = data
.GetU64(&offset
);
478 lldbassert(k_num_regs
== k_num_reg_infos
);
481 size_t RegisterContextMinidump_ARM::GetRegisterCountStatic() {
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();
491 // Used for unit testing so we can verify register info is filled in.
493 RegisterContextMinidump_ARM::GetRegisterInfoAtIndexStatic(size_t reg
,
495 if (reg
< k_num_reg_infos
) {
498 return &g_reg_info_apple_fp
;
501 return &g_reg_info_fp
;
503 return &g_reg_infos
[reg
];
509 RegisterContextMinidump_ARM::GetRegisterInfoAtIndex(size_t reg
) {
510 return GetRegisterInfoAtIndexStatic(reg
, m_apple
);
513 size_t RegisterContextMinidump_ARM::GetRegisterSetCount() {
514 return k_num_reg_sets
;
517 const RegisterSet
*RegisterContextMinidump_ARM::GetRegisterSet(size_t set
) {
518 if (set
< k_num_reg_sets
)
519 return &g_reg_sets
[set
];
523 const char *RegisterContextMinidump_ARM::GetRegisterName(unsigned reg
) {
524 if (reg
< k_num_reg_infos
)
525 return g_reg_infos
[reg
].name
;
529 bool RegisterContextMinidump_ARM::ReadRegister(const RegisterInfo
*reg_info
,
530 RegisterValue
®_value
) {
532 reg_value
.SetFromMemoryData(
533 *reg_info
, (const uint8_t *)&m_regs
+ reg_info
->byte_offset
,
534 reg_info
->byte_size
, lldb::eByteOrderLittle
, error
);
535 return error
.Success();
538 bool RegisterContextMinidump_ARM::WriteRegister(const RegisterInfo
*,
539 const RegisterValue
&) {
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
)
549 return LLDB_INVALID_REGNUM
;