Browse Source

fix the panic error for riscv64 (#1123)

* fix the panic error for riscv64
linfeng 1 day ago
parent
commit
91cc4adba9

+ 2 - 1
kernel/Cargo.lock

@@ -1816,7 +1816,8 @@ dependencies = [
 [[package]]
 name = "unwinding"
 version = "0.2.3"
-source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/unwinding?rev=4eb845da62#4eb845da624f4c9899639ca116beb6d2f87e18bc"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "637d511437df708cee34bdec7ba2f1548d256b7acf3ff20e0a1c559f9bf3a987"
 dependencies = [
  "gimli 0.31.1",
 ]

+ 22 - 12
kernel/Cargo.toml

@@ -10,14 +10,11 @@ edition = "2021"
 crate-type = ["staticlib"]
 
 [workspace]
-members = [ 
-    "crates/*",
-]
+members = ["crates/*"]
 
 [features]
-default = ["backtrace", "kvm", "fatfs", "fatfs-secure", "static_keys_test"]
+default = ["fatfs", "kvm", "fatfs-secure", "static_keys_test"]
 # 内核栈回溯
-backtrace = ["dep:unwinding"]
 # kvm
 kvm = []
 
@@ -51,8 +48,19 @@ klog_types = { path = "crates/klog_types" }
 linkme = "=0.3.27"
 num = { version = "=0.4.0", default-features = false }
 num-derive = "=0.3"
-num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false }
-smoltcp = { version = "=0.11.0", default-features = false, features = ["log", "alloc",  "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
+num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev = "1597c1c", default-features = false }
+smoltcp = { version = "=0.11.0", default-features = false, features = [
+    "log",
+    "alloc",
+    "socket-raw",
+    "socket-udp",
+    "socket-tcp",
+    "socket-icmp",
+    "socket-dhcpv4",
+    "socket-dns",
+    "proto-ipv4",
+    "proto-ipv6",
+] }
 system_error = { path = "crates/system_error" }
 uefi = { version = "=0.26.0", features = ["alloc"] }
 uefi-raw = "=0.5.0"
@@ -69,12 +77,12 @@ rbpf = { path = "crates/rbpf" }
 printf-compat = { version = "0.1.1", default-features = false }
 
 static-keys = "=0.6.1"
-unwinding = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/unwinding", rev = "4eb845da62", default-features = false,  optional = true, features = [
+unwinding = { version = "=0.2.3", default-features = false, features = [
     "unwinder",
     "fde-gnu-eh-frame-hdr",
     "panic",
-    "personality"
-]}
+    "personality",
+] }
 defer = "0.2.1"
 cfg-if = { version = "1.0.0" }
 
@@ -87,7 +95,9 @@ x86_64 = "=0.14.10"
 
 # target为riscv64时,使用下面的依赖
 [target.'cfg(target_arch = "riscv64")'.dependencies]
-riscv = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/riscv.git", rev = "4241a97", features = [ "s-mode" ] }
+riscv = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/riscv.git", rev = "4241a97", features = [
+    "s-mode",
+] }
 sbi-rt = { version = "=0.0.3", features = ["legacy"] }
 
 
@@ -103,7 +113,7 @@ features = ["spin_no_std"]
 # The development profile, used for `cargo build`
 [profile.dev]
 # opt-level = 0  # Controls the --opt-level the compiler builds with
-debug = true   # Controls whether the compiler passes `-g`
+debug = true # Controls whether the compiler passes `-g`
 
 # The release profile, used for `cargo build --release`
 [profile.release]

+ 1 - 1
kernel/Makefile

@@ -26,7 +26,7 @@ clean:
 fmt:
 	RUSTFLAGS="$(RUSTFLAGS)" cargo fmt --all $(FMT_CHECK)
 ifeq ($(ARCH), x86_64)
-	RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 clippy --all-features
+	RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 clippy --all-features --target x86_64-unknown-none
 endif
 
 

+ 2 - 2
kernel/crates/intertrait/src/lib.rs

@@ -124,11 +124,11 @@ static mut CASTER_MAP: Option<HashMap<(TypeId, TypeId), BoxedCaster, BuildFastHa
 #[cfg(target_os = "none")]
 #[allow(static_mut_refs)]
 pub fn caster_map() -> &'static HashMap<(TypeId, TypeId), BoxedCaster, BuildFastHasher> {
-    return unsafe {
+    unsafe {
         CASTER_MAP.as_ref().unwrap_or_else(|| {
             panic!("intertrait_caster_map() must be called after CASTER_MAP is initialized")
         })
-    };
+    }
 }
 
 /// Initializes the global [`CASTER_MAP`] with [`CASTERS`].

+ 7 - 0
kernel/src/arch/riscv64/mod.rs

@@ -32,3 +32,10 @@ pub use self::ipc::signal::RiscV64SignalArch as CurrentSignalArch;
 pub use crate::arch::smp::RiscV64SMPArch as CurrentSMPArch;
 
 pub use crate::arch::sched::RiscV64SchedArch as CurrentSchedArch;
+
+pub fn panic_pre_work() {
+    unsafe { riscv::register::sstatus::set_fs(riscv::register::sstatus::FS::Initial) };
+}
+pub fn panic_post_work() {
+    unsafe { riscv::register::sstatus::set_fs(riscv::register::sstatus::FS::Off) };
+}

+ 2 - 10
kernel/src/arch/riscv64/syscall/mod.rs

@@ -36,16 +36,8 @@ pub(super) fn syscall_handler(syscall_num: usize, frame: &mut TrapFrame) -> () {
 
     let args = [frame.a0, frame.a1, frame.a2, frame.a3, frame.a4, frame.a5];
     let mut syscall_handle = || -> usize {
-        #[cfg(feature = "backtrace")]
-        {
-            Syscall::catch_handle(syscall_num, &args, frame)
-                .unwrap_or_else(|e| e.to_posix_errno() as usize)
-        }
-        #[cfg(not(feature = "backtrace"))]
-        {
-            Syscall::handle(syscall_num, &args, frame)
-                .unwrap_or_else(|e| e.to_posix_errno() as usize)
-        }
+        Syscall::catch_handle(syscall_num, &args, frame)
+            .unwrap_or_else(|e| e.to_posix_errno() as usize)
     };
     syscall_return!(syscall_handle(), frame, false);
 }

+ 3 - 0
kernel/src/arch/x86_64/mod.rs

@@ -48,3 +48,6 @@ pub use crate::arch::vm::x86_kvm_ops as kvm_arch_ops;
 
 pub use crate::arch::vm::kvm_host::vcpu::X86VcpuArch as VirtCpuArch;
 pub use crate::arch::vm::kvm_host::KvmVcpuStat as VirtCpuStat;
+
+pub fn panic_pre_work() {}
+pub fn panic_post_work() {}

+ 2 - 10
kernel/src/arch/x86_64/syscall/mod.rs

@@ -120,16 +120,8 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) {
         _ => {}
     }
     let mut syscall_handle = || -> u64 {
-        #[cfg(feature = "backtrace")]
-        {
-            Syscall::catch_handle(syscall_num, &args, frame)
-                .unwrap_or_else(|e| e.to_posix_errno() as usize) as u64
-        }
-        #[cfg(not(feature = "backtrace"))]
-        {
-            Syscall::handle(syscall_num, &args, frame)
-                .unwrap_or_else(|e| e.to_posix_errno() as usize) as u64
-        }
+        Syscall::catch_handle(syscall_num, &args, frame)
+            .unwrap_or_else(|e| e.to_posix_errno() as usize) as u64
     };
     syscall_return!(syscall_handle(), frame, show);
 }

+ 2 - 2
kernel/src/debug/kallsyms.c

@@ -61,7 +61,7 @@ int read_symbol(FILE *filp, struct kernel_symbol_entry_t *entry)
     int retval = sscanf(str, "%llx %c %512c", &entry->vaddr, &entry->type, symbol_name);
 
     // 如果当前行不符合要求
-    if (retval != 3)
+    if (retval != 3 || entry->type != 'T')
     {
         return -1;
     }
@@ -217,4 +217,4 @@ int main(int argc, char **argv)
     read_map(stdin);
 
     generate_result();
-}
+}

+ 27 - 17
kernel/src/debug/panic/hook.rs

@@ -1,24 +1,34 @@
 use crate::debug::traceback::lookup_kallsyms;
-use unwinding::abi::{UnwindContext, UnwindReasonCode, _Unwind_GetIP};
-use unwinding::panic::UserUnwindTrace;
+use crate::libs::spinlock::SpinLock;
+use core::ffi::c_void;
+use unwinding::abi::{UnwindContext, UnwindReasonCode, _Unwind_Backtrace, _Unwind_GetIP};
 
-/// User hook for unwinding
-///
-/// During stack backtrace, the user can print the function location of the current stack frame.
-pub struct Tracer;
-pub struct CallbackData {
-    pub counter: usize,
-}
-impl UserUnwindTrace for Tracer {
-    type Arg = CallbackData;
-
-    fn trace(ctx: &UnwindContext<'_>, arg: *mut Self::Arg) -> UnwindReasonCode {
-        let data = unsafe { &mut *(arg) };
+pub fn print_stack_trace() {
+    static GLOBAL_LOCK: SpinLock<()> = SpinLock::new(());
+    let _lock = GLOBAL_LOCK.lock();
+    println!("Rust Panic Backtrace:");
+    struct CallbackData {
+        counter: usize,
+        kernel_main: bool,
+    }
+    extern "C" fn callback(unwind_ctx: &UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode {
+        let data = unsafe { &mut *(arg as *mut CallbackData) };
+        if data.kernel_main {
+            // If we are in kernel_main, we don't need to print the backtrace.
+            return UnwindReasonCode::NORMAL_STOP;
+        }
         data.counter += 1;
-        let pc = _Unwind_GetIP(ctx);
-        unsafe {
-            lookup_kallsyms(pc as u64, data.counter as i32);
+        let pc = _Unwind_GetIP(unwind_ctx);
+        if pc > 0 {
+            let is_kernel_main = unsafe { lookup_kallsyms(pc as u64, data.counter as i32) };
+            data.kernel_main = is_kernel_main;
         }
         UnwindReasonCode::NO_REASON
     }
+
+    let mut data = CallbackData {
+        counter: 0,
+        kernel_main: false,
+    };
+    _Unwind_Backtrace(callback, &mut data as *mut _ as _);
 }

+ 66 - 13
kernel/src/debug/panic/mod.rs

@@ -1,7 +1,12 @@
-#[cfg(feature = "backtrace")]
 mod hook;
+use alloc::boxed::Box;
 use cfg_if::cfg_if;
 
+use log::error;
+
+use crate::process;
+use system_error::SystemError;
+
 cfg_if! {
     if #[cfg(target_os = "none")] {
         use core::panic::PanicInfo;
@@ -10,15 +15,29 @@ cfg_if! {
         static PANIC_COUNTER: AtomicU8 = AtomicU8::new(0);
     }
 }
+
+#[derive(Debug)]
+struct PanicGuard;
+
+impl PanicGuard {
+    pub fn new() -> Self {
+        crate::arch::panic_pre_work();
+        Self
+    }
+}
+
+impl Drop for PanicGuard {
+    fn drop(&mut self) {
+        crate::arch::panic_post_work();
+    }
+}
+
 /// 全局的panic处理函数
 ///
 #[cfg(target_os = "none")]
 #[panic_handler]
 #[no_mangle]
 pub fn panic(info: &PanicInfo) -> ! {
-    use log::error;
-
-    use crate::process;
     PANIC_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
     error!("Kernel Panic Occurred.");
 
@@ -43,15 +62,12 @@ pub fn panic(info: &PanicInfo) -> ! {
         );
         loop {}
     }
-    #[cfg(feature = "backtrace")]
-    {
-        let mut data = hook::CallbackData { counter: 0 };
-        println!("Rust Panic Backtrace:");
-        let _res = unwinding::panic::begin_panic_with_hook::<hook::Tracer>(
-            alloc::boxed::Box::new(()),
-            &mut data,
-        );
-        // log::error!("panic unreachable: {:?}", res.0);
+
+    if info.can_unwind() {
+        let guard = Box::new(PanicGuard::new());
+        hook::print_stack_trace();
+        let _res = unwinding::panic::begin_panic(guard);
+        // log::error!("panic unreachable: {:?}", _res.0);
     }
     println!(
         "Current PCB:\n\t{:?}",
@@ -59,3 +75,40 @@ pub fn panic(info: &PanicInfo) -> ! {
     );
     process::ProcessManager::exit(usize::MAX);
 }
+
+/// The wrapper of `unwinding::panic::begin_panic`. If the panic is
+/// caught, it will return the result of the function.
+/// If the panic is not caught, it will return an error.
+pub fn kernel_catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, SystemError> {
+    let res = unwinding::panic::catch_unwind(f);
+    match res {
+        Ok(r) => Ok(r),
+        Err(e) => {
+            log::error!("Catch Unwind Error: {:?}", e);
+            Err(SystemError::MAXERRNO)
+        }
+    }
+}
+
+#[allow(unused)]
+pub fn test_unwind() {
+    struct UnwindTest;
+    impl Drop for UnwindTest {
+        fn drop(&mut self) {
+            log::info!("Drop UnwindTest");
+        }
+    }
+    log::error!("Test unwind");
+    let res1 = unwinding::panic::catch_unwind(|| {
+        let _unwind_test = UnwindTest;
+        log::error!("Test panic...");
+        panic!("Test panic");
+    });
+    assert!(res1.is_err());
+    let res2 = unwinding::panic::catch_unwind(|| {
+        let _unwind_test = UnwindTest;
+        log::error!("Test no panic...");
+        0
+    });
+    assert!(res2.is_ok());
+}

+ 17 - 4
kernel/src/debug/traceback/mod.rs

@@ -13,7 +13,9 @@ fn kallsyms_names_index() {}
 #[no_mangle]
 fn kallsyms_names() {}
 
-pub unsafe fn lookup_kallsyms(addr: u64, level: i32) -> Option<()> {
+/// print the func name according to the pc address and
+/// return true if the func is kernel_main
+pub unsafe fn lookup_kallsyms(addr: u64, level: i32) -> bool {
     let sym_names = kallsyms_names as *const u8;
     // 由于符号表使用nm -n生成,因此是按照地址升序排列的,因此可以二分
     let sym_num = kallsyms_num as usize;
@@ -28,10 +30,14 @@ pub unsafe fn lookup_kallsyms(addr: u64, level: i32) -> Option<()> {
             break;
         }
     }
-    return if index < sym_num {
+    let mut is_kernel_main = false;
+    if index < sym_num {
         let sym_name = CStr::from_ptr(sym_names.add(sym_names_index[index] as usize) as _)
             .to_str()
             .unwrap();
+        if sym_name.starts_with("kernel_main") {
+            is_kernel_main = true;
+        }
         println!(
             "[{}] function:{}() \t(+) {:04} address:{:#018x}",
             level,
@@ -39,11 +45,18 @@ pub unsafe fn lookup_kallsyms(addr: u64, level: i32) -> Option<()> {
             addr - kallsyms_address_list[index],
             addr
         );
-        Some(())
     } else {
-        None
+        println!(
+            "[{}] function:unknown \t(+) {:04} address:{:#018x}",
+            level,
+            addr - kallsyms_address_list[sym_num - 1],
+            addr
+        );
     };
+    return is_kernel_main;
 }
+
+/// Get the address of the symbol
 pub unsafe fn addr_from_symbol(symbol: &str) -> Option<u64> {
     let sym_num = kallsyms_num as usize;
     let sym_names = kallsyms_names as *const u8;

+ 2 - 1
kernel/src/lib.rs

@@ -1,4 +1,5 @@
 #![no_main] // <1>
+#![no_std]
 #![feature(alloc_error_handler)]
 #![feature(new_zeroed_alloc)]
 #![feature(allocator_api)]
@@ -20,7 +21,7 @@
 #![feature(c_variadic)]
 #![feature(asm_goto)]
 #![feature(linkage)]
-#![cfg_attr(target_os = "none", no_std)]
+#![feature(panic_can_unwind)]
 #![allow(static_mut_refs, non_local_definitions, internal_features)]
 // clippy的配置
 #![deny(clippy::all)]

+ 1 - 1
kernel/src/mm/allocator/kernel_allocator.rs

@@ -154,7 +154,7 @@ fn dealloc_debug_log(source: LogSource, layout: Layout, ptr: *mut u8) {
     )
 }
 
-/// 为内核slab分配器实现Allocator特性
+// 为内核slab分配器实现Allocator特性
 // unsafe impl Allocator for KernelAllocator {
 //     fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
 //         let memory = unsafe {self.local_alloc(layout)};

+ 3 - 5
kernel/src/syscall/mod.rs

@@ -5,6 +5,7 @@ use core::{
 
 use crate::{
     arch::{ipc::signal::SigSet, syscall::nr::*},
+    debug::panic::kernel_catch_unwind,
     filesystem::vfs::syscall::{PosixStatfs, PosixStatx},
     ipc::shm::{ShmCtlCmd, ShmFlags, ShmId, ShmKey},
     libs::{futex::constant::FutexFlag, rand::GRandFlags},
@@ -77,16 +78,13 @@ impl Syscall {
     /// 系统调用分发器,用于分发系统调用。
     ///
     /// 与[handle]不同,这个函数会捕获系统调用处理函数的panic,返回错误码。
-    #[cfg(feature = "backtrace")]
     pub fn catch_handle(
         syscall_num: usize,
         args: &[usize],
         frame: &mut TrapFrame,
     ) -> Result<usize, SystemError> {
-        let res = unwinding::panic::catch_unwind(|| Self::handle(syscall_num, args, frame));
-        res.unwrap_or_else(|_| loop {
-            core::hint::spin_loop();
-        })
+        let res = kernel_catch_unwind(|| Self::handle(syscall_num, args, frame))?;
+        res
     }
     /// @brief 系统调用分发器,用于分发系统调用。
     ///