Skip to content

[SBPF] Recover interpreter backtraces in LLDB - #221

Draft
djolertrk wants to merge 2 commits into
anza-xyz:solana-rustc/22.1-2026-01-27from
djolertrk:feat/improve-bt
Draft

djolertrk wants to merge 2 commits into
anza-xyz:solana-rustc/22.1-2026-01-27from
djolertrk:feat/improve-bt

Conversation

@djolertrk

Copy link
Copy Markdown

Recover SBPF interpreter caller frames through the qSBPFCallStack remote protocol extension, following the WebAssembly approach. Preserve distinct recursive frames and support stepping out.
Also, enable the Rust Dexter caller test.

Note: It requires the coordinated SBPF (anza-xyz/sbpf#239) and gdbstub changes.

Use a dedicated qSBPFCallStack remote packet to recover return PCs and
frame pointers held in the interpreter host-side call-frame array.

Represent recovered frames with stable CFAs that account for SBPF's
upward-growing stack, and expose historical PC and FP values through a
read-only register context. Fall back to normal unwinding when the
runtime does not implement the packet.

Run Dexter against the coordinated Walnut SBPF and gdbstub branches,
and make recovered Rust callers an expected pass.

Document and test the binary protocol.
Use depth from the oldest physical frame to identify and order SBPF
frames independently of guest stack direction or changes to r10. Keep
native address-based identity and inline scope comparisons intact.

Report CFA as unavailable instead of exposing an inverted frame pointer
to DWARF expressions and the public API. Continue exposing the actual
r10 through the register context without changing the remote packet.

Cover dynamic and recursive stacks, CFA reporting, and stepping out in
unit and API tests. Add a Rust recursion case and update the stepping
expectation for distinct columns on the same source line. Run the new
checks and SBPF runtime tests in the coordinated Dexter CI job.
@djolertrk

Copy link
Copy Markdown
Author

@djolertrk

Copy link
Copy Markdown
Author

cc @LucasSte @nagisa

@nagisa

nagisa commented Oct 6, 2026 •

Copy link
Copy Markdown

Hm, I'm not sure this is the right design if it needs sBPF specific changes to LLDB to make this work. We can merge this in, of course, but I am suspicious that upstream1 will not want to take anything sBPF specific if there is a possibility of this being generally applicable to plain eBPF.

Footnotes

  1. this is relevant for when we tune down the fork effort. ↩

@djolertrk

Copy link
Copy Markdown
Author

Hm, I'm not sure this is the right design if it needs sBPF specific changes to LLDB to make this work. We can merge this in, of course, but I am suspicious that upstream1 will not want to take anything sBPF specific if there is a possibility of this being generally applicable to plain eBPF.

That’s a fair concern, I am also in favour of finding a more general solution. I’ll investigate an alternative using DWARF CFI (the .debug_frame section) and LLDB’s generic unwinder. The runtime would expose its saved call-frame state through standard remote register and memory reads, with CFI describing how to recover callers.
This approach should apply to both SBPF and eBPF, keeping runtime-specific details in the debug ABI and allowing any necessary LLDB fixes to be proposed upstream as general improvements. I’ll follow up with the results and remaining tradeoffs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants