go-delve/delve · error

failed to set xstate: %v

Error message

failed to set xstate: %v

What it means

ptraceSetXsave writes the thread's extended XSAVE state back with PT_SETXSTATE on FreeBSD/amd64. A non-zero return from ptrace is wrapped in this error. It means the kernel refused the xstate write (invalid buffer length, unsupported features in the buffer, or dead thread).

Source

Thrown at pkg/proc/native/ptrace_freebsd_amd64.go:62

// ptraceGetXsave gets the X86 XSAVE data for the given tid.
func ptraceGetXsave(tid int) ([]byte, error) {
	len, err := ptraceXsaveLen(tid)
	if err != nil {
		return nil, err
	}
	xsaveBuf := make([]byte, len)
	ret, err := C.ptrace(C.PT_GETXSTATE, C.pid_t(tid), C.caddr_t(unsafe.Pointer(&xsaveBuf[0])), C.int(len))
	if ret != 0 {
		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
}

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Confirm the target thread is alive before calling SetRegs-style register writes
  2. Ensure the xsave buffer length matches the CPU's xstate size (query once via PT_GETXSTATE and reuse that length)
  3. Upgrade/verify the FreeBSD kernel supports PT_SETXSTATE for the running CPU
  4. Capture errno properly if the formatted error is empty to identify the true cause

Example fix

// before
if regset.Xsave != nil {
	return ptraceSetXsave(id, regset.Xsave)
}
// after
if regset.Xsave != nil {
	if err := ptraceSetXsave(id, regset.Xsave); err != nil {
		return fmt.Errorf("setxstate tid=%d: %w", id, err)
	}
}
Defensive patterns

Strategy: validation

Validate before calling

// before writing xstate
if !isThreadAlive(dbp, id) {
	return fmt.Errorf("thread %d gone; skipping xstate write", id)
}
if len(xsaveBuf) != knownXstateSize {
	return fmt.Errorf("xstate buffer %d != expected %d", len(xsaveBuf), knownXstateSize)
}

Type guard

func isXstateWriteErr(err error) bool {
	return err != nil && strings.Contains(err.Error(), "failed to set xstate")
}

Prevention

When it happens

Trigger: ptraceSetRegset -> ptraceSetXsave when the xsave buffer size does not match what the kernel expects for the CPU's enabled xstate features, the tid has exited, or PT_SETXSTATE is unsupported by the running kernel.

Common situations: Setting registers after the debuggee thread died; kernel/CPU with different XSAVE feature set than the buffer captured earlier (e.g. after exec of a new binary); running in restricted environments (jails/VMs) lacking xstate write support.

Related errors


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