From 081428c0d832cde99834cf8f94a0f2a1f41c9704 Mon Sep 17 00:00:00 2001 From: linfeng Date: Tue, 19 Nov 2024 21:55:22 +0800 Subject: [PATCH] feat: update to new backtrace lib (#1049) * feat: update to new backtrace lib * feat: enable unwind for riscv64 --------- Co-authored-by: longjin --- kernel/Cargo.toml | 10 ++- kernel/Makefile | 6 +- kernel/src/Makefile | 28 +++++-- kernel/src/arch/riscv64/link.ld | 2 + .../riscv64/riscv64gc-unknown-none-elf.json | 28 +++++++ kernel/src/arch/riscv64/syscall/mod.rs | 3 +- kernel/src/arch/x86_64/link.lds | 2 + kernel/src/arch/x86_64/syscall/mod.rs | 4 +- .../src/arch/x86_64/x86_64-unknown-none.json | 2 +- kernel/src/lib.rs | 84 +++++++++++++++---- kernel/src/syscall/mod.rs | 15 ++++ 11 files changed, 151 insertions(+), 33 deletions(-) create mode 100644 kernel/src/arch/riscv64/riscv64gc-unknown-none-elf.json diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 46c6b889..414df828 100644 --- a/kernel/Cargo.toml +++ b/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" diff --git a/kernel/Makefile b/kernel/Makefile index ac09fc83..4429fb1d 100644 --- a/kernel/Makefile +++ b/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: diff --git a/kernel/src/Makefile b/kernel/src/Makefile index f78d7cfb..9028420c 100644 --- a/kernel/src/Makefile +++ b/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" diff --git a/kernel/src/arch/riscv64/link.ld b/kernel/src/arch/riscv64/link.ld index 5d628f39..bcd47fdd 100644 --- a/kernel/src/arch/riscv64/link.ld +++ b/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 = .; diff --git a/kernel/src/arch/riscv64/riscv64gc-unknown-none-elf.json b/kernel/src/arch/riscv64/riscv64gc-unknown-none-elf.json new file mode 100644 index 00000000..b474a6fb --- /dev/null +++ b/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" +} diff --git a/kernel/src/arch/riscv64/syscall/mod.rs b/kernel/src/arch/riscv64/syscall/mod.rs index 5609084a..450c0e85 100644 --- a/kernel/src/arch/riscv64/syscall/mod.rs +++ b/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 ); diff --git a/kernel/src/arch/x86_64/link.lds b/kernel/src/arch/x86_64/link.lds index 9c729ed9..6371c095 100644 --- a/kernel/src/arch/x86_64/link.lds +++ b/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 = .; diff --git a/kernel/src/arch/x86_64/syscall/mod.rs b/kernel/src/arch/x86_64/syscall/mod.rs index 4ed274c2..df656b3b 100644 --- a/kernel/src/arch/x86_64/syscall/mod.rs +++ b/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 ); diff --git a/kernel/src/arch/x86_64/x86_64-unknown-none.json b/kernel/src/arch/x86_64/x86_64-unknown-none.json index fbc13a4a..c676f377 100644 --- a/kernel/src/arch/x86_64/x86_64-unknown-none.json +++ b/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" } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 0c9ccbe4..c650b9d5 100644 --- a/kernel/src/lib.rs +++ b/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::( + 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 {} +} + +/// 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; + + 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 } - - println!("Current PCB:\n\t{:?}", (ProcessManager::current_pcb())); - - ProcessManager::exit(usize::MAX); } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index c83b6729..9157fcfe 100644 --- a/kernel/src/syscall/mod.rs +++ b/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 { + let res = unwinding::panic::catch_unwind(|| Self::handle(syscall_num, args, frame)); + res.unwrap_or_else(|_| loop { + spin_loop(); + }) + } /// @brief 系统调用分发器,用于分发系统调用。 /// /// 这个函数内,需要根据系统调用号,调用对应的系统调用处理函数。