Kaynağa Gözat

feat: update to new backtrace lib (#1049)

* feat: update to new backtrace lib

* feat: enable unwind for riscv64

---------

Co-authored-by: longjin <[email protected]>
linfeng 3 ay önce
ebeveyn
işleme
081428c0d8

+ 8 - 2
kernel/Cargo.toml

@@ -17,7 +17,7 @@ members = [
 [features]
 default = ["backtrace", "kvm", "fatfs", "fatfs-secure", "static_keys_test"]
 # 内核栈回溯
-backtrace = []
+backtrace = ["dep:unwinding"]
 # kvm
 kvm = []
 
@@ -68,11 +68,17 @@ lru = "0.12.3"
 
 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 = [
+    "unwinder",
+    "fde-gnu-eh-frame-hdr",
+    "panic",
+    "personality"
+]}
 
 # target为x86_64时,使用下面的依赖
 [target.'cfg(target_arch = "x86_64")'.dependencies]
-mini-backtrace = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/mini-backtrace.git", rev = "e0b1d90940" }
 multiboot2 = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/multiboot2", rev = "05739aab40" }
 raw-cpuid = "11.0.1"
 x86 = "=0.52.0"

+ 3 - 3
kernel/Makefile

@@ -6,7 +6,7 @@ include ./env.mk
 ifeq ($(ARCH), x86_64)
 	export TARGET_JSON=arch/x86_64/x86_64-unknown-none.json
 else ifeq ($(ARCH), riscv64)
-	export TARGET_JSON=riscv64gc-unknown-none-elf
+	export TARGET_JSON=arch/riscv64/riscv64gc-unknown-none-elf.json
 endif
 
 export CARGO_ZBUILD=-Z build-std=core,alloc,compiler_builtins -Z build-std-features=compiler-builtins-mem
@@ -27,7 +27,7 @@ clean:
 fmt:
 	RUSTFLAGS="$(RUSTFLAGS)" cargo fmt --all $(FMT_CHECK)
 ifeq ($(ARCH), x86_64)
-	RUSTFLAGS="$(RUSTFLAGS)" cargo clippy --all-features
+	RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 clippy --all-features
 endif
 
 
@@ -38,7 +38,7 @@ check: ECHO
 ifeq ($(ARCH), x86_64)
 	RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 check --workspace $(CARGO_ZBUILD) --message-format=json --target ./src/$(TARGET_JSON)
 else ifeq ($(ARCH), riscv64)
-	RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 check --workspace $(CARGO_ZBUILD) --message-format=json --target $(TARGET_JSON)
+	RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 check --workspace $(CARGO_ZBUILD) --message-format=json --target ./src/$(TARGET_JSON)
 endif
 
 test:

+ 22 - 6
kernel/src/Makefile

@@ -14,11 +14,9 @@ CFLAGS_UNWIND =
 LDFLAGS_UNWIND =
 RUSTFLAGS_UNWIND =
 ifeq ($(UNWIND_ENABLE), yes)
-    CFLAGS_UNWIND = -funwind-tables
-ifeq ($(ARCH), x86_64)
-    LDFLAGS_UNWIND = --eh-frame-hdr
-    RUSTFLAGS_UNWIND = -Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld
-endif
+	CFLAGS_UNWIND = -funwind-tables
+	LDFLAGS_UNWIND = --eh-frame-hdr
+	RUSTFLAGS_UNWIND = -Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld
 endif
 
 RUSTFLAGS += $(RUSTFLAGS_UNWIND)
@@ -58,7 +56,6 @@ ECHO:
 	@echo "$@"
 
 $(kernel_subdirs): ECHO
-
 	$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)"  kernel_root_path="$(shell pwd)"
 
 kernel: $(kernel_subdirs) kernel_rust
@@ -66,7 +63,26 @@ kernel: $(kernel_subdirs) kernel_rust
 __link_riscv64_kernel:
 	@echo "Linking kernel..."
 	$(LD) -b elf64-littleriscv -z muldefs $(LDFLAGS_UNWIND) -o kernel $(shell find . -name "*.o") ../target/riscv64gc-unknown-none-elf/release/libdragonos_kernel.a -T arch/riscv64/link.ld --no-relax
+	# 生成kallsyms
+	current_dir=$(pwd)
+
+	@dbg='debug';for x in $$dbg; do \
+		cd $$x;\
+		$(MAKE) generate_kallsyms kernel_root_path="$(shell pwd)"||exit 1;\
+		cd ..;\
+	done
+
+# 重新链接
+	@echo "Re-Linking kernel..."
+	@echo $(shell find . -name "*.o")
+	$(LD) -b elf64-littleriscv -z muldefs $(LDFLAGS_UNWIND) -o kernel $(shell find . -name "*.o") ../target/riscv64gc-unknown-none-elf/release/libdragonos_kernel.a ./debug/kallsyms.o  -T arch/riscv64/link.ld --no-relax
+	@echo "Generating kernel ELF file..."
+
+ifeq ($(UNWIND_ENABLE), yes)
+	$(OBJCOPY) -I elf64-littleriscv -O elf64-littleriscv kernel ../../bin/kernel/kernel.elf
+else
 	$(OBJCOPY) -I elf64-littleriscv -O elf64-littleriscv -R ".eh_frame" kernel ../../bin/kernel/kernel.elf
+endif
 	@rm kernel
 	$(MAKE) __dragon_stub PAYLOAD_ELF="$(shell pwd)/../../bin/kernel/kernel.elf"
 

+ 2 - 0
kernel/src/arch/riscv64/link.ld

@@ -28,6 +28,7 @@ SECTIONS
 
 	. = ALIGN(4096);
 	text_start_pa = .;
+	__executable_start = .;
 	.text (text_start_pa): AT(text_start_pa - KERNEL_VMA)
 	{
 		_text = .;
@@ -39,6 +40,7 @@ SECTIONS
 		*(.text.*)
 
 		_etext = .;
+		__etext = .;
 	}
 	. = ALIGN(32768);
 	data_start_pa = .;

+ 28 - 0
kernel/src/arch/riscv64/riscv64gc-unknown-none-elf.json

@@ -0,0 +1,28 @@
+{
+  "arch": "riscv64",
+  "code-model": "medium",
+  "cpu": "generic-rv64",
+  "crt-objects-fallback": "false",
+  "data-layout": "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
+  "eh-frame-header": false,
+  "emit-debug-gdb-scripts": false,
+  "features": "+m,+a,+f,+d,+c",
+  "linker": "rust-lld",
+  "linker-flavor": "gnu-lld",
+  "llvm-abiname": "lp64d",
+  "llvm-target": "riscv64",
+  "max-atomic-width": 64,
+  "metadata": {
+    "description": "Bare RISC-V (RV64IMAFDC ISA)",
+    "host_tools": false,
+    "std": false,
+    "tier": 2
+  },
+  "panic-strategy": "unwind",
+  "relocation-model": "static",
+  "supported-sanitizers": [
+    "shadow-call-stack",
+    "kernel-address"
+  ],
+  "target-pointer-width": "64"
+}

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

@@ -36,7 +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];
     syscall_return!(
-        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),
         frame,
         false
     );

+ 2 - 0
kernel/src/arch/x86_64/link.lds

@@ -26,6 +26,7 @@ SECTIONS
 	. = ALIGN(32768);
 	. += KERNEL_VMA;
 	text_start_pa = .;
+	__executable_start = .;
 	.text (text_start_pa): AT(text_start_pa - KERNEL_VMA)
 	{
 		_text = .;
@@ -37,6 +38,7 @@ SECTIONS
 		*(.text.*)
 
 		_etext = .;
+		__etext = .;
 	}
 	. = ALIGN(32768);
 	data_start_pa = .;

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

@@ -118,8 +118,8 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) {
         _ => {}
     }
     syscall_return!(
-        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,
         frame,
         show
     );

+ 1 - 1
kernel/src/arch/x86_64/x86_64-unknown-none.json

@@ -11,5 +11,5 @@
   "executables": true,
   "features": "-mmx,-sse,+soft-float",
   "disable-redzone": true,
-  "panic-strategy": "abort"
+  "panic-strategy": "unwind"
 }

+ 64 - 16
kernel/src/lib.rs

@@ -94,8 +94,11 @@ extern crate wait_queue_macros;
 
 use crate::mm::allocator::kernel_allocator::KernelAllocator;
 
-#[cfg(all(feature = "backtrace", target_arch = "x86_64"))]
-extern crate mini_backtrace;
+#[cfg(feature = "backtrace")]
+use unwinding::{
+    abi::{UnwindContext, UnwindReasonCode, _Unwind_GetIP},
+    panic::UserUnwindTrace,
+};
 
 extern "C" {
     fn lookup_kallsyms(addr: u64, level: i32) -> i32;
@@ -106,12 +109,37 @@ extern "C" {
 pub static KERNEL_ALLOCATOR: KernelAllocator = KernelAllocator;
 
 /// 全局的panic处理函数
+///
+/// How to use unwinding lib:
+///
+/// ```
+/// pub fn test_unwind() {
+///    struct UnwindTest;
+///    impl Drop for UnwindTest {
+///        fn drop(&mut self) {
+///            println!("Drop UnwindTest");
+///        }
+///    }
+///    let res1 = unwinding::panic::catch_unwind(|| {
+///        let _unwind_test = UnwindTest;
+///        println!("Test panic...");
+///        panic!("Test panic");
+///    });
+///    assert_eq!(res1.is_err(), true);
+///    let res2 = unwinding::panic::catch_unwind(|| {
+///        let _unwind_test = UnwindTest;
+///        println!("Test no panic...");
+///        0
+///    });
+///    assert_eq!(res2.is_ok(), true);
+/// }
+/// ```
+///
 #[cfg(target_os = "none")]
 #[panic_handler]
 #[no_mangle]
 pub fn panic(info: &PanicInfo) -> ! {
     use log::error;
-    use process::ProcessManager;
 
     error!("Kernel Panic Occurred.");
 
@@ -129,21 +157,41 @@ pub fn panic(info: &PanicInfo) -> ! {
         }
     }
     println!("Message:\n\t{}", info.message());
-
-    #[cfg(all(feature = "backtrace", target_arch = "x86_64"))]
+    #[cfg(feature = "backtrace")]
     {
-        unsafe {
-            let bt = mini_backtrace::Backtrace::<16>::capture();
-            println!("Rust Panic Backtrace:");
-            let mut level = 0;
-            for frame in bt.frames {
-                lookup_kallsyms(frame as u64, level);
-                level += 1;
-            }
-        };
+        let mut data = CallbackData { counter: 0 };
+        println!("Rust Panic Backtrace:");
+        let res = unwinding::panic::begin_panic_with_hook::<Tracer>(
+            alloc::boxed::Box::new(()),
+            &mut data,
+        );
+        log::error!("panic unreachable: {:?}", res.0);
     }
+    println!(
+        "Current PCB:\n\t{:?}",
+        process::ProcessManager::current_pcb()
+    );
+    process::ProcessManager::exit(usize::MAX);
+    loop {}
+}
 
-    println!("Current PCB:\n\t{:?}", (ProcessManager::current_pcb()));
+/// User hook for unwinding
+///
+/// During stack backtrace, the user can print the function location of the current stack frame.
+struct Tracer;
+struct CallbackData {
+    counter: usize,
+}
+impl UserUnwindTrace for Tracer {
+    type Arg = CallbackData;
 
-    ProcessManager::exit(usize::MAX);
+    fn trace(ctx: &UnwindContext<'_>, arg: *mut Self::Arg) -> UnwindReasonCode {
+        let data = unsafe { &mut *(arg) };
+        data.counter += 1;
+        let pc = _Unwind_GetIP(ctx);
+        unsafe {
+            lookup_kallsyms(pc as u64, data.counter as i32);
+        }
+        UnwindReasonCode::NO_REASON
+    }
 }

+ 15 - 0
kernel/src/syscall/mod.rs

@@ -1,5 +1,6 @@
 use core::{
     ffi::{c_int, c_void},
+    hint::spin_loop,
     sync::atomic::{AtomicBool, Ordering},
 };
 
@@ -10,6 +11,7 @@ use crate::{
     libs::{futex::constant::FutexFlag, rand::GRandFlags},
     mm::{page::PAGE_4K_SIZE, syscall::MremapFlags},
     net::syscall::MsgHdr,
+    process,
     process::{
         fork::KernelCloneArgs,
         resource::{RLimit64, RUsage},
@@ -74,6 +76,19 @@ impl Syscall {
 
         return r;
     }
+    /// 系统调用分发器,用于分发系统调用。
+    ///
+    /// 与[handle]不同,这个函数会捕获系统调用处理函数的panic,返回错误码。
+    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 {
+            spin_loop();
+        })
+    }
     /// @brief 系统调用分发器,用于分发系统调用。
     ///
     /// 这个函数内,需要根据系统调用号,调用对应的系统调用处理函数。