Files

116 lines
3.0 KiB
Go
Raw Permalink Normal View History

2026-09-25 21:46:40 +02:00
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: BSD-3-Clause
//go:build freebsd && riscv64
package debug
import (
"fmt"
"golang.org/x/sys/unix"
)
// GetRegs reads the general-purpose registers of the stopped debuggee and
// converts the FreeBSD struct reg into the portable layout. Sstatus rides
// the kernel's struct but the portable surface carries the GPRs and PC.
func (s *Session) GetRegs() (Regs, error) {
var ur unix.Reg
if err := unix.PtraceGetRegs(s.pid, &ur); err != nil {
return Regs{}, fmt.Errorf("debug: PT_GETREGS: %w", err)
}
return Regs{
PC: ur.Sepc,
Ra: ur.Ra,
Sp: ur.Sp,
Gp: ur.Gp,
Tp: ur.Tp,
T0: ur.T[0],
T1: ur.T[1],
T2: ur.T[2],
S0: ur.S[0],
S1: ur.S[1],
A0: ur.A[0],
A1: ur.A[1],
A2: ur.A[2],
A3: ur.A[3],
A4: ur.A[4],
A5: ur.A[5],
A6: ur.A[6],
A7: ur.A[7],
S2: ur.S[2],
S3: ur.S[3],
S4: ur.S[4],
S5: ur.S[5],
S6: ur.S[6],
S7: ur.S[7],
S8: ur.S[8],
S9: ur.S[9],
S10: ur.S[10],
S11: ur.S[11],
T3: ur.T[3],
T4: ur.T[4],
T5: ur.T[5],
T6: ur.T[6],
}, nil
}
// SetRegs writes the general-purpose registers of the stopped debuggee.
// Read-modify-write keeps sstatus, which the kernel owns, intact.
func (s *Session) SetRegs(regs *Regs) error {
var ur unix.Reg
if err := unix.PtraceGetRegs(s.pid, &ur); err != nil {
return fmt.Errorf("debug: PT_GETREGS: %w", err)
}
ur.Sepc = regs.PC
ur.Ra = regs.Ra
ur.Sp = regs.Sp
ur.Gp = regs.Gp
ur.Tp = regs.Tp
ur.T = [7]uint64{regs.T0, regs.T1, regs.T2, regs.T3, regs.T4, regs.T5, regs.T6}
ur.S = [12]uint64{regs.S0, regs.S1, regs.S2, regs.S3, regs.S4, regs.S5,
regs.S6, regs.S7, regs.S8, regs.S9, regs.S10, regs.S11}
ur.A = [8]uint64{regs.A0, regs.A1, regs.A2, regs.A3, regs.A4, regs.A5, regs.A6, regs.A7}
return unix.PtraceSetRegs(s.pid, &ur)
}
// FPRegs holds the RISC-V FP register state (32 64-bit FP registers plus
// fcsr).
type FPRegs struct {
F [32]uint64 // F0-F31 (64-bit FP registers)
FCSR uint32
}
// GetFPRegs retrieves the FP register state via PT_GETFPREGS. The FreeBSD
// struct fpreg carries each 64-bit FP register in a 128-bit slot (fp_x is
// the flat [64]-word area the x/sys type renders as [32][2]); the low word
// holds the register, and FCSR rides the tail.
func (s *Session) GetFPRegs() (FPRegs, error) {
var fp FPRegs
var fr unix.FpReg
if err := unix.PtraceGetFpRegs(s.pid, &fr); err != nil {
return fp, fmt.Errorf("debug: PT_GETFPREGS: %w", err)
}
for i := range 32 {
fp.F[i] = fr.X[i][0]
}
fp.FCSR = uint32(fr.Fcsr)
return fp, nil
}
// VectorRegs holds the FP register state shown by the regs command
// (riscv64 has 32 64-bit FP registers and fcsr).
type VectorRegs struct {
F [32]uint64
FCSR uint32
}
// GetVectorRegs retrieves the FP registers.
func (s *Session) GetVectorRegs() (VectorRegs, error) {
fp, err := s.GetFPRegs()
if err != nil {
return VectorRegs{}, err
}
return VectorRegs{F: fp.F, FCSR: fp.FCSR}, nil
}