go-delve/delve · error

procstat_open_sysctl failed: %v

Error message

procstat_open_sysctl failed: %v

What it means

nativeProcess.EntryPoint on FreeBSD calls libprocstat's procstat_open_sysctl() to obtain a handle on kernel process information. If that open fails, delve reports 'procstat_open_sysctl failed'. Without this handle the entry point (AT_ENTRY from the auxiliary vector) cannot be located.

Source

Thrown at pkg/proc/native/proc_freebsd.go:586

	return pickedTrapThread, nil
}

// Used by Detach
func (dbp *nativeProcess) detach(kill bool) error {
	if !kill {
		for _, th := range dbp.threads {
			ptraceResume(th.ID)
		}
	}
	return ptraceDetach(dbp.pid)
}

// EntryPoint returns the entry point address of the process.
func (dbp *nativeProcess) EntryPoint() (uint64, error) {
	ps, err := C.procstat_open_sysctl()
	if err != nil {
		return 0, fmt.Errorf("procstat_open_sysctl failed: %v", err)
	}
	defer C.procstat_close(ps)

	var count C.uint
	kipp, err := C.procstat_getprocs(ps, C.KERN_PROC_PID, C.int(dbp.pid), &count)
	if err != nil {
		return 0, fmt.Errorf("procstat_getprocs failed: %v", err)
	}
	defer C.procstat_freeprocs(ps, kipp)
	if count == 0 {
		return 0, errors.New("procstat_getprocs returned no processes")
	}

	auxv, err := C.procstat_getauxv(ps, kipp, &count)
	if err != nil {
		return 0, fmt.Errorf("procstat_getauxv failed: %v", err)
	}
	defer C.procstat_freeauxv(ps, auxv)

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Run delve as root (or the same user as the target) so kernel process metadata is readable.
  2. Verify the target pid exists: procstat -a | grep <pid>.
  3. Check you are on a FreeBSD version whose libprocstat supports procstat_getauxv (FreeBSD 12+); otherwise entry-point lookup cannot work.
  4. As a workaround, read AT_ENTRY from the binary's auxv via other means or set breakpoints at explicit addresses.

Example fix

// before
ep, err := dbp.EntryPoint() // procstat_open_sysctl failed: ...

// after
ep, err := dbp.EntryPoint()
if err != nil {
    // fall back to ELF entry if procstat is unavailable
    if f, ferr := elf.Open(exePath); ferr == nil {
        ep = f.Entry
    }
}
Defensive patterns

Strategy: fallback

Validate before calling

// FreeBSD: verify procstat availability before relying on EntryPoint
func procstatAvailable() bool {
    return exec.Command("procstat", "-a").Run() == nil
}

Try / catch

ep, err := proc.EntryPoint()
if err != nil && strings.Contains(err.Error(), "procstat_open_sysctl failed") {
    // fall back to ELF entry point
    if f, ferr := elf.Open(exePath); ferr == nil {
        ep, err = f.Entry, nil
        f.Close()
    }
}

Prevention

When it happens

Trigger: Calling EntryPoint (directly or via debugger APIs that need the entry address, e.g. setting breakpoints at process start) on FreeBSD when procstat_open_sysctl fails — typically due to kernel metadata (kvm) access restrictions.

Common situations: Running as unprivileged user with restricted access to kernel process data (security.bsd.see_other_uids, jail/ Capsicum restrictions); FreeBSD versions lacking the procstat auxv API; delve built against mismatched libprocstat headers.

Related errors


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