Print backtrace when there is uncaught panic

This commit is contained in:
Zhang Junyang
2023-11-09 12:26:20 +08:00
committed by Tate, Hongliang Tian
parent ec3daca5fd
commit c776954dfc
3 changed files with 65 additions and 6 deletions

1
Cargo.lock generated
View File

@ -640,6 +640,7 @@ dependencies = [
"bitvec", "bitvec",
"buddy_system_allocator", "buddy_system_allocator",
"cfg-if", "cfg-if",
"gimli",
"inherit-methods-macro", "inherit-methods-macro",
"int-to-c-enum", "int-to-c-enum",
"intrusive-collections", "intrusive-collections",

View File

@ -12,6 +12,7 @@ bitflags = "1.3"
bitvec = { version = "1.0", default-features = false, features = ["alloc"] } bitvec = { version = "1.0", default-features = false, features = ["alloc"] }
buddy_system_allocator = "0.9.0" buddy_system_allocator = "0.9.0"
cfg-if = "1.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" } 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" } int-to-c-enum = { path = "../../services/libs/int-to-c-enum" }
intrusive-collections = "0.9.5" intrusive-collections = "0.9.5"

View File

@ -1,9 +1,27 @@
//! Panic support. //! Panic support.
use alloc::{boxed::Box, string::ToString}; use alloc::{boxed::Box, string::ToString};
use core::ffi::c_void;
use crate::arch::qemu::{exit_qemu, QemuExitCode}; 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] #[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! { 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, col: info.location().unwrap().column() as usize,
}; };
// Throw an exception and expecting it to be caught. // Throw an exception and expecting it to be caught.
unwinding::panic::begin_panic(Box::new(throw_info.clone())); begin_panic(Box::new(throw_info.clone()));
// If the exception is not caught (e.g. by ktest), then print the information // If the exception is not caught (e.g. by ktest) and resumed,
// and exit failed using the debug device. // then print the information and abort.
println!("[uncaught panic] {}", info); error!("Uncaught panic!");
exit_qemu(QemuExitCode::Failed); 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 _);
} }