go-delve/delve · error

cannot establish frame at uprobe PC %#x: %w

Error message

cannot establish frame at uprobe PC %#x: %w

What it means

After finding the FDE for the uprobe PC, Delve calls fde.EstablishFrame to build the frame context at that exact instruction. If EstablishFrame fails (malformed or incomplete CFI program at that address), the CFA offset required for the uprobe argument layout cannot be computed, so the eBPF tracepoint setup fails.

Source

Thrown at pkg/proc/breakpoints.go:710

// 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")
	}

	n, err := parser.ParseExpr(expr)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Retry with the latest Delve version (DWARF CFI parser gains opcode support over time)
  2. Trace a different function or adjust the tracepoint to FirstPCAfterPrologue via the normal API rather than fn.Entry
  3. Recompile with a standard Go toolchain and DWARF enabled (no -w) to get well-formed frame data
  4. Fall back to the non-eBPF trace backend

Example fix

// before
dlv trace --ebpf myAsmWrapper
// after
dlv trace myAsmWrapper  // software tracepoint backend
Defensive patterns

Strategy: fallback

Validate before calling

fde, err := bi.frameEntries.FDEForPC(pc)
if err == nil {
    if _, err := fde.EstablishFrame(pc); err != nil { /* fallback to software tracepoint */ }
}

Try / catch

if err != nil && strings.Contains(err.Error(), "cannot establish frame at uprobe PC") {
    log.Printf("CFI unusable at %#x, falling back", uprobePC)
    return setSoftwareTracepoint(t, fn)
}

Prevention

When it happens

Trigger: setEBPFTracepointOnFunc on a function whose FDE exists but whose CFI program cannot be evaluated at uprobePC — corrupt/truncated .debug_frame, unsupported DWARF CFI opcodes, or a PC inside an exotic prologue region.

Common situations: Binaries produced by toolchains emitting DWARF variants Delve's frame parser doesn't fully support; uprobe placed mid-prologue where the frame description has no rule yet; mixing C/asm objects with different DWARF versions.

Related errors


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