Author: Jason Molenda Date: 2025-04-23T22:10:15-07:00 New Revision: 096ab51de03437e38f97a48b8f2d453fb903414a
URL: https://github.com/llvm/llvm-project/commit/096ab51de03437e38f97a48b8f2d453fb903414a DIFF: https://github.com/llvm/llvm-project/commit/096ab51de03437e38f97a48b8f2d453fb903414a.diff LOG: [lldb][MachO] MachO corefile support for riscv32 binaries (#137092) Add support for reading a macho corefile with CPU_TYPE_RISCV and the riscv32 general purpose register file. I added code for the floating point and exception registers too, but haven't exercised this. If we start putting the full CSR register bank in a riscv corefile, it'll be in separate 4k byte chunks, but I don't have a corefile to test against that so I haven't written the code to read it. The RegisterContextDarwin_riscv32 is copied & in the style of the other RegisterContextDarwin classes; it's not the first choice I would make for representing this, but it wasn't worth changing for this cputype. rdar://145014653 Added: lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.cpp lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.h lldb/test/API/macosx/riscv32-corefile/Makefile lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py lldb/test/API/macosx/riscv32-corefile/create-empty-riscv-corefile.cpp Modified: lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp lldb/source/Plugins/Process/Utility/CMakeLists.txt Removed: ################################################################################ diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index f31b56b9f81e6..9d5e0f886a4a5 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -12,6 +12,7 @@ #include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" #include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" #include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" +#include "Plugins/Process/Utility/RegisterContextDarwin_riscv32.h" #include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -769,6 +770,147 @@ class RegisterContextDarwin_arm64_Mach : public RegisterContextDarwin_arm64 { } }; +class RegisterContextDarwin_riscv32_Mach + : public RegisterContextDarwin_riscv32 { +public: + RegisterContextDarwin_riscv32_Mach(lldb_private::Thread &thread, + const DataExtractor &data) + : RegisterContextDarwin_riscv32(thread, 0) { + SetRegisterDataFrom_LC_THREAD(data); + } + + void InvalidateAllRegisters() override { + // Do nothing... registers are always valid... + } + + void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) { + lldb::offset_t offset = 0; + SetError(GPRRegSet, Read, -1); + SetError(FPURegSet, Read, -1); + SetError(EXCRegSet, Read, -1); + SetError(CSRRegSet, Read, -1); + bool done = false; + while (!done) { + int flavor = data.GetU32(&offset); + uint32_t count = data.GetU32(&offset); + lldb::offset_t next_thread_state = offset + (count * 4); + switch (flavor) { + case GPRRegSet: + // x0-x31 + pc + if (count >= 32) { + for (uint32_t i = 0; i < 32; ++i) + ((uint32_t *)&gpr.x0)[i] = data.GetU32(&offset); + gpr.pc = data.GetU32(&offset); + SetError(GPRRegSet, Read, 0); + } + offset = next_thread_state; + break; + case FPURegSet: { + // f0-f31 + fcsr + if (count >= 32) { + for (uint32_t i = 0; i < 32; ++i) + ((uint32_t *)&fpr.f0)[i] = data.GetU32(&offset); + fpr.fcsr = data.GetU32(&offset); + SetError(FPURegSet, Read, 0); + } + } + offset = next_thread_state; + break; + case EXCRegSet: + if (count == 3) { + exc.exception = data.GetU32(&offset); + exc.fsr = data.GetU32(&offset); + exc.far = data.GetU32(&offset); + SetError(EXCRegSet, Read, 0); + } + offset = next_thread_state; + break; + default: + done = true; + break; + } + } + } + + static bool Create_LC_THREAD(Thread *thread, Stream &data) { + RegisterContextSP reg_ctx_sp(thread->GetRegisterContext()); + if (reg_ctx_sp) { + RegisterContext *reg_ctx = reg_ctx_sp.get(); + + data.PutHex32(GPRRegSet); // Flavor + data.PutHex32(GPRWordCount); + PrintRegisterValue(reg_ctx, "x0", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x1", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x2", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x3", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x4", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x5", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x6", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x7", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x8", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x9", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x10", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x11", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x12", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x13", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x14", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x15", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x16", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x17", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x18", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x19", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x20", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x21", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x22", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x23", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x24", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x25", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x26", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x27", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x28", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x29", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x30", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "x31", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "pc", nullptr, 4, data); + data.PutHex32(0); // uint32_t pad at the end + + // Write out the EXC registers + data.PutHex32(EXCRegSet); + data.PutHex32(EXCWordCount); + PrintRegisterValue(reg_ctx, "exception", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "fsr", nullptr, 4, data); + PrintRegisterValue(reg_ctx, "far", nullptr, 4, data); + return true; + } + return false; + } + +protected: + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return -1; } + + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return -1; } + + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return -1; } + + int DoReadCSR(lldb::tid_t tid, int flavor, CSR &csr) override { return -1; } + + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override { + return 0; + } + + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override { + return 0; + } + + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override { + return 0; + } + + int DoWriteCSR(lldb::tid_t tid, int flavor, const CSR &csr) override { + return 0; + } +}; + static uint32_t MachHeaderSizeFromMagic(uint32_t magic) { switch (magic) { case MH_MAGIC: @@ -5827,6 +5969,11 @@ ObjectFileMachO::GetThreadContextAtIndex(uint32_t idx, reg_ctx_sp = std::make_shared<RegisterContextDarwin_x86_64_Mach>(thread, data); break; + + case llvm::MachO::CPU_TYPE_RISCV: + reg_ctx_sp = + std::make_shared<RegisterContextDarwin_riscv32_Mach>(thread, data); + break; } } } @@ -6695,6 +6842,11 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, RegisterContextDarwin_x86_64_Mach::Create_LC_THREAD( thread_sp.get(), LC_THREAD_datas[thread_idx]); break; + + case llvm::MachO::CPU_TYPE_RISCV: + RegisterContextDarwin_riscv32_Mach::Create_LC_THREAD( + thread_sp.get(), LC_THREAD_datas[thread_idx]); + break; } } } diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt index f269f5d7d4d74..d29605fddd5cb 100644 --- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt @@ -20,6 +20,7 @@ add_lldb_library(lldbPluginProcessUtility RegisterContextDarwin_arm.cpp RegisterContextDarwin_arm64.cpp RegisterContextDarwin_i386.cpp + RegisterContextDarwin_riscv32.cpp RegisterContextDarwin_x86_64.cpp RegisterContextDummy.cpp RegisterContextFreeBSD_i386.cpp diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.cpp new file mode 100644 index 0000000000000..14f5bc3ea8c49 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.cpp @@ -0,0 +1,1313 @@ +//===-- RegisterContextDarwin_riscv32.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 "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Scalar.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Compiler.h" + +#include <cstddef> + +#include <memory> + +#include "RegisterContextDarwin_riscv32.h" +#include "Utility/RISCV_DWARF_Registers.h" + +using namespace lldb; +using namespace lldb_private; + +enum { + gpr_x0 = 0, + gpr_x1, + gpr_x2, + gpr_x3, + gpr_x4, + gpr_x5, + gpr_x6, + gpr_x7, + gpr_x8, + gpr_x9, + gpr_x10, + gpr_x11, + gpr_x12, + gpr_x13, + gpr_x14, + gpr_x15, + gpr_x16, + gpr_x17, + gpr_x18, + gpr_x19, + gpr_x20, + gpr_x21, + gpr_x22, + gpr_x23, + gpr_x24, + gpr_x25, + gpr_x26, + gpr_x27, + gpr_x28, + gpr_x29, + gpr_x30, + gpr_x31, + gpr_pc, + + fpr_f0, + fpr_f1, + fpr_f2, + fpr_f3, + fpr_f4, + fpr_f5, + fpr_f6, + fpr_f7, + fpr_f8, + fpr_f9, + fpr_f10, + fpr_f11, + fpr_f12, + fpr_f13, + fpr_f14, + fpr_f15, + fpr_f16, + fpr_f17, + fpr_f18, + fpr_f19, + fpr_f20, + fpr_f21, + fpr_f22, + fpr_f23, + fpr_f24, + fpr_f25, + fpr_f26, + fpr_f27, + fpr_f28, + fpr_f29, + fpr_f30, + fpr_f31, + fpr_fcsr, + + exc_exception, + exc_fsr, + exc_far, + + csr_bank, + + k_num_registers +}; + +/* clang-format off */ +#define GPR_OFFSET(reg) \ + (LLVM_EXTENSION offsetof(RegisterContextDarwin_riscv32::GPR, reg)) +#define FPU_OFFSET(reg) \ + (LLVM_EXTENSION offsetof(RegisterContextDarwin_riscv32::FPU, reg) + \ + sizeof(RegisterContextDarwin_riscv32::GPR)) +#define EXC_OFFSET(reg) \ + (LLVM_EXTENSION offsetof(RegisterContextDarwin_riscv32::EXC, reg) + \ + sizeof(RegisterContextDarwin_riscv32::GPR) + \ + sizeof(RegisterContextDarwin_riscv32::FPU)) + +// These macros will auto define the register name, alt name, register size, +// register offset, encoding, format and native register. This ensures that the +// register state structures are defined correctly and have the correct sizes +// and offsets. +#define DEFINE_GPR_ABI(reg, canon) \ + #reg, #canon, \ + sizeof(((RegisterContextDarwin_riscv32::GPR *)nullptr)->canon), \ + GPR_OFFSET(canon), eEncodingUint, eFormatHex +#define DEFINE_GPR(reg) \ + #reg, nullptr, \ + sizeof(((RegisterContextDarwin_riscv32::GPR *)nullptr)->reg), \ + GPR_OFFSET(reg), eEncodingUint, eFormatHex +#define DEFINE_FPU_ABI(reg, canon) \ + #reg, #canon, \ + sizeof(((RegisterContextDarwin_riscv32::FPU *)nullptr)->canon), \ + FPU_OFFSET(canon), eEncodingUint, eFormatHex +#define DEFINE_FPU(reg) \ + #reg, nullptr, \ + sizeof(((RegisterContextDarwin_riscv32::FPU *)nullptr)->reg), \ + FPU_OFFSET(reg), eEncodingUint, eFormatHex +#define DEFINE_EXC(reg) \ + #reg, nullptr, \ + sizeof(((RegisterContextDarwin_riscv32::EXC *)nullptr)->reg), \ + EXC_OFFSET(reg), eEncodingUint, eFormatHex +#define REG_CONTEXT_SIZE \ + (sizeof(RegisterContextDarwin_riscv32::GPR) + \ + sizeof(RegisterContextDarwin_riscv32::FPU) + \ + sizeof(RegisterContextDarwin_riscv32::EXC) + \ + sizeof(RegisterContextDarwin_riscv32::CSR)) +/* clang-format on */ + +static RegisterInfo g_register_infos[] = { + { + DEFINE_GPR_ABI(zero, x0), + {riscv_dwarf::dwarf_gpr_x0, riscv_dwarf::dwarf_gpr_x0, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x0}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(ra, x1), + {riscv_dwarf::dwarf_gpr_x1, riscv_dwarf::dwarf_gpr_x1, + LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, gpr_x1}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(sp, x2), + {riscv_dwarf::dwarf_gpr_x2, riscv_dwarf::dwarf_gpr_x2, + LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, gpr_x2}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(gp, x3), + {riscv_dwarf::dwarf_gpr_x3, riscv_dwarf::dwarf_gpr_x3, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x3}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(tp, x4), + {riscv_dwarf::dwarf_gpr_x4, riscv_dwarf::dwarf_gpr_x4, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x4}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(t0, x5), + {riscv_dwarf::dwarf_gpr_x5, riscv_dwarf::dwarf_gpr_x5, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x5}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(t1, x6), + {riscv_dwarf::dwarf_gpr_x6, riscv_dwarf::dwarf_gpr_x6, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x6}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(t2, x7), + {riscv_dwarf::dwarf_gpr_x7, riscv_dwarf::dwarf_gpr_x7, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x7}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(fp, x8), + {riscv_dwarf::dwarf_gpr_x8, riscv_dwarf::dwarf_gpr_x8, + LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, gpr_x8}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(s1, x9), + {riscv_dwarf::dwarf_gpr_x9, riscv_dwarf::dwarf_gpr_x9, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x9}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(a0, x10), + {riscv_dwarf::dwarf_gpr_x10, riscv_dwarf::dwarf_gpr_x10, + LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, gpr_x10}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(a1, x11), + {riscv_dwarf::dwarf_gpr_x11, riscv_dwarf::dwarf_gpr_x11, + LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, gpr_x11}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(a2, x12), + {riscv_dwarf::dwarf_gpr_x12, riscv_dwarf::dwarf_gpr_x12, + LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, gpr_x12}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(a3, x13), + {riscv_dwarf::dwarf_gpr_x13, riscv_dwarf::dwarf_gpr_x13, + LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, gpr_x13}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(a4, x14), + {riscv_dwarf::dwarf_gpr_x14, riscv_dwarf::dwarf_gpr_x14, + LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, gpr_x14}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(a5, x15), + {riscv_dwarf::dwarf_gpr_x15, riscv_dwarf::dwarf_gpr_x15, + LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, gpr_x15}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(a6, x16), + {riscv_dwarf::dwarf_gpr_x16, riscv_dwarf::dwarf_gpr_x16, + LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM, gpr_x16}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(a7, x17), + {riscv_dwarf::dwarf_gpr_x17, riscv_dwarf::dwarf_gpr_x17, + LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM, gpr_x17}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(s2, x18), + {riscv_dwarf::dwarf_gpr_x18, riscv_dwarf::dwarf_gpr_x18, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x18}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(s3, x19), + {riscv_dwarf::dwarf_gpr_x19, riscv_dwarf::dwarf_gpr_x19, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x19}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(s4, x20), + {riscv_dwarf::dwarf_gpr_x20, riscv_dwarf::dwarf_gpr_x20, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x20}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(s5, x21), + {riscv_dwarf::dwarf_gpr_x21, riscv_dwarf::dwarf_gpr_x21, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x21}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(s6, x22), + {riscv_dwarf::dwarf_gpr_x22, riscv_dwarf::dwarf_gpr_x22, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x22}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(s7, x23), + {riscv_dwarf::dwarf_gpr_x23, riscv_dwarf::dwarf_gpr_x23, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x23}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(s8, x24), + {riscv_dwarf::dwarf_gpr_x24, riscv_dwarf::dwarf_gpr_x24, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x24}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(s9, x25), + {riscv_dwarf::dwarf_gpr_x25, riscv_dwarf::dwarf_gpr_x25, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x25}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(s10, x26), + {riscv_dwarf::dwarf_gpr_x26, riscv_dwarf::dwarf_gpr_x26, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x26}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(s11, x27), + {riscv_dwarf::dwarf_gpr_x27, riscv_dwarf::dwarf_gpr_x27, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x27}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(t3, x28), + {riscv_dwarf::dwarf_gpr_x28, riscv_dwarf::dwarf_gpr_x28, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x28}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(t4, x29), + {riscv_dwarf::dwarf_gpr_x29, riscv_dwarf::dwarf_gpr_x29, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x29}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(t5, x30), + {riscv_dwarf::dwarf_gpr_x30, riscv_dwarf::dwarf_gpr_x30, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x30}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR_ABI(t6, x31), + {riscv_dwarf::dwarf_gpr_x31, riscv_dwarf::dwarf_gpr_x31, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x31}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_GPR(pc), + {riscv_dwarf::dwarf_gpr_pc, riscv_dwarf::dwarf_gpr_pc, + LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, gpr_pc}, + nullptr, + nullptr, + nullptr, + }, + + { + DEFINE_FPU_ABI(ft0, f0), + {riscv_dwarf::dwarf_fpr_f0, riscv_dwarf::dwarf_fpr_f0, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f0}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(ft1, f1), + {riscv_dwarf::dwarf_fpr_f1, riscv_dwarf::dwarf_fpr_f1, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f1}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(ft2, f2), + {riscv_dwarf::dwarf_fpr_f2, riscv_dwarf::dwarf_fpr_f2, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f2}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(ft3, f3), + {riscv_dwarf::dwarf_fpr_f3, riscv_dwarf::dwarf_fpr_f3, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f3}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(ft4, f4), + {riscv_dwarf::dwarf_fpr_f4, riscv_dwarf::dwarf_fpr_f4, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f4}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(ft5, f5), + {riscv_dwarf::dwarf_fpr_f5, riscv_dwarf::dwarf_fpr_f5, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f5}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(ft6, f6), + {riscv_dwarf::dwarf_fpr_f6, riscv_dwarf::dwarf_fpr_f6, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f6}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(ft7, f7), + {riscv_dwarf::dwarf_fpr_f7, riscv_dwarf::dwarf_fpr_f7, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f7}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs0, f8), + {riscv_dwarf::dwarf_fpr_f8, riscv_dwarf::dwarf_fpr_f8, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f8}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs1, f9), + {riscv_dwarf::dwarf_fpr_f9, riscv_dwarf::dwarf_fpr_f9, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f9}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fa0, f10), + {riscv_dwarf::dwarf_fpr_f10, riscv_dwarf::dwarf_fpr_f10, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f10}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fa1, f11), + {riscv_dwarf::dwarf_fpr_f11, riscv_dwarf::dwarf_fpr_f11, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f11}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fa2, f12), + {riscv_dwarf::dwarf_fpr_f12, riscv_dwarf::dwarf_fpr_f12, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f12}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fa3, f13), + {riscv_dwarf::dwarf_fpr_f13, riscv_dwarf::dwarf_fpr_f13, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f13}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fa4, f14), + {riscv_dwarf::dwarf_fpr_f14, riscv_dwarf::dwarf_fpr_f14, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f14}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fa5, f15), + {riscv_dwarf::dwarf_fpr_f15, riscv_dwarf::dwarf_fpr_f15, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f15}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fa6, f16), + {riscv_dwarf::dwarf_fpr_f16, riscv_dwarf::dwarf_fpr_f16, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f16}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fa7, f17), + {riscv_dwarf::dwarf_fpr_f17, riscv_dwarf::dwarf_fpr_f17, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f17}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs2, f18), + {riscv_dwarf::dwarf_fpr_f18, riscv_dwarf::dwarf_fpr_f18, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f18}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs3, f19), + {riscv_dwarf::dwarf_fpr_f19, riscv_dwarf::dwarf_fpr_f19, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f19}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs4, f20), + {riscv_dwarf::dwarf_fpr_f20, riscv_dwarf::dwarf_fpr_f20, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f20}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs5, f21), + {riscv_dwarf::dwarf_fpr_f21, riscv_dwarf::dwarf_fpr_f21, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f21}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs6, f22), + {riscv_dwarf::dwarf_fpr_f22, riscv_dwarf::dwarf_fpr_f22, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f22}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs7, f23), + {riscv_dwarf::dwarf_fpr_f23, riscv_dwarf::dwarf_fpr_f23, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f23}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs8, f24), + {riscv_dwarf::dwarf_fpr_f24, riscv_dwarf::dwarf_fpr_f24, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f24}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs9, f25), + {riscv_dwarf::dwarf_fpr_f25, riscv_dwarf::dwarf_fpr_f25, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f25}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs10, f26), + {riscv_dwarf::dwarf_fpr_f26, riscv_dwarf::dwarf_fpr_f26, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f26}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(fs11, f27), + {riscv_dwarf::dwarf_fpr_f27, riscv_dwarf::dwarf_fpr_f27, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f27}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(ft8, f28), + {riscv_dwarf::dwarf_fpr_f28, riscv_dwarf::dwarf_fpr_f28, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f28}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(ft9, f29), + {riscv_dwarf::dwarf_fpr_f29, riscv_dwarf::dwarf_fpr_f29, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f29}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(ft10, f30), + {riscv_dwarf::dwarf_fpr_f30, riscv_dwarf::dwarf_fpr_f30, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f30}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU_ABI(ft11, f31), + {riscv_dwarf::dwarf_fpr_f31, riscv_dwarf::dwarf_fpr_f31, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f31}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_FPU(fcsr), + {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, fpr_fcsr}, + nullptr, + nullptr, + nullptr, + }, + + { + DEFINE_EXC(exception), + {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, exc_exception}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_EXC(fsr), + {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, exc_fsr}, + nullptr, + nullptr, + nullptr, + }, + { + DEFINE_EXC(far), + {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, exc_far}, + nullptr, + nullptr, + nullptr, + }, + {"csr", + nullptr, + 1024 * sizeof(uint32_t), + 0, + eEncodingVector, + eFormatVectorOfUInt32, + {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, csr_bank}, + nullptr, + nullptr, + nullptr}}; + +static size_t k_num_register_infos = std::size(g_register_infos); + +RegisterContextDarwin_riscv32::RegisterContextDarwin_riscv32( + Thread &thread, uint32_t concrete_frame_idx) + : RegisterContext(thread, concrete_frame_idx), gpr(), fpr(), exc() { + uint32_t i; + for (i = 0; i < kNumErrors; i++) { + gpr_errs[i] = -1; + fpr_errs[i] = -1; + exc_errs[i] = -1; + csr_errs[i] = -1; + } +} + +RegisterContextDarwin_riscv32::~RegisterContextDarwin_riscv32() = default; + +void RegisterContextDarwin_riscv32::InvalidateAllRegisters() { + InvalidateAllRegisterStates(); +} + +size_t RegisterContextDarwin_riscv32::GetRegisterCount() { + assert(k_num_register_infos == k_num_registers); + return k_num_registers; +} + +const RegisterInfo * +RegisterContextDarwin_riscv32::GetRegisterInfoAtIndex(size_t reg) { + assert(k_num_register_infos == k_num_registers); + if (reg < k_num_registers) + return &g_register_infos[reg]; + return nullptr; +} + +size_t RegisterContextDarwin_riscv32::GetRegisterInfosCount() { + return k_num_register_infos; +} + +const RegisterInfo *RegisterContextDarwin_riscv32::GetRegisterInfos() { + return g_register_infos; +} + +// General purpose registers +static uint32_t g_gpr_regnums[] = { + gpr_x0, gpr_x1, gpr_x2, gpr_x3, gpr_x4, gpr_x5, gpr_x6, + gpr_x7, gpr_x8, gpr_x9, gpr_x10, gpr_x11, gpr_x12, gpr_x13, + gpr_x14, gpr_x15, gpr_x16, gpr_x17, gpr_x18, gpr_x19, gpr_x20, + gpr_x21, gpr_x22, gpr_x23, gpr_x24, gpr_x25, gpr_x26, gpr_x27, + gpr_x28, gpr_x29, gpr_x30, gpr_x31, gpr_pc}; + +// Floating point registers +static uint32_t g_fpr_regnums[] = { + fpr_f0, fpr_f1, fpr_f2, fpr_f3, fpr_f4, fpr_f5, fpr_f6, + fpr_f7, fpr_f8, fpr_f9, fpr_f10, fpr_f11, fpr_f12, fpr_f13, + fpr_f14, fpr_f15, fpr_f16, fpr_f17, fpr_f18, fpr_f19, fpr_f20, + fpr_f21, fpr_f22, fpr_f23, fpr_f24, fpr_f25, fpr_f26, fpr_f27, + fpr_f28, fpr_f29, fpr_f30, fpr_f31, fpr_fcsr}; + +// Exception registers + +static uint32_t g_exc_regnums[] = {exc_exception, exc_fsr, exc_far}; + +// CSR bank registers +static uint32_t g_csr_regnums[] = {csr_bank}; + +// Number of registers in each register set +const size_t k_num_gpr_registers = std::size(g_gpr_regnums); +const size_t k_num_fpr_registers = std::size(g_fpr_regnums); +const size_t k_num_exc_registers = std::size(g_exc_regnums); +const size_t k_num_csr_registers = std::size(g_csr_regnums); + +// Register set definitions. The first definitions at register set index of +// zero is for all registers, followed by other registers sets. The register +// information for the all register set need not be filled in. +static const RegisterSet g_reg_sets[] = { + { + "General Purpose Registers", + "gpr", + k_num_gpr_registers, + g_gpr_regnums, + }, + {"Floating Point Registers", "fpr", k_num_fpr_registers, g_fpr_regnums}, + {"Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums}, + {"CSR register bank", "csr", k_num_csr_registers, g_csr_regnums}}; + +const size_t k_num_regsets = std::size(g_reg_sets); + +size_t RegisterContextDarwin_riscv32::GetRegisterSetCount() { + return k_num_regsets; +} + +const RegisterSet * +RegisterContextDarwin_riscv32::GetRegisterSet(size_t reg_set) { + if (reg_set < k_num_regsets) + return &g_reg_sets[reg_set]; + return nullptr; +} + +// Register information definitions for 32 bit riscv32. +int RegisterContextDarwin_riscv32::GetSetForNativeRegNum(int reg_num) { + if (reg_num < fpr_f0) + return GPRRegSet; + else if (reg_num < exc_exception) + return FPURegSet; + else if (reg_num < csr_bank) + return EXCRegSet; + else if (reg_num < k_num_registers) + return CSRRegSet; + return -1; +} + +void RegisterContextDarwin_riscv32::LogGPR(Log *log, const char *title) { + if (log) { + if (title) + LLDB_LOGF(log, "%s", title); + for (uint32_t i = 0; i < k_num_gpr_registers; i++) { + uint32_t reg = gpr_x0 + i; + LLDB_LOGF(log, "%12s = 0x%4.4x", g_register_infos[reg].name, + (&gpr.x0)[reg]); + } + } +} + +int RegisterContextDarwin_riscv32::ReadGPR(bool force) { + int set = GPRRegSet; + if (force || !RegisterSetIsCached(set)) { + SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr)); + } + return GetError(set, Read); +} + +int RegisterContextDarwin_riscv32::ReadFPU(bool force) { + int set = FPURegSet; + if (force || !RegisterSetIsCached(set)) { + SetError(set, Read, DoReadFPU(GetThreadID(), set, fpr)); + } + return GetError(set, Read); +} + +int RegisterContextDarwin_riscv32::ReadEXC(bool force) { + int set = EXCRegSet; + if (force || !RegisterSetIsCached(set)) { + SetError(set, Read, DoReadEXC(GetThreadID(), set, exc)); + } + return GetError(set, Read); +} + +int RegisterContextDarwin_riscv32::ReadCSR(bool force) { + int set = CSRRegSet; + if (force || !RegisterSetIsCached(set)) { + SetError(set, Read, DoReadCSR(GetThreadID(), set, csr)); + } + return GetError(set, Read); +} + +int RegisterContextDarwin_riscv32::WriteGPR() { + int set = GPRRegSet; + if (!RegisterSetIsCached(set)) { + SetError(set, Write, -1); + return -1; + } + SetError(set, Write, DoWriteGPR(GetThreadID(), set, gpr)); + SetError(set, Read, -1); + return GetError(set, Write); +} + +int RegisterContextDarwin_riscv32::WriteFPU() { + int set = FPURegSet; + if (!RegisterSetIsCached(set)) { + SetError(set, Write, -1); + return -1; + } + SetError(set, Write, DoWriteFPU(GetThreadID(), set, fpr)); + SetError(set, Read, -1); + return GetError(set, Write); +} + +int RegisterContextDarwin_riscv32::WriteEXC() { + int set = EXCRegSet; + if (!RegisterSetIsCached(set)) { + SetError(set, Write, -1); + return -1; + } + SetError(set, Write, DoWriteEXC(GetThreadID(), set, exc)); + SetError(set, Read, -1); + return GetError(set, Write); +} + +int RegisterContextDarwin_riscv32::WriteCSR() { + int set = CSRRegSet; + if (!RegisterSetIsCached(set)) { + SetError(set, Write, -1); + return -1; + } + SetError(set, Write, DoWriteCSR(GetThreadID(), set, csr)); + SetError(set, Read, -1); + return GetError(set, Write); +} + +int RegisterContextDarwin_riscv32::ReadRegisterSet(uint32_t set, bool force) { + switch (set) { + case GPRRegSet: + return ReadGPR(force); + case FPURegSet: + return ReadFPU(force); + case EXCRegSet: + return ReadEXC(force); + case CSRRegSet: + return ReadCSR(force); + default: + break; + } + return -1; +} + +int RegisterContextDarwin_riscv32::WriteRegisterSet(uint32_t set) { + // Make sure we have a valid context to set. + if (RegisterSetIsCached(set)) { + switch (set) { + case GPRRegSet: + return WriteGPR(); + case FPURegSet: + return WriteFPU(); + case EXCRegSet: + return WriteEXC(); + case CSRRegSet: + return WriteCSR(); + default: + break; + } + } + return -1; +} + +bool RegisterContextDarwin_riscv32::ReadRegister(const RegisterInfo *reg_info, + RegisterValue &value) { + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + int set = RegisterContextDarwin_riscv32::GetSetForNativeRegNum(reg); + + if (set == -1) + return false; + + if (ReadRegisterSet(set, false) != 0) + return false; + + switch (reg) { + case gpr_x0: + case gpr_x1: + case gpr_x2: + case gpr_x3: + case gpr_x4: + case gpr_x5: + case gpr_x6: + case gpr_x7: + case gpr_x8: + case gpr_x9: + case gpr_x10: + case gpr_x11: + case gpr_x12: + case gpr_x13: + case gpr_x14: + case gpr_x15: + case gpr_x16: + case gpr_x17: + case gpr_x18: + case gpr_x19: + case gpr_x20: + case gpr_x21: + case gpr_x22: + case gpr_x23: + case gpr_x24: + case gpr_x25: + case gpr_x26: + case gpr_x27: + case gpr_x28: + case gpr_x29: + case gpr_x30: + case gpr_x31: + case gpr_pc: + value = (&gpr.x0)[reg - gpr_x0]; + break; + + case fpr_f0: + case fpr_f1: + case fpr_f2: + case fpr_f3: + case fpr_f4: + case fpr_f5: + case fpr_f6: + case fpr_f7: + case fpr_f8: + case fpr_f9: + case fpr_f10: + case fpr_f11: + case fpr_f12: + case fpr_f13: + case fpr_f14: + case fpr_f15: + case fpr_f16: + case fpr_f17: + case fpr_f18: + case fpr_f19: + case fpr_f20: + case fpr_f21: + case fpr_f22: + case fpr_f23: + case fpr_f24: + case fpr_f25: + case fpr_f26: + case fpr_f27: + case fpr_f28: + case fpr_f29: + case fpr_f30: + case fpr_f31: + case fpr_fcsr: + value = (&fpr.f0)[reg - fpr_f0]; + break; + + case exc_exception: + value = exc.exception; + break; + + case exc_fsr: + value = exc.fsr; + break; + + case exc_far: + value = exc.far; + break; + + case csr_bank: + // These values don't fit into scalar types, + // RegisterContext::ReadRegisterBytes() must be used for these registers + //::memcpy (reg_value.value.vector.uint8, fpu.stmm[reg - fpu_stmm0].bytes, + // 10); + + // AArch64 copies NEON registers with + // value.SetBytes(csr.bytes, reg_info->byte_size, + // endian::InlHostByteOrder()); + return false; + + default: + return false; + } + return true; +} + +bool RegisterContextDarwin_riscv32::WriteRegister(const RegisterInfo *reg_info, + const RegisterValue &value) { + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + int set = GetSetForNativeRegNum(reg); + + if (set == -1) + return false; + + if (ReadRegisterSet(set, false) != 0) + return false; + + switch (reg) { + case gpr_x0: + case gpr_x1: + case gpr_x2: + case gpr_x3: + case gpr_x4: + case gpr_x5: + case gpr_x6: + case gpr_x7: + case gpr_x8: + case gpr_x9: + case gpr_x10: + case gpr_x11: + case gpr_x12: + case gpr_x13: + case gpr_x14: + case gpr_x15: + case gpr_x16: + case gpr_x17: + case gpr_x18: + case gpr_x19: + case gpr_x20: + case gpr_x21: + case gpr_x22: + case gpr_x23: + case gpr_x24: + case gpr_x25: + case gpr_x26: + case gpr_x27: + case gpr_x28: + case gpr_x29: + case gpr_x30: + case gpr_x31: + case gpr_pc: + (&gpr.x0)[reg - gpr_x0] = value.GetAsUInt32(); + break; + + case fpr_f0: + case fpr_f1: + case fpr_f2: + case fpr_f3: + case fpr_f4: + case fpr_f5: + case fpr_f6: + case fpr_f7: + case fpr_f8: + case fpr_f9: + case fpr_f10: + case fpr_f11: + case fpr_f12: + case fpr_f13: + case fpr_f14: + case fpr_f15: + case fpr_f16: + case fpr_f17: + case fpr_f18: + case fpr_f19: + case fpr_f20: + case fpr_f21: + case fpr_f22: + case fpr_f23: + case fpr_f24: + case fpr_f25: + case fpr_f26: + case fpr_f27: + case fpr_f28: + case fpr_f29: + case fpr_f30: + case fpr_f31: + case fpr_fcsr: + (&fpr.f0)[reg - fpr_f0] = value.GetAsUInt32(); + break; + + case exc_exception: + exc.exception = value.GetAsUInt32(); + break; + + case exc_fsr: + exc.fsr = value.GetAsUInt32(); + break; + + case exc_far: + exc.far = value.GetAsUInt32(); + break; + + case csr_bank: + // These values don't fit into scalar types, + // RegisterContext::ReadRegisterBytes() must be used for these registers + //::memcpy(csr.bytes, value.GetBytes(), + // value.GetByteSize()); + return false; + + default: + return false; + } + return WriteRegisterSet(set) == 0; +} + +bool RegisterContextDarwin_riscv32::ReadAllRegisterValues( + lldb::WritableDataBufferSP &data_sp) { + data_sp = std::make_shared<DataBufferHeap>(REG_CONTEXT_SIZE, 0); + if (ReadGPR(false) == 0 && ReadFPU(false) == 0 && ReadEXC(false) == 0 && + ReadCSR(false) == 0) { + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, &gpr, sizeof(gpr)); + dst += sizeof(gpr); + + ::memcpy(dst, &fpr, sizeof(fpr)); + dst += sizeof(gpr); + + ::memcpy(dst, &exc, sizeof(exc)); + return true; + + ::memcpy(dst, &csr, sizeof(csr)); + return true; + } + return false; +} + +bool RegisterContextDarwin_riscv32::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { + const uint8_t *src = data_sp->GetBytes(); + ::memcpy(&gpr, src, sizeof(gpr)); + src += sizeof(gpr); + + ::memcpy(&fpr, src, sizeof(fpr)); + src += sizeof(fpr); + + ::memcpy(&exc, src, sizeof(exc)); + src += sizeof(exc); + + ::memcpy(&csr, src, sizeof(csr)); + uint32_t success_count = 0; + + if (WriteGPR() == 0) + ++success_count; + if (WriteFPU() == 0) + ++success_count; + if (WriteEXC() == 0) + ++success_count; + if (WriteCSR() == 0) + ++success_count; + return success_count == 3; + } + return false; +} + +uint32_t RegisterContextDarwin_riscv32::ConvertRegisterKindToRegisterNumber( + lldb::RegisterKind kind, uint32_t reg) { + if (kind == eRegisterKindGeneric) { + switch (reg) { + case LLDB_REGNUM_GENERIC_PC: + return gpr_pc; + case LLDB_REGNUM_GENERIC_SP: + return gpr_x2; + case LLDB_REGNUM_GENERIC_FP: + return gpr_x8; + case LLDB_REGNUM_GENERIC_RA: + return gpr_x1; + default: + break; + } + } else if (kind == eRegisterKindEHFrame || kind == eRegisterKindDWARF) { + switch (reg) { + case riscv_dwarf::dwarf_gpr_x0: + case riscv_dwarf::dwarf_gpr_x1: + case riscv_dwarf::dwarf_gpr_x2: + case riscv_dwarf::dwarf_gpr_x3: + case riscv_dwarf::dwarf_gpr_x4: + case riscv_dwarf::dwarf_gpr_x5: + case riscv_dwarf::dwarf_gpr_x6: + case riscv_dwarf::dwarf_gpr_x7: + case riscv_dwarf::dwarf_gpr_x8: + case riscv_dwarf::dwarf_gpr_x9: + case riscv_dwarf::dwarf_gpr_x10: + case riscv_dwarf::dwarf_gpr_x11: + case riscv_dwarf::dwarf_gpr_x12: + case riscv_dwarf::dwarf_gpr_x13: + case riscv_dwarf::dwarf_gpr_x14: + case riscv_dwarf::dwarf_gpr_x15: + case riscv_dwarf::dwarf_gpr_x16: + case riscv_dwarf::dwarf_gpr_x17: + case riscv_dwarf::dwarf_gpr_x18: + case riscv_dwarf::dwarf_gpr_x19: + case riscv_dwarf::dwarf_gpr_x20: + case riscv_dwarf::dwarf_gpr_x21: + case riscv_dwarf::dwarf_gpr_x22: + case riscv_dwarf::dwarf_gpr_x23: + case riscv_dwarf::dwarf_gpr_x24: + case riscv_dwarf::dwarf_gpr_x25: + case riscv_dwarf::dwarf_gpr_x26: + case riscv_dwarf::dwarf_gpr_x27: + case riscv_dwarf::dwarf_gpr_x28: + case riscv_dwarf::dwarf_gpr_x29: + case riscv_dwarf::dwarf_gpr_x30: + case riscv_dwarf::dwarf_gpr_x31: + return gpr_x0 + (reg - riscv_dwarf::dwarf_gpr_x0); + + case riscv_dwarf::dwarf_fpr_f0: + case riscv_dwarf::dwarf_fpr_f1: + case riscv_dwarf::dwarf_fpr_f2: + case riscv_dwarf::dwarf_fpr_f3: + case riscv_dwarf::dwarf_fpr_f4: + case riscv_dwarf::dwarf_fpr_f5: + case riscv_dwarf::dwarf_fpr_f6: + case riscv_dwarf::dwarf_fpr_f7: + case riscv_dwarf::dwarf_fpr_f8: + case riscv_dwarf::dwarf_fpr_f9: + case riscv_dwarf::dwarf_fpr_f10: + case riscv_dwarf::dwarf_fpr_f11: + case riscv_dwarf::dwarf_fpr_f12: + case riscv_dwarf::dwarf_fpr_f13: + case riscv_dwarf::dwarf_fpr_f14: + case riscv_dwarf::dwarf_fpr_f15: + case riscv_dwarf::dwarf_fpr_f16: + case riscv_dwarf::dwarf_fpr_f17: + case riscv_dwarf::dwarf_fpr_f18: + case riscv_dwarf::dwarf_fpr_f19: + case riscv_dwarf::dwarf_fpr_f20: + case riscv_dwarf::dwarf_fpr_f21: + case riscv_dwarf::dwarf_fpr_f22: + case riscv_dwarf::dwarf_fpr_f23: + case riscv_dwarf::dwarf_fpr_f24: + case riscv_dwarf::dwarf_fpr_f25: + case riscv_dwarf::dwarf_fpr_f26: + case riscv_dwarf::dwarf_fpr_f27: + case riscv_dwarf::dwarf_fpr_f28: + case riscv_dwarf::dwarf_fpr_f29: + case riscv_dwarf::dwarf_fpr_f30: + case riscv_dwarf::dwarf_fpr_f31: + return fpr_f0 + (reg - riscv_dwarf::dwarf_fpr_f0); + + default: + break; + } + } else if (kind == eRegisterKindLLDB) { + return reg; + } + return LLDB_INVALID_REGNUM; +} diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.h b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.h new file mode 100644 index 0000000000000..22d61aef712a6 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.h @@ -0,0 +1,260 @@ +//===-- RegisterContextDarwin_riscv32.h -------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_RISCV32_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_RISCV32_H + +#include "lldb/Target/RegisterContext.h" +#include "lldb/lldb-private.h" + +class RegisterContextDarwin_riscv32 : public lldb_private::RegisterContext { +public: + RegisterContextDarwin_riscv32(lldb_private::Thread &thread, + uint32_t concrete_frame_idx); + + ~RegisterContextDarwin_riscv32() override; + + void InvalidateAllRegisters() override; + + size_t GetRegisterCount() override; + + const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; + + size_t GetRegisterSetCount() override; + + const lldb_private::RegisterSet *GetRegisterSet(size_t set) override; + + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value) override; + + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value) override; + + bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override; + + bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, + uint32_t num) override; + + struct GPR { + uint32_t x0; + uint32_t x1; + uint32_t x2; + uint32_t x3; + uint32_t x4; + uint32_t x5; + uint32_t x6; + uint32_t x7; + uint32_t x8; + uint32_t x9; + uint32_t x10; + uint32_t x11; + uint32_t x12; + uint32_t x13; + uint32_t x14; + uint32_t x15; + uint32_t x16; + uint32_t x17; + uint32_t x18; + uint32_t x19; + uint32_t x20; + uint32_t x21; + uint32_t x22; + uint32_t x23; + uint32_t x24; + uint32_t x25; + uint32_t x26; + uint32_t x27; + uint32_t x28; + uint32_t x29; + uint32_t x30; + uint32_t x31; + uint32_t pc; + }; + + struct FPU { + uint32_t f0; + uint32_t f1; + uint32_t f2; + uint32_t f3; + uint32_t f4; + uint32_t f5; + uint32_t f6; + uint32_t f7; + uint32_t f8; + uint32_t f9; + uint32_t f10; + uint32_t f11; + uint32_t f12; + uint32_t f13; + uint32_t f14; + uint32_t f15; + uint32_t f16; + uint32_t f17; + uint32_t f18; + uint32_t f19; + uint32_t f20; + uint32_t f21; + uint32_t f22; + uint32_t f23; + uint32_t f24; + uint32_t f25; + uint32_t f26; + uint32_t f27; + uint32_t f28; + uint32_t f29; + uint32_t f30; + uint32_t f31; + uint32_t fcsr; + }; + + struct EXC { + uint32_t exception; + uint32_t fsr; + uint32_t far; + }; + + struct CSR { + uint32_t csr[1024]; + }; + +protected: + enum { + GPRRegSet = 2, // RV32_THREAD_STATE + EXCRegSet = 3, // RV32_EXCEPTION_STATE + FPURegSet = 4, // RV_FP32_STATE + CSRRegSet1 = 6, // RV_CSR_STATE1 + CSRRegSet2 = 7, // RV_CSR_STATE2 + CSRRegSet3 = 8, // RV_CSR_STATE3 + CSRRegSet4 = 9, // RV_CSR_STATE4 + CSRRegSet = 10 // full 16kbyte CSR reg bank + }; + + enum { + GPRWordCount = sizeof(GPR) / sizeof(uint32_t), + FPUWordCount = sizeof(FPU) / sizeof(uint32_t), + EXCWordCount = sizeof(EXC) / sizeof(uint32_t), + CSRWordCount = sizeof(CSR) / sizeof(uint32_t) + }; + + enum { Read = 0, Write = 1, kNumErrors = 2 }; + + GPR gpr; + FPU fpr; + EXC exc; + CSR csr; + int gpr_errs[2]; // Read/Write errors + int fpr_errs[2]; // Read/Write errors + int exc_errs[2]; // Read/Write errors + int csr_errs[2]; // Read/Write errors + + void InvalidateAllRegisterStates() { + SetError(GPRRegSet, Read, -1); + SetError(FPURegSet, Read, -1); + SetError(EXCRegSet, Read, -1); + SetError(CSRRegSet, Read, -1); + } + + int GetError(int flavor, uint32_t err_idx) const { + if (err_idx < kNumErrors) { + switch (flavor) { + // When getting all errors, just OR all values together to see if + // we got any kind of error. + case GPRRegSet: + return gpr_errs[err_idx]; + case FPURegSet: + return fpr_errs[err_idx]; + case EXCRegSet: + return exc_errs[err_idx]; + case CSRRegSet: + return csr_errs[err_idx]; + default: + break; + } + } + return -1; + } + + bool SetError(int flavor, uint32_t err_idx, int err) { + if (err_idx < kNumErrors) { + switch (flavor) { + case GPRRegSet: + gpr_errs[err_idx] = err; + return true; + + case FPURegSet: + fpr_errs[err_idx] = err; + return true; + + case EXCRegSet: + exc_errs[err_idx] = err; + return true; + + case CSRRegSet: + csr_errs[err_idx] = err; + return true; + + default: + break; + } + } + return false; + } + + bool RegisterSetIsCached(int set) const { return GetError(set, Read) == 0; } + + void LogGPR(lldb_private::Log *log, const char *title); + + int ReadGPR(bool force); + + int ReadFPU(bool force); + + int ReadEXC(bool force); + + int ReadCSR(bool force); + + int WriteGPR(); + + int WriteFPU(); + + int WriteEXC(); + + int WriteCSR(); + + // Subclasses override these to do the actual reading. + virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) = 0; + + virtual int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpr) = 0; + + virtual int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) = 0; + + virtual int DoReadCSR(lldb::tid_t tid, int flavor, CSR &exc) = 0; + + virtual int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) = 0; + + virtual int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpr) = 0; + + virtual int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) = 0; + + virtual int DoWriteCSR(lldb::tid_t tid, int flavor, const CSR &exc) = 0; + + int ReadRegisterSet(uint32_t set, bool force); + + int WriteRegisterSet(uint32_t set); + + static uint32_t GetRegisterNumber(uint32_t reg_kind, uint32_t reg_num); + + static int GetSetForNativeRegNum(int reg_num); + + static size_t GetRegisterInfosCount(); + + static const lldb_private::RegisterInfo *GetRegisterInfos(); +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_RISCV32_H diff --git a/lldb/test/API/macosx/riscv32-corefile/Makefile b/lldb/test/API/macosx/riscv32-corefile/Makefile new file mode 100644 index 0000000000000..04f268758d00c --- /dev/null +++ b/lldb/test/API/macosx/riscv32-corefile/Makefile @@ -0,0 +1,7 @@ +MAKE_DSYM := NO +CXX_SOURCES := create-empty-riscv-corefile.cpp +EXE := create-empty-riscv-corefile + +all: create-empty-riscv-corefile + +include Makefile.rules diff --git a/lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py b/lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py new file mode 100644 index 0000000000000..8d11821d38985 --- /dev/null +++ b/lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py @@ -0,0 +1,82 @@ +"""Test that all of the GPR registers are read correctly from a riscv32 corefile.""" + +import os +import re +import subprocess + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestRV32MachOCorefile(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + @skipUnlessDarwin + def test_riscv32_gpr_corefile_registers(self): + self.build() + create_corefile = self.getBuildArtifact("create-empty-riscv-corefile") + corefile = self.getBuildArtifact("core") + call(create_corefile + " " + corefile, shell=True) + + target = self.dbg.CreateTarget("") + process = target.LoadCore(corefile) + + process = target.GetProcess() + self.assertEqual(process.GetNumThreads(), 1) + + thread = process.GetThreadAtIndex(0) + self.assertEqual(thread.GetNumFrames(), 1) + + frame = thread.GetFrameAtIndex(0) + gpr_regs = frame.registers.GetValueAtIndex(0) + + self.assertEqual(gpr_regs.GetName(), "General Purpose Registers") + self.assertEqual(gpr_regs.GetNumChildren(), 33) + regnames = [ + "zero", + "ra", + "sp", + "gp", + "tp", + "t0", + "t1", + "t2", + "fp", + "s1", + "a0", + "a1", + "a2", + "a3", + "a4", + "a5", + "a6", + "a7", + "s2", + "s3", + "s4", + "s5", + "s6", + "s7", + "s8", + "s9", + "s10", + "s11", + "t3", + "t4", + "t5", + "t6", + "pc", + ] + + idx = 0 + while idx < len(regnames): + self.assertEqual(gpr_regs.GetChildAtIndex(idx).GetName(), regnames[idx]) + idx = idx + 1 + + idx = 0 + while idx < len(regnames): + val = idx | (idx << 8) | (idx << 16) | (idx << 24) + self.assertEqual(gpr_regs.GetChildAtIndex(idx).GetValueAsUnsigned(), val) + idx = idx + 1 diff --git a/lldb/test/API/macosx/riscv32-corefile/create-empty-riscv-corefile.cpp b/lldb/test/API/macosx/riscv32-corefile/create-empty-riscv-corefile.cpp new file mode 100644 index 0000000000000..907cca3b70b41 --- /dev/null +++ b/lldb/test/API/macosx/riscv32-corefile/create-empty-riscv-corefile.cpp @@ -0,0 +1,116 @@ +#include <inttypes.h> +#include <mach-o/loader.h> +#include <mach/thread_status.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <string> +#include <sys/errno.h> +#include <uuid/uuid.h> +#include <vector> + +#define CPU_TYPE_RISCV 24 +#define CPU_SUBTYPE_RISCV_ALL 0 +#define RV32_THREAD_STATE 2 +// x0-x31 + pc, all 32-bit +#define RV32_THREAD_STATE_COUNT 33 + +union uint32_buf { + uint8_t bytebuf[4]; + uint32_t val; +}; + +union uint64_buf { + uint8_t bytebuf[8]; + uint64_t val; +}; + +void add_uint64(std::vector<uint8_t> &buf, uint64_t val) { + uint64_buf conv; + conv.val = val; + for (int i = 0; i < 8; i++) + buf.push_back(conv.bytebuf[i]); +} + +void add_uint32(std::vector<uint8_t> &buf, uint32_t val) { + uint32_buf conv; + conv.val = val; + for (int i = 0; i < 4; i++) + buf.push_back(conv.bytebuf[i]); +} + +std::vector<uint8_t> lc_thread_load_command() { + std::vector<uint8_t> data; + add_uint32(data, LC_THREAD); // thread_command.cmd + add_uint32(data, 4 + 4 + 4 + 4 + + (RV32_THREAD_STATE_COUNT * 4)); // thread_command.cmdsize + add_uint32(data, RV32_THREAD_STATE); // thread_command.flavor + add_uint32(data, RV32_THREAD_STATE_COUNT); // thread_command.count + for (int i = 0; i < RV32_THREAD_STATE_COUNT; i++) { + add_uint32(data, i | (i << 8) | (i << 16) | (i << 24)); + } + return data; +} + +int main(int argc, char **argv) { + if (argc != 2) { + fprintf(stderr, + "usage: create-empty-riscv-corefile output-corefile-name\n"); + exit(1); + } + + cpu_type_t cputype = CPU_TYPE_RISCV; + cpu_subtype_t cpusubtype = CPU_SUBTYPE_RISCV_ALL; + + // An array of load commands (in the form of byte arrays) + std::vector<std::vector<uint8_t>> load_commands; + + // An array of corefile contents (page data, lc_note data, etc) + std::vector<uint8_t> payload; + + // First add all the load commands / payload so we can figure out how large + // the load commands will actually be. + load_commands.push_back(lc_thread_load_command()); + + int size_of_load_commands = 0; + for (const auto &lc : load_commands) + size_of_load_commands += lc.size(); + + int header_and_load_cmd_room = + sizeof(struct mach_header_64) + size_of_load_commands; + + // Erase the load commands / payload now that we know how much space is + // needed, redo it. + load_commands.clear(); + payload.clear(); + + load_commands.push_back(lc_thread_load_command()); + + struct mach_header mh; + mh.magic = MH_MAGIC; + mh.cputype = cputype; + + mh.cpusubtype = cpusubtype; + mh.filetype = MH_CORE; + mh.ncmds = load_commands.size(); + mh.sizeofcmds = size_of_load_commands; + mh.flags = 0; + + FILE *f = fopen(argv[1], "w"); + + if (f == nullptr) { + fprintf(stderr, "Unable to open file %s for writing\n", argv[1]); + exit(1); + } + + fwrite(&mh, sizeof(struct mach_header), 1, f); + + for (const auto &lc : load_commands) + fwrite(lc.data(), lc.size(), 1, f); + + fseek(f, header_and_load_cmd_room, SEEK_SET); + + fwrite(payload.data(), payload.size(), 1, f); + + fclose(f); +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits