mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-30 12:53:55 +00:00
Provide the way to override the panic handler.
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
3c857d746e
commit
131a25c15c
@ -68,7 +68,7 @@ pub struct CallbackElement {
|
||||
|
||||
impl CallbackElement {
|
||||
pub fn call(&self, element: &TrapFrame) {
|
||||
self.function.call((element,));
|
||||
(self.function)(element);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,12 +118,18 @@ pub fn init() {
|
||||
///
|
||||
/// This function should be only called from the bootloader-specific module.
|
||||
pub(crate) fn call_ostd_main() -> ! {
|
||||
// The entry point of kernel code, which should be defined by the package that
|
||||
// uses OSTD.
|
||||
extern "Rust" {
|
||||
fn __ostd_main() -> !;
|
||||
}
|
||||
|
||||
// SAFETY: The function is called only once on the BSP.
|
||||
unsafe { crate::init() };
|
||||
|
||||
// SAFETY: This external function is defined by the package that uses OSTD,
|
||||
// which should be generated by the `ostd::main` macro. So it is safe.
|
||||
unsafe {
|
||||
// The entry point of kernel code, which should be defined by the package that
|
||||
// uses OSTD.
|
||||
extern "Rust" {
|
||||
fn __ostd_main() -> !;
|
||||
}
|
||||
__ostd_main();
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#![feature(generic_const_exprs)]
|
||||
#![feature(iter_from_coroutine)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(linkage)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(ptr_sub_ptr)]
|
||||
@ -36,7 +37,7 @@ mod error;
|
||||
pub mod io_mem;
|
||||
pub mod logger;
|
||||
pub mod mm;
|
||||
pub mod panicking;
|
||||
pub mod panic;
|
||||
pub mod prelude;
|
||||
pub mod smp;
|
||||
pub mod sync;
|
||||
@ -47,7 +48,7 @@ pub mod user;
|
||||
|
||||
use core::sync::atomic::AtomicBool;
|
||||
|
||||
pub use ostd_macros::main;
|
||||
pub use ostd_macros::{main, panic_handler};
|
||||
pub use ostd_pod::Pod;
|
||||
|
||||
pub use self::{error::Error, prelude::Result};
|
||||
@ -65,7 +66,7 @@ pub use self::{error::Error, prelude::Result};
|
||||
// make inter-initialization-dependencies more clear and reduce usages of
|
||||
// boot stage only global variables.
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn init() {
|
||||
unsafe fn init() {
|
||||
arch::enable_cpu_features();
|
||||
arch::serial::init();
|
||||
|
||||
@ -153,6 +154,6 @@ pub mod ktest {
|
||||
//! It is rather discouraged to use the definitions here directly. The
|
||||
//! `ktest` attribute is sufficient for all normal use cases.
|
||||
|
||||
pub use ostd_macros::test_main as main;
|
||||
pub use ostd_macros::{test_main as main, test_panic_handler as panic_handler};
|
||||
pub use ostd_test::*;
|
||||
}
|
||||
|
@ -4,60 +4,45 @@
|
||||
|
||||
use core::ffi::c_void;
|
||||
|
||||
pub use unwinding::panic::{begin_panic, catch_unwind};
|
||||
|
||||
use crate::{
|
||||
arch::qemu::{exit_qemu, QemuExitCode},
|
||||
cpu_local_cell, early_print, early_println,
|
||||
early_print, early_println,
|
||||
sync::SpinLock,
|
||||
};
|
||||
|
||||
extern crate cfg_if;
|
||||
extern crate gimli;
|
||||
|
||||
use gimli::Register;
|
||||
use unwinding::abi::{
|
||||
UnwindContext, UnwindReasonCode, _Unwind_Backtrace, _Unwind_FindEnclosingFunction,
|
||||
_Unwind_GetGR, _Unwind_GetIP,
|
||||
};
|
||||
|
||||
cpu_local_cell! {
|
||||
static IN_PANIC: bool = false;
|
||||
}
|
||||
|
||||
/// The asterinas panic handler.
|
||||
/// The default panic handler for OSTD based kernels.
|
||||
///
|
||||
/// The panic handler must be defined in the binary crate or in the crate that the binary
|
||||
/// crate explicitly declares by `extern crate`. We cannot let the base crate depend on OSTD
|
||||
/// due to prismatic dependencies. That's why we export this symbol and state the
|
||||
/// panic handler in the binary crate.
|
||||
#[export_name = "__aster_panic_handler"]
|
||||
pub fn panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||
/// The user can override it by defining their own panic handler with the macro
|
||||
/// `#[ostd::panic_handler]`.
|
||||
#[cfg(not(ktest))]
|
||||
#[no_mangle]
|
||||
pub fn __ostd_panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||
let _irq_guard = crate::trap::disable_local();
|
||||
|
||||
crate::cpu_local_cell! {
|
||||
static IN_PANIC: bool = false;
|
||||
}
|
||||
|
||||
if IN_PANIC.load() {
|
||||
early_println!("{}", info);
|
||||
early_println!("The panic handler panicked when processing the above panic. Aborting.");
|
||||
early_println!("The panic handler panicked {:#?}", info);
|
||||
abort();
|
||||
}
|
||||
|
||||
// If in ktest, we would like to catch the panics and resume the test.
|
||||
#[cfg(ktest)]
|
||||
{
|
||||
use alloc::{boxed::Box, string::ToString};
|
||||
IN_PANIC.store(true);
|
||||
|
||||
use unwinding::panic::begin_panic;
|
||||
early_println!("Non-resettable panic! {:#?}", info);
|
||||
|
||||
let throw_info = ostd_test::PanicInfo {
|
||||
message: info.message().to_string(),
|
||||
file: info.location().unwrap().file().to_string(),
|
||||
line: info.location().unwrap().line() as usize,
|
||||
col: info.location().unwrap().column() as usize,
|
||||
resolve_panic: || {
|
||||
IN_PANIC.store(false);
|
||||
},
|
||||
};
|
||||
// Throw an exception and expecting it to be caught.
|
||||
begin_panic(Box::new(throw_info.clone()));
|
||||
}
|
||||
early_println!("{}", info);
|
||||
print_stack_trace();
|
||||
abort();
|
||||
}
|
||||
@ -67,7 +52,10 @@ pub fn abort() -> ! {
|
||||
exit_qemu(QemuExitCode::Failed);
|
||||
}
|
||||
|
||||
fn print_stack_trace() {
|
||||
/// Prints the stack trace of the current thread to the console.
|
||||
///
|
||||
/// The printing procedure is protected by a spin lock to prevent interleaving.
|
||||
pub fn print_stack_trace() {
|
||||
/// We acquire a global lock to prevent the frames in the stack trace from
|
||||
/// interleaving. The spin lock is used merely for its simplicity.
|
||||
static BACKTRACE_PRINT_LOCK: SpinLock<()> = SpinLock::new(());
|
||||
@ -98,6 +86,10 @@ fn print_stack_trace() {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "x86_64")] {
|
||||
let reg_name = gimli::X86_64::register_name(Register(i)).unwrap_or("unknown");
|
||||
} else if #[cfg(target_arch = "riscv64")] {
|
||||
let reg_name = gimli::RiscV::register_name(Register(i)).unwrap_or("unknown");
|
||||
} else if #[cfg(target_arch = "aarch64")] {
|
||||
let reg_name = gimli::AArch64::register_name(Register(i)).unwrap_or("unknown");
|
||||
} else {
|
||||
let reg_name = "unknown";
|
||||
}
|
@ -15,5 +15,5 @@ pub use ostd_macros::ktest;
|
||||
pub use crate::{
|
||||
early_print as print, early_println as println,
|
||||
mm::{Paddr, Vaddr},
|
||||
panicking::abort,
|
||||
panic::abort,
|
||||
};
|
||||
|
@ -170,7 +170,7 @@ impl TaskOptions {
|
||||
extern "C" fn kernel_task_entry() {
|
||||
let current_task = current_task()
|
||||
.expect("no current task, it should have current task in kernel task entry");
|
||||
current_task.func.call(());
|
||||
(current_task.func)();
|
||||
current_task.exit();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user