111 lines
2.7 KiB
Rust

use core::{fmt, sync::atomic::AtomicUsize};
use crate::io::{
managed::{stderr, FILE},
Write,
};
struct PanicPrinter {
buffer: [u8; 1024],
pos: usize,
print: Option<&'static mut FILE>,
}
impl fmt::Write for PanicPrinter {
fn write_str(&mut self, s: &str) -> fmt::Result {
for ch in s.bytes() {
self.push(ch);
}
Ok(())
}
}
impl PanicPrinter {
pub fn new() -> Self {
let print = unsafe { stderr.as_mut() };
Self {
buffer: [0; 1024],
pos: 0,
print,
}
}
fn flush(&mut self) {
let text = &self.buffer[..self.pos];
if !text.is_empty() {
// Print to debug trace
yggdrasil_rt::debug::trace_raw(text);
// Print to stderr
if let Some(print) = self.print.as_mut() {
print.write_all(text).ok();
print.write_all(b"\n").ok();
}
}
self.pos = 0;
}
pub fn push(&mut self, ch: u8) {
if self.pos >= self.buffer.len() {
return;
}
if ch == b'\n' {
self.flush();
} else {
self.buffer[self.pos] = ch;
self.pos += 1;
}
}
}
#[thread_local]
static PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);
#[cfg(any(not(test), rust_analyzer))]
#[panic_handler]
fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
use core::{fmt::Write, sync::atomic::Ordering};
use crate::{error::EResult, process, thread::Thread};
match PANIC_COUNT.fetch_add(1, Ordering::Relaxed) {
0 => {
let mut printer = PanicPrinter::new();
writeln!(printer, "!!! ygglibc panic !!!").ok();
if let Some(location) = pi.location() {
writeln!(printer, "{}:{}:", location.file(), location.line()).ok();
}
writeln!(printer, " {}", pi.message()).ok();
let pthread_self = Thread::this();
if let EResult::Ok(this) = pthread_self {
if this == 0 {
writeln!(printer, "* Main thread panicked *").ok();
} else {
writeln!(printer, "* Thread {} panicked*", this).ok();
}
}
writeln!(printer, "Stack trace:");
crate::unwind::unwind(|frame| {
writeln!(printer, "* {:#x}", frame.pc);
true
});
printer.flush();
}
1 => {
yggdrasil_rt::debug_trace!("{pi:?}");
yggdrasil_rt::debug_trace!("!!! ygglibc panicked while panicking !!!");
}
_ => {}
}
process::abort();
}