115 lines
2.8 KiB
Go
115 lines
2.8 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
//go:build freebsd && arm64
|
|
|
|
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 (x[30], lr, sp, elr, spsr) into the
|
|
// portable layout.
|
|
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{
|
|
X0: ur.X[0],
|
|
X1: ur.X[1],
|
|
X2: ur.X[2],
|
|
X3: ur.X[3],
|
|
X4: ur.X[4],
|
|
X5: ur.X[5],
|
|
X6: ur.X[6],
|
|
X7: ur.X[7],
|
|
X8: ur.X[8],
|
|
X9: ur.X[9],
|
|
X10: ur.X[10],
|
|
X11: ur.X[11],
|
|
X12: ur.X[12],
|
|
X13: ur.X[13],
|
|
X14: ur.X[14],
|
|
X15: ur.X[15],
|
|
X16: ur.X[16],
|
|
X17: ur.X[17],
|
|
X18: ur.X[18],
|
|
X19: ur.X[19],
|
|
X20: ur.X[20],
|
|
X21: ur.X[21],
|
|
X22: ur.X[22],
|
|
X23: ur.X[23],
|
|
X24: ur.X[24],
|
|
X25: ur.X[25],
|
|
X26: ur.X[26],
|
|
X27: ur.X[27],
|
|
X28: ur.X[28],
|
|
X29: ur.X[29],
|
|
X30: ur.Lr,
|
|
SP: ur.Sp,
|
|
PC: ur.Elr,
|
|
PSTATE: uint64(ur.Spsr),
|
|
}, nil
|
|
}
|
|
|
|
// SetRegs writes the general-purpose registers of the stopped debuggee.
|
|
func (s *Session) SetRegs(regs *Regs) error {
|
|
var ur unix.Reg
|
|
ur.X = [30]uint64{
|
|
regs.X0, regs.X1, regs.X2, regs.X3, regs.X4, regs.X5, regs.X6,
|
|
regs.X7, regs.X8, regs.X9, regs.X10, regs.X11, regs.X12, regs.X13,
|
|
regs.X14, regs.X15, regs.X16, regs.X17, regs.X18, regs.X19, regs.X20,
|
|
regs.X21, regs.X22, regs.X23, regs.X24, regs.X25, regs.X26, regs.X27,
|
|
regs.X28, regs.X29,
|
|
}
|
|
ur.Lr = regs.X30
|
|
ur.Sp = regs.SP
|
|
ur.Elr = regs.PC
|
|
ur.Spsr = uint32(regs.PSTATE)
|
|
return unix.PtraceSetRegs(s.pid, &ur)
|
|
}
|
|
|
|
// FPRegs holds the arm64 FP/NEON register state: the 32 128-bit V
|
|
// registers, then FPSR and FPCR (the user_fpsimd shape).
|
|
type FPRegs struct {
|
|
V [32][16]byte // V0-V31 (128-bit NEON/FP registers)
|
|
FPSR uint32
|
|
FPCR uint32
|
|
}
|
|
|
|
// GetFPRegs retrieves the FP/NEON register state via PT_GETFPREGS. The
|
|
// FreeBSD struct fpreg holds the 32 128-bit V registers followed by FPSR
|
|
// and FPCR, the user_fpsimd shape.
|
|
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 {
|
|
copy(fp.V[i][:], fr.Q[i][:])
|
|
}
|
|
return fp, nil
|
|
}
|
|
|
|
// VectorRegs holds the full SIMD register state.
|
|
type VectorRegs struct {
|
|
V [32][16]byte // V0-V31 (128-bit)
|
|
}
|
|
|
|
// GetVectorRegs retrieves the SIMD registers.
|
|
func (s *Session) GetVectorRegs() (VectorRegs, error) {
|
|
var v VectorRegs
|
|
fp, err := s.GetFPRegs()
|
|
if err != nil {
|
|
return v, err
|
|
}
|
|
copy(v.V[:][:], fp.V[:][:])
|
|
return v, nil
|
|
}
|