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(&regset.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, &regset, cpuid.AMD64XstateZMMHi256Offset())
	return &regset, 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(&regset.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 nil

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Re-check that the process/thread is alive and still traced before reading registers
  2. Re-list threads after process exit/exec and drop stale IDs
  3. Ensure delve has permission to ptrace the target (same UID or root; check securelevel/jail restrictions)
  4. 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(&regset.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(&regset.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

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


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/ba995d60d15088ec. Report an issue: GitHub.