2026-08-01 02:34:00 +02:00
|
|
|
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (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
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-04 21:55:28 +02:00
|
|
|
// 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
|
|
|
|
|
}
|
2026-08-29 15:40:31 +02:00
|
|
|
for i := range 16 {
|
|
|
|
|
for j := range 16 {
|
2026-08-04 21:55:28 +02:00
|
|
|
v.YMM[i][j] = fp.XMM[i][j]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return v, nil
|
|
|
|
|
}
|