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.
This commit is contained in:
+21
-5
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+21
-9
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user