diff --git a/Cargo.lock b/Cargo.lock index 19c96e690..9ff23c888 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -640,6 +640,7 @@ dependencies = [ "bitvec", "buddy_system_allocator", "cfg-if", + "gimli", "inherit-methods-macro", "int-to-c-enum", "intrusive-collections", diff --git a/framework/jinux-frame/Cargo.toml b/framework/jinux-frame/Cargo.toml index 294237fd6..ad99cea1b 100644 --- a/framework/jinux-frame/Cargo.toml +++ b/framework/jinux-frame/Cargo.toml @@ -12,6 +12,7 @@ bitflags = "1.3" bitvec = { version = "1.0", default-features = false, features = ["alloc"] } buddy_system_allocator = "0.9.0" cfg-if = "1.0" +gimli = { version = "0.28", default-features = false, features = ["read-core"] } inherit-methods-macro = { git = "https://github.com/jinzhao-dev/inherit-methods-macro", rev = "98f7e3e" } int-to-c-enum = { path = "../../services/libs/int-to-c-enum" } intrusive-collections = "0.9.5" diff --git a/framework/jinux-frame/src/panicking.rs b/framework/jinux-frame/src/panicking.rs index ec4148278..9c005b4e1 100644 --- a/framework/jinux-frame/src/panicking.rs +++ b/framework/jinux-frame/src/panicking.rs @@ -1,9 +1,27 @@ //! Panic support. use alloc::{boxed::Box, string::ToString}; +use core::ffi::c_void; use crate::arch::qemu::{exit_qemu, QemuExitCode}; -use crate::println; +use crate::{print, println}; +use log::error; + +extern crate cfg_if; +extern crate gimli; +use gimli::Register; + +use unwinding::{ + abi::{ + UnwindContext, UnwindReasonCode, _Unwind_Backtrace, _Unwind_FindEnclosingFunction, + _Unwind_GetGR, _Unwind_GetIP, + }, + panic::begin_panic, +}; + +fn abort() -> ! { + exit_qemu(QemuExitCode::Failed); +} #[panic_handler] fn panic_handler(info: &core::panic::PanicInfo) -> ! { @@ -14,9 +32,48 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! { col: info.location().unwrap().column() as usize, }; // Throw an exception and expecting it to be caught. - unwinding::panic::begin_panic(Box::new(throw_info.clone())); - // If the exception is not caught (e.g. by ktest), then print the information - // and exit failed using the debug device. - println!("[uncaught panic] {}", info); - exit_qemu(QemuExitCode::Failed); + begin_panic(Box::new(throw_info.clone())); + // If the exception is not caught (e.g. by ktest) and resumed, + // then print the information and abort. + error!("Uncaught panic!"); + println!("{}", info); + println!("printing stack trace:"); + print_stack_trace(); + abort(); +} + +fn print_stack_trace() { + struct CallbackData { + counter: usize, + } + extern "C" fn callback(unwind_ctx: &UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode { + let data = unsafe { &mut *(arg as *mut CallbackData) }; + data.counter += 1; + let pc = _Unwind_GetIP(unwind_ctx); + let fde_initial_address = _Unwind_FindEnclosingFunction(pc as *mut c_void) as usize; + println!( + "{:4}: fn {:#18x} - pc {:#18x} / registers:", + data.counter, fde_initial_address, pc, + ); + // Print the first 8 general registers for any architecture. The register number follows + // the DWARF standard. + for i in 0..8u16 { + let reg_i = _Unwind_GetGR(unwind_ctx, i as i32); + cfg_if::cfg_if! { + if #[cfg(target_arch = "x86_64")] { + let reg_name = gimli::X86_64::register_name(Register(i)).unwrap_or("unknown"); + } else { + let reg_name = "unknown"; + } + } + if i % 4 == 0 { + print!("\n "); + } + print!(" {} {:#18x};", reg_name, reg_i); + } + print!("\n\n"); + UnwindReasonCode::NO_REASON + } + let mut data = CallbackData { counter: 0 }; + _Unwind_Backtrace(callback, &mut data as *mut _ as _); }