blob: a0476c962070c9ea286dacfd3ed70e9cac7dd620 [file] [log] [blame]
//===-- 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 &reg_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;
}