https://github.com/mchoo7 updated https://github.com/llvm/llvm-project/pull/180549
>From 19d3f0817d24a365f6e37c55aa78344c0e6179c5 Mon Sep 17 00:00:00 2001 From: Minsoo Choo <[email protected]> Date: Wed, 28 Jan 2026 19:28:59 -0500 Subject: [PATCH 1/2] [lldb][Process/FreeBSD] Add riscv64 support Signed-off-by: Minsoo Choo <[email protected]> --- lldb/docs/index.rst | 2 +- .../Plugins/Process/FreeBSD/CMakeLists.txt | 1 + .../NativeRegisterContextFreeBSD_riscv64.cpp | 559 ++++++++++++++++++ .../NativeRegisterContextFreeBSD_riscv64.h | 81 +++ .../Process/elf-core/ThreadElfCore.cpp | 2 + llvm/docs/ReleaseNotes.md | 1 + 6 files changed, 645 insertions(+), 1 deletion(-) create mode 100644 lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.cpp create mode 100644 lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.h diff --git a/lldb/docs/index.rst b/lldb/docs/index.rst index 10683c7593b01..53a37cb462a1a 100644 --- a/lldb/docs/index.rst +++ b/lldb/docs/index.rst @@ -73,7 +73,7 @@ are welcome: * iOS, tvOS, and watchOS simulator debugging on i386, x86_64 and AArch64 * iOS, tvOS, and watchOS device debugging on ARM and AArch64 * Linux user-space debugging for i386, x86_64, ARM, AArch64, PPC64le, s390x -* FreeBSD user-space debugging for i386, x86_64, ARM, AArch64, PPC +* FreeBSD user-space debugging for i386, x86_64, ARM, AArch64, PPC, RISCV64 * FreeBSD kernel debugging for i386, x86_64, AArch64 * NetBSD user-space debugging for i386 and x86_64 * Windows user-space debugging for i386, x86_64, ARM and AArch64 (*) diff --git a/lldb/source/Plugins/Process/FreeBSD/CMakeLists.txt b/lldb/source/Plugins/Process/FreeBSD/CMakeLists.txt index 8574df58b4ada..b7b4b969dbfe0 100644 --- a/lldb/source/Plugins/Process/FreeBSD/CMakeLists.txt +++ b/lldb/source/Plugins/Process/FreeBSD/CMakeLists.txt @@ -4,6 +4,7 @@ add_lldb_library(lldbPluginProcessFreeBSD NativeRegisterContextFreeBSD_arm.cpp NativeRegisterContextFreeBSD_arm64.cpp NativeRegisterContextFreeBSD_powerpc.cpp + NativeRegisterContextFreeBSD_riscv64.cpp NativeRegisterContextFreeBSD_x86_64.cpp NativeThreadFreeBSD.cpp diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.cpp new file mode 100644 index 0000000000000..3464d0a377bd5 --- /dev/null +++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.cpp @@ -0,0 +1,559 @@ +//===-- NativeRegisterContextFreeBSD_riscv64.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__riscv) && __riscv_xlen == 64 + +#include "NativeRegisterContextFreeBSD_riscv64.h" + +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h" + +// clang-format off +#include <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +// clang-format on + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +// Translation between RegisterInfoPosix_riscv64 and reg.h +// https://github.com/freebsd/freebsd-src/blob/main/sys/riscv/include/reg.h: +// +// struct reg { +// __uint64_t ra; /* return address */ +// __uint64_t sp; /* stack pointer */ +// __uint64_t gp; /* global pointer */ +// __uint64_t tp; /* thread pointer */ +// __uint64_t t[7]; /* temporaries */ +// __uint64_t s[12]; /* saved registers */ +// __uint64_t a[8]; /* function arguments */ +// __uint64_t sepc; /* exception program counter */ +// __uint64_t sstatus; /* status register */ +// }; +// +// struct fpreg { +// __uint64_t fp_x[32][2]; /* Floating point registers */ +// __uint64_t fp_fcsr; /* Floating point control reg */ +// }; +// +// struct dbreg { +// int dummy; +// }; + +// ============================================================================ +// Static Conversion Functions between FreeBSD and POSIX +// ============================================================================ + +void NativeRegisterContextFreeBSD_riscv64::FreeBSDToPOSIXGPR( + const struct reg &freebsd_gpr, RegisterInfoPOSIX_riscv64::GPR &posix_gpr) { + posix_gpr.gpr[gpr_pc_riscv64] = freebsd_gpr.sepc; // x0/pc + posix_gpr.gpr[gpr_ra_riscv64] = freebsd_gpr.ra; // x1/ra + posix_gpr.gpr[gpr_sp_riscv64] = freebsd_gpr.sp; // x2/sp + posix_gpr.gpr[gpr_gp_riscv64] = freebsd_gpr.gp; // x3/gp + posix_gpr.gpr[gpr_tp_riscv64] = freebsd_gpr.tp; // x4/tp + + // x5-x7: t0-t2 + posix_gpr.gpr[gpr_t0_riscv64] = freebsd_gpr.t[0]; + posix_gpr.gpr[gpr_t1_riscv64] = freebsd_gpr.t[1]; + posix_gpr.gpr[gpr_t2_riscv64] = freebsd_gpr.t[2]; + + // x8-x9: s0-s1 (s0 is also fp) + posix_gpr.gpr[gpr_s0_riscv64] = freebsd_gpr.s[0]; + posix_gpr.gpr[gpr_s1_riscv64] = freebsd_gpr.s[1]; + + // x10-x17: a0-a7 + for (int i = 0; i < 8; i++) + posix_gpr.gpr[gpr_a0_riscv64 + i] = freebsd_gpr.a[i]; + + // x18-x27: s2-s11 + for (int i = 0; i < 10; i++) + posix_gpr.gpr[gpr_s2_riscv64 + i] = freebsd_gpr.s[2 + i]; + + // x28-x31: t3-t6 + posix_gpr.gpr[gpr_t3_riscv64] = freebsd_gpr.t[3]; + posix_gpr.gpr[gpr_t4_riscv64] = freebsd_gpr.t[4]; + posix_gpr.gpr[gpr_t5_riscv64] = freebsd_gpr.t[5]; + posix_gpr.gpr[gpr_t6_riscv64] = freebsd_gpr.t[6]; +} + +void NativeRegisterContextFreeBSD_riscv64::POSIXToFreeBSDGPR( + const RegisterInfoPOSIX_riscv64::GPR &posix_gpr, struct reg &freebsd_gpr) { + freebsd_gpr.sepc = posix_gpr.gpr[gpr_pc_riscv64]; // x0/pc + freebsd_gpr.ra = posix_gpr.gpr[gpr_ra_riscv64]; // x1/ra + freebsd_gpr.sp = posix_gpr.gpr[gpr_sp_riscv64]; // x2/sp + freebsd_gpr.gp = posix_gpr.gpr[gpr_gp_riscv64]; // x3/gp + freebsd_gpr.tp = posix_gpr.gpr[gpr_tp_riscv64]; // x4/tp + + // x5-x7: t0-t2 + freebsd_gpr.t[0] = posix_gpr.gpr[gpr_t0_riscv64]; + freebsd_gpr.t[1] = posix_gpr.gpr[gpr_t1_riscv64]; + freebsd_gpr.t[2] = posix_gpr.gpr[gpr_t2_riscv64]; + + // x8-x9: s0-s1 + freebsd_gpr.s[0] = posix_gpr.gpr[gpr_s0_riscv64]; + freebsd_gpr.s[1] = posix_gpr.gpr[gpr_s1_riscv64]; + + // x10-x17: a0-a7 + for (int i = 0; i < 8; i++) + freebsd_gpr.a[i] = posix_gpr.gpr[gpr_a0_riscv64 + i]; + + // x18-x27: s2-s11 + for (int i = 0; i < 10; i++) + freebsd_gpr.s[2 + i] = posix_gpr.gpr[gpr_s2_riscv64 + i]; + + // x28-x31: t3-t6 + freebsd_gpr.t[3] = posix_gpr.gpr[gpr_t3_riscv64]; + freebsd_gpr.t[4] = posix_gpr.gpr[gpr_t4_riscv64]; + freebsd_gpr.t[5] = posix_gpr.gpr[gpr_t5_riscv64]; + freebsd_gpr.t[6] = posix_gpr.gpr[gpr_t6_riscv64]; +} + +void NativeRegisterContextFreeBSD_riscv64::FreeBSDToPOSIXFPR( + const struct fpreg &freebsd_fpr, + RegisterInfoPOSIX_riscv64::FPR &posix_fpr) { + // FreeBSD stores FP registers as 128-bit (fp_x[32][2]) + // POSIX expects 64-bit (fpr[32]) + // We only use the lower 64 bits (D extension, double precision) + for (int i = 0; i < 32; i++) + posix_fpr.fpr[i] = freebsd_fpr.fp_x[i][0]; + + // FCSR: FreeBSD has 64-bit, POSIX expects 32-bit + posix_fpr.fcsr = static_cast<uint32_t>(freebsd_fpr.fp_fcsr); +} + +void NativeRegisterContextFreeBSD_riscv64::POSIXToFreeBSDFPR( + const RegisterInfoPOSIX_riscv64::FPR &posix_fpr, + struct fpreg &freebsd_fpr) { + // POSIX has 64-bit FP registers, FreeBSD expects 128-bit + for (int i = 0; i < 32; i++) { + freebsd_fpr.fp_x[i][0] = posix_fpr.fpr[i]; // Lower 64 bits + freebsd_fpr.fp_x[i][1] = 0; // Upper 64 bits (unused for D) + } + + // FCSR: POSIX has 32-bit, FreeBSD expects 64-bit + freebsd_fpr.fp_fcsr = static_cast<uint64_t>(posix_fpr.fcsr); +} + +// ============================================================================ +// Constructor and Setup +// ============================================================================ + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) { + return new NativeRegisterContextFreeBSD_riscv64(target_arch, native_thread); +} + +NativeRegisterContextFreeBSD_riscv64::NativeRegisterContextFreeBSD_riscv64( + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) + : NativeRegisterContextFreeBSD(native_thread), m_gpr(), m_fpr(), + m_gpr_is_valid(false), m_fpr_is_valid(false) { + m_register_info_interface_up = + std::make_unique<RegisterInfoPOSIX_riscv64>(target_arch, 0); + + ::memset(&m_gpr, 0, sizeof(m_gpr)); + ::memset(&m_fpr, 0, sizeof(m_fpr)); +} + +RegisterInfoPOSIX_riscv64 & +NativeRegisterContextFreeBSD_riscv64::GetRegisterInfo() const { + return static_cast<RegisterInfoPOSIX_riscv64 &>( + *m_register_info_interface_up); +} + +// ============================================================================ +// Register Set Information +// ============================================================================ + +uint32_t NativeRegisterContextFreeBSD_riscv64::GetRegisterSetCount() const { + return GetRegisterInfo().GetRegisterSetCount(); +} + +const RegisterSet * +NativeRegisterContextFreeBSD_riscv64::GetRegisterSet(uint32_t set_index) const { + return GetRegisterInfo().GetRegisterSet(set_index); +} + +uint32_t NativeRegisterContextFreeBSD_riscv64::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) + count += GetRegisterSet(set_index)->num_registers; + return count; +} + +void NativeRegisterContextFreeBSD_riscv64::InvalidateAllRegisters() { + m_gpr_is_valid = false; + m_fpr_is_valid = false; +} + +// ============================================================================ +// Ptrace Wrappers +// ============================================================================ + +Status NativeRegisterContextFreeBSD_riscv64::ReadGPR() { + if (m_gpr_is_valid) + return Status(); + + Status error = + NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), &m_gpr); + + if (error.Success()) + m_gpr_is_valid = true; + + return error; +} + +Status NativeRegisterContextFreeBSD_riscv64::WriteGPR() { + Status error = + NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), &m_gpr); + + if (error.Success()) + m_gpr_is_valid = true; + + return error; +} + +Status NativeRegisterContextFreeBSD_riscv64::ReadFPR() { + if (m_fpr_is_valid) + return Status(); + + Status error = NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, + m_thread.GetID(), &m_fpr); + + if (error.Success()) + m_fpr_is_valid = true; + + return error; +} + +Status NativeRegisterContextFreeBSD_riscv64::WriteFPR() { + Status error = NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, + m_thread.GetID(), &m_fpr); + + if (error.Success()) + m_fpr_is_valid = true; + + return error; +} + +// ============================================================================ +// Single Register Access Helpers +// ============================================================================ + +Status +NativeRegisterContextFreeBSD_riscv64::GetGPRValue(uint32_t reg_index, + uint64_t &value) const { + // Map LLDB register index to FreeBSD struct reg field + switch (reg_index) { + case gpr_pc_riscv64: + value = m_gpr.sepc; + return Status(); + case gpr_ra_riscv64: + value = m_gpr.ra; + return Status(); + case gpr_sp_riscv64: + value = m_gpr.sp; + return Status(); + case gpr_gp_riscv64: + value = m_gpr.gp; + return Status(); + case gpr_tp_riscv64: + value = m_gpr.tp; + return Status(); + + // t0-t6 + case gpr_t0_riscv64: + case gpr_t1_riscv64: + case gpr_t2_riscv64: + value = m_gpr.t[reg_index - gpr_t0_riscv64]; + return Status(); + case gpr_t3_riscv64: + case gpr_t4_riscv64: + case gpr_t5_riscv64: + case gpr_t6_riscv64: + value = m_gpr.t[reg_index - gpr_t3_riscv64 + 3]; + return Status(); + + // s0-s11 + case gpr_s0_riscv64: + case gpr_s1_riscv64: + value = m_gpr.s[reg_index - gpr_s0_riscv64]; + return Status(); + case gpr_s2_riscv64: + case gpr_s3_riscv64: + case gpr_s4_riscv64: + case gpr_s5_riscv64: + case gpr_s6_riscv64: + case gpr_s7_riscv64: + case gpr_s8_riscv64: + case gpr_s9_riscv64: + case gpr_s10_riscv64: + case gpr_s11_riscv64: + value = m_gpr.s[reg_index - gpr_s2_riscv64 + 2]; + return Status(); + + // a0-a7 + case gpr_a0_riscv64: + case gpr_a1_riscv64: + case gpr_a2_riscv64: + case gpr_a3_riscv64: + case gpr_a4_riscv64: + case gpr_a5_riscv64: + case gpr_a6_riscv64: + case gpr_a7_riscv64: + value = m_gpr.a[reg_index - gpr_a0_riscv64]; + return Status(); + + default: + return Status::FromErrorStringWithFormat("invalid GPR register index: %u", + reg_index); + } +} + +Status NativeRegisterContextFreeBSD_riscv64::SetGPRValue(uint32_t reg_index, + uint64_t value) { + switch (reg_index) { + case gpr_pc_riscv64: + m_gpr.sepc = value; + return Status(); + case gpr_ra_riscv64: + m_gpr.ra = value; + return Status(); + case gpr_sp_riscv64: + m_gpr.sp = value; + return Status(); + case gpr_gp_riscv64: + m_gpr.gp = value; + return Status(); + case gpr_tp_riscv64: + m_gpr.tp = value; + return Status(); + + case gpr_t0_riscv64: + case gpr_t1_riscv64: + case gpr_t2_riscv64: + m_gpr.t[reg_index - gpr_t0_riscv64] = value; + return Status(); + case gpr_t3_riscv64: + case gpr_t4_riscv64: + case gpr_t5_riscv64: + case gpr_t6_riscv64: + m_gpr.t[reg_index - gpr_t3_riscv64 + 3] = value; + return Status(); + + case gpr_s0_riscv64: + case gpr_s1_riscv64: + m_gpr.s[reg_index - gpr_s0_riscv64] = value; + return Status(); + case gpr_s2_riscv64: + case gpr_s3_riscv64: + case gpr_s4_riscv64: + case gpr_s5_riscv64: + case gpr_s6_riscv64: + case gpr_s7_riscv64: + case gpr_s8_riscv64: + case gpr_s9_riscv64: + case gpr_s10_riscv64: + case gpr_s11_riscv64: + m_gpr.s[reg_index - gpr_s2_riscv64 + 2] = value; + return Status(); + + case gpr_a0_riscv64: + case gpr_a1_riscv64: + case gpr_a2_riscv64: + case gpr_a3_riscv64: + case gpr_a4_riscv64: + case gpr_a5_riscv64: + case gpr_a6_riscv64: + case gpr_a7_riscv64: + m_gpr.a[reg_index - gpr_a0_riscv64] = value; + return Status(); + + default: + return Status::FromErrorStringWithFormat("invalid GPR register index: %u", + reg_index); + } +} + +// ============================================================================ +// Single Register Read/Write +// ============================================================================ + +Status +NativeRegisterContextFreeBSD_riscv64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + if (!reg_info) + return Status::FromErrorString("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status::FromErrorStringWithFormat( + "no lldb regnum for %s", reg_info->name ? reg_info->name : "<unknown>"); + + if (GetRegisterInfo().IsGPR(reg)) { + Status error = ReadGPR(); + if (error.Fail()) + return error; + + uint64_t value; + error = GetGPRValue(reg, value); + if (error.Fail()) + return error; + + reg_value = value; + return Status(); + } + + if (GetRegisterInfo().IsFPR(reg)) { + Status error = ReadFPR(); + if (error.Fail()) + return error; + + uint32_t fpr_index = + reg - GetRegisterInfo().GetRegisterInfo()[reg].kinds[eRegisterKindLLDB]; + + if (fpr_index < 32) { + reg_value = m_fpr.fp_x[fpr_index][0]; // Lower 64 bits + } else if (fpr_index == 32) { + reg_value = static_cast<uint32_t>(m_fpr.fp_fcsr); + } else { + return Status::FromErrorString("invalid FPR index"); + } + + return Status(); + } + + return Status::FromErrorString("unsupported register type"); +} + +Status NativeRegisterContextFreeBSD_riscv64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + if (!reg_info) + return Status::FromErrorString("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status::FromErrorStringWithFormat( + "no lldb regnum for %s", reg_info->name ? reg_info->name : "<unknown>"); + + if (GetRegisterInfo().IsGPR(reg)) { + Status error = ReadGPR(); // Read first to preserve other registers + if (error.Fail()) + return error; + + error = SetGPRValue(reg, reg_value.GetAsUInt64()); + if (error.Fail()) + return error; + + return WriteGPR(); + } + + if (GetRegisterInfo().IsFPR(reg)) { + Status error = ReadFPR(); + if (error.Fail()) + return error; + + uint32_t fpr_index = + reg - GetRegisterInfo().GetRegisterInfo()[reg].kinds[eRegisterKindLLDB]; + + if (fpr_index < 32) { + m_fpr.fp_x[fpr_index][0] = reg_value.GetAsUInt64(); + m_fpr.fp_x[fpr_index][1] = 0; + } else if (fpr_index == 32) { + m_fpr.fp_fcsr = reg_value.GetAsUInt32(); + } else { + return Status::FromErrorString("invalid FPR index"); + } + + return WriteFPR(); + } + + return Status::FromErrorString("unsupported register type"); +} + +// ============================================================================ +// Bulk Register Read/Write (using conversion functions) +// ============================================================================ + +Status NativeRegisterContextFreeBSD_riscv64::ReadAllRegisterValues( + lldb::WritableDataBufferSP &data_sp) { + // Read from kernel + Status error = ReadGPR(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + // Allocate buffer for POSIX format + const size_t total_size = sizeof(RegisterInfoPOSIX_riscv64::GPR) + + sizeof(RegisterInfoPOSIX_riscv64::FPR); + data_sp = std::make_shared<DataBufferHeap>(total_size, 0); + if (!data_sp || !data_sp->GetBytes()) + return Status::FromErrorString("failed to allocate data buffer"); + + // Get pointers to GPR and FPR sections of buffer + auto *gpr_dst = + reinterpret_cast<RegisterInfoPOSIX_riscv64::GPR *>(data_sp->GetBytes()); + auto *fpr_dst = reinterpret_cast<RegisterInfoPOSIX_riscv64::FPR *>( + data_sp->GetBytes() + sizeof(RegisterInfoPOSIX_riscv64::GPR)); + + // Convert FreeBSD format to POSIX format + FreeBSDToPOSIXGPR(m_gpr, *gpr_dst); + FreeBSDToPOSIXFPR(m_fpr, *fpr_dst); + + return Status(); +} + +Status NativeRegisterContextFreeBSD_riscv64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + if (!data_sp) + return Status::FromErrorString("invalid data_sp provided"); + + const size_t expected_size = sizeof(RegisterInfoPOSIX_riscv64::GPR) + + sizeof(RegisterInfoPOSIX_riscv64::FPR); + + if (data_sp->GetByteSize() != expected_size) { + return Status::FromErrorStringWithFormat( + "data_sp size mismatch, expected %zu, actual %" PRIu64, expected_size, + data_sp->GetByteSize()); + } + + const uint8_t *src = data_sp->GetBytes(); + if (!src) + return Status::FromErrorString("DataBuffer::GetBytes() returned null"); + + // Get pointers to GPR and FPR sections of buffer + const auto *gpr_src = + reinterpret_cast<const RegisterInfoPOSIX_riscv64::GPR *>(src); + const auto *fpr_src = + reinterpret_cast<const RegisterInfoPOSIX_riscv64::FPR *>( + src + sizeof(RegisterInfoPOSIX_riscv64::GPR)); + + // Convert POSIX format to FreeBSD format + POSIXToFreeBSDGPR(*gpr_src, m_gpr); + POSIXToFreeBSDFPR(*fpr_src, m_fpr); + + // Write to kernel + Status error = WriteGPR(); + if (error.Fail()) + return error; + + return WriteFPR(); +} + +#endif // defined(__riscv) && __riscv_xlen == 64 diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.h b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.h new file mode 100644 index 0000000000000..cd8d72cc60773 --- /dev/null +++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.h @@ -0,0 +1,81 @@ +//===-- NativeRegisterContextFreeBSD_riscv64.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__riscv) && __riscv_xlen == 64 + +#ifndef lldb_NativeRegisterContextFreeBSD_riscv64_h +#define lldb_NativeRegisterContextFreeBSD_riscv64_h + +// clang-format off +#include <sys/types.h> +#include <sys/param.h> +#include <machine/reg.h> +// clang-format on + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h" + +namespace lldb_private { +namespace process_freebsd { + +class NativeRegisterContextFreeBSD_riscv64 + : public NativeRegisterContextFreeBSD { +public: + NativeRegisterContextFreeBSD_riscv64(const ArchSpec &target_arch, + NativeThreadFreeBSD &native_thread); + + uint32_t GetRegisterSetCount() const override; + uint32_t GetUserRegisterCount() const override; + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override; + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + void InvalidateAllRegisters() override; + +private: + // FreeBSD's native register structures + struct reg m_gpr; + struct fpreg m_fpr; + + bool m_gpr_is_valid; + bool m_fpr_is_valid; + + // Ptrace wrappers + Status ReadGPR(); + Status WriteGPR(); + Status ReadFPR(); + Status WriteFPR(); + + // Conversion functions between FreeBSD and POSIX layouts + static void FreeBSDToPOSIXGPR(const struct reg &freebsd_gpr, + RegisterInfoPOSIX_riscv64::GPR &posix_gpr); + static void POSIXToFreeBSDGPR(const RegisterInfoPOSIX_riscv64::GPR &posix_gpr, + struct reg &freebsd_gpr); + static void FreeBSDToPOSIXFPR(const struct fpreg &freebsd_fpr, + RegisterInfoPOSIX_riscv64::FPR &posix_fpr); + static void POSIXToFreeBSDFPR(const RegisterInfoPOSIX_riscv64::FPR &posix_fpr, + struct fpreg &freebsd_fpr); + + // Single register conversion helpers + Status GetGPRValue(uint32_t reg_index, uint64_t &value) const; + Status SetGPRValue(uint32_t reg_index, uint64_t value); + + RegisterInfoPOSIX_riscv64 &GetRegisterInfo() const; +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_riscv64_h +#endif // defined(__riscv) && __riscv_xlen == 64 diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index b51d34a2614f1..fbf85012430bf 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -97,6 +97,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { case llvm::Triple::ppc64le: reg_interface = new RegisterContextFreeBSD_powerpc64(arch); break; + case llvm::Triple::riscv64: + break; case llvm::Triple::x86: reg_interface = new RegisterContextFreeBSD_i386(arch); break; diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 8dabcecf3ece8..2fe27f25ef896 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -180,6 +180,7 @@ Changes to LLDB * Support for FreeBSD on MIPS64 has been removed. * The minimum assumed version of FreeBSD is now 14. The effect of which is that watchpoints are assumed to be supported. +* Support for FreeBSD on RISCV64 has been added. Changes to BOLT --------------- >From 3e48d2c6a59c6417b226524963108f6b1d0a5f7b Mon Sep 17 00:00:00 2001 From: Minsoo Choo <[email protected]> Date: Tue, 10 Feb 2026 09:43:03 -0500 Subject: [PATCH 2/2] fixup! [lldb][Process/FreeBSD] Add riscv64 support Signed-off-by: Minsoo Choo <[email protected]> --- .../NativeRegisterContextFreeBSD_riscv64.cpp | 46 ++++--------------- 1 file changed, 9 insertions(+), 37 deletions(-) diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.cpp index 3464d0a377bd5..6cf5ea5c52d8e 100644 --- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.cpp @@ -51,10 +51,6 @@ using namespace lldb_private::process_freebsd; // int dummy; // }; -// ============================================================================ -// Static Conversion Functions between FreeBSD and POSIX -// ============================================================================ - void NativeRegisterContextFreeBSD_riscv64::FreeBSDToPOSIXGPR( const struct reg &freebsd_gpr, RegisterInfoPOSIX_riscv64::GPR &posix_gpr) { posix_gpr.gpr[gpr_pc_riscv64] = freebsd_gpr.sepc; // x0/pc @@ -145,10 +141,6 @@ void NativeRegisterContextFreeBSD_riscv64::POSIXToFreeBSDFPR( freebsd_fpr.fp_fcsr = static_cast<uint64_t>(posix_fpr.fcsr); } -// ============================================================================ -// Constructor and Setup -// ============================================================================ - NativeRegisterContextFreeBSD * NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) { @@ -172,10 +164,6 @@ NativeRegisterContextFreeBSD_riscv64::GetRegisterInfo() const { *m_register_info_interface_up); } -// ============================================================================ -// Register Set Information -// ============================================================================ - uint32_t NativeRegisterContextFreeBSD_riscv64::GetRegisterSetCount() const { return GetRegisterInfo().GetRegisterSetCount(); } @@ -197,10 +185,6 @@ void NativeRegisterContextFreeBSD_riscv64::InvalidateAllRegisters() { m_fpr_is_valid = false; } -// ============================================================================ -// Ptrace Wrappers -// ============================================================================ - Status NativeRegisterContextFreeBSD_riscv64::ReadGPR() { if (m_gpr_is_valid) return Status(); @@ -247,10 +231,6 @@ Status NativeRegisterContextFreeBSD_riscv64::WriteFPR() { return error; } -// ============================================================================ -// Single Register Access Helpers -// ============================================================================ - Status NativeRegisterContextFreeBSD_riscv64::GetGPRValue(uint32_t reg_index, uint64_t &value) const { @@ -386,10 +366,6 @@ Status NativeRegisterContextFreeBSD_riscv64::SetGPRValue(uint32_t reg_index, } } -// ============================================================================ -// Single Register Read/Write -// ============================================================================ - Status NativeRegisterContextFreeBSD_riscv64::ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) { @@ -424,18 +400,18 @@ NativeRegisterContextFreeBSD_riscv64::ReadRegister(const RegisterInfo *reg_info, uint32_t fpr_index = reg - GetRegisterInfo().GetRegisterInfo()[reg].kinds[eRegisterKindLLDB]; - if (fpr_index < 32) { + if (fpr_index < 32) reg_value = m_fpr.fp_x[fpr_index][0]; // Lower 64 bits - } else if (fpr_index == 32) { + else if (fpr_index == 32) reg_value = static_cast<uint32_t>(m_fpr.fp_fcsr); - } else { + else return Status::FromErrorString("invalid FPR index"); - } return Status(); } - return Status::FromErrorString("unsupported register type"); + return Status::FromErrorStringWithFormat("unsupported register type: %u", + reg); } Status NativeRegisterContextFreeBSD_riscv64::WriteRegister( @@ -481,16 +457,12 @@ Status NativeRegisterContextFreeBSD_riscv64::WriteRegister( return WriteFPR(); } - return Status::FromErrorString("unsupported register type"); + return Status::FromErrorStringWithFormat("unsupported register type: %u", + reg); } -// ============================================================================ -// Bulk Register Read/Write (using conversion functions) -// ============================================================================ - Status NativeRegisterContextFreeBSD_riscv64::ReadAllRegisterValues( lldb::WritableDataBufferSP &data_sp) { - // Read from kernel Status error = ReadGPR(); if (error.Fail()) return error; @@ -504,7 +476,8 @@ Status NativeRegisterContextFreeBSD_riscv64::ReadAllRegisterValues( sizeof(RegisterInfoPOSIX_riscv64::FPR); data_sp = std::make_shared<DataBufferHeap>(total_size, 0); if (!data_sp || !data_sp->GetBytes()) - return Status::FromErrorString("failed to allocate data buffer"); + return Status::FromErrorString( + "failed to allocate data buffer for POSIX-layout register data"); // Get pointers to GPR and FPR sections of buffer auto *gpr_dst = @@ -548,7 +521,6 @@ Status NativeRegisterContextFreeBSD_riscv64::WriteAllRegisterValues( POSIXToFreeBSDGPR(*gpr_src, m_gpr); POSIXToFreeBSDFPR(*fpr_src, m_fpr); - // Write to kernel Status error = WriteGPR(); if (error.Fail()) return error; _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
