go-delve/delve · error
failed to get FP registers: %v
Error message
failed to get FP registers: %v
What it means
ptraceGetRegset reads the x87/SSE floating-point register block of a FreeBSD/amd64 thread with PT_GETFPREGS. If the ptrace call fails, the errno is wrapped as 'failed to get FP registers'. This aborts the whole register read since FP registers cannot be fetched.
Source
Thrown at pkg/proc/native/ptrace_freebsd_amd64.go:71
return nil, fmt.Errorf("failed to get xstate: %v", err)
}
return xsaveBuf, nil
}
// ptraceSetXsave sets the X86 XSAVE data for the given tid.
func ptraceSetXsave(tid int, xsaveBuf []byte) error {
ret, err := C.ptrace(C.PT_SETXSTATE, C.pid_t(tid), C.caddr_t(unsafe.Pointer(&xsaveBuf[0])), C.int(len(xsaveBuf)))
if ret != 0 {
return fmt.Errorf("failed to set xstate: %v", err)
}
return nil
}
func ptraceGetRegset(id int) (*amd64util.AMD64Xstate, error) {
var regset amd64util.AMD64Xstate
ret, err := C.ptrace(C.PT_GETFPREGS, C.pid_t(id), C.caddr_t(unsafe.Pointer(®set.AMD64PtraceFpRegs)), C.int(0))
if ret != 0 {
return nil, fmt.Errorf("failed to get FP registers: %v", err)
}
regset.Xsave, err = ptraceGetXsave(id)
if err != nil {
return nil, err
}
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set, cpuid.AMD64XstateZMMHi256Offset())
return ®set, err
}
func ptraceSetRegset(id int, regset *amd64util.AMD64Xstate) error {
ret, err := C.ptrace(C.PT_SETFPREGS, C.pid_t(id), C.caddr_t(unsafe.Pointer(®set.AMD64PtraceFpRegs)), C.int(0))
if ret != 0 {
return fmt.Errorf("failed to set FP registers: %v", err)
}
if regset.Xsave != nil {
return ptraceSetXsave(id, regset.Xsave)
}
return nilView on GitHub (pinned to a23773e6c3)
Solutions
- Re-check that the process/thread is alive and still traced before reading registers
- Re-list threads after process exit/exec and drop stale IDs
- Ensure delve has permission to ptrace the target (same UID or root; check securelevel/jail restrictions)
- Retry the operation if it raced with a stop event; otherwise let the debugger mark the thread dead
Example fix
// before
ret, err := C.ptrace(C.PT_GETFPREGS, C.pid_t(id), C.caddr_t(unsafe.Pointer(®set.AMD64PtraceFpRegs)), C.int(0))
if ret != 0 {
return nil, fmt.Errorf("failed to get FP registers: %v", err)
}
// after
ret, err := C.ptrace(C.PT_GETFPREGS, C.pid_t(id), C.caddr_t(unsafe.Pointer(®set.AMD64PtraceFpRegs)), C.int(0))
if ret != 0 {
if errors.Is(err, syscall.ESRCH) {
return nil, fmt.Errorf("thread %d exited: %w", id, err)
}
return nil, fmt.Errorf("failed to get FP registers: %v", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if dbp.proc == nil || !procAlive(dbp) {
return fmt.Errorf("process not available for FP register read")
}
if !isThreadAlive(dbp, thread.ID) {
return fmt.Errorf("thread %d exited", thread.ID)
} Type guard
func fpRegErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to get FP registers")
} Try / catch
fpregs, err := thread.fpRegisters()
if fpRegErr(err) {
// GPRs may still be valid; degrade to GPR-only registers
return thread.Registers(), nil
} Prevention
- Handle ESRCH-style failures as thread-dead rather than retrying
- Keep ptrace permissions correct (yama/ptrace_scope, container caps)
- Re-enumerate threads after stop events to avoid stale tids
When it happens
Trigger: Reading registers of a thread (nativeThread.Registers -> fpRegisters -> ptraceGetRegset) whose tid no longer exists, when the process is not stopped/attached properly, or when ptrace privileges are missing.
Common situations: Debuggee exited or crashed while a register read was in flight; attaching to a process without sufficient permission; a stale cached thread ID after the target execed or forked.
Related errors
- failed to set FP registers: %v
- failed to get xstate info: %v
- failed to get xstate: %v
- failed to set xstate: %v
- procstat_getprocs returned no processes
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/ba995d60d15088ec.
Report an issue: GitHub.