go-delve/delve · error
failed to extract call destination from instruction at PC %#
Error message
failed to extract call destination from instruction at PC %#x
What it means
After successfully disassembling the instruction at the dynamic call site, Delve expects exactly one instruction whose DestLoc carries the runtime call destination PC. This error is thrown when disasm is empty or disasm[0].DestLoc is nil, i.e. the decoded instruction did not yield a resolvable destination. It means the breakpoint PC no longer corresponds to a decodable call instruction at callback time.
Source
Thrown at service/debugger/debugger.go:1509
regs, err := th.Registers()
if err != nil {
return false, fmt.Errorf("registers inside callback returned err")
}
// Disassemble the instruction at the current PC to get the call destination
pc := instr.Loc.PC
maxInstLen := uint64(tgt.BinInfo().Arch.MaxInstructionLength())
disasm, err := proc.Disassemble(t.Memory(), regs, t.Breakpoints(), tgt.BinInfo(), pc, pc+maxInstLen)
if err != nil {
return false, fmt.Errorf("failed to disassemble instruction: %w", err)
}
// Extract address from the decoded instruction's destination location
var addr uint64
if len(disasm) > 0 && disasm[0].DestLoc != nil {
addr = disasm[0].DestLoc.PC
} else {
return false, fmt.Errorf("failed to extract call destination from instruction at PC %#x", pc)
}
fn := tgt.BinInfo().PCToFunc(addr)
if fn == nil {
return false, fmt.Errorf("PCToFunc returned nil")
}
err = createFunctionTracepoints(d, fn.Name, rootstr, followCalls)
if err != nil {
return false, fmt.Errorf("error creating tracepoint in function %s", fn.Name)
}
dynchildren, err := d.traverse(t, fn, sdepth+1, followCalls, rootstr)
if err != nil {
return false, fmt.Errorf("error calling traverse on dynamic children")
}
for _, child := range dynchildren {
err := createFunctionTracepoints(d, child, rootstr, followCalls)
if err != nil {
return false, fmt.Errorf("error creating tracepoint in function %s", child)
}View on GitHub (pinned to a23773e6c3)
Solutions
- Check that regs from th.Registers() correspond to the thread that actually hit the breakpoint (PC should equal the breakpoint PC).
- Retry the trace; transient state (e.g. breakpoint just being stepped over) can produce empty disassembly.
- Verify the binary was not rebuilt/reloaded after breakpoints were set (recompile invalidates cached instruction bytes).
- Report the exact PC and GOARCH to the Delve project if consistently reproducible.
Example fix
// before
if len(disasm) > 0 && disasm[0].DestLoc != nil {
addr = disasm[0].DestLoc.PC
} else {
return false, fmt.Errorf("failed to extract call destination from instruction at PC %#x", pc)
}
// after (treat missing destination as benign skip, not fatal, when depth budget is tight)
if len(disasm) == 0 || disasm[0].DestLoc == nil {
log.Debugf("no resolvable destination for call at %#x; skipping", pc)
return false, nil
}
addr = disasm[0].DestLoc.PC Defensive patterns
Strategy: fallback
Validate before calling
// sanity-check that indirect call sites in your hot functions are resolvable
// by disassembling the function statically before tracing:
out, err := exec.Command("go", "tool", "objdump", "-s", "myfunc", os.Args[1]).Output()
if err != nil {
log.Fatal("cannot disassemble target binary; trace will fail on indirect calls")
} Try / catch
if err := runTrace(); err != nil {
if strings.Contains(err.Error(), "failed to extract call destination") {
log.Println("indirect call could not be resolved; retrying without dynamic breakpoints")
_ = runTrace(TraceOpts{FollowCalls: 0})
return
}
return err
} Prevention
- Avoid rebuilding the binary after starting a trace session (stale instruction bytes).
- Pin trace sessions to binaries built with a supported Go toolchain.
- Report persistent unresolved-call PCs with GOARCH details upstream.
- Prefer tracing direct-call-heavy functions when using follow-calls.
When it happens
Trigger: dynCallback found len(disasm) == 0 or disasm[0].DestLoc == nil after proc.Disassemble over [pc, pc+maxInstructionLength) for an indirect call during follow-calls eBPF tracing.
Common situations: Register state stale so an indirect call through a register cannot be resolved; the instruction at pc changed (self-modifying/overwritten text); disassembler returned zero instructions for the range; address-size confusion on unusual architectures.
Related errors
- failed to disassemble instruction: %w
- ebpf composite memory: %w
- disassemble failed with error %w
- PCToFunc returned nil
- error calling traverse on dynamic children
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/542b9c4370cfabc8.
Report an issue: GitHub.