mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 00:43:24 +00:00
Provide the way to override the panic handler.
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
3c857d746e
commit
131a25c15c
29
Cargo.lock
generated
29
Cargo.lock
generated
@ -282,7 +282,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -344,7 +344,7 @@ checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -514,7 +514,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -549,7 +549,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
@ -655,7 +655,7 @@ checksum = "ba330b70a5341d3bc730b8e205aaee97ddab5d9c448c4f51a7c2d924266fa8f9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -755,7 +755,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1034,7 +1034,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1088,7 +1088,6 @@ version = "0.9.3"
|
||||
dependencies = [
|
||||
"ostd",
|
||||
"owo-colors 4.0.0",
|
||||
"unwinding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1141,7 +1140,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rand",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1369,7 +1368,7 @@ checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1456,9 +1455,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.77"
|
||||
version = "2.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1507,7 +1506,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1621,7 +1620,7 @@ checksum = "c19ee3a01d435eda42cb9931269b349d28a1762f91ddf01c68d276f74b957cc3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1809,5 +1808,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
@ -6,7 +6,7 @@ extern crate #TARGET_NAME#;
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
extern "Rust" {
|
||||
pub fn __aster_panic_handler(info: &core::panic::PanicInfo) -> !;
|
||||
pub fn __ostd_panic_handler(info: &core::panic::PanicInfo) -> !;
|
||||
}
|
||||
unsafe { __aster_panic_handler(info); }
|
||||
unsafe { __ostd_panic_handler(info); }
|
||||
}
|
||||
|
@ -11,4 +11,3 @@ repository ="https://github.com/asterinas/asterinas"
|
||||
[dependencies]
|
||||
ostd = { version = "0.9.3", path = "../../ostd" }
|
||||
owo-colors = "4.0.0"
|
||||
unwinding = { version = "0.2.3", default-features = false, features = ["fde-gnu-eh-frame-hdr", "hide-trace", "panic", "personality", "unwinder"] }
|
||||
|
@ -16,7 +16,7 @@ use alloc::{boxed::Box, collections::BTreeSet, string::String, vec::Vec};
|
||||
use core::{any::Any, format_args};
|
||||
|
||||
use ostd::{
|
||||
early_print,
|
||||
early_print, early_println,
|
||||
ktest::{
|
||||
get_ktest_crate_whitelist, get_ktest_test_whitelist, KtestError, KtestItem, KtestIter,
|
||||
},
|
||||
@ -54,11 +54,32 @@ fn main() {
|
||||
unreachable!("The spawn method will NOT return in the boot context")
|
||||
}
|
||||
|
||||
#[ostd::ktest::panic_handler]
|
||||
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||
let _irq_guard = ostd::trap::disable_local();
|
||||
|
||||
use alloc::{boxed::Box, string::ToString};
|
||||
|
||||
use ostd::panic::begin_panic;
|
||||
|
||||
let throw_info = ostd::ktest::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,
|
||||
};
|
||||
|
||||
// Throw an exception and expecting it to be caught.
|
||||
begin_panic(Box::new(throw_info.clone()));
|
||||
|
||||
// If not caught, abort the kernel.
|
||||
early_println!("An uncaught panic occurred: {:#?}", throw_info);
|
||||
|
||||
ostd::prelude::abort();
|
||||
}
|
||||
|
||||
/// Run all the tests registered by `#[ktest]` in the `.ktest_array` section.
|
||||
///
|
||||
/// Need to provide a print function `print` to print the test result, and a `catch_unwind`
|
||||
/// implementation to catch the panic.
|
||||
///
|
||||
/// The `whitelist` argument is optional. If it is `None`, all tests compiled will be run.
|
||||
/// If it is `Some`, only the tests whose test path being the suffix of any paths in the whitelist
|
||||
/// will be run.
|
||||
@ -129,7 +150,7 @@ fn run_crate_ktests(crate_: &KtestCrate, whitelist: &Option<SuffixTrie>) -> Ktes
|
||||
);
|
||||
debug_assert_eq!(test.info().package, crate_name);
|
||||
match test.run(
|
||||
&(unwinding::panic::catch_unwind::<(), fn()>
|
||||
&(ostd::panic::catch_unwind::<(), fn()>
|
||||
as fn(fn()) -> Result<(), Box<(dyn Any + Send + 'static)>>),
|
||||
) {
|
||||
Ok(()) => {
|
||||
|
@ -31,8 +31,6 @@ pub fn main(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
#[no_mangle]
|
||||
#[linkage = "weak"]
|
||||
extern "Rust" fn __ostd_main() -> ! {
|
||||
// SAFETY: The function is called only once on the BSP.
|
||||
unsafe { ostd::init() };
|
||||
#main_fn_name();
|
||||
ostd::prelude::abort();
|
||||
}
|
||||
@ -58,8 +56,6 @@ pub fn test_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
quote!(
|
||||
#[no_mangle]
|
||||
extern "Rust" fn __ostd_main() -> ! {
|
||||
// SAFETY: The function is called only once on the BSP.
|
||||
unsafe { ostd::init() };
|
||||
#main_fn_name();
|
||||
ostd::prelude::abort();
|
||||
}
|
||||
@ -69,6 +65,49 @@ pub fn test_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
.into()
|
||||
}
|
||||
|
||||
/// A macro attribute for the panic handler.
|
||||
///
|
||||
/// The attributed function will be used to override OSTD's default
|
||||
/// implementation of Rust's `#[panic_handler]`. The function takes a single
|
||||
/// parameter of type `&core::panic::PanicInfo` and does not return.
|
||||
#[proc_macro_attribute]
|
||||
pub fn panic_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let handler_fn = parse_macro_input!(item as ItemFn);
|
||||
let handler_fn_name = &handler_fn.sig.ident;
|
||||
|
||||
quote!(
|
||||
#[cfg(not(ktest))]
|
||||
#[no_mangle]
|
||||
extern "Rust" fn __ostd_panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||
#handler_fn_name(info);
|
||||
}
|
||||
|
||||
#[cfg(not(ktest))]
|
||||
#handler_fn
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// A macro attribute for the panic handler.
|
||||
///
|
||||
/// This macro is used for internal OSDK implementation. Do not use it
|
||||
/// directly.
|
||||
#[proc_macro_attribute]
|
||||
pub fn test_panic_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let handler_fn = parse_macro_input!(item as ItemFn);
|
||||
let handler_fn_name = &handler_fn.sig.ident;
|
||||
|
||||
quote!(
|
||||
#[no_mangle]
|
||||
extern "Rust" fn __ostd_panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||
#handler_fn_name(info);
|
||||
}
|
||||
|
||||
#handler_fn
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// The test attribute macro to mark a test function.
|
||||
///
|
||||
/// # Example
|
||||
|
@ -75,7 +75,6 @@ pub struct PanicInfo {
|
||||
pub file: String,
|
||||
pub line: usize,
|
||||
pub col: usize,
|
||||
pub resolve_panic: fn(),
|
||||
}
|
||||
|
||||
impl core::fmt::Display for PanicInfo {
|
||||
@ -163,7 +162,6 @@ impl KtestItem {
|
||||
Ok(()) => Err(KtestError::ShouldPanicButNoPanic),
|
||||
Err(e) => match e.downcast::<PanicInfo>() {
|
||||
Ok(s) => {
|
||||
(s.resolve_panic)();
|
||||
if let Some(expected) = self.should_panic.1 {
|
||||
if s.message == expected {
|
||||
Ok(())
|
||||
|
@ -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() -> ! {
|
||||
unsafe {
|
||||
// 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 {
|
||||
__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! {
|
||||
/// The default panic handler for OSTD based kernels.
|
||||
///
|
||||
/// 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;
|
||||
}
|
||||
|
||||
/// The asterinas panic handler.
|
||||
///
|
||||
/// 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) -> ! {
|
||||
let _irq_guard = crate::trap::disable_local();
|
||||
|
||||
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