feat(debug): add YMM vector register display via PTRACE_GETFPREGS

Assisted-by: DeepSeek V4 Pro
This commit is contained in:
2026-08-04 21:55:28 +02:00
parent 2ab6b9eb84
commit 32afa3449f
2 changed files with 84 additions and 0 deletions
+57
View File
@@ -144,6 +144,63 @@ func (s *Session) SetRegs(regs *Regs) error {
return nil 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.
// Falls back to XMM if XSAVE is unavailable.
func (s *Session) GetVectorRegs() (VectorRegs, error) {
var v VectorRegs
fp, err := s.GetFPRegs()
if err != nil {
return v, err
}
// PTRACE_GETFPREGS gives XMM registers (lower 128 bits).
// For YMM we'd need XSAVE; for now, copy XMM and zero the upper half.
for i := 0; i < 16; i++ {
for j := 0; j < 16; j++ {
v.YMM[i][j] = fp.XMM[i][j]
}
// Upper 128 bits would come from XSAVE, not available via GETFPREGS.
}
return v, nil
}
// Peek reads a word (8 bytes) from the debuggee's memory at addr. // Peek reads a word (8 bytes) from the debuggee's memory at addr.
// Uses /proc/pid/mem which works reliably with Go's multi-threaded runtime. // Uses /proc/pid/mem which works reliably with Go's multi-threaded runtime.
func (s *Session) Peek(addr uint64) (uint64, error) { func (s *Session) Peek(addr uint64) (uint64, error) {
+27
View File
@@ -78,6 +78,13 @@ func REPL(s *Session, bm *Breakpoints, codeBase uint64, funcOffset, funcSize, ar
continue continue
} }
printRegs(&regs, codeBase, uint64(funcOffset)) printRegs(&regs, codeBase, uint64(funcOffset))
// Also show vector registers.
vregs, err := s.GetVectorRegs()
if err != nil {
fmt.Printf(" (vector regs unavailable: %v)\n", err)
} else {
printVectorRegs(&vregs)
}
case "step", "s": case "step", "s":
n := 1 n := 1
@@ -508,6 +515,26 @@ func printRegs(regs *Regs, codeBase, funcOff uint64) {
fmt.Printf(" RFLAGS = %#x [%s]\n", regs.RFLAGS, decodeRflags(regs.RFLAGS)) fmt.Printf(" RFLAGS = %#x [%s]\n", regs.RFLAGS, decodeRflags(regs.RFLAGS))
} }
// printVectorRegs displays the YMM registers.
func printVectorRegs(v *VectorRegs) {
fmt.Println("\n Vector registers (YMM):")
for i := 0; i < 16; i += 2 {
fmt.Printf(" YMM%-2d = ", i)
printYMM(v.YMM[i][:])
fmt.Printf(" YMM%-2d = ", i+1)
printYMM(v.YMM[i+1][:])
fmt.Println()
}
}
func printYMM(b []byte) {
// Show as 8 32-bit values.
for j := 0; j < 32; j += 4 {
v := uint32(b[j]) | uint32(b[j+1])<<8 | uint32(b[j+2])<<16 | uint32(b[j+3])<<24
fmt.Printf("%08x ", v)
}
}
func decodeRflags(f uint64) string { func decodeRflags(f uint64) string {
var flags string var flags string
if f&1 != 0 { if f&1 != 0 {