go-delve/delve · error

could not open elf file to resolve symbol offset: %w

Error message

could not open elf file to resolve symbol offset: %w

What it means

SetUProbe (used by the eBPF non-stop tracing backend) locates the image containing the target function via PCToImage and then opens the ELF file with elf.Open to resolve symbol offsets for the uprobe attachment. If the ELF file cannot be opened — missing file, wrong path recorded in debug info, or permission problems — this wrapped error is returned and the uprobe is not installed.

Source

Thrown at pkg/proc/native/proc_linux.go:994

	}
	key := entryPC
	err = dbp.os.ebpf.UpdateArgMap(key, goidOffset, args, offset, false)
	if err != nil {
		return err
	}

	debugname := dbp.bi.Images[0].Path

	// First attach a uprobe at all return addresses. We do this instead of using a uretprobe
	// for two reasons:
	// 1. uretprobes do not play well with Go
	// 2. uretprobes seem to not restore the function return addr on the stack when removed, destroying any
	//    kind of workaround we could come up with.
	// TODO(derekparker): this whole thing could likely be optimized a bit.
	img := dbp.BinInfo().PCToImage(fn.Entry)
	f, err := elf.Open(img.Path)
	if err != nil {
		return fmt.Errorf("could not open elf file to resolve symbol offset: %w", err)
	}

	var regs proc.Registers
	mem := dbp.Memory()
	regs, _ = dbp.memthread.Registers()
	instructions, err := proc.Disassemble(mem, regs, &proc.BreakpointMap{}, dbp.BinInfo(), fn.Entry, fn.End)
	if err != nil {
		return err
	}

	var addrs []uint64
	for _, instruction := range instructions {
		if instruction.IsRet() {
			addrs = append(addrs, instruction.Loc.PC)
		}
	}
	addrs = append(addrs, proc.FindDeferReturnCalls(instructions)...)
	for _, addr := range addrs {

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Verify the file at the path in the error exists and is readable (ls -l <path> from the error's wrapped message).
  2. Rebuild with absolute paths / don't move or delete the binary while tracing (dlv exec <absolute-path>).
  3. If debugging inside a container, run dlv inside the same container or mount the binary at the same path it was built at.
  4. Fall back to the non-eBPF tracing backend (dlv trace without eBPF support) if the ELF cannot be restored.

Example fix

// before: binary replaced after start, stale path
sudo dlv trace --ebpf ./myapp
// after: keep the exact binary that was executed
sudo cp myapp /opt/app/myapp
sudo dlv trace --ebpf --exec /opt/app/myapp
Defensive patterns

Strategy: validation

Validate before calling

// verify the ELF at the path recorded in debug info is openable before tracing
f, err := elf.Open(binPath)
if err != nil {
    return fmt.Errorf("ELF for eBPF tracing unavailable: %w", err)
}
f.Close()
// and confirm the binary hasn't been replaced since launch
fi1, _ := os.Stat(binPath); _ = fi1

Try / catch

err := dlvTrace(binPath, fn)
if err != nil && strings.Contains(err.Error(), "could not open elf file") {
    // locate the real image path from build info and retry with absolute path
    realPath, _ := filepath.Abs(binPath)
    dlvTrace(realPath, fn)
}

Prevention

When it happens

Trigger: Running `dlv trace` with the eBPF backend (SetUProbe) when the ELF file at img.Path (the path recorded in the binary's DWARF/debug info) cannot be opened: binary deleted or rebuilt after the process started, relative/incorrect build path, or read permission denied.

Common situations: Binary was rebuilt or replaced after the process was launched (stale DWARF path); debugging a binary built in a container/CI path that doesn't exist on the host; stripped or relocated binaries; cross-mounted filesystems where the original build path is unavailable.

Related errors


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