{"record":{"id":"bd245967fa6a4cf6","repo":"go-delve/delve","slug":"pctofunc-returned-nil","errorCode":null,"errorMessage":"PCToFunc returned nil","messagePattern":"PCToFunc returned nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/debugger/debugger.go","lineNumber":1513,"sourceCode":"\t\t\t\t\t}\n\t\t\t\t\t// Disassemble the instruction at the current PC to get the call destination\n\t\t\t\t\tpc := instr.Loc.PC\n\t\t\t\t\tmaxInstLen := uint64(tgt.BinInfo().Arch.MaxInstructionLength())\n\t\t\t\t\tdisasm, err := proc.Disassemble(t.Memory(), regs, t.Breakpoints(), tgt.BinInfo(), pc, pc+maxInstLen)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn false, fmt.Errorf(\"failed to disassemble instruction: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Extract address from the decoded instruction's destination location\n\t\t\t\t\tvar addr uint64\n\t\t\t\t\tif len(disasm) > 0 && disasm[0].DestLoc != nil {\n\t\t\t\t\t\taddr = disasm[0].DestLoc.PC\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn false, fmt.Errorf(\"failed to extract call destination from instruction at PC %#x\", pc)\n\t\t\t\t\t}\n\t\t\t\t\tfn := tgt.BinInfo().PCToFunc(addr)\n\t\t\t\t\tif fn == nil {\n\t\t\t\t\t\treturn false, fmt.Errorf(\"PCToFunc returned nil\")\n\t\t\t\t\t}\n\t\t\t\t\terr = createFunctionTracepoints(d, fn.Name, rootstr, followCalls)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn false, fmt.Errorf(\"error creating tracepoint in function %s\", fn.Name)\n\t\t\t\t\t}\n\t\t\t\t\tdynchildren, err := d.traverse(t, fn, sdepth+1, followCalls, rootstr)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn false, fmt.Errorf(\"error calling traverse on dynamic children\")\n\t\t\t\t\t}\n\t\t\t\t\tfor _, child := range dynchildren {\n\t\t\t\t\t\terr := createFunctionTracepoints(d, child, rootstr, followCalls)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn false, fmt.Errorf(\"error creating tracepoint in function %s\", child)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\t\t\t\tfor _, dynBrklet := range dynbp.Breaklets {","sourceCodeStart":1495,"sourceCodeEnd":1531,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/service/debugger/debugger.go#L1495-L1531","documentation":"Once the destination address is extracted from the instruction, Delve maps it back to a Go function with BinInfo.PCToFunc to name and trace it. This error is returned when PCToFunc finds no function covering that address. The call target is real code but outside any known Go function — typically runtime traps, cgo/C code, or text not covered by debug info.","triggerScenarios":"dynCallback resolved disasm[0].DestLoc.PC to an address for which tgt.BinInfo().PCToFunc(addr) returned nil while creating follow-calls tracepoints.","commonSituations":"Indirect calls into cgo/C shared libraries (no Go func entries); calls into runtime assembler stubs excluded from the function map; stripped binary or missing symbol table so PCToFunc lookups fail; PLT/thunk trampolines on some platforms.","solutions":["Check whether the target address is in C/cgo code (dlv: 'disassemble <addr>' or nm/objdump); skip such targets — eBPF uprobes on Go functions cannot trace them.","Rebuild the binary unstripped (no -s -w) so the function table is complete.","Confirm you are tracing a Go binary built with the same toolchain Delve indexed; stale binaries cause lookup misses.","Extend skip-lists (like the existing runtime.* filter) to also skip unresolved destinations instead of erroring."],"exampleFix":"// before\nfn := tgt.BinInfo().PCToFunc(addr)\nif fn == nil {\n\treturn false, fmt.Errorf(\"PCToFunc returned nil\")\n}\n// after (skip non-Go destinations such as cgo trampolines)\nfn := tgt.BinInfo().PCToFunc(addr)\nif fn == nil {\n\tlog.Debugf(\"call destination %#x is not a Go function; skipping\", addr)\n\treturn false, nil\n}","handlingStrategy":"validation","validationCode":"// before tracing, confirm the binary exposes Go symbols\nf, err := elf.Open(binPath)\nif err != nil { log.Fatal(err) }\nsyms, err := f.Symbols()\nif err != nil || len(syms) == 0 {\n\tlog.Fatal(\"no symbol table: PCToFunc will fail for call destinations\")\n}\nf.Close()","typeGuard":"func isUnresolvedDestination(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"PCToFunc returned nil\")\n}","tryCatchPattern":"if err := runTrace(); err != nil {\n\tif isUnresolvedDestination(err) {\n\t\tlog.Println(\"call target is cgo/C or runtime stub; excluding it from follow-calls\")\n\t\treturn runTrace(TraceOpts{Skip: unresolvedTargets})\n\t}\n\treturn err\n}","preventionTips":["Do not strip Go binaries that will be traced.","Expect cgo boundaries to be untraceable with eBPF follow-calls; exclude them.","Match the binary under test to the one Delve indexed (same build).","Filter runtime.* targets in your trace patterns to avoid stub destinations."],"tags":["debugger","symbols","ebpf","follow-calls"],"backgroundTag":"pc-to-func-lookup-failed","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}