[lldb] [llvm] [lldb][Process/FreeBSD] Add riscv64 support (PR #180549)

via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 9 07:47:27 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v

Author: Minsoo Choo (mchoo7)

<details>
<summary>Changes</summary>

LLDB needs to maintain separate structure for FreeBSD's riscv register structure. The translation is done through `FreeBSDToPOSIXGPR`, `FreeBSDToPOSIXFPR`, `POSIXToFreeBSDGPR`, and `POSIXToFreeBSDFPR`.

---

Patch is 23.45 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/180549.diff


6 Files Affected:

- (modified) lldb/docs/index.rst (+1-1) 
- (modified) lldb/source/Plugins/Process/FreeBSD/CMakeLists.txt (+1) 
- (added) lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.cpp (+559) 
- (added) lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_riscv64.h (+81) 
- (modified) lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp (+2) 
- (modified) llvm/docs/ReleaseNotes.md (+1) 


``````````diff
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 &reg_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 &reg_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...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/180549


More information about the llvm-commits mailing list