From 0f6fe3f7eab06e00dab8c8334fd312483ecae450 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Sat, 11 Jul 2026 03:25:23 +0300 Subject: [PATCH] bootstrap: add debug breadcrumbs and robust panic handler start() now emits single-char breadcrumbs (BS:0 through BS:5) via debug fd 1 after each major mprotect step, so serial output reveals exactly how far execution gets before any crash. The panic handler now attempts to open a fresh debug scheme handle if fd 1 write fails, ensuring panic messages are visible even when stdout was never set up successfully. --- bootstrap/src/main.rs | 26 +++++++++++++++++++++----- bootstrap/src/start.rs | 30 +++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/bootstrap/src/main.rs b/bootstrap/src/main.rs index c838313e95..ceb9a0ec32 100644 --- a/bootstrap/src/main.rs +++ b/bootstrap/src/main.rs @@ -39,17 +39,33 @@ use syscall::flag::MapFlags; fn panic_handler(info: &core::panic::PanicInfo) -> ! { use core::fmt::Write; - struct Writer; + // Try fd 1 first (opened in start()). If that fails, open a fresh debug handle. + struct Writer { + fd: usize, + } impl Write for Writer { fn write_str(&mut self, s: &str) -> core::fmt::Result { - libredox::call::write(1, s.as_bytes()) - .map_err(|_| core::fmt::Error) - .map(|_| ()) + // Try writing to our fd. If it fails and we're on fd 1, + // attempt to open a fresh debug handle. + if libredox::call::write(self.fd, s.as_bytes()).is_ok() { + return Ok(()); + } + if self.fd == 1 { + let debug_root = + syscall::UPPER_FDTBL_TAG + syscall::data::GlobalSchemes::Debug as usize; + if let Ok(new_fd) = + libredox::call::openat(debug_root, "", syscall::O_WRONLY as i32, 0) + { + self.fd = new_fd; + let _ = libredox::call::write(self.fd, s.as_bytes()); + } + } + Ok(()) // Always succeed so writeln! continues formatting } } - let _ = writeln!(&mut Writer, "{}", info); + let _ = writeln!(Writer { fd: 1 }, "{}", info); core::intrinsics::abort(); } diff --git a/bootstrap/src/start.rs b/bootstrap/src/start.rs index 722ee1df47..e551071448 100644 --- a/bootstrap/src/start.rs +++ b/bootstrap/src/start.rs @@ -2,13 +2,10 @@ use syscall::flag::MapFlags; mod offsets { unsafe extern "C" { - // text (R-X) static __text_start: u8; static __text_end: u8; - // rodata (R--) static __rodata_start: u8; static __rodata_end: u8; - // data+bss (RW-) static __data_start: u8; static __bss_end: u8; } @@ -38,42 +35,56 @@ mod offsets { } } +fn dbg(msg: &[u8]) { + let _ = libredox::call::write(1, msg); +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn start() -> ! { - // Remap self, from the previous RWX - let (text_start, text_end) = offsets::text(); let (rodata_start, rodata_end) = offsets::rodata(); let (data_start, data_end) = offsets::data_and_bss(); - // NOTE: Assuming the debug scheme root fd is always placed at this position let debug_fd = syscall::UPPER_FDTBL_TAG + syscall::data::GlobalSchemes::Debug as usize; - let _ = libredox::call::openat(debug_fd, "", syscall::O_RDONLY as i32, 0); // stdin - let _ = libredox::call::openat(debug_fd, "", syscall::O_WRONLY as i32, 0); // stdout - let _ = libredox::call::openat(debug_fd, "", syscall::O_WRONLY as i32, 0); // stderr + let _ = libredox::call::openat(debug_fd, "", syscall::O_RDONLY as i32, 0); + let _ = libredox::call::openat(debug_fd, "", syscall::O_WRONLY as i32, 0); + let _ = libredox::call::openat(debug_fd, "", syscall::O_WRONLY as i32, 0); + + dbg(b"BS:0\n"); unsafe { let _ = syscall::mprotect(4096, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE) .expect("mprotect failed for initfs header page"); + dbg(b"BS:1\n"); + let _ = syscall::mprotect( text_start, text_end - text_start, MapFlags::PROT_READ | MapFlags::PROT_EXEC | MapFlags::MAP_PRIVATE, ) .expect("mprotect failed for .text"); + + dbg(b"BS:2\n"); + let _ = syscall::mprotect( rodata_start, rodata_end - rodata_start, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE, ) .expect("mprotect failed for .rodata"); + + dbg(b"BS:3\n"); + let _ = syscall::mprotect( data_start, data_end - data_start, MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE, ) .expect("mprotect failed for .data/.bss"); + + dbg(b"BS:4\n"); + let _ = syscall::mprotect( data_end, crate::arch::STACK_START - data_end, @@ -82,5 +93,6 @@ pub unsafe extern "C" fn start() -> ! { .expect("mprotect failed for rest of memory"); } + dbg(b"BS:5\n"); crate::exec::main(); }