blob: eb48785263fcbb8ada08943ea8729c0b83b1e305 [file] [log] [blame]
//===-- RegisterContextMinidump_ARM.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_ARM.h"
#include "Utility/ARM_DWARF_Registers.h"
#include "Utility/ARM_ehframe_Registers.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/lldb-enumerations.h"
// C includes
#include <assert.h>
// C++ includes
using namespace lldb;
using namespace lldb_private;
using namespace minidump;
#define INV LLDB_INVALID_REGNUM
#define OFFSET(r) (offsetof(RegisterContextMinidump_ARM::Context, r))
#define DEF_R(i) \
{ \
"r" #i, nullptr, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \
{ehframe_r##i, dwarf_r##i, INV, INV, reg_r##i}, \
nullptr, nullptr, nullptr, 0 \
}
#define DEF_R_ARG(i, n) \
{ \
"r" #i, "arg" #n, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \
{ehframe_r##i, dwarf_r##i, LLDB_REGNUM_GENERIC_ARG1 + i, INV, reg_r##i}, \
nullptr, nullptr, nullptr, 0 \
}
#define DEF_D(i) \
{ \
"d" #i, nullptr, 8, OFFSET(d) + i * 8, eEncodingVector, \
eFormatVectorOfUInt8, {dwarf_d##i, dwarf_d##i, INV, INV, reg_d##i}, \
nullptr, nullptr, nullptr, 0 \
}
#define DEF_S(i) \
{ \
"s" #i, nullptr, 4, OFFSET(s) + i * 4, eEncodingIEEE754, eFormatFloat, \
{dwarf_s##i, dwarf_s##i, INV, INV, reg_s##i}, \
nullptr, nullptr, nullptr, 0 \
}
#define DEF_Q(i) \
{ \
"q" #i, nullptr, 16, OFFSET(q) + i * 16, eEncodingVector, \
eFormatVectorOfUInt8, {dwarf_q##i, dwarf_q##i, INV, INV, reg_q##i}, \
nullptr, nullptr, nullptr, 0 \
}
// Zero based LLDB register numbers for this register context
enum {
// General Purpose Registers
reg_r0,
reg_r1,
reg_r2,
reg_r3,
reg_r4,
reg_r5,
reg_r6,
reg_r7,
reg_r8,
reg_r9,
reg_r10,
reg_r11,
reg_r12,
reg_sp,
reg_lr,
reg_pc,
reg_cpsr,
// Floating Point Registers
reg_fpscr,
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_q0,
reg_q1,
reg_q2,
reg_q3,
reg_q4,
reg_q5,
reg_q6,
reg_q7,
reg_q8,
reg_q9,
reg_q10,
reg_q11,
reg_q12,
reg_q13,
reg_q14,
reg_q15,
k_num_regs
};
static RegisterInfo g_reg_info_apple_fp = {
"fp",
"r7",
4,
OFFSET(r) + 7 * 4,
eEncodingUint,
eFormatHex,
{ehframe_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, INV, reg_r7},
nullptr,
nullptr,
nullptr,
0};
static RegisterInfo g_reg_info_fp = {
"fp",
"r11",
4,
OFFSET(r) + 11 * 4,
eEncodingUint,
eFormatHex,
{ehframe_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, INV, reg_r11},
nullptr,
nullptr,
nullptr,
0};
// Register info definitions for this register context
static RegisterInfo g_reg_infos[] = {
DEF_R_ARG(0, 1),
DEF_R_ARG(1, 2),
DEF_R_ARG(2, 3),
DEF_R_ARG(3, 4),
DEF_R(4),
DEF_R(5),
DEF_R(6),
DEF_R(7),
DEF_R(8),
DEF_R(9),
DEF_R(10),
DEF_R(11),
DEF_R(12),
{"sp",
"r13",
4,
OFFSET(r) + 13 * 4,
eEncodingUint,
eFormatHex,
{ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, INV, reg_sp},
nullptr,
nullptr,
nullptr,
0},
{"lr",
"r14",
4,
OFFSET(r) + 14 * 4,
eEncodingUint,
eFormatHex,
{ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, INV, reg_lr},
nullptr,
nullptr,
nullptr,
0},
{"pc",
"r15",
4,
OFFSET(r) + 15 * 4,
eEncodingUint,
eFormatHex,
{ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc},
nullptr,
nullptr,
nullptr,
0},
{"cpsr",
"psr",
4,
OFFSET(cpsr),
eEncodingUint,
eFormatHex,
{ehframe_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr},
nullptr,
nullptr,
nullptr,
0},
{"fpscr",
nullptr,
8,
OFFSET(fpscr),
eEncodingUint,
eFormatHex,
{INV, INV, INV, INV, reg_fpscr},
nullptr,
nullptr,
nullptr,
0},
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),
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),
DEF_Q(0),
DEF_Q(1),
DEF_Q(2),
DEF_Q(3),
DEF_Q(4),
DEF_Q(5),
DEF_Q(6),
DEF_Q(7),
DEF_Q(8),
DEF_Q(9),
DEF_Q(10),
DEF_Q(11),
DEF_Q(12),
DEF_Q(13),
DEF_Q(14),
DEF_Q(15)};
constexpr size_t k_num_reg_infos = llvm::array_lengthof(g_reg_infos);
// ARM general purpose registers.
const uint32_t g_gpr_regnums[] = {
reg_r0,
reg_r1,
reg_r2,
reg_r3,
reg_r4,
reg_r5,
reg_r6,
reg_r7,
reg_r8,
reg_r9,
reg_r10,
reg_r11,
reg_r12,
reg_sp,
reg_lr,
reg_pc,
reg_cpsr,
LLDB_INVALID_REGNUM // register sets need to end with this flag
};
const uint32_t g_fpu_regnums[] = {
reg_fpscr,
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_q0,
reg_q1,
reg_q2,
reg_q3,
reg_q4,
reg_q5,
reg_q6,
reg_q7,
reg_q8,
reg_q9,
reg_q10,
reg_q11,
reg_q12,
reg_q13,
reg_q14,
reg_q15,
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 = llvm::array_lengthof(g_gpr_regnums) - 1;
constexpr size_t k_num_fpu_regs = llvm::array_lengthof(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 = llvm::array_lengthof(g_reg_sets);
RegisterContextMinidump_ARM::RegisterContextMinidump_ARM(
lldb_private::Thread &thread, const DataExtractor &data, bool apple)
: RegisterContext(thread, 0), m_apple(apple) {
lldb::offset_t offset = 0;
m_regs.context_flags = data.GetU32(&offset);
for (unsigned i = 0; i < llvm::array_lengthof(m_regs.r); ++i)
m_regs.r[i] = data.GetU32(&offset);
m_regs.cpsr = data.GetU32(&offset);
m_regs.fpscr = data.GetU64(&offset);
for (unsigned i = 0; i < llvm::array_lengthof(m_regs.d); ++i)
m_regs.d[i] = data.GetU64(&offset);
lldbassert(k_num_regs == k_num_reg_infos);
}
size_t RegisterContextMinidump_ARM::GetRegisterCountStatic() {
return k_num_regs;
}
// Used for unit testing so we can verify register info is filled in for
// all register flavors (DWARF, EH Frame, generic, etc).
size_t RegisterContextMinidump_ARM::GetRegisterCount() {
return GetRegisterCountStatic();
}
// Used for unit testing so we can verify register info is filled in.
const RegisterInfo *
RegisterContextMinidump_ARM::GetRegisterInfoAtIndexStatic(size_t reg,
bool apple) {
if (reg < k_num_reg_infos) {
if (apple) {
if (reg == reg_r7)
return &g_reg_info_apple_fp;
} else {
if (reg == reg_r11)
return &g_reg_info_fp;
}
return &g_reg_infos[reg];
}
return nullptr;
}
const RegisterInfo *
RegisterContextMinidump_ARM::GetRegisterInfoAtIndex(size_t reg) {
return GetRegisterInfoAtIndexStatic(reg, m_apple);
}
size_t RegisterContextMinidump_ARM::GetRegisterSetCount() {
return k_num_reg_sets;
}
const RegisterSet *RegisterContextMinidump_ARM::GetRegisterSet(size_t set) {
if (set < k_num_reg_sets)
return &g_reg_sets[set];
return nullptr;
}
const char *RegisterContextMinidump_ARM::GetRegisterName(unsigned reg) {
if (reg < k_num_reg_infos)
return g_reg_infos[reg].name;
return nullptr;
}
bool RegisterContextMinidump_ARM::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_ARM::WriteRegister(const RegisterInfo *,
const RegisterValue &) {
return false;
}
uint32_t RegisterContextMinidump_ARM::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;
}