go-delve/delve · error
no FDE for uprobe PC %#x: %w
Error message
no FDE for uprobe PC %#x: %w
What it means
Before setting an eBPF uprobe, Delve computes the CFA (canonical frame address) offset from the binary's DWARF frame table. FDEForPC returned an error, meaning no Frame Description Entry covers the uprobe PC, so the frame layout cannot be determined and the tracepoint cannot be set.
Source
Thrown at pkg/proc/breakpoints.go:706
// Finally, set the uprobe on the function.
return t.proc.SetUProbe(fn.Name, goidOffset, args)
}
// uprobeEntryPointCFA returns the uprobe PC (FirstPCAfterPrologue) and
// the CFA-from-RSP offset at that PC (i.e. the constant N in CFA = RSP + N).
// This offset is used as inputRegs.CFA when evaluating DWARF locations for
// input parameters so that DW_OP_fbreg expressions yield RSP-relative offsets
// directly — see the comment in setEBPFTracepointOnFunc for the full derivation.
func uprobeEntryPointCFA(t *Target, fn *Function) (uint64, int64, error) {
uprobePC, err := FirstPCAfterPrologue(t, fn, false)
if err != nil {
return 0, 0, err
}
bi := t.BinInfo()
fde, err := bi.frameEntries.FDEForPC(uprobePC)
if err != nil {
return 0, 0, fmt.Errorf("no FDE for uprobe PC %#x: %w", uprobePC, err)
}
framectx, err := fde.EstablishFrame(uprobePC)
if err != nil {
return 0, 0, fmt.Errorf("cannot establish frame at uprobe PC %#x: %w", uprobePC, err)
}
if framectx.CFA.Rule != frame.RuleCFA {
return 0, 0, fmt.Errorf("unexpected CFA rule %d at uprobe PC %#x", framectx.CFA.Rule, uprobePC)
}
return uprobePC, framectx.CFA.Offset, nil
}
// SetWatchpoint sets a data breakpoint at addr and stores it in the
// process wide break point table.
func (t *Target) SetWatchpoint(logicalID int, scope *EvalScope, expr string, wtype WatchType, cond ast.Expr) (*Breakpoint, error) {
if (wtype&WatchWrite == 0) && (wtype&WatchRead == 0) {
return nil, errors.New("at least one of read and write must be set for watchpoint")
}
View on GitHub (pinned to a23773e6c3)
Solutions
- Trace a normal Go function with DWARF unwind info instead of an assembly/runtime function
- Rebuild the binary keeping frame and debug info (default go build flags; avoid -ldflags '-s -w' and don't strip the binary)
- Use the non-eBPF trace backend (dlv trace without --ebpf) which does not need CFI
- Inspect the wrapped error to confirm which PC lacks an FDE and whether the binary has .debug_frame
Example fix
// before dlv trace --ebpf runtime.duffzero // after dlv trace --ebpf mypkg.MyFunc
Defensive patterns
Strategy: fallback
Validate before calling
bi := t.BinInfo()
if _, err := bi.frameEntries.FDEForPC(fn.Entry); err != nil { /* choose non-eBPF backend */ } Try / catch
pc, cfa, err := uprobeEntryPointCFA(t, uprobePC)
if err != nil && strings.Contains(err.Error(), "no FDE for uprobe PC") {
return setSoftwareTracepoint(t, fn) // fallback backend
} Prevention
- Avoid --ebpf tracing for assembly and runtime functions
- Verify the binary contains .debug_frame/.eh_frame (readelf -S) before enabling eBPF tracing
- Don't strip or -s -w the target binary
- Prefer FirstPCAfterPrologue over fn.Entry for uprobe placement
When it happens
Trigger: Calling setEBPFTracepointOnFunc (e.g. 'dlv trace' with --ebpf) on a function whose chosen uprobe PC (from FirstPCAfterPrologue or fn.Entry) falls in a code region without DWARF CFI, such as hand-written assembly, generated thunks, or code compiled without -funwind-tables.
Common situations: Tracing runtime/assembly functions (e.g. runtime.duffzero, runtime.morestack) with the eBPF backend; binaries stripped of .eh_frame/.debug_frame; cross-compiled binaries missing frame sections.
Related errors
- cannot establish frame at uprobe PC %#x: %w
- unexpected CFA rule %d at uprobe PC %#x
- ErrStackUnderflow
- ErrStackIndexOutOfBounds
- ErrMemoryReadUnavailable
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/c145b4437581fab3.
Report an issue: GitHub.