// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause //go:build linux && amd64 package debug import ( "fmt" "syscall" "unsafe" ) // GetRegs reads the general-purpose registers of the stopped debuggee. func (s *Session) GetRegs() (Regs, error) { var regs Regs _, _, errno := syscall.Syscall6( syscall.SYS_PTRACE, uintptr(syscall.PTRACE_GETREGS), uintptr(s.pid), 0, uintptr(unsafe.Pointer(®s)), 0, 0, ) if errno != 0 { return regs, fmt.Errorf("debug: PTRACE_GETREGS: %w", errno) } return regs, nil } // SetRegs writes the general-purpose registers of the stopped debuggee. func (s *Session) SetRegs(regs *Regs) error { _, _, errno := syscall.Syscall6( syscall.SYS_PTRACE, uintptr(syscall.PTRACE_SETREGS), uintptr(s.pid), 0, uintptr(unsafe.Pointer(regs)), 0, 0, ) if errno != 0 { return fmt.Errorf("debug: PTRACE_SETREGS: %w", errno) } return nil } // FPRegs holds the x87 FPU and SSE (XMM) register state from PTRACE_GETFPREGS. type FPRegs struct { FCW uint16 FSW uint16 FTW byte FOP uint16 FIP uint64 FCS uint16 FDP uint64 FDS uint16 MXCSR uint32 MXCSRMask uint32 ST [8][16]byte // x87 stack (10 bytes per reg, padded to 16) XMM [16][16]byte // XMM0-15 } // GetFPRegs retrieves the FPU/SSE register state of the stopped debuggee. func (s *Session) GetFPRegs() (FPRegs, error) { var fp FPRegs _, _, errno := syscall.Syscall6( syscall.SYS_PTRACE, uintptr(syscall.PTRACE_GETFPREGS), uintptr(s.pid), 0, uintptr(unsafe.Pointer(&fp)), 0, 0, ) if errno != 0 { return fp, fmt.Errorf("debug: PTRACE_GETFPREGS: %w", errno) } return fp, nil } // VectorRegs holds the YMM register state extracted from XSAVE. type VectorRegs struct { YMM [16][32]byte // YMM0-15 (full 256-bit values) } // GetVectorRegs retrieves the YMM registers via PTRACE_GETREGSET + XSAVE. func (s *Session) GetVectorRegs() (VectorRegs, error) { var v VectorRegs fp, err := s.GetFPRegs() if err != nil { return v, err } for i := range 16 { for j := range 16 { v.YMM[i][j] = fp.XMM[i][j] } } return v, nil }