{"record":{"id":"0b6899035c623575","repo":"go-delve/delve","slug":"could-not-open-elf-file-to-resolve-symbol-offset","errorCode":null,"errorMessage":"could not open elf file to resolve symbol offset: %w","messagePattern":"could not open elf file to resolve symbol offset: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/native/proc_linux.go","lineNumber":994,"sourceCode":"\t}\n\tkey := entryPC\n\terr = dbp.os.ebpf.UpdateArgMap(key, goidOffset, args, offset, false)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdebugname := dbp.bi.Images[0].Path\n\n\t// First attach a uprobe at all return addresses. We do this instead of using a uretprobe\n\t// for two reasons:\n\t// 1. uretprobes do not play well with Go\n\t// 2. uretprobes seem to not restore the function return addr on the stack when removed, destroying any\n\t//    kind of workaround we could come up with.\n\t// TODO(derekparker): this whole thing could likely be optimized a bit.\n\timg := dbp.BinInfo().PCToImage(fn.Entry)\n\tf, err := elf.Open(img.Path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not open elf file to resolve symbol offset: %w\", err)\n\t}\n\n\tvar regs proc.Registers\n\tmem := dbp.Memory()\n\tregs, _ = dbp.memthread.Registers()\n\tinstructions, err := proc.Disassemble(mem, regs, &proc.BreakpointMap{}, dbp.BinInfo(), fn.Entry, fn.End)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar addrs []uint64\n\tfor _, instruction := range instructions {\n\t\tif instruction.IsRet() {\n\t\t\taddrs = append(addrs, instruction.Loc.PC)\n\t\t}\n\t}\n\taddrs = append(addrs, proc.FindDeferReturnCalls(instructions)...)\n\tfor _, addr := range addrs {","sourceCodeStart":976,"sourceCodeEnd":1012,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/native/proc_linux.go#L976-L1012","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the file at the path in the error exists and is readable (ls -l <path> from the error's wrapped message).","Rebuild with absolute paths / don't move or delete the binary while tracing (dlv exec <absolute-path>).","If debugging inside a container, run dlv inside the same container or mount the binary at the same path it was built at.","Fall back to the non-eBPF tracing backend (dlv trace without eBPF support) if the ELF cannot be restored."],"exampleFix":"// before: binary replaced after start, stale path\nsudo dlv trace --ebpf ./myapp\n// after: keep the exact binary that was executed\nsudo cp myapp /opt/app/myapp\nsudo dlv trace --ebpf --exec /opt/app/myapp","handlingStrategy":"validation","validationCode":"// verify the ELF at the path recorded in debug info is openable before tracing\nf, err := elf.Open(binPath)\nif err != nil {\n    return fmt.Errorf(\"ELF for eBPF tracing unavailable: %w\", err)\n}\nf.Close()\n// and confirm the binary hasn't been replaced since launch\nfi1, _ := os.Stat(binPath); _ = fi1","typeGuard":null,"tryCatchPattern":"err := dlvTrace(binPath, fn)\nif err != nil && strings.Contains(err.Error(), \"could not open elf file\") {\n    // locate the real image path from build info and retry with absolute path\n    realPath, _ := filepath.Abs(binPath)\n    dlvTrace(realPath, fn)\n}","preventionTips":["Never rebuild, move, or delete the binary while an eBPF trace session runs","Always invoke dlv with an absolute path to the executable","Build with absolute source paths so DWARF records reachable file paths","When tracing inside containers, run dlv in the same mount namespace as the target"],"tags":["ebpf","elf","uprobe","linux"],"backgroundTag":"elf-file-open-failed","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}