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

David Spickett via lldb-commits lldb-commits at lists.llvm.org
Tue Feb 10 03:05:13 PST 2026


================
@@ -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");
----------------
DavidSpickett wrote:

Might as well put the number of the type in there. Since you have formatted an error earlier. Don't worry about printing the actual enum name, only LLDB developers will be seeing the message anyway.

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


More information about the lldb-commits mailing list