[Based on #2090] runtime,cl: preserve panic-site frames across defer and recover#2026
Open
cpunion wants to merge 4 commits into
Open
[Based on #2090] runtime,cl: preserve panic-site frames across defer and recover#2026cpunion wants to merge 4 commits into
cpunion wants to merge 4 commits into
Conversation
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 4, 2026 07:53
554625e to
9c33770
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 4, 2026 12:29
9c33770 to
157d48d
Compare
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
2 times, most recently
from
July 4, 2026 14:05
9a4beda to
f102328
Compare
cpunion
added a commit
to cpunion/llgo
that referenced
this pull request
Jul 4, 2026
…libunwind + FP chain) Hardware faults — SIGSEGV/SIGBUS and previously-fatal SIGFPE — now convert to ordinary recoverable Go panics, and the unrecovered traceback shows the fault-site chain: C frames down through the Go callers. - A SA_SIGINFO handler captures the interrupted context; the handler's own frame-pointer chain dead-ends at the signal trampoline, which is why the ucontext pc/fp is required. - The capture prefers a dynamically-resolved libunwind (dlopen/dlsym at install time only — no link-time -lunwind; LLGO_DYNUNWIND=0 disables): DWARF/compact-unwind stepping survives C frames compiled without frame pointers, and the nongnu flavor's unw_get_proc_name reads .symtab, naming static C symbols dladdr cannot see (they otherwise display under a neighboring Go function via nearest-below). Where unwind info runs out, the walk resumes along the FP chain from libunwind's final cursor. Flavors: darwin libSystem, linux nongnu (arch-prefixed symbols), linux LLVM (context translated). - Only man-page async-signal-safe unw_* calls run in the handler (resolution and a lazy-state warm-up happen at install). Fault-context walks probe page readability (msync) before dereferencing — an arithmetic-valid frame pointer can still point into an unmapped hole, and faulting inside the fault path would recurse; a re-entered handler restores the default disposition for one clean core. - The unrecovered dump goes through a new PanicTraceback hook (gc-style frames via the funcinfo tables; libunwind's name for dot-less C symbols); non-fault panics keep the existing clite dump. Verified: darwin/arm64 (libSystem flavor); linux/amd64 with a -fomit-frame-pointer C chain — the FP-only walk recovers 2 frames with a misattributed name, the dynamic path recovers the full chain with correct static names. Overlaps with the fault half of xgo-dev#2026 (panic-site snapshots); whichever lands second rebases to drop its duplicate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 4, 2026 16:12
f102328 to
2de72d5
Compare
This was referenced Jul 6, 2026
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 8, 2026 05:27
2de72d5 to
f9e5617
Compare
cpunion
added a commit
to cpunion/llgo
that referenced
this pull request
Jul 8, 2026
…libunwind + FP chain) Hardware faults — SIGSEGV/SIGBUS and previously-fatal SIGFPE — now convert to ordinary recoverable Go panics, and the unrecovered traceback shows the fault-site chain: C frames down through the Go callers. - A SA_SIGINFO handler captures the interrupted context; the handler's own frame-pointer chain dead-ends at the signal trampoline, which is why the ucontext pc/fp is required. - The capture prefers a dynamically-resolved libunwind (dlopen/dlsym at install time only — no link-time -lunwind; LLGO_DYNUNWIND=0 disables): DWARF/compact-unwind stepping survives C frames compiled without frame pointers, and the nongnu flavor's unw_get_proc_name reads .symtab, naming static C symbols dladdr cannot see (they otherwise display under a neighboring Go function via nearest-below). Where unwind info runs out, the walk resumes along the FP chain from libunwind's final cursor. Flavors: darwin libSystem, linux nongnu (arch-prefixed symbols), linux LLVM (context translated). - Only man-page async-signal-safe unw_* calls run in the handler (resolution and a lazy-state warm-up happen at install). Fault-context walks probe page readability (msync) before dereferencing — an arithmetic-valid frame pointer can still point into an unmapped hole, and faulting inside the fault path would recurse; a re-entered handler restores the default disposition for one clean core. - The unrecovered dump goes through a new PanicTraceback hook (gc-style frames via the funcinfo tables; libunwind's name for dot-less C symbols); non-fault panics keep the existing clite dump. Verified: darwin/arm64 (libSystem flavor); linux/amd64 with a -fomit-frame-pointer C chain — the FP-only walk recovers 2 frames with a misattributed name, the dynamic path recovers the full chain with correct static names. Overlaps with the fault half of xgo-dev#2026 (panic-site snapshots); whichever lands second rebases to drop its duplicate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 8, 2026 07:02
f9e5617 to
1c0db95
Compare
cpunion
added a commit
to cpunion/llgo
that referenced
this pull request
Jul 8, 2026
…libunwind + FP chain) Hardware faults — SIGSEGV/SIGBUS and previously-fatal SIGFPE — now convert to ordinary recoverable Go panics, and the unrecovered traceback shows the fault-site chain: C frames down through the Go callers. - A SA_SIGINFO handler captures the interrupted context; the handler's own frame-pointer chain dead-ends at the signal trampoline, which is why the ucontext pc/fp is required. - The capture prefers a dynamically-resolved libunwind (dlopen/dlsym at install time only — no link-time -lunwind; LLGO_DYNUNWIND=0 disables): DWARF/compact-unwind stepping survives C frames compiled without frame pointers, and the nongnu flavor's unw_get_proc_name reads .symtab, naming static C symbols dladdr cannot see (they otherwise display under a neighboring Go function via nearest-below). Where unwind info runs out, the walk resumes along the FP chain from libunwind's final cursor. Flavors: darwin libSystem, linux nongnu (arch-prefixed symbols), linux LLVM (context translated). - Only man-page async-signal-safe unw_* calls run in the handler (resolution and a lazy-state warm-up happen at install). Fault-context walks probe page readability (msync) before dereferencing — an arithmetic-valid frame pointer can still point into an unmapped hole, and faulting inside the fault path would recurse; a re-entered handler restores the default disposition for one clean core. - The unrecovered dump goes through a new PanicTraceback hook (gc-style frames via the funcinfo tables; libunwind's name for dot-less C symbols); non-fault panics keep the existing clite dump. Verified: darwin/arm64 (libSystem flavor); linux/amd64 with a -fomit-frame-pointer C chain — the FP-only walk recovers 2 frames with a misattributed name, the dynamic path recovers the full chain with correct static names. Overlaps with the fault half of xgo-dev#2026 (panic-site snapshots); whichever lands second rebases to drop its duplicate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 8, 2026 11:16
1c0db95 to
63bbc3d
Compare
cpunion
added a commit
to cpunion/llgo
that referenced
this pull request
Jul 8, 2026
…libunwind + FP chain) Hardware faults — SIGSEGV/SIGBUS and previously-fatal SIGFPE — now convert to ordinary recoverable Go panics, and the unrecovered traceback shows the fault-site chain: C frames down through the Go callers. - A SA_SIGINFO handler captures the interrupted context; the handler's own frame-pointer chain dead-ends at the signal trampoline, which is why the ucontext pc/fp is required. - The capture prefers a dynamically-resolved libunwind (dlopen/dlsym at install time only — no link-time -lunwind; LLGO_DYNUNWIND=0 disables): DWARF/compact-unwind stepping survives C frames compiled without frame pointers, and the nongnu flavor's unw_get_proc_name reads .symtab, naming static C symbols dladdr cannot see (they otherwise display under a neighboring Go function via nearest-below). Where unwind info runs out, the walk resumes along the FP chain from libunwind's final cursor. Flavors: darwin libSystem, linux nongnu (arch-prefixed symbols), linux LLVM (context translated). - Only man-page async-signal-safe unw_* calls run in the handler (resolution and a lazy-state warm-up happen at install). Fault-context walks probe page readability (msync) before dereferencing — an arithmetic-valid frame pointer can still point into an unmapped hole, and faulting inside the fault path would recurse; a re-entered handler restores the default disposition for one clean core. - The unrecovered dump goes through a new PanicTraceback hook (gc-style frames via the funcinfo tables; libunwind's name for dot-less C symbols); non-fault panics keep the existing clite dump. Verified: darwin/arm64 (libSystem flavor); linux/amd64 with a -fomit-frame-pointer C chain — the FP-only walk recovers 2 frames with a misattributed name, the dynamic path recovers the full chain with correct static names. Overlaps with the fault half of xgo-dev#2026 (panic-site snapshots); whichever lands second rebases to drop its duplicate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cpunion
added a commit
to cpunion/llgo
that referenced
this pull request
Jul 8, 2026
…libunwind + FP chain) Hardware faults — SIGSEGV/SIGBUS and previously-fatal SIGFPE — now convert to ordinary recoverable Go panics, and the unrecovered traceback shows the fault-site chain: C frames down through the Go callers. - A SA_SIGINFO handler captures the interrupted context; the handler's own frame-pointer chain dead-ends at the signal trampoline, which is why the ucontext pc/fp is required. - The capture prefers a dynamically-resolved libunwind (dlopen/dlsym at install time only — no link-time -lunwind; LLGO_DYNUNWIND=0 disables): DWARF/compact-unwind stepping survives C frames compiled without frame pointers, and the nongnu flavor's unw_get_proc_name reads .symtab, naming static C symbols dladdr cannot see (they otherwise display under a neighboring Go function via nearest-below). Where unwind info runs out, the walk resumes along the FP chain from libunwind's final cursor. Flavors: darwin libSystem, linux nongnu (arch-prefixed symbols), linux LLVM (context translated). - Only man-page async-signal-safe unw_* calls run in the handler (resolution and a lazy-state warm-up happen at install). Fault-context walks probe page readability (msync) before dereferencing — an arithmetic-valid frame pointer can still point into an unmapped hole, and faulting inside the fault path would recurse; a re-entered handler restores the default disposition for one clean core. - The unrecovered dump goes through a new PanicTraceback hook (gc-style frames via the funcinfo tables; libunwind's name for dot-less C symbols); non-fault panics keep the existing clite dump. Verified: darwin/arm64 (libSystem flavor); linux/amd64 with a -fomit-frame-pointer C chain — the FP-only walk recovers 2 frames with a misattributed name, the dynamic path recovers the full chain with correct static names. Overlaps with the fault half of xgo-dev#2026 (panic-site snapshots); whichever lands second rebases to drop its duplicate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
2 times, most recently
from
July 9, 2026 05:30
78cd80e to
96a7100
Compare
cpunion
added a commit
to cpunion/llgo
that referenced
this pull request
Jul 9, 2026
…libunwind + FP chain) Hardware faults — SIGSEGV/SIGBUS and previously-fatal SIGFPE — now convert to ordinary recoverable Go panics, and the unrecovered traceback shows the fault-site chain: C frames down through the Go callers. - A SA_SIGINFO handler captures the interrupted context; the handler's own frame-pointer chain dead-ends at the signal trampoline, which is why the ucontext pc/fp is required. - The capture prefers a dynamically-resolved libunwind (dlopen/dlsym at install time only — no link-time -lunwind; LLGO_DYNUNWIND=0 disables): DWARF/compact-unwind stepping survives C frames compiled without frame pointers, and the nongnu flavor's unw_get_proc_name reads .symtab, naming static C symbols dladdr cannot see (they otherwise display under a neighboring Go function via nearest-below). Where unwind info runs out, the walk resumes along the FP chain from libunwind's final cursor. Flavors: darwin libSystem, linux nongnu (arch-prefixed symbols), linux LLVM (context translated). - Only man-page async-signal-safe unw_* calls run in the handler (resolution and a lazy-state warm-up happen at install). Fault-context walks probe page readability (msync) before dereferencing — an arithmetic-valid frame pointer can still point into an unmapped hole, and faulting inside the fault path would recurse; a re-entered handler restores the default disposition for one clean core. - The unrecovered dump goes through a new PanicTraceback hook (gc-style frames via the funcinfo tables; libunwind's name for dot-less C symbols); non-fault panics keep the existing clite dump. Verified: darwin/arm64 (libSystem flavor); linux/amd64 with a -fomit-frame-pointer C chain — the FP-only walk recovers 2 frames with a misattributed name, the dynamic path recovers the full chain with correct static names. Overlaps with the fault half of xgo-dev#2026 (panic-site snapshots); whichever lands second rebases to drop its duplicate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 11, 2026 03:04
96a7100 to
05aafd4
Compare
8 tasks
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 12, 2026 12:13
05aafd4 to
4486503
Compare
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 15, 2026 06:06
65b284f to
65919ea
Compare
20 tasks
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 16, 2026 04:37
65919ea to
370694c
Compare
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
6 times, most recently
from
July 23, 2026 10:50
07a7e04 to
1d02702
Compare
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 24, 2026 03:29
1d02702 to
4e494fa
Compare
…ks see the panic frames gc runs deferred functions on top of the panicked stack; LLGo's longjmp unwinding removes those frames physically, so runtime.Caller / CallersFrames / debug.Stack from a deferred function (before or after recover) could not see the panic site. Now: - Panic() captures the physical pc chain (the existing SavePanicCallerFrames hook, empty since the shadow stack left) into a per-thread snapshot; Recover() marks the recovering frame so the snapshot stays observable exactly while that frame is live. - Caller-info walks splice the snapshot below the live deferred frames at the defer-owner junction, keeping one panic-machinery frame where gc has runtime.gopanic (fixed Caller depths count it). - Hardware faults (SIGSEGV/SIGBUS and previously-fatal SIGFPE) install a SA_SIGINFO handler that captures from the interrupted ucontext pc/fp — the handler's own chain dead-ends at the signal trampoline — so fault tracebacks start at the fault site, through C frames into the Go callers. C is compiled with -fno-omit-frame-pointer so x86-64 chains hold. - Defer execution is attributed to the function's closing brace like gc, and explicit panic statements get their own statement anchor. Signal-path robustness (the reflectmake flake, ~7% -> 0 over 300 runs): - The recover mark reads the frame-pointer chain, which after siglongjmp can reach a stale/unmapped slot; the guarded read (msync page probe) lives in the public runtime via a RecoverMark hook, and the core just calls it — an unguarded read self-faulted and corrupted the value the recover was extracting. - The fault handler does no async-signal-unsafe work: the snapshot buffer is preallocated (no bdwgc malloc in signal context) and the page size is primed at install (no sysconf). SA_NODEFER + an unblock on capture keep a savemask=0 longjmp escape from leaving the fault signal blocked, and a re-entered handler restores the default disposition for one clean core; fault-context walks probe page readability before dereferencing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove issue14646/issue5856/issue33724 xfails; the C-fault regression runs three sequential faults (a handler leaving the signal blocked after the longjmp escape cores on the second) and asserts the fault-site chain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cpunion
force-pushed
the
codex/stage5-panic-snapshot
branch
from
July 24, 2026 03:34
4e494fa to
34d6829
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Depends on #2090
Problem
LLGo implements panic/recover with longjmp. The jump removes panicking frames before deferred functions run, while gc keeps those logical frames visible to
runtime.Caller,runtime.Callers/CallersFrames, anddebug.Stack, including afterrecoveruntil the recovering defer returns.#2028 already owns recoverable hardware faults, the
SA_SIGINFOhandler, and fault-context unwinding. The missing layer is preserving ordinary panic snapshots and exposing ordinary and fault snapshots through caller APIs.Implementation
panicPCStorein runtime: store goroutine state behind pthread-key getg #2090's pthread-keyg;getgpath for ordinary panic and hardware-fault snapshots;panic;The snapshot state adds no pthread key and no second lifetime mechanism. The LLGo integration test keeps two goroutines alive concurrently and verifies that PCs, fault flags, and recover-frame marks remain isolated from each other and from main.
This PR has an independent diff of
+708/-109across 16 files.Conformance
Removed xfails for:
fixedbugs/issue14646.gofixedbugs/issue5856.gofixedbugs/issue33724.goValidation
Tests were serialized with
GOMAXPROCS=2,GOMEMLIMIT=8GiB, and-p=1.runtime/internal/runtimecompiles under the host Go toolchain.Limits