| //===-- RegisterContextMinidump_ARM64.cpp ---------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "RegisterContextMinidump_ARM64.h" |
| |
| #include "Utility/ARM64_DWARF_Registers.h" |
| #include "lldb/Utility/RegisterValue.h" |
| #include "lldb/Utility/DataExtractor.h" |
| #include "lldb/lldb-enumerations.h" |
| |
| // C includes |
| #include <cassert> |
| |
| // C++ includes |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| using namespace minidump; |
| |
| #define INV LLDB_INVALID_REGNUM |
| #define OFFSET(r) (offsetof(RegisterContextMinidump_ARM64::Context, r)) |
| |
| #define DEF_X(i) \ |
| { \ |
| "x" #i, nullptr, 8, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \ |
| {arm64_dwarf::x##i, arm64_dwarf::x##i, INV, INV, reg_x##i}, \ |
| nullptr, nullptr, nullptr, \ |
| } |
| |
| #define DEF_W(i) \ |
| { \ |
| "w" #i, nullptr, 4, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \ |
| {INV, INV, INV, INV, reg_w##i}, nullptr, nullptr, nullptr, \ |
| } |
| |
| #define DEF_X_ARG(i, n) \ |
| { \ |
| "x" #i, "arg" #n, 8, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \ |
| {arm64_dwarf::x##i, arm64_dwarf::x##i, LLDB_REGNUM_GENERIC_ARG1 + i, \ |
| INV, reg_x##i}, nullptr, nullptr, nullptr, \ |
| } |
| |
| #define DEF_V(i) \ |
| { \ |
| "v" #i, nullptr, 16, OFFSET(v) + i * 16, eEncodingVector, \ |
| eFormatVectorOfUInt8, {arm64_dwarf::v##i, arm64_dwarf::v##i, INV, INV, \ |
| reg_v##i}, nullptr, nullptr, nullptr, \ |
| } |
| |
| #define DEF_D(i) \ |
| { \ |
| "d" #i, nullptr, 8, OFFSET(v) + i * 16, eEncodingVector, \ |
| eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_d##i}, nullptr, \ |
| nullptr, nullptr, \ |
| } |
| |
| #define DEF_S(i) \ |
| { \ |
| "s" #i, nullptr, 4, OFFSET(v) + i * 16, eEncodingVector, \ |
| eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_s##i}, nullptr, \ |
| nullptr, nullptr, \ |
| } |
| |
| #define DEF_H(i) \ |
| { \ |
| "h" #i, nullptr, 2, OFFSET(v) + i * 16, eEncodingVector, \ |
| eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_h##i}, nullptr, \ |
| nullptr, nullptr, \ |
| } |
| |
| // Zero based LLDB register numbers for this register context |
| enum { |
| // General Purpose Registers |
| reg_x0 = 0, |
| reg_x1, |
| reg_x2, |
| reg_x3, |
| reg_x4, |
| reg_x5, |
| reg_x6, |
| reg_x7, |
| reg_x8, |
| reg_x9, |
| reg_x10, |
| reg_x11, |
| reg_x12, |
| reg_x13, |
| reg_x14, |
| reg_x15, |
| reg_x16, |
| reg_x17, |
| reg_x18, |
| reg_x19, |
| reg_x20, |
| reg_x21, |
| reg_x22, |
| reg_x23, |
| reg_x24, |
| reg_x25, |
| reg_x26, |
| reg_x27, |
| reg_x28, |
| reg_fp, |
| reg_lr, |
| reg_sp, |
| reg_pc, |
| reg_w0, |
| reg_w1, |
| reg_w2, |
| reg_w3, |
| reg_w4, |
| reg_w5, |
| reg_w6, |
| reg_w7, |
| reg_w8, |
| reg_w9, |
| reg_w10, |
| reg_w11, |
| reg_w12, |
| reg_w13, |
| reg_w14, |
| reg_w15, |
| reg_w16, |
| reg_w17, |
| reg_w18, |
| reg_w19, |
| reg_w20, |
| reg_w21, |
| reg_w22, |
| reg_w23, |
| reg_w24, |
| reg_w25, |
| reg_w26, |
| reg_w27, |
| reg_w28, |
| reg_w29, |
| reg_w30, |
| reg_w31, |
| reg_cpsr, |
| // Floating Point Registers |
| reg_fpsr, |
| reg_fpcr, |
| reg_v0, |
| reg_v1, |
| reg_v2, |
| reg_v3, |
| reg_v4, |
| reg_v5, |
| reg_v6, |
| reg_v7, |
| reg_v8, |
| reg_v9, |
| reg_v10, |
| reg_v11, |
| reg_v12, |
| reg_v13, |
| reg_v14, |
| reg_v15, |
| reg_v16, |
| reg_v17, |
| reg_v18, |
| reg_v19, |
| reg_v20, |
| reg_v21, |
| reg_v22, |
| reg_v23, |
| reg_v24, |
| reg_v25, |
| reg_v26, |
| reg_v27, |
| reg_v28, |
| reg_v29, |
| reg_v30, |
| reg_v31, |
| reg_d0, |
| reg_d1, |
| reg_d2, |
| reg_d3, |
| reg_d4, |
| reg_d5, |
| reg_d6, |
| reg_d7, |
| reg_d8, |
| reg_d9, |
| reg_d10, |
| reg_d11, |
| reg_d12, |
| reg_d13, |
| reg_d14, |
| reg_d15, |
| reg_d16, |
| reg_d17, |
| reg_d18, |
| reg_d19, |
| reg_d20, |
| reg_d21, |
| reg_d22, |
| reg_d23, |
| reg_d24, |
| reg_d25, |
| reg_d26, |
| reg_d27, |
| reg_d28, |
| reg_d29, |
| reg_d30, |
| reg_d31, |
| reg_s0, |
| reg_s1, |
| reg_s2, |
| reg_s3, |
| reg_s4, |
| reg_s5, |
| reg_s6, |
| reg_s7, |
| reg_s8, |
| reg_s9, |
| reg_s10, |
| reg_s11, |
| reg_s12, |
| reg_s13, |
| reg_s14, |
| reg_s15, |
| reg_s16, |
| reg_s17, |
| reg_s18, |
| reg_s19, |
| reg_s20, |
| reg_s21, |
| reg_s22, |
| reg_s23, |
| reg_s24, |
| reg_s25, |
| reg_s26, |
| reg_s27, |
| reg_s28, |
| reg_s29, |
| reg_s30, |
| reg_s31, |
| reg_h0, |
| reg_h1, |
| reg_h2, |
| reg_h3, |
| reg_h4, |
| reg_h5, |
| reg_h6, |
| reg_h7, |
| reg_h8, |
| reg_h9, |
| reg_h10, |
| reg_h11, |
| reg_h12, |
| reg_h13, |
| reg_h14, |
| reg_h15, |
| reg_h16, |
| reg_h17, |
| reg_h18, |
| reg_h19, |
| reg_h20, |
| reg_h21, |
| reg_h22, |
| reg_h23, |
| reg_h24, |
| reg_h25, |
| reg_h26, |
| reg_h27, |
| reg_h28, |
| reg_h29, |
| reg_h30, |
| reg_h31, |
| k_num_regs |
| }; |
| |
| // Register info definitions for this register context |
| static RegisterInfo g_reg_infos[] = { |
| DEF_X_ARG(0, 1), |
| DEF_X_ARG(1, 2), |
| DEF_X_ARG(2, 3), |
| DEF_X_ARG(3, 4), |
| DEF_X_ARG(4, 5), |
| DEF_X_ARG(5, 6), |
| DEF_X_ARG(6, 7), |
| DEF_X_ARG(7, 8), |
| DEF_X(8), |
| DEF_X(9), |
| DEF_X(10), |
| DEF_X(11), |
| DEF_X(12), |
| DEF_X(13), |
| DEF_X(14), |
| DEF_X(15), |
| DEF_X(16), |
| DEF_X(17), |
| DEF_X(18), |
| DEF_X(19), |
| DEF_X(20), |
| DEF_X(21), |
| DEF_X(22), |
| DEF_X(23), |
| DEF_X(24), |
| DEF_X(25), |
| DEF_X(26), |
| DEF_X(27), |
| DEF_X(28), |
| {"fp", |
| "x29", |
| 8, |
| OFFSET(x) + 29 * 8, |
| eEncodingUint, |
| eFormatHex, |
| {arm64_dwarf::x29, arm64_dwarf::x29, LLDB_REGNUM_GENERIC_FP, INV, reg_fp}, |
| nullptr, |
| nullptr, |
| nullptr, |
| }, |
| {"lr", |
| "x30", |
| 8, |
| OFFSET(x) + 30 * 8, |
| eEncodingUint, |
| eFormatHex, |
| {arm64_dwarf::x30, arm64_dwarf::x30, LLDB_REGNUM_GENERIC_RA, INV, reg_lr}, |
| nullptr, |
| nullptr, |
| nullptr, |
| }, |
| {"sp", |
| "x31", |
| 8, |
| OFFSET(x) + 31 * 8, |
| eEncodingUint, |
| eFormatHex, |
| {arm64_dwarf::x31, arm64_dwarf::x31, LLDB_REGNUM_GENERIC_SP, INV, reg_sp}, |
| nullptr, |
| nullptr, |
| nullptr, |
| }, |
| {"pc", |
| nullptr, |
| 8, |
| OFFSET(pc), |
| eEncodingUint, |
| eFormatHex, |
| {arm64_dwarf::pc, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc}, |
| nullptr, |
| nullptr, |
| nullptr, |
| }, |
| // w0 - w31 |
| DEF_W(0), |
| DEF_W(1), |
| DEF_W(2), |
| DEF_W(3), |
| DEF_W(4), |
| DEF_W(5), |
| DEF_W(6), |
| DEF_W(7), |
| DEF_W(8), |
| DEF_W(9), |
| DEF_W(10), |
| DEF_W(11), |
| DEF_W(12), |
| DEF_W(13), |
| DEF_W(14), |
| DEF_W(15), |
| DEF_W(16), |
| DEF_W(17), |
| DEF_W(18), |
| DEF_W(19), |
| DEF_W(20), |
| DEF_W(21), |
| DEF_W(22), |
| DEF_W(23), |
| DEF_W(24), |
| DEF_W(25), |
| DEF_W(26), |
| DEF_W(27), |
| DEF_W(28), |
| DEF_W(29), |
| DEF_W(30), |
| DEF_W(31), |
| {"cpsr", |
| "psr", |
| 4, |
| OFFSET(cpsr), |
| eEncodingUint, |
| eFormatHex, |
| {INV, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr}, |
| nullptr, |
| nullptr, |
| nullptr, |
| }, |
| {"fpsr", |
| nullptr, |
| 4, |
| OFFSET(fpsr), |
| eEncodingUint, |
| eFormatHex, |
| {INV, INV, INV, INV, reg_fpsr}, |
| nullptr, |
| nullptr, |
| nullptr, |
| }, |
| {"fpcr", |
| nullptr, |
| 4, |
| OFFSET(fpcr), |
| eEncodingUint, |
| eFormatHex, |
| {INV, INV, INV, INV, reg_fpcr}, |
| nullptr, |
| nullptr, |
| nullptr, |
| }, |
| // v0 - v31 |
| DEF_V(0), |
| DEF_V(1), |
| DEF_V(2), |
| DEF_V(3), |
| DEF_V(4), |
| DEF_V(5), |
| DEF_V(6), |
| DEF_V(7), |
| DEF_V(8), |
| DEF_V(9), |
| DEF_V(10), |
| DEF_V(11), |
| DEF_V(12), |
| DEF_V(13), |
| DEF_V(14), |
| DEF_V(15), |
| DEF_V(16), |
| DEF_V(17), |
| DEF_V(18), |
| DEF_V(19), |
| DEF_V(20), |
| DEF_V(21), |
| DEF_V(22), |
| DEF_V(23), |
| DEF_V(24), |
| DEF_V(25), |
| DEF_V(26), |
| DEF_V(27), |
| DEF_V(28), |
| DEF_V(29), |
| DEF_V(30), |
| DEF_V(31), |
| // d0 - d31 |
| DEF_D(0), |
| DEF_D(1), |
| DEF_D(2), |
| DEF_D(3), |
| DEF_D(4), |
| DEF_D(5), |
| DEF_D(6), |
| DEF_D(7), |
| DEF_D(8), |
| DEF_D(9), |
| DEF_D(10), |
| DEF_D(11), |
| DEF_D(12), |
| DEF_D(13), |
| DEF_D(14), |
| DEF_D(15), |
| DEF_D(16), |
| DEF_D(17), |
| DEF_D(18), |
| DEF_D(19), |
| DEF_D(20), |
| DEF_D(21), |
| DEF_D(22), |
| DEF_D(23), |
| DEF_D(24), |
| DEF_D(25), |
| DEF_D(26), |
| DEF_D(27), |
| DEF_D(28), |
| DEF_D(29), |
| DEF_D(30), |
| DEF_D(31), |
| // s0 - s31 |
| DEF_S(0), |
| DEF_S(1), |
| DEF_S(2), |
| DEF_S(3), |
| DEF_S(4), |
| DEF_S(5), |
| DEF_S(6), |
| DEF_S(7), |
| DEF_S(8), |
| DEF_S(9), |
| DEF_S(10), |
| DEF_S(11), |
| DEF_S(12), |
| DEF_S(13), |
| DEF_S(14), |
| DEF_S(15), |
| DEF_S(16), |
| DEF_S(17), |
| DEF_S(18), |
| DEF_S(19), |
| DEF_S(20), |
| DEF_S(21), |
| DEF_S(22), |
| DEF_S(23), |
| DEF_S(24), |
| DEF_S(25), |
| DEF_S(26), |
| DEF_S(27), |
| DEF_S(28), |
| DEF_S(29), |
| DEF_S(30), |
| DEF_S(31), |
| // h0 - h31 |
| DEF_H(0), |
| DEF_H(1), |
| DEF_H(2), |
| DEF_H(3), |
| DEF_H(4), |
| DEF_H(5), |
| DEF_H(6), |
| DEF_H(7), |
| DEF_H(8), |
| DEF_H(9), |
| DEF_H(10), |
| DEF_H(11), |
| DEF_H(12), |
| DEF_H(13), |
| DEF_H(14), |
| DEF_H(15), |
| DEF_H(16), |
| DEF_H(17), |
| DEF_H(18), |
| DEF_H(19), |
| DEF_H(20), |
| DEF_H(21), |
| DEF_H(22), |
| DEF_H(23), |
| DEF_H(24), |
| DEF_H(25), |
| DEF_H(26), |
| DEF_H(27), |
| DEF_H(28), |
| DEF_H(29), |
| DEF_H(30), |
| DEF_H(31), |
| }; |
| |
| constexpr size_t k_num_reg_infos = std::size(g_reg_infos); |
| |
| // ARM64 general purpose registers. |
| const uint32_t g_gpr_regnums[] = { |
| reg_x0, |
| reg_x1, |
| reg_x2, |
| reg_x3, |
| reg_x4, |
| reg_x5, |
| reg_x6, |
| reg_x7, |
| reg_x8, |
| reg_x9, |
| reg_x10, |
| reg_x11, |
| reg_x12, |
| reg_x13, |
| reg_x14, |
| reg_x15, |
| reg_x16, |
| reg_x17, |
| reg_x18, |
| reg_x19, |
| reg_x20, |
| reg_x21, |
| reg_x22, |
| reg_x23, |
| reg_x24, |
| reg_x25, |
| reg_x26, |
| reg_x27, |
| reg_x28, |
| reg_fp, |
| reg_lr, |
| reg_sp, |
| reg_w0, |
| reg_w1, |
| reg_w2, |
| reg_w3, |
| reg_w4, |
| reg_w5, |
| reg_w6, |
| reg_w7, |
| reg_w8, |
| reg_w9, |
| reg_w10, |
| reg_w11, |
| reg_w12, |
| reg_w13, |
| reg_w14, |
| reg_w15, |
| reg_w16, |
| reg_w17, |
| reg_w18, |
| reg_w19, |
| reg_w20, |
| reg_w21, |
| reg_w22, |
| reg_w23, |
| reg_w24, |
| reg_w25, |
| reg_w26, |
| reg_w27, |
| reg_w28, |
| reg_w29, |
| reg_w30, |
| reg_w31, |
| reg_pc, |
| reg_cpsr, |
| LLDB_INVALID_REGNUM // register sets need to end with this flag |
| }; |
| const uint32_t g_fpu_regnums[] = { |
| reg_v0, |
| reg_v1, |
| reg_v2, |
| reg_v3, |
| reg_v4, |
| reg_v5, |
| reg_v6, |
| reg_v7, |
| reg_v8, |
| reg_v9, |
| reg_v10, |
| reg_v11, |
| reg_v12, |
| reg_v13, |
| reg_v14, |
| reg_v15, |
| reg_v16, |
| reg_v17, |
| reg_v18, |
| reg_v19, |
| reg_v20, |
| reg_v21, |
| reg_v22, |
| reg_v23, |
| reg_v24, |
| reg_v25, |
| reg_v26, |
| reg_v27, |
| reg_v28, |
| reg_v29, |
| reg_v30, |
| reg_v31, |
| reg_d0, |
| reg_d1, |
| reg_d2, |
| reg_d3, |
| reg_d4, |
| reg_d5, |
| reg_d6, |
| reg_d7, |
| reg_d8, |
| reg_d9, |
| reg_d10, |
| reg_d11, |
| reg_d12, |
| reg_d13, |
| reg_d14, |
| reg_d15, |
| reg_d16, |
| reg_d17, |
| reg_d18, |
| reg_d19, |
| reg_d20, |
| reg_d21, |
| reg_d22, |
| reg_d23, |
| reg_d24, |
| reg_d25, |
| reg_d26, |
| reg_d27, |
| reg_d28, |
| reg_d29, |
| reg_d30, |
| reg_d31, |
| reg_s0, |
| reg_s1, |
| reg_s2, |
| reg_s3, |
| reg_s4, |
| reg_s5, |
| reg_s6, |
| reg_s7, |
| reg_s8, |
| reg_s9, |
| reg_s10, |
| reg_s11, |
| reg_s12, |
| reg_s13, |
| reg_s14, |
| reg_s15, |
| reg_s16, |
| reg_s17, |
| reg_s18, |
| reg_s19, |
| reg_s20, |
| reg_s21, |
| reg_s22, |
| reg_s23, |
| reg_s24, |
| reg_s25, |
| reg_s26, |
| reg_s27, |
| reg_s28, |
| reg_s29, |
| reg_s30, |
| reg_s31, |
| reg_h0, |
| reg_h1, |
| reg_h2, |
| reg_h3, |
| reg_h4, |
| reg_h5, |
| reg_h6, |
| reg_h7, |
| reg_h8, |
| reg_h9, |
| reg_h10, |
| reg_h11, |
| reg_h12, |
| reg_h13, |
| reg_h14, |
| reg_h15, |
| reg_h16, |
| reg_h17, |
| reg_h18, |
| reg_h19, |
| reg_h20, |
| reg_h21, |
| reg_h22, |
| reg_h23, |
| reg_h24, |
| reg_h25, |
| reg_h26, |
| reg_h27, |
| reg_h28, |
| reg_h29, |
| reg_h30, |
| reg_h31, |
| reg_fpsr, |
| reg_fpcr, |
| LLDB_INVALID_REGNUM // register sets need to end with this flag |
| }; |
| |
| // Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1 |
| constexpr size_t k_num_gpr_regs = std::size(g_gpr_regnums) - 1; |
| constexpr size_t k_num_fpu_regs = std::size(g_fpu_regnums) - 1; |
| |
| static RegisterSet g_reg_sets[] = { |
| {"General Purpose Registers", "gpr", k_num_gpr_regs, g_gpr_regnums}, |
| {"Floating Point Registers", "fpu", k_num_fpu_regs, g_fpu_regnums}, |
| }; |
| |
| constexpr size_t k_num_reg_sets = std::size(g_reg_sets); |
| |
| RegisterContextMinidump_ARM64::RegisterContextMinidump_ARM64( |
| lldb_private::Thread &thread, const DataExtractor &data) |
| : RegisterContext(thread, 0) { |
| lldb::offset_t offset = 0; |
| m_regs.context_flags = data.GetU64(&offset); |
| for (unsigned i = 0; i < 32; ++i) |
| m_regs.x[i] = data.GetU64(&offset); |
| m_regs.pc = data.GetU64(&offset); |
| m_regs.cpsr = data.GetU32(&offset); |
| m_regs.fpsr = data.GetU32(&offset); |
| m_regs.fpcr = data.GetU32(&offset); |
| auto regs_data = data.GetData(&offset, sizeof(m_regs.v)); |
| if (regs_data) |
| memcpy(m_regs.v, regs_data, sizeof(m_regs.v)); |
| static_assert(k_num_regs == k_num_reg_infos); |
| } |
| size_t RegisterContextMinidump_ARM64::GetRegisterCount() { return k_num_regs; } |
| |
| const RegisterInfo * |
| RegisterContextMinidump_ARM64::GetRegisterInfoAtIndex(size_t reg) { |
| if (reg < k_num_reg_infos) |
| return &g_reg_infos[reg]; |
| return nullptr; |
| } |
| |
| size_t RegisterContextMinidump_ARM64::GetRegisterSetCount() { |
| return k_num_reg_sets; |
| } |
| |
| const RegisterSet *RegisterContextMinidump_ARM64::GetRegisterSet(size_t set) { |
| if (set < k_num_reg_sets) |
| return &g_reg_sets[set]; |
| return nullptr; |
| } |
| |
| const char *RegisterContextMinidump_ARM64::GetRegisterName(unsigned reg) { |
| if (reg < k_num_reg_infos) |
| return g_reg_infos[reg].name; |
| return nullptr; |
| } |
| |
| bool RegisterContextMinidump_ARM64::ReadRegister(const RegisterInfo *reg_info, |
| RegisterValue ®_value) { |
| Status error; |
| reg_value.SetFromMemoryData( |
| *reg_info, (const uint8_t *)&m_regs + reg_info->byte_offset, |
| reg_info->byte_size, lldb::eByteOrderLittle, error); |
| return error.Success(); |
| } |
| |
| bool RegisterContextMinidump_ARM64::WriteRegister(const RegisterInfo *, |
| const RegisterValue &) { |
| return false; |
| } |
| |
| uint32_t RegisterContextMinidump_ARM64::ConvertRegisterKindToRegisterNumber( |
| lldb::RegisterKind kind, uint32_t num) { |
| for (size_t i = 0; i < k_num_regs; ++i) { |
| if (g_reg_infos[i].kinds[kind] == num) |
| return i; |
| } |
| return LLDB_INVALID_REGNUM; |
| } |