diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 9af8c25..b5e5f2d 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -36,6 +36,7 @@ use crate::{ use arch::x86_64::memory::mapping; use core::arch::asm; use limine::BaseRevision; +use std::unwind::UNWINDER; use x86_64::VirtAddr; pub mod arch; @@ -144,5 +145,7 @@ pub fn boot() -> Result<(), &'static str> { x86_64::instructions::interrupts::enable(); debugln!("[Success]"); + UNWINDER.lock(); // Initialises the Unwinder once and only once :fingers_crossed:. + Ok(()) } diff --git a/kernel/src/std/unwind/mod.rs b/kernel/src/std/unwind/mod.rs index cb3bc81..dc512dd 100644 --- a/kernel/src/std/unwind/mod.rs +++ b/kernel/src/std/unwind/mod.rs @@ -1,3 +1,23 @@ +use core::arch::asm; + +use eh_info::ELF; +use spin::{Lazy, Mutex}; +use unwinder::{RegisterSet, Unwinder}; + pub mod eh_info; pub mod panic; pub mod unwinder; + +/// We should initialise on program start. +pub static UNWINDER: Lazy> = Lazy::new(|| { + // Setup stack traces and proper panic handler. TODO: Handle panics + // differently if not initialised. + let eh_frame_ptr = ELF + .get_section_addr(".eh_frame_hdr") + .expect("Could not get `.eh_frame_hdr` address."); + + let eh_info = unsafe { eh_info::EhInfo::from_hdr_ptr(eh_frame_ptr) }; + let mut registers = RegisterSet::default(); + + Mutex::new(Unwinder::new(eh_info, registers)) +}); diff --git a/kernel/src/std/unwind/panic.rs b/kernel/src/std/unwind/panic.rs index 203c41a..a24863c 100644 --- a/kernel/src/std/unwind/panic.rs +++ b/kernel/src/std/unwind/panic.rs @@ -10,7 +10,7 @@ use super::unwinder::Unwinder; use crate::{ hcf, prelude::*, - std::unwind::{eh_info::ELF, unwinder::RegisterSet}, + std::unwind::{UNWINDER, eh_info::ELF, unwinder::RegisterSet}, }; #[panic_handler] @@ -19,27 +19,18 @@ pub fn panic_handler(info: &PanicInfo<'_>) -> ! { println!("Kernel panic: {}", info); serial_println!("Kernel panic: {}", info); - // Setup stack traces and proper panic handler. TODO: Handle panics - // differently if not initialised. - let eh_frame_ptr = ELF - .get_section_addr(".eh_frame_hdr") - .expect("Could not get `.eh_frame_hdr` address."); - - let eh_info = unsafe { super::eh_info::EhInfo::from_hdr_ptr(eh_frame_ptr) }; - let mut registers = RegisterSet::default(); - let mut rip: u64; let mut rsp: u64; - unsafe { asm!("lea {0}, [rip]", "mov {1}, rsp", out(reg) rip, out(reg) rsp); } - registers.set_pc(rip); - registers.set_stack_ptr(rsp); - let mut unwinder = Unwinder::new(eh_info, registers); + let mut unwinder = UNWINDER.lock(); + unwinder.regs.set_pc(rip); + unwinder.regs.set_stack_ptr(rsp); + while let Some(call_frame) = unwinder.next().unwrap_or_else(|err| { // If an unwind error occurred. eprintln!("{:?}", err); diff --git a/kernel/src/std/unwind/unwinder.rs b/kernel/src/std/unwind/unwinder.rs index 4811b1f..f64ef57 100644 --- a/kernel/src/std/unwind/unwinder.rs +++ b/kernel/src/std/unwind/unwinder.rs @@ -27,7 +27,7 @@ pub struct Unwinder { unwind_ctx: UnwindContext, /// The current values of ABI/architecture independent registers. There are /// used by DWARF. - regs: RegisterSet, + pub regs: RegisterSet, /// The current CFA address. cfa: u64, /// Is this the first iteration? @@ -112,7 +112,10 @@ impl FallibleIterator for Unwinder { }; // REVIEWME: Must be a nicer way of doing this. - let pc = pc - 1; + let Some(pc) = pc.checked_sub(1) else { + // REVIEWME: This should handle underflow now. + return Ok(None); + }; self.regs.set_pc(pc);