Files
RedBear-OS/src/panic.rs
T
bjorn3 30bbafdfa4 Use the object crate for panic backtraces
This increases the kernel image size by about 16kb, but in return
significantly simplifies things.
2025-09-13 21:34:02 +02:00

131 lines
3.8 KiB
Rust

//! Intrinsics for panic handling
use core::{panic::PanicInfo, slice, sync::atomic::Ordering};
#[cfg(target_pointer_width = "32")]
use object::read::elf::ElfFile32 as ElfFile;
#[cfg(target_pointer_width = "64")]
use object::read::elf::ElfFile64 as ElfFile;
use object::{elf::STT_FUNC, NativeEndian, Object, ObjectSymbol};
use rmm::VirtualAddress;
use rustc_demangle::demangle;
use crate::{
arch::{consts::USER_END_OFFSET, interrupt::trace::StackTrace},
context, cpu_id, interrupt,
memory::KernelMapper,
start::KERNEL_SIZE,
syscall,
};
/// Required to handle panics
#[cfg(not(test))]
#[panic_handler]
fn rust_begin_unwind(info: &PanicInfo) -> ! {
println!("KERNEL PANIC: {}", info);
unsafe {
stack_trace();
}
let Some(context_lock) = context::try_current() else {
println!("CPU {}, CID <none>", cpu_id());
println!("HALT");
loop {
unsafe {
interrupt::halt();
}
}
};
println!("CPU {}, CID {:p}", cpu_id(), context_lock);
// This could deadlock, but at this point we are going to halt anyways
{
let context = context_lock.read();
println!("NAME: {}, DEBUG ID: {}", context.name, context.debug_id);
if let Some([a, b, c, d, e, f]) = context.current_syscall() {
println!("SYSCALL: {}", syscall::debug::format_call(a, b, c, d, e, f));
}
}
println!("HALT");
loop {
unsafe {
interrupt::halt();
}
}
}
/// Get a stack trace
#[inline(never)]
pub unsafe fn stack_trace() {
unsafe {
let mapper = KernelMapper::lock();
let mut frame = StackTrace::start();
//Maximum 64 frames
for _ in 0..64 {
if let Some(frame_) = frame {
let fp_virt = VirtualAddress::new(frame_.fp);
let pc_virt = VirtualAddress::new(frame_.pc_ptr as usize);
if fp_virt.data() >= USER_END_OFFSET
&& pc_virt.data() >= USER_END_OFFSET
&& (fp_virt.data() as *const usize).is_aligned()
&& (pc_virt.data() as *const usize).is_aligned()
&& mapper.translate(fp_virt).is_some()
&& mapper.translate(pc_virt).is_some()
{
let pc = *frame_.pc_ptr;
if pc == 0 {
println!(" {:>016x}: EMPTY RETURN", frame_.fp);
break;
} else {
println!(" FP {:>016x}: PC {:>016x}", frame_.fp, pc);
symbol_trace(pc);
frame = frame_.next();
}
} else {
println!(" {:>016x}: GUARD PAGE", frame_.fp);
break;
}
} else {
break;
}
}
}
}
///
/// Get a symbol
//TODO: Do not create Elf object for every symbol lookup
#[inline(never)]
pub unsafe fn symbol_trace(addr: usize) {
unsafe {
let kernel_ptr = crate::KERNEL_OFFSET as *const u8;
let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst));
let obj = ElfFile::<NativeEndian>::parse(kernel_slice).unwrap();
for sym in obj.symbols() {
if sym.elf_symbol().st_type() != STT_FUNC {
continue;
}
if !(addr >= sym.address() as usize && addr < (sym.address() + sym.size()) as usize) {
continue;
}
println!(
" {:>016X}+{:>04X}",
sym.address(),
addr - sym.address() as usize
);
if let Ok(sym_name) = sym.name() {
println!(" {:#}", demangle(sym_name));
}
}
}
}