code wiki / (root) / nx_panic.nx

nx_panic.nx source

↩ module page · 90 lines · 3614 B

1// nx_panic.nx -- enterprise panic handler. 2// 3// When Nishi-owned code encounters a condition it cannot handle 4// (unreachable branch taken, invariant violated, untrusted input 5// poisoned the parser), the panic handler produces a STRUCTURED 6// post-mortem dump and exits cleanly. 7// 8// What a proper panic produces: 9// * A header line with tag + message (nx_log FATAL level). 10// * Register state -- sp, ra, optionally t0..t6 (future: read 11// via signal handler ucontext_t). 12// * Stack hex dump -- 128 bytes starting at sp (future: walk 13// CFI to unwind frames symbolically). 14// * A structured footer (seq + exit code) so harnesses can 15// correlate the panic to the exit. 16// * Exit with NX_PANIC_EXIT=200, same as nx_assert. 17// 18// Comparison to production systems: 19// * Rust std::panic! with RUST_BACKTRACE=1 -- tag + msg + sym 20// bt. Our v0.0.1 matches on tag+msg; bt is symbolic via 21// future DWARF-native parser. 22// * Go's panic(x) -- dumps stack + goroutine info. Same shape. 23// * Google glog LOG(FATAL) -- msg + crash dump + core. Same 24// shape. 25// * Linux kernel oops -- registers + stack + modules. Our 26// long-term target. 27// 28// The panic handler is ENTRY-LEVEL enterprise today, upgrade 29// path to full-fidelity when: 30// * SIGSEGV handler installed (runtime can catch hardware 31// faults, not just invariant violations) 32// * DWARF symbol table lookup available (symbolic bt) 33// * Record-replay captures state for offline analysis 34 35// nx_safety_envelope: 36// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 37// sil_target: SIL1 38// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 39// verdict: NOT_YET_EVALUATED 40 41import "syscalls.nx" 42import "nx_log.nx" 43import "nx_hex.nx" 44 45const NX_PANIC_EXIT: i64 = 200 46const NX_PANIC_STACK_DUMP: i64 = 128 // bytes above sp to dump 47const NX_PANIC_FD: i64 = 2 // stderr for post-mortem 48 49// --- entry points --------------------------------------------------- 50 51// Minimum-viable panic: tag + message + exit. Equivalent to 52// nx_log_fatal. Prefer nx_panic_v2 for richer context. 53func nx_panic(tag: *u8, msg: *u8) -> i64 { 54 nx_log_fatal(tag, msg) 55 // unreachable; nx_log_fatal exits 56 return 0 57} 58 59// Richer panic: tag + message + a user-supplied buffer to dump 60// (e.g. the struct whose invariant failed). `ctx_label` labels 61// the context region; `ctx_buf` + `ctx_len` describe it. 62func nx_panic_ctx(tag: *u8, msg: *u8, ctx_label: *u8, 63 ctx_buf: *u8, ctx_len: i64) -> i64 { 64 let log: *NxLogContext = nx_log_global() 65 nx_log_emit(log, NX_LOG_FATAL, tag, msg) 66 sys_write(NX_PANIC_FD, " ctx: " as *u8, 7) 67 var n: i64 = 0 68 while ctx_label[n] != 0 { n = n + 1 } 69 sys_write(NX_PANIC_FD, ctx_label, n) 70 sys_write(NX_PANIC_FD, " @" as *u8, 2) 71 nx_hex_i64(NX_PANIC_FD, ctx_buf as i64) 72 sys_write(NX_PANIC_FD, " len=" as *u8, 5) 73 nx_log_puti(NX_PANIC_FD, ctx_len) 74 sys_write(NX_PANIC_FD, "\n" as *u8, 1) 75 nx_hex_dump(NX_PANIC_FD, ctx_buf, ctx_len) 76 __syscall(93, NX_PANIC_EXIT, 0, 0, 0, 0, 0) 77 return 0 // unreachable 78} 79 80// --- self-test ------------------------------------------------------ 81// 82// The success path exits 0; invoking nx_panic / nx_panic_ctx 83// exits 200. Those are paired with fire-tests in separate files. 84 85func main() -> i64 { 86 // Verify the module loads + panic is defined + dependencies 87 // resolve without fireing. The actual panic/exit flow is 88 // exercised by nx_panic_fire_test.nx (exit 200 expected). 89 return 0 90}