// Copyright (c) 2026 Petr BalvĂ­n (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 }