From 02b5c86f8937edbbe8bbe79fedbab374156b4134 Mon Sep 17 00:00:00 2001 From: Nick Spinale Date: Mon, 12 Dec 2022 11:06:09 +0000 Subject: [PATCH 01/40] Add fde-custom feature --- Cargo.toml | 1 + README.md | 1 + src/lib.rs | 3 + src/unwinder/find_fde/custom.rs | 165 ++++++++++++++++++++++++++++++++ src/unwinder/find_fde/mod.rs | 14 +++ src/unwinder/mod.rs | 3 + 6 files changed, 187 insertions(+) create mode 100644 src/unwinder/find_fde/custom.rs diff --git a/Cargo.toml b/Cargo.toml index 973fa00..96288e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ fde-phdr-aux = ["fde-phdr"] fde-registry = ["alloc"] fde-static = [] fde-gnu-eh-frame-hdr = [] +fde-custom = [] dwarf-expr = [] hide-trace = [] personality = [] diff --git a/README.md b/README.md index 21f5509..abe55cd 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ The unwinder can be enabled with `unwinder` feature. Here are the feature gates | fde-registry | Yes | Provide `__register__frame` and others for dynamic registration. Requires either `libc` or `spin` for a mutex implementation. | | fde-gnu-eh-frame-hdr | No | Use `__executable_start`, `__etext` and `__GNU_EH_FRAME_HDR` to retrieve frame unwind table. The former two symbols are usually provided by the linker, while the last one is provided if GNU LD is used and --eh-frame-hdr option is enabled. | | fde-static | No | Use `__executable_start`, `__etext` and `__eh_frame` to retrieve frame unwind table. The former two symbols are usually provided by the linker, while the last one would need to be provided by the user via linker script. | +| fde-custom | No | Allow the program to provide a custom means of retrieving frame unwind table at runtime via the `set_custom_eh_frame_finder` function. | | dwarf-expr | Yes | Enable the dwarf expression evaluator. Usually not necessary for Rust | | hide-trace | Yes | Hide unwinder frames in back trace | diff --git a/src/lib.rs b/src/lib.rs index bdeb56d..6152309 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,9 @@ extern crate alloc; #[cfg(feature = "unwinder")] mod unwinder; +#[cfg(all(feature = "unwinder", feature = "fde-custom"))] +pub use unwinder::custom_eh_frame_finder; + pub mod abi; mod arch; diff --git a/src/unwinder/find_fde/custom.rs b/src/unwinder/find_fde/custom.rs new file mode 100644 index 0000000..cf9883d --- /dev/null +++ b/src/unwinder/find_fde/custom.rs @@ -0,0 +1,165 @@ +use super::{FDEFinder, FDESearchResult}; +use crate::util::{deref_pointer, get_unlimited_slice}; + +use core::sync::atomic::{AtomicU32, Ordering}; +use gimli::{BaseAddresses, EhFrame, EhFrameHdr, NativeEndian, UnwindSection}; + +pub(crate) struct CustomFinder(()); + +pub(crate) fn get_finder() -> &'static CustomFinder { + &CustomFinder(()) +} + +impl FDEFinder for CustomFinder { + fn find_fde(&self, pc: usize) -> Option { + get_custom_eh_frame_finder().and_then(|eh_frame_finder| find_fde(eh_frame_finder, pc)) + } +} + +/// A trait for types whose values can be used as the global EH frame finder set by [`set_custom_eh_frame_finder`]. +pub unsafe trait EhFrameFinder { + fn find(&self, pc: usize) -> Option; +} + +pub struct FrameInfo { + pub text_base: usize, + pub kind: FrameInfoKind, +} + +pub enum FrameInfoKind { + EhFrameHdr(usize), + EhFrame(usize), +} + +static mut CUSTOM_EH_FRAME_FINDER: Option<&(dyn EhFrameFinder + Sync)> = None; + +static CUSTOM_EH_FRAME_FINDER_STATE: AtomicU32 = AtomicU32::new(UNINITIALIZED); + +const UNINITIALIZED: u32 = 0; +const INITIALIZING: u32 = 1; +const INITIALIZED: u32 = 2; + +/// The type returned by [`set_custom_eh_frame_finder`] if [`set_custom_eh_frame_finder`] has +/// already been called. +#[derive(Debug)] +pub struct SetCustomEhFrameFinderError(()); + +/// Sets the global EH frame finder. +/// +/// This function should only be called once during the lifetime of the program. +/// +/// # Errors +/// +/// An error is returned if this function has already been called during the lifetime of the +/// program. +pub fn set_custom_eh_frame_finder( + fde_finder: &'static (dyn EhFrameFinder + Sync), +) -> Result<(), SetCustomEhFrameFinderError> { + match CUSTOM_EH_FRAME_FINDER_STATE.compare_exchange( + UNINITIALIZED, + INITIALIZING, + Ordering::SeqCst, + Ordering::SeqCst, + ) { + Ok(UNINITIALIZED) => { + unsafe { + CUSTOM_EH_FRAME_FINDER = Some(fde_finder); + } + CUSTOM_EH_FRAME_FINDER_STATE.store(INITIALIZED, Ordering::SeqCst); + Ok(()) + } + Err(INITIALIZING) => { + while CUSTOM_EH_FRAME_FINDER_STATE.load(Ordering::SeqCst) == INITIALIZING { + core::hint::spin_loop(); + } + Err(SetCustomEhFrameFinderError(())) + } + Err(INITIALIZED) => Err(SetCustomEhFrameFinderError(())), + _ => { + unreachable!() + } + } +} + +fn get_custom_eh_frame_finder() -> Option<&'static dyn EhFrameFinder> { + if CUSTOM_EH_FRAME_FINDER_STATE.load(Ordering::SeqCst) == INITIALIZED { + Some(unsafe { CUSTOM_EH_FRAME_FINDER.unwrap() }) + } else { + None + } +} + +fn find_fde(eh_frame_finder: &T, pc: usize) -> Option { + let info = eh_frame_finder.find(pc)?; + let text_base = info.text_base; + match info.kind { + FrameInfoKind::EhFrameHdr(eh_frame_hdr) => { + find_fde_with_eh_frame_hdr(pc, text_base, eh_frame_hdr) + } + FrameInfoKind::EhFrame(eh_frame) => find_fde_with_eh_frame(pc, text_base, eh_frame), + } +} + +fn find_fde_with_eh_frame_hdr( + pc: usize, + text_base: usize, + eh_frame_hdr: usize, +) -> Option { + unsafe { + let bases = BaseAddresses::default() + .set_text(text_base as _) + .set_eh_frame_hdr(eh_frame_hdr as _); + let eh_frame_hdr = EhFrameHdr::new( + get_unlimited_slice(eh_frame_hdr as usize as _), + NativeEndian, + ) + .parse(&bases, core::mem::size_of::() as _) + .ok()?; + let eh_frame = deref_pointer(eh_frame_hdr.eh_frame_ptr()); + let bases = bases.set_eh_frame(eh_frame as _); + let eh_frame = EhFrame::new(get_unlimited_slice(eh_frame as _), NativeEndian); + + // Use binary search table for address if available. + if let Some(table) = eh_frame_hdr.table() { + if let Ok(fde) = + table.fde_for_address(&eh_frame, &bases, pc as _, EhFrame::cie_from_offset) + { + return Some(FDESearchResult { + fde, + bases, + eh_frame, + }); + } + } + + // Otherwise do the linear search. + if let Ok(fde) = eh_frame.fde_for_address(&bases, pc as _, EhFrame::cie_from_offset) { + return Some(FDESearchResult { + fde, + bases, + eh_frame, + }); + } + + None + } +} + +fn find_fde_with_eh_frame(pc: usize, text_base: usize, eh_frame: usize) -> Option { + unsafe { + let bases = BaseAddresses::default() + .set_text(text_base as _) + .set_eh_frame(eh_frame as _); + let eh_frame = EhFrame::new(get_unlimited_slice(eh_frame as _), NativeEndian); + + if let Ok(fde) = eh_frame.fde_for_address(&bases, pc as _, EhFrame::cie_from_offset) { + return Some(FDESearchResult { + fde, + bases, + eh_frame, + }); + } + + None + } +} diff --git a/src/unwinder/find_fde/mod.rs b/src/unwinder/find_fde/mod.rs index d203df4..4db64a0 100644 --- a/src/unwinder/find_fde/mod.rs +++ b/src/unwinder/find_fde/mod.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "fde-custom")] +mod custom; #[cfg(feature = "fde-static")] mod fixed; #[cfg(feature = "fde-gnu-eh-frame-hdr")] @@ -10,6 +12,14 @@ mod registry; use crate::util::*; use gimli::{BaseAddresses, EhFrame, FrameDescriptionEntry}; +#[cfg(feature = "fde-custom")] +pub mod custom_eh_frame_finder { + pub use super::custom::{ + set_custom_eh_frame_finder, EhFrameFinder, FrameInfo, FrameInfoKind, + SetCustomEhFrameFinderError, + }; +} + #[derive(Debug)] pub struct FDESearchResult { pub fde: FrameDescriptionEntry, @@ -25,6 +35,10 @@ pub struct GlobalFinder(()); impl FDEFinder for GlobalFinder { fn find_fde(&self, pc: usize) -> Option { + #[cfg(feature = "fde-custom")] + if let Some(v) = custom::get_finder().find_fde(pc) { + return Some(v); + } #[cfg(feature = "fde-registry")] if let Some(v) = registry::get_finder().find_fde(pc) { return Some(v); diff --git a/src/unwinder/mod.rs b/src/unwinder/mod.rs index a62a911..07ee029 100644 --- a/src/unwinder/mod.rs +++ b/src/unwinder/mod.rs @@ -13,6 +13,9 @@ use arch::*; use find_fde::FDEFinder; use frame::Frame; +#[cfg(feature = "fde-custom")] +pub use find_fde::custom_eh_frame_finder; + #[repr(C)] pub struct UnwindException { pub exception_class: u64, From 3dba9da864e9da0d5c8d05be708608a94471a01c Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Tue, 21 Mar 2023 05:47:41 +0800 Subject: [PATCH 02/40] Correct a typo in x86_64.rs --- src/unwinder/arch/x86_64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unwinder/arch/x86_64.rs b/src/unwinder/arch/x86_64.rs index e15a229..4d0fbc7 100644 --- a/src/unwinder/arch/x86_64.rs +++ b/src/unwinder/arch/x86_64.rs @@ -121,7 +121,7 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { mov r14, [rdi + 0x70] mov r15, [rdi + 0x78] - /* RDI resotred last */ + /* RDI restored last */ mov rdi, [rdi + 0x28] ret From c88a9016fc313d1ef2360acc18c365ab6c583c99 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 26 Mar 2023 17:40:33 +0900 Subject: [PATCH 03/40] Add RISC-V RV32 support --- README.md | 2 +- src/unwinder/arch/mod.rs | 6 ++ src/unwinder/arch/riscv32.rs | 203 +++++++++++++++++++++++++++++++++++ src/unwinder/arch/riscv64.rs | 3 + 4 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 src/unwinder/arch/riscv32.rs diff --git a/README.md b/README.md index abe55cd..3b5f86b 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This library serves two purposes: 1. Provide a pure Rust alternative to libgcc_eh or libunwind. 2. Provide easier unwinding support for `#![no_std]` targets. -Currently supports x86_64, x86, RV64 and AArch64. +Currently supports x86_64, x86, RV64, RV32 and AArch64. ## Unwinder diff --git a/src/unwinder/arch/mod.rs b/src/unwinder/arch/mod.rs index 67d08c1..8158353 100644 --- a/src/unwinder/arch/mod.rs +++ b/src/unwinder/arch/mod.rs @@ -13,6 +13,11 @@ mod riscv64; #[cfg(target_arch = "riscv64")] pub use riscv64::*; +#[cfg(target_arch = "riscv32")] +mod riscv32; +#[cfg(target_arch = "riscv32")] +pub use riscv32::*; + #[cfg(target_arch = "aarch64")] mod aarch64; #[cfg(target_arch = "aarch64")] @@ -22,6 +27,7 @@ pub use aarch64::*; target_arch = "x86_64", target_arch = "x86", target_arch = "riscv64", + target_arch = "riscv32", target_arch = "aarch64" )))] compile_error!("Current architecture is not supported"); diff --git a/src/unwinder/arch/riscv32.rs b/src/unwinder/arch/riscv32.rs new file mode 100644 index 0000000..e845bdd --- /dev/null +++ b/src/unwinder/arch/riscv32.rs @@ -0,0 +1,203 @@ +use core::arch::asm; +use core::fmt; +use core::ops; +use gimli::{Register, RiscV}; + +// Match DWARF_FRAME_REGISTERS in libgcc +pub const MAX_REG_RULES: usize = 65; + +#[cfg(all(target_feature = "f", not(target_feature = "d")))] +compile_error!("RISC-V with only F extension is not supported"); + +#[repr(C)] +#[derive(Clone, Default)] +pub struct Context { + pub gp: [usize; 32], + #[cfg(target_feature = "d")] + pub fp: [u64; 32], +} + +impl fmt::Debug for Context { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut fmt = fmt.debug_struct("Context"); + for i in 0..=31 { + fmt.field(RiscV::register_name(Register(i as _)).unwrap(), &self.gp[i]); + } + #[cfg(target_feature = "d")] + for i in 0..=31 { + fmt.field( + RiscV::register_name(Register((i + 32) as _)).unwrap(), + &self.fp[i], + ); + } + fmt.finish() + } +} + +impl ops::Index for Context { + type Output = usize; + + fn index(&self, reg: Register) -> &usize { + match reg { + Register(0..=31) => &self.gp[reg.0 as usize], + // We cannot support indexing fp here. It is 64-bit if D extension is implemented, + // and 32-bit if only F extension is implemented. + _ => unimplemented!(), + } + } +} + +impl ops::IndexMut for Context { + fn index_mut(&mut self, reg: Register) -> &mut usize { + match reg { + Register(0..=31) => &mut self.gp[reg.0 as usize], + // We cannot support indexing fp here. It is 64-bit if D extension is implemented, + // and 32-bit if only F extension is implemented. + _ => unimplemented!(), + } + } +} + +macro_rules! code { + (save_gp) => { + " + sw x0, 0x00(a0) + sw ra, 0x04(a0) + sw sp, 0x08(a0) + sw gp, 0x0C(a0) + sw tp, 0x10(a0) + sw s0, 0x20(a0) + sw s1, 0x24(a0) + sw s2, 0x48(a0) + sw s3, 0x4C(a0) + sw s4, 0x50(a0) + sw s5, 0x54(a0) + sw s6, 0x58(a0) + sw s7, 0x5C(a0) + sw s8, 0x60(a0) + sw s9, 0x64(a0) + sw s10, 0x68(a0) + sw s11, 0x6C(a0) + " + }; + (save_fp) => { + " + fsd fs0, 0xC0(a0) + fsd fs1, 0xC8(a0) + fsd fs2, 0x110(a0) + fsd fs3, 0x118(a0) + fsd fs4, 0x120(a0) + fsd fs5, 0x128(a0) + fsd fs6, 0x130(a0) + fsd fs7, 0x138(a0) + fsd fs8, 0x140(a0) + fsd fs9, 0x148(a0) + fsd fs10, 0x150(a0) + fsd fs11, 0x158(a0) + " + }; + (restore_gp) => { + " + lw ra, 0x04(a0) + lw sp, 0x08(a0) + lw gp, 0x0C(a0) + lw tp, 0x10(a0) + lw t0, 0x14(a0) + lw t1, 0x18(a0) + lw t2, 0x1C(a0) + lw s0, 0x20(a0) + lw s1, 0x24(a0) + lw a1, 0x2C(a0) + lw a2, 0x30(a0) + lw a3, 0x34(a0) + lw a4, 0x38(a0) + lw a5, 0x3C(a0) + lw a6, 0x40(a0) + lw a7, 0x44(a0) + lw s2, 0x48(a0) + lw s3, 0x4C(a0) + lw s4, 0x50(a0) + lw s5, 0x54(a0) + lw s6, 0x58(a0) + lw s7, 0x5C(a0) + lw s8, 0x60(a0) + lw s9, 0x64(a0) + lw s10, 0x68(a0) + lw s11, 0x6C(a0) + lw t3, 0x70(a0) + lw t4, 0x74(a0) + lw t5, 0x78(a0) + lw t6, 0x7C(a0) + " + }; + (restore_fp) => { + " + fld ft0, 0x80(a0) + fld ft1, 0x88(a0) + fld ft2, 0x90(a0) + fld ft3, 0x98(a0) + fld ft4, 0xA0(a0) + fld ft5, 0xA8(a0) + fld ft6, 0xB0(a0) + fld ft7, 0xB8(a0) + fld fs0, 0xC0(a0) + fld fs1, 0xC8(a0) + fld fa0, 0xD0(a0) + fld fa1, 0xD8(a0) + fld fa2, 0xE0(a0) + fld fa3, 0xE8(a0) + fld fa4, 0xF0(a0) + fld fa5, 0xF8(a0) + fld fa6, 0x100(a0) + fld fa7, 0x108(a0) + fld fs2, 0x110(a0) + fld fs3, 0x118(a0) + fld fs4, 0x120(a0) + fld fs5, 0x128(a0) + fld fs6, 0x130(a0) + fld fs7, 0x138(a0) + fld fs8, 0x140(a0) + fld fs9, 0x148(a0) + fld fs10, 0x150(a0) + fld fs11, 0x158(a0) + fld ft8, 0x160(a0) + fld ft9, 0x168(a0) + fld ft10, 0x170(a0) + fld ft11, 0x178(a0) + " + }; +} + +#[naked] +pub extern "C-unwind" fn save_context() -> Context { + // No need to save caller-saved registers here. + #[cfg(target_feature = "d")] + unsafe { + asm!( + concat!(code!(save_gp), code!(save_fp), "ret"), + options(noreturn) + ); + } + #[cfg(not(target_feature = "d"))] + unsafe { + asm!(concat!(code!(save_gp), "ret"), options(noreturn)); + } +} + +#[naked] +pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { + #[cfg(target_feature = "d")] + unsafe { + asm!( + concat!(code!(restore_fp), code!(restore_gp), "lw a0, 0x28(a0)\nret"), + options(noreturn) + ); + } + #[cfg(not(target_feature = "d"))] + unsafe { + asm!( + concat!(code!(restore_gp), "lw a0, 0x28(a0)\nret"), + options(noreturn) + ); + } +} diff --git a/src/unwinder/arch/riscv64.rs b/src/unwinder/arch/riscv64.rs index 4852b93..8a2413c 100644 --- a/src/unwinder/arch/riscv64.rs +++ b/src/unwinder/arch/riscv64.rs @@ -6,6 +6,9 @@ use gimli::{Register, RiscV}; // Match DWARF_FRAME_REGISTERS in libgcc pub const MAX_REG_RULES: usize = 65; +#[cfg(all(target_feature = "f", not(target_feature = "d")))] +compile_error!("RISC-V with only F extension is not supported"); + #[repr(C)] #[derive(Clone, Default)] pub struct Context { From b2ff52837f3429ab19094905bd79626be291e296 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 26 Mar 2023 23:26:57 +0100 Subject: [PATCH 04/40] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 96288e6..89445eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "unwinding" -version = "0.1.5" +version = "0.1.6" authors = ["Gary Guo "] edition = "2018" license = "MIT OR Apache-2.0" From 77f8403aae838a4a09c31b0cb7c182ece87e517f Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 6 May 2023 23:59:35 +0100 Subject: [PATCH 05/40] Remove stabilised feature --- example/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/example/src/main.rs b/example/src/main.rs index 689df99..24ada05 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -1,6 +1,5 @@ #![no_std] #![feature(start)] -#![feature(default_alloc_error_handler)] extern crate alloc; extern crate unwinding; From a331c22665d000577a812f07b513ccf7a365bed8 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 7 May 2023 00:10:38 +0100 Subject: [PATCH 06/40] Use libc abort instead intrinsic abort when available --- src/panic.rs | 4 ++-- src/panic_handler.rs | 4 ++-- src/panic_handler_dummy.rs | 2 +- src/util.rs | 16 ++++++++++++++++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/panic.rs b/src/panic.rs index 8d5bd9d..d61f5e9 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -18,7 +18,7 @@ impl Drop for DropGuard { { drop_panic(); } - core::intrinsics::abort(); + crate::util::abort(); } } @@ -57,7 +57,7 @@ pub fn catch_unwind R>(f: F) -> Result> { foreign_exception(); } - core::intrinsics::abort(); + crate::util::abort(); } Some(e) => { #[cfg(feature = "panic-handler")] diff --git a/src/panic_handler.rs b/src/panic_handler.rs index 508ad8c..beca6ff 100644 --- a/src/panic_handler.rs +++ b/src/panic_handler.rs @@ -80,7 +80,7 @@ fn do_panic(msg: Box) -> ! { if PANIC_COUNT.get() >= 1 { stack_trace(); eprintln!("thread panicked while processing panic. aborting."); - core::intrinsics::abort(); + crate::util::abort(); } PANIC_COUNT.set(1); if check_env() { @@ -88,7 +88,7 @@ fn do_panic(msg: Box) -> ! { } let code = crate::panic::begin_panic(Box::new(msg)); eprintln!("failed to initiate panic, error {}", code.0); - core::intrinsics::abort(); + crate::util::abort(); } #[panic_handler] diff --git a/src/panic_handler_dummy.rs b/src/panic_handler_dummy.rs index 74c8a5d..6770705 100644 --- a/src/panic_handler_dummy.rs +++ b/src/panic_handler_dummy.rs @@ -2,5 +2,5 @@ use core::panic::PanicInfo; #[panic_handler] fn panic(_info: &PanicInfo<'_>) -> ! { - core::intrinsics::abort(); + crate::util::abort(); } diff --git a/src/util.rs b/src/util.rs index 1d738ce..e28a8a0 100644 --- a/src/util.rs +++ b/src/util.rs @@ -23,3 +23,19 @@ pub use libc::c_int; #[cfg(not(feature = "libc"))] #[allow(non_camel_case_types)] pub type c_int = i32; + +#[cfg(all( + any(feature = "panicking", feature = "panic-handler-dummy"), + feature = "libc" +))] +pub fn abort() -> ! { + unsafe { libc::abort() }; +} + +#[cfg(all( + any(feature = "panicking", feature = "panic-handler-dummy"), + not(feature = "libc") +))] +pub fn abort() -> ! { + core::intrinsics::abort(); +} From 863a10ed9ad4c2d50f5efc0ef5f33292611c1604 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 7 May 2023 00:15:01 +0100 Subject: [PATCH 07/40] Create ci.yml --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d83ae19 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,22 @@ +name: CI + +on: + push: + branches: [ "trunk" ] + pull_request: + branches: [ "trunk" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose From c7f06f852b79a018ca1e7382b98ed1ee5b017ec5 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 7 May 2023 00:29:39 +0100 Subject: [PATCH 08/40] Run the example as a CI test --- .github/workflows/ci.yml | 21 +++++++++++++++------ example/src/main.rs | 7 ++++--- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d83ae19..b92a6e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,13 +10,22 @@ env: CARGO_TERM_COLOR: always jobs: - build: - + test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Build - run: cargo build --verbose - - name: Run tests - run: cargo test --verbose + - name: Install Rust + run: rustup update nightly && rustup default nightly + - name: Run Example Binary + run: (cargo run --release 2>&1 | tee ../run.log) || true + working-directory: example + - name: Check Log + run: | + grep "panicked at 'panic', example/src/main.rs:36:5" run.log + grep 'note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace' run.log + grep 'dropped: "string"' run.log + grep 'caught' run.log + grep "panicked at 'panic', example/src/main.rs:46:5" run.log + grep "panicked at 'panic on drop', example/src/main.rs:25:9" run.log + grep "thread panicked while processing panic. aborting." run.log diff --git a/example/src/main.rs b/example/src/main.rs index 24ada05..c5295a3 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -14,7 +14,7 @@ struct PrintOnDrop(String); impl Drop for PrintOnDrop { fn drop(&mut self) { - println!("dropped: {:?}", self.0); + eprintln!("dropped: {:?}", self.0); } } @@ -26,6 +26,7 @@ impl Drop for PanicOnDrop { } } +#[track_caller] fn foo() { panic!("panic"); } @@ -38,9 +39,9 @@ fn bar() { fn main() { let _ = unwinding::panic::catch_unwind(|| { bar(); - println!("done"); + eprintln!("done"); }); - println!("caught"); + eprintln!("caught"); let _p = PanicOnDrop; foo(); } From 6dc1ed4d80706b05f3479b41b4b6c235e3edab0e Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 7 May 2023 00:33:30 +0100 Subject: [PATCH 09/40] Test multiple targets in CI --- .github/workflows/ci.yml | 45 +++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b92a6e4..02525d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,26 +1,55 @@ name: CI -on: - push: - branches: [ "trunk" ] - pull_request: - branches: [ "trunk" ] +on: [push, pull_request] env: CARGO_TERM_COLOR: always jobs: test: + strategy: + matrix: + target: + - x86_64-unknown-linux-gnu + - aarch64-unknown-linux-gnu + - riscv64gc-unknown-linux-gnu + build_std: [false] + include: + - target: riscv32gc-unknown-linux-gnu + build_std: true runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install Rust - run: rustup update nightly && rustup default nightly - - name: Run Example Binary + run: | + rustup update nightly + rustup default nightly + - name: Install Rust standard library source + if: matrix.build_std + run: rustup component add rust-src + - name: Install cross-compilation tools + uses: taiki-e/setup-cross-toolchain-action@v1 + with: + target: ${{ matrix.target }} + + - name: Build example binary + if: '!matrix.build_std' + run: cargo build --release + - name: Build example binary + if: matrix.build_std + run: cargo build --release -Zbuild-std + + - name: Run example binary + if: '!matrix.build_std' run: (cargo run --release 2>&1 | tee ../run.log) || true working-directory: example - - name: Check Log + - name: Run example binary + if: matrix.build_std + run: (cargo run --release -Zbuild-std 2>&1 | tee ../run.log) || true + working-directory: example + + - name: Check log run: | grep "panicked at 'panic', example/src/main.rs:36:5" run.log grep 'note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace' run.log From a9bec9e719298f3961dae89aa55dd22d144bffaf Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 7 May 2023 01:00:25 +0100 Subject: [PATCH 10/40] Change save_context to invoke callback instead --- src/unwinder/arch/aarch64.rs | 35 ++++-- src/unwinder/arch/riscv32.rs | 107 +++++++++++------ src/unwinder/arch/riscv64.rs | 107 +++++++++++------ src/unwinder/arch/x86.rs | 42 ++++--- src/unwinder/arch/x86_64.rs | 36 +++--- src/unwinder/mod.rs | 222 ++++++++++++++++++++--------------- 6 files changed, 342 insertions(+), 207 deletions(-) diff --git a/src/unwinder/arch/aarch64.rs b/src/unwinder/arch/aarch64.rs index abe588c..f65332c 100644 --- a/src/unwinder/arch/aarch64.rs +++ b/src/unwinder/arch/aarch64.rs @@ -59,25 +59,34 @@ impl ops::IndexMut for Context { } #[naked] -pub extern "C-unwind" fn save_context() -> Context { +pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) { // No need to save caller-saved registers here. unsafe { asm!( " - stp d8, d9, [x8, 0x140] - stp d10, d11, [x8, 0x150] - stp d12, d13, [x8, 0x160] - stp d14, d15, [x8, 0x170] - - str x19, [x8, 0x98] - stp x20, x21, [x8, 0xA0] - stp x22, x23, [x8, 0xB0] - stp x24, x25, [x8, 0xC0] - stp x26, x27, [x8, 0xD0] - stp x28, x29, [x8, 0xE0] + stp x29, x30, [sp, -16]! + sub sp, sp, 512 + mov x8, x0 mov x0, sp - stp x30, x0, [x8, 0xF0] + stp d8, d9, [sp, 0x140] + stp d10, d11, [sp, 0x150] + stp d12, d13, [sp, 0x160] + stp d14, d15, [sp, 0x170] + + str x19, [sp, 0x98] + stp x20, x21, [sp, 0xA0] + stp x22, x23, [sp, 0xB0] + stp x24, x25, [sp, 0xC0] + stp x26, x27, [sp, 0xD0] + stp x28, x29, [sp, 0xE0] + add x2, sp, 528 + stp x30, x2, [sp, 0xF0] + + blr x8 + + add sp, sp, 512 + ldp x29, x30, [sp], 16 ret ", options(noreturn) diff --git a/src/unwinder/arch/riscv32.rs b/src/unwinder/arch/riscv32.rs index e845bdd..1e8709e 100644 --- a/src/unwinder/arch/riscv32.rs +++ b/src/unwinder/arch/riscv32.rs @@ -61,39 +61,39 @@ impl ops::IndexMut for Context { macro_rules! code { (save_gp) => { " - sw x0, 0x00(a0) - sw ra, 0x04(a0) - sw sp, 0x08(a0) - sw gp, 0x0C(a0) - sw tp, 0x10(a0) - sw s0, 0x20(a0) - sw s1, 0x24(a0) - sw s2, 0x48(a0) - sw s3, 0x4C(a0) - sw s4, 0x50(a0) - sw s5, 0x54(a0) - sw s6, 0x58(a0) - sw s7, 0x5C(a0) - sw s8, 0x60(a0) - sw s9, 0x64(a0) - sw s10, 0x68(a0) - sw s11, 0x6C(a0) + sw x0, 0x00(sp) + sw ra, 0x04(sp) + sw t0, 0x08(sp) + sw gp, 0x0C(sp) + sw tp, 0x10(sp) + sw s0, 0x20(sp) + sw s1, 0x24(sp) + sw s2, 0x48(sp) + sw s3, 0x4C(sp) + sw s4, 0x50(sp) + sw s5, 0x54(sp) + sw s6, 0x58(sp) + sw s7, 0x5C(sp) + sw s8, 0x60(sp) + sw s9, 0x64(sp) + sw s10, 0x68(sp) + sw s11, 0x6C(sp) " }; (save_fp) => { " - fsd fs0, 0xC0(a0) - fsd fs1, 0xC8(a0) - fsd fs2, 0x110(a0) - fsd fs3, 0x118(a0) - fsd fs4, 0x120(a0) - fsd fs5, 0x128(a0) - fsd fs6, 0x130(a0) - fsd fs7, 0x138(a0) - fsd fs8, 0x140(a0) - fsd fs9, 0x148(a0) - fsd fs10, 0x150(a0) - fsd fs11, 0x158(a0) + fsd fs0, 0xC0(sp) + fsd fs1, 0xC8(sp) + fsd fs2, 0x110(sp) + fsd fs3, 0x118(sp) + fsd fs4, 0x120(sp) + fsd fs5, 0x128(sp) + fsd fs6, 0x130(sp) + fsd fs7, 0x138(sp) + fsd fs8, 0x140(sp) + fsd fs9, 0x148(sp) + fsd fs10, 0x150(sp) + fsd fs11, 0x158(sp) " }; (restore_gp) => { @@ -169,18 +169,48 @@ macro_rules! code { } #[naked] -pub extern "C-unwind" fn save_context() -> Context { +pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) { // No need to save caller-saved registers here. #[cfg(target_feature = "d")] unsafe { asm!( - concat!(code!(save_gp), code!(save_fp), "ret"), + " + mv t0, sp + add sp, sp, -0x188 + sw ra, 0x180(sp) + ", + code!(save_gp), + code!(save_fp), + " + mv t0, a0 + mv a0, sp + jalr t0 + lw ra, 0x180(sp) + add sp, sp, 0x188 + ret + ", options(noreturn) ); } #[cfg(not(target_feature = "d"))] unsafe { - asm!(concat!(code!(save_gp), "ret"), options(noreturn)); + asm!( + " + mv t0, sp + add sp, sp, -0x88 + sw ra, 0x80(sp) + ", + code!(save_gp), + " + mv t0, a0 + mv a0, sp + jalr t0 + lw ra, 0x80(sp) + add sp, sp, 0x88 + ret + ", + options(noreturn) + ); } } @@ -189,14 +219,23 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { #[cfg(target_feature = "d")] unsafe { asm!( - concat!(code!(restore_fp), code!(restore_gp), "lw a0, 0x28(a0)\nret"), + code!(restore_fp), + code!(restore_gp), + " + lw a0, 0x28(a0) + ret + ", options(noreturn) ); } #[cfg(not(target_feature = "d"))] unsafe { asm!( - concat!(code!(restore_gp), "lw a0, 0x28(a0)\nret"), + code!(restore_gp), + " + lw a0, 0x28(a0) + ret + ", options(noreturn) ); } diff --git a/src/unwinder/arch/riscv64.rs b/src/unwinder/arch/riscv64.rs index 8a2413c..a680d70 100644 --- a/src/unwinder/arch/riscv64.rs +++ b/src/unwinder/arch/riscv64.rs @@ -61,39 +61,39 @@ impl ops::IndexMut for Context { macro_rules! code { (save_gp) => { " - sd x0, 0x00(a0) - sd ra, 0x08(a0) - sd sp, 0x10(a0) - sd gp, 0x18(a0) - sd tp, 0x20(a0) - sd s0, 0x40(a0) - sd s1, 0x48(a0) - sd s2, 0x90(a0) - sd s3, 0x98(a0) - sd s4, 0xA0(a0) - sd s5, 0xA8(a0) - sd s6, 0xB0(a0) - sd s7, 0xB8(a0) - sd s8, 0xC0(a0) - sd s9, 0xC8(a0) - sd s10, 0xD0(a0) - sd s11, 0xD8(a0) + sd x0, 0x00(sp) + sd ra, 0x08(sp) + sd t0, 0x10(sp) + sd gp, 0x18(sp) + sd tp, 0x20(sp) + sd s0, 0x40(sp) + sd s1, 0x48(sp) + sd s2, 0x90(sp) + sd s3, 0x98(sp) + sd s4, 0xA0(sp) + sd s5, 0xA8(sp) + sd s6, 0xB0(sp) + sd s7, 0xB8(sp) + sd s8, 0xC0(sp) + sd s9, 0xC8(sp) + sd s10, 0xD0(sp) + sd s11, 0xD8(sp) " }; (save_fp) => { " - fsd fs0, 0x140(a0) - fsd fs1, 0x148(a0) - fsd fs2, 0x190(a0) - fsd fs3, 0x198(a0) - fsd fs4, 0x1A0(a0) - fsd fs5, 0x1A8(a0) - fsd fs6, 0x1B0(a0) - fsd fs7, 0x1B8(a0) - fsd fs8, 0x1C0(a0) - fsd fs9, 0x1C8(a0) - fsd fs10, 0x1D0(a0) - fsd fs11, 0x1D8(a0) + fsd fs0, 0x140(sp) + fsd fs1, 0x148(sp) + fsd fs2, 0x190(sp) + fsd fs3, 0x198(sp) + fsd fs4, 0x1A0(sp) + fsd fs5, 0x1A8(sp) + fsd fs6, 0x1B0(sp) + fsd fs7, 0x1B8(sp) + fsd fs8, 0x1C0(sp) + fsd fs9, 0x1C8(sp) + fsd fs10, 0x1D0(sp) + fsd fs11, 0x1D8(sp) " }; (restore_gp) => { @@ -169,18 +169,48 @@ macro_rules! code { } #[naked] -pub extern "C-unwind" fn save_context() -> Context { +pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) { // No need to save caller-saved registers here. #[cfg(target_feature = "d")] unsafe { asm!( - concat!(code!(save_gp), code!(save_fp), "ret"), + " + mv t0, sp + add sp, sp, -0x210 + sd ra, 0x200(sp) + ", + code!(save_gp), + code!(save_fp), + " + mv t0, a0 + mv a0, sp + jalr t0 + ld ra, 0x200(sp) + add sp, sp, 0x210 + ret + ", options(noreturn) ); } #[cfg(not(target_feature = "d"))] unsafe { - asm!(concat!(code!(save_gp), "ret"), options(noreturn)); + asm!( + " + mv t0, sp + add sp, sp, -0x110 + sd ra, 0x100(sp) + ", + code!(save_gp), + " + mv t0, a0 + mv a0, sp + jalr t0 + ld ra, 0x100(sp) + add sp, sp, 0x110 + ret + ", + options(noreturn) + ); } } @@ -189,14 +219,23 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { #[cfg(target_feature = "d")] unsafe { asm!( - concat!(code!(restore_fp), code!(restore_gp), "ld a0, 0x50(a0)\nret"), + code!(restore_fp), + code!(restore_gp), + " + ld a0, 0x50(a0) + ret + ", options(noreturn) ); } #[cfg(not(target_feature = "d"))] unsafe { asm!( - concat!(code!(restore_gp), "ld a0, 0x50(a0)\nret"), + code!(restore_gp), + " + ld a0, 0x50(a0) + ret + ", options(noreturn) ); } diff --git a/src/unwinder/arch/x86.rs b/src/unwinder/arch/x86.rs index 181378c..696ad3d 100644 --- a/src/unwinder/arch/x86.rs +++ b/src/unwinder/arch/x86.rs @@ -56,28 +56,40 @@ impl ops::IndexMut for Context { } #[naked] -pub extern "C-unwind" fn save_context() -> Context { +pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) { // No need to save caller-saved registers here. unsafe { asm!( " - mov eax, [esp + 4] - mov [eax + 4], ecx - mov [eax + 8], edx - mov [eax + 12], ebx - mov [eax + 20], ebp - mov [eax + 24], esi - mov [eax + 28], edi + sub esp, 44 + + mov [esp + 4], ecx + mov [esp + 8], edx + mov [esp + 12], ebx /* Adjust the stack to account for the return address */ - lea edx, [esp + 4] - mov [eax + 16], edx + lea eax, [esp + 48] + mov [esp + 16], eax - mov edx, [esp] - mov [eax + 32], edx - stmxcsr [eax + 36] - fnstcw [eax + 40] - ret 4 + mov [esp + 20], ebp + mov [esp + 24], esi + mov [esp + 28], edi + + /* Return address */ + mov eax, [esp + 44] + mov [esp + 32], eax + + stmxcsr [esp + 36] + fnstcw [esp + 40] + + mov eax, [esp + 52] + mov ecx, esp + push eax + push ecx + call [esp + 56] + + add esp, 52 + ret ", options(noreturn) ); diff --git a/src/unwinder/arch/x86_64.rs b/src/unwinder/arch/x86_64.rs index 4d0fbc7..4387686 100644 --- a/src/unwinder/arch/x86_64.rs +++ b/src/unwinder/arch/x86_64.rs @@ -58,27 +58,35 @@ impl ops::IndexMut for Context { } #[naked] -pub extern "C-unwind" fn save_context() -> Context { +pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) { // No need to save caller-saved registers here. unsafe { asm!( " - mov rax, rdi - mov [rax + 0x18], rbx - mov [rax + 0x30], rbp + sub rsp, 0x98 + mov [rsp + 0x18], rbx + mov [rsp + 0x30], rbp /* Adjust the stack to account for the return address */ - lea rdi, [rsp + 8] - mov [rax + 0x38], rdi + lea rax, [rsp + 0xA0] + mov [rsp + 0x38], rax - mov [rax + 0x60], r12 - mov [rax + 0x68], r13 - mov [rax + 0x70], r14 - mov [rax + 0x78], r15 - mov rdx, [rsp] - mov [rax + 0x80], rdx - stmxcsr [rax + 0x88] - fnstcw [rax + 0x90] + mov [rsp + 0x60], r12 + mov [rsp + 0x68], r13 + mov [rsp + 0x70], r14 + mov [rsp + 0x78], r15 + + /* Return address */ + mov rax, [rsp + 0x98] + mov [rsp + 0x80], rax + + stmxcsr [rsp + 0x88] + fnstcw [rsp + 0x90] + + mov rax, rdi + mov rdi, rsp + call rax + add rsp, 0x98 ret ", options(noreturn) diff --git a/src/unwinder/mod.rs b/src/unwinder/mod.rs index 07ee029..3309f47 100644 --- a/src/unwinder/mod.rs +++ b/src/unwinder/mod.rs @@ -16,6 +16,33 @@ use frame::Frame; #[cfg(feature = "fde-custom")] pub use find_fde::custom_eh_frame_finder; +// Helper function to turn `save_context` which takes function pointer to a closure-taking function. +fn with_context T>(f: F) -> T { + use core::mem::ManuallyDrop; + + union Data { + f: ManuallyDrop, + t: ManuallyDrop, + } + + extern "C" fn delegate T>(ctx: &mut Context, ptr: *mut ()) { + // SAFETY: This function is called exactly once; it extracts the function, call it and + // store the return value. This function is `extern "C"` so we don't need to worry about + // unwinding past it. + unsafe { + let data = &mut *ptr.cast::>(); + let t = ManuallyDrop::take(&mut data.f)(ctx); + data.t = ManuallyDrop::new(t); + } + } + + let mut data = Data { + f: ManuallyDrop::new(f), + }; + save_context(delegate::, ptr::addr_of_mut!(data).cast()); + unsafe { ManuallyDrop::into_inner(data.t) } +} + #[repr(C)] pub struct UnwindException { pub exception_class: u64, @@ -125,53 +152,52 @@ macro_rules! try2 { pub extern "C-unwind" fn _Unwind_RaiseException( exception: &mut UnwindException, ) -> UnwindReasonCode { - let saved_ctx = save_context(); + with_context(|saved_ctx| { + // Phase 1: Search for handler + let mut ctx = saved_ctx.clone(); + let mut signal = false; + loop { + if let Some(frame) = try1!(Frame::from_context(&ctx, signal)) { + if let Some(personality) = frame.personality() { + let result = personality( + 1, + UnwindAction::SEARCH_PHASE, + exception.exception_class, + exception, + &mut UnwindContext { + frame: Some(&frame), + ctx: &mut ctx, + signal, + }, + ); - // Phase 1: Search for handler - let mut ctx = saved_ctx.clone(); - let mut signal = false; - loop { - if let Some(frame) = try1!(Frame::from_context(&ctx, signal)) { - if let Some(personality) = frame.personality() { - let result = personality( - 1, - UnwindAction::SEARCH_PHASE, - exception.exception_class, - exception, - &mut UnwindContext { - frame: Some(&frame), - ctx: &mut ctx, - signal, - }, - ); - - match result { - UnwindReasonCode::CONTINUE_UNWIND => (), - UnwindReasonCode::HANDLER_FOUND => { - break; + match result { + UnwindReasonCode::CONTINUE_UNWIND => (), + UnwindReasonCode::HANDLER_FOUND => { + break; + } + _ => return UnwindReasonCode::FATAL_PHASE1_ERROR, } - _ => return UnwindReasonCode::FATAL_PHASE1_ERROR, } + + ctx = try1!(frame.unwind(&ctx)); + signal = frame.is_signal_trampoline(); + } else { + return UnwindReasonCode::END_OF_STACK; } - - ctx = try1!(frame.unwind(&ctx)); - signal = frame.is_signal_trampoline(); - } else { - return UnwindReasonCode::END_OF_STACK; } - } - // Disambiguate normal frame and signal frame. - let handler_cfa = ctx[Arch::SP] - signal as usize; - exception.private_1 = None; - exception.private_2 = handler_cfa; + // Disambiguate normal frame and signal frame. + let handler_cfa = ctx[Arch::SP] - signal as usize; + exception.private_1 = None; + exception.private_2 = handler_cfa; - let mut ctx = saved_ctx; - let code = raise_exception_phase2(exception, &mut ctx, handler_cfa); - match code { - UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(&ctx) }, - _ => code, - } + let code = raise_exception_phase2(exception, saved_ctx, handler_cfa); + match code { + UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(saved_ctx) }, + _ => code, + } + }) } fn raise_exception_phase2( @@ -225,16 +251,16 @@ pub extern "C-unwind" fn _Unwind_ForcedUnwind( stop: UnwindStopFn, stop_arg: *mut c_void, ) -> UnwindReasonCode { - let mut ctx = save_context(); + with_context(|ctx| { + exception.private_1 = Some(stop); + exception.private_2 = stop_arg as _; - exception.private_1 = Some(stop); - exception.private_2 = stop_arg as _; - - let code = force_unwind_phase2(exception, &mut ctx, stop, stop_arg); - match code { - UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(&ctx) }, - _ => code, - } + let code = force_unwind_phase2(exception, ctx, stop, stop_arg); + match code { + UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(ctx) }, + _ => code, + } + }) } fn force_unwind_phase2( @@ -304,21 +330,21 @@ fn force_unwind_phase2( #[inline(never)] #[no_mangle] pub extern "C-unwind" fn _Unwind_Resume(exception: &mut UnwindException) -> ! { - let mut ctx = save_context(); + with_context(|ctx| { + let code = match exception.private_1 { + None => { + let handler_cfa = exception.private_2; + raise_exception_phase2(exception, ctx, handler_cfa) + } + Some(stop) => { + let stop_arg = exception.private_2 as _; + force_unwind_phase2(exception, ctx, stop, stop_arg) + } + }; + assert!(code == UnwindReasonCode::INSTALL_CONTEXT); - let code = match exception.private_1 { - None => { - let handler_cfa = exception.private_2; - raise_exception_phase2(exception, &mut ctx, handler_cfa) - } - Some(stop) => { - let stop_arg = exception.private_2 as _; - force_unwind_phase2(exception, &mut ctx, stop, stop_arg) - } - }; - assert!(code == UnwindReasonCode::INSTALL_CONTEXT); - - unsafe { restore_context(&ctx) } + unsafe { restore_context(ctx) } + }) } #[inline(never)] @@ -331,13 +357,13 @@ pub extern "C-unwind" fn _Unwind_Resume_or_Rethrow( Some(v) => v, }; - let mut ctx = save_context(); + with_context(|ctx| { + let stop_arg = exception.private_2 as _; + let code = force_unwind_phase2(exception, ctx, stop, stop_arg); + assert!(code == UnwindReasonCode::INSTALL_CONTEXT); - let stop_arg = exception.private_2 as _; - let code = force_unwind_phase2(exception, &mut ctx, stop, stop_arg); - assert!(code == UnwindReasonCode::INSTALL_CONTEXT); - - unsafe { restore_context(&ctx) } + unsafe { restore_context(ctx) } + }) } #[no_mangle] @@ -353,36 +379,38 @@ pub extern "C-unwind" fn _Unwind_Backtrace( trace: UnwindTraceFn, trace_argument: *mut c_void, ) -> UnwindReasonCode { - let mut ctx = save_context(); - let mut signal = false; - let mut skipping = cfg!(feature = "hide-trace"); + with_context(|ctx| { + let mut ctx = ctx.clone(); + let mut signal = false; + let mut skipping = cfg!(feature = "hide-trace"); - loop { - let frame = try1!(Frame::from_context(&ctx, signal)); - if !skipping { - let code = trace( - &mut UnwindContext { - frame: frame.as_ref(), - ctx: &mut ctx, - signal, - }, - trace_argument, - ); - match code { - UnwindReasonCode::NO_REASON => (), - _ => return UnwindReasonCode::FATAL_PHASE1_ERROR, - } - } - if let Some(frame) = frame { - if skipping { - if frame.initial_address() == _Unwind_Backtrace as usize { - skipping = false; + loop { + let frame = try1!(Frame::from_context(&ctx, signal)); + if !skipping { + let code = trace( + &mut UnwindContext { + frame: frame.as_ref(), + ctx: &mut ctx, + signal, + }, + trace_argument, + ); + match code { + UnwindReasonCode::NO_REASON => (), + _ => return UnwindReasonCode::FATAL_PHASE1_ERROR, } } - ctx = try1!(frame.unwind(&ctx)); - signal = frame.is_signal_trampoline(); - } else { - return UnwindReasonCode::END_OF_STACK; + if let Some(frame) = frame { + if skipping { + if frame.initial_address() == _Unwind_Backtrace as usize { + skipping = false; + } + } + ctx = try1!(frame.unwind(&ctx)); + signal = frame.is_signal_trampoline(); + } else { + return UnwindReasonCode::END_OF_STACK; + } } - } + }) } From 87851eb776dba416b0c352bfee8a71197074e0d7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 7 May 2023 01:03:15 +0100 Subject: [PATCH 11/40] Add i686 to CI matrix --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02525d6..2724f61 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ jobs: matrix: target: - x86_64-unknown-linux-gnu + - i686-unknown-linux-gnu - aarch64-unknown-linux-gnu - riscv64gc-unknown-linux-gnu build_std: [false] From 73c9fbf66e5f9742d45618b01e58747842e464ce Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 7 May 2023 12:15:24 +0100 Subject: [PATCH 12/40] Ensure 16B stack alignment for x86 --- src/unwinder/arch/x86.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/unwinder/arch/x86.rs b/src/unwinder/arch/x86.rs index 696ad3d..992afb6 100644 --- a/src/unwinder/arch/x86.rs +++ b/src/unwinder/arch/x86.rs @@ -61,14 +61,14 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p unsafe { asm!( " - sub esp, 44 + sub esp, 52 mov [esp + 4], ecx mov [esp + 8], edx mov [esp + 12], ebx /* Adjust the stack to account for the return address */ - lea eax, [esp + 48] + lea eax, [esp + 56] mov [esp + 16], eax mov [esp + 20], ebp @@ -76,19 +76,19 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p mov [esp + 28], edi /* Return address */ - mov eax, [esp + 44] + mov eax, [esp + 52] mov [esp + 32], eax stmxcsr [esp + 36] fnstcw [esp + 40] - mov eax, [esp + 52] + mov eax, [esp + 60] mov ecx, esp push eax push ecx - call [esp + 56] + call [esp + 64] - add esp, 52 + add esp, 60 ret ", options(noreturn) From dcb6ae6dc14684a670adaffc1c682e48c403a7d9 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 7 May 2023 12:15:37 +0100 Subject: [PATCH 13/40] Add a dbg macro to the print utility --- src/print.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/print.rs b/src/print.rs index 26c16a9..fc6d9ac 100644 --- a/src/print.rs +++ b/src/print.rs @@ -49,3 +49,22 @@ macro_rules! eprint { let _ = core::write!($crate::print::StderrPrinter, $($arg)*); }) } + +#[macro_export] +macro_rules! dbg { + () => { + $crate::eprintln!("[{}:{}]", ::core::file!(), ::core::line!()) + }; + ($val:expr $(,)?) => { + match $val { + tmp => { + $crate::eprintln!("[{}:{}] {} = {:#?}", + ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp); + tmp + } + } + }; + ($($val:expr),+ $(,)?) => { + ($($crate::dbg!($val)),+,) + }; +} From e3cf678839eefbfc33caa1b02211a85698f2f67f Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 7 May 2023 12:17:05 +0100 Subject: [PATCH 14/40] Support DW_CFA_GNU_args_size --- src/unwinder/frame.rs | 5 +++++ src/unwinder/mod.rs | 14 ++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/unwinder/frame.rs b/src/unwinder/frame.rs index 0053899..8659bfe 100644 --- a/src/unwinder/frame.rs +++ b/src/unwinder/frame.rs @@ -125,6 +125,11 @@ impl Frame { Err(gimli::Error::UnsupportedEvaluation) } + pub fn adjust_stack_for_args(&self, ctx: &mut Context) { + let size = self.row.saved_args_size(); + ctx[Arch::SP] = ctx[Arch::SP].wrapping_add(size as usize); + } + pub fn unwind(&self, ctx: &Context) -> Result { let row = &self.row; let mut new_ctx = ctx.clone(); diff --git a/src/unwinder/mod.rs b/src/unwinder/mod.rs index 3309f47..968566b 100644 --- a/src/unwinder/mod.rs +++ b/src/unwinder/mod.rs @@ -229,7 +229,10 @@ fn raise_exception_phase2( match code { UnwindReasonCode::CONTINUE_UNWIND => (), - UnwindReasonCode::INSTALL_CONTEXT => break, + UnwindReasonCode::INSTALL_CONTEXT => { + frame.adjust_stack_for_args(ctx); + return UnwindReasonCode::INSTALL_CONTEXT; + } _ => return UnwindReasonCode::FATAL_PHASE2_ERROR, } } @@ -240,8 +243,6 @@ fn raise_exception_phase2( return UnwindReasonCode::FATAL_PHASE2_ERROR; } } - - UnwindReasonCode::INSTALL_CONTEXT } #[inline(never)] @@ -312,7 +313,10 @@ fn force_unwind_phase2( match code { UnwindReasonCode::CONTINUE_UNWIND => (), - UnwindReasonCode::INSTALL_CONTEXT => break, + UnwindReasonCode::INSTALL_CONTEXT => { + frame.adjust_stack_for_args(ctx); + return UnwindReasonCode::INSTALL_CONTEXT; + } _ => return UnwindReasonCode::FATAL_PHASE2_ERROR, } } @@ -323,8 +327,6 @@ fn force_unwind_phase2( return UnwindReasonCode::END_OF_STACK; } } - - UnwindReasonCode::INSTALL_CONTEXT } #[inline(never)] From 372cb02d2a2dede92824611b410f302c1ecf88f2 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 7 May 2023 12:27:34 +0100 Subject: [PATCH 15/40] Version bump --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 89445eb..5081cc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "unwinding" -version = "0.1.6" +version = "0.1.7" authors = ["Gary Guo "] edition = "2018" license = "MIT OR Apache-2.0" From 5fbf47a2d711b62469e550afc60cdd4ce9ca323d Mon Sep 17 00:00:00 2001 From: Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> Date: Sat, 1 Jul 2023 18:49:12 +0530 Subject: [PATCH 16/40] Update Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5081cc0..d84a5bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ members = ["cdylib", "example"] [dependencies] gimli = { version = "0.26.1", default-features = false, features = ["read-core"] } libc = { version = "0.2", optional = true } -spin = { version = "0.9", optional = true, default-features = false, features = ["mutex", "spin_mutex"] } +spin = { version = "0.9.8", optional = true, default-features = false, features = ["mutex", "spin_mutex"] } [features] alloc = [] From 5c96fa704232c003ec5ed9f5755c4c8ce6e2bd4e Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 16 Jul 2023 21:40:00 +0900 Subject: [PATCH 17/40] Simplify CI config --- .github/workflows/ci.yml | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2724f61..0f8155d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,10 +14,7 @@ jobs: - i686-unknown-linux-gnu - aarch64-unknown-linux-gnu - riscv64gc-unknown-linux-gnu - build_std: [false] - include: - - target: riscv32gc-unknown-linux-gnu - build_std: true + - riscv32gc-unknown-linux-gnu runs-on: ubuntu-latest steps: @@ -26,28 +23,16 @@ jobs: run: | rustup update nightly rustup default nightly - - name: Install Rust standard library source - if: matrix.build_std - run: rustup component add rust-src - name: Install cross-compilation tools uses: taiki-e/setup-cross-toolchain-action@v1 with: target: ${{ matrix.target }} - name: Build example binary - if: '!matrix.build_std' - run: cargo build --release - - name: Build example binary - if: matrix.build_std - run: cargo build --release -Zbuild-std + run: cargo build --release $BUILD_STD - name: Run example binary - if: '!matrix.build_std' - run: (cargo run --release 2>&1 | tee ../run.log) || true - working-directory: example - - name: Run example binary - if: matrix.build_std - run: (cargo run --release -Zbuild-std 2>&1 | tee ../run.log) || true + run: (cargo run --release $BUILD_STD 2>&1 | tee ../run.log) || true working-directory: example - name: Check log From 29d292637b0bd7a1deb9cc51607b62531109b2bb Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 29 Jul 2023 15:02:45 +0100 Subject: [PATCH 18/40] Allow unwinding_dyn to be built as staticlib --- cdylib/Cargo.toml | 2 +- cdylib/src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cdylib/Cargo.toml b/cdylib/Cargo.toml index e79d1b9..ce3168f 100644 --- a/cdylib/Cargo.toml +++ b/cdylib/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Gary Guo "] edition = "2018" [lib] -crate-type = ["cdylib"] +crate-type = ["cdylib", "staticlib"] [dependencies] unwinding = { path = "../", features = ["system-alloc", "personality-dummy", "panic-handler-dummy"] } diff --git a/cdylib/src/lib.rs b/cdylib/src/lib.rs index 71cdd2e..d9d98d4 100644 --- a/cdylib/src/lib.rs +++ b/cdylib/src/lib.rs @@ -1,5 +1,4 @@ #![no_std] -#![feature(default_alloc_error_handler)] #![warn(rust_2018_idioms)] #![warn(unsafe_op_in_unsafe_fn)] From 3a161265505bbc6e2b2cd5876987388e09fcecfc Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 5 Aug 2023 16:01:57 +0100 Subject: [PATCH 19/40] Allow non-dummy feature to absorb dummy feature This will allow building with --all-features --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6152309..d36d4a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ pub mod print; #[cfg(feature = "personality")] mod personality; -#[cfg(feature = "personality-dummy")] +#[cfg(all(not(feature = "personality"), feature = "personality-dummy"))] mod personality_dummy; #[cfg(feature = "panic")] @@ -43,7 +43,7 @@ pub mod panicking; #[cfg(feature = "panic-handler")] mod panic_handler; -#[cfg(feature = "panic-handler-dummy")] +#[cfg(all(not(feature = "panic-handler"), feature = "panic-handler-dummy"))] mod panic_handler_dummy; #[cfg(feature = "system-alloc")] From e50b916b7f0f3b384bff09ae0f46cb6868759a76 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 5 Aug 2023 16:04:53 +0100 Subject: [PATCH 20/40] Allow internal_features lint --- src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index d36d4a3..97cb357 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,10 @@ #![doc = include_str!("../README.md")] #![feature(c_unwind)] #![feature(naked_functions)] +// lang_items is an internal feature. `internal_features` lint is added recently +// so also allow unknown lints to prevent warning in older nightly versions. +#![allow(unknown_lints)] +#![allow(internal_features)] #![cfg_attr( any(feature = "personality", feature = "personality-dummy"), feature(lang_items) From 953591ff1b16cf3b6164988a893fd9a6d8de1178 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 5 Aug 2023 16:44:24 +0100 Subject: [PATCH 21/40] Fix CI text check to account for new panic info fmt --- .github/workflows/ci.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f8155d..1946b16 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,10 +37,4 @@ jobs: - name: Check log run: | - grep "panicked at 'panic', example/src/main.rs:36:5" run.log - grep 'note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace' run.log - grep 'dropped: "string"' run.log - grep 'caught' run.log - grep "panicked at 'panic', example/src/main.rs:46:5" run.log - grep "panicked at 'panic on drop', example/src/main.rs:25:9" run.log - grep "thread panicked while processing panic. aborting." run.log + grep -Pz 'panicked at example/src/main.rs:36:5:\npanic\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\ndropped: "string"\ncaught\npanicked at example/src/main.rs:46:5:\npanic\npanicked at example/src/main.rs:25:9:\npanic on drop\n( *\d+:.*\n)+thread panicked while processing panic\. aborting\.' run.log From 1b30c6a79df4e5bd5ba3d09214b1913a4516d4a6 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Sat, 5 Aug 2023 20:41:26 +0800 Subject: [PATCH 22/40] cargo: support building as part of libstd Support using `unwinding` as a backend for the libstd `unwind` crate. This will enable unwinding support for new targets while allowing us to continue to use `libunwind` from llvm for supported targets. Signed-off-by: Sean Cross --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index d84a5bc..f0ec722 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,8 @@ members = ["cdylib", "example"] gimli = { version = "0.26.1", default-features = false, features = ["read-core"] } libc = { version = "0.2", optional = true } spin = { version = "0.9.8", optional = true, default-features = false, features = ["mutex", "spin_mutex"] } +core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' } +compiler_builtins = { version = "0.1.2", optional = true } [features] alloc = [] @@ -36,6 +38,7 @@ panic-handler = ["print", "panic"] panic-handler-dummy = [] system-alloc = [] default = ["unwinder", "dwarf-expr", "hide-trace", "fde-phdr-dl", "fde-registry"] +rustc-dep-of-std = ["core", "gimli/rustc-dep-of-std", "compiler_builtins"] [profile.release] debug = true From 2f9e37443193b658a7bfa50751576ae3ba66d9a8 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Sat, 5 Aug 2023 20:44:54 +0800 Subject: [PATCH 23/40] find_fde: make `text_base` optional No platforms currently use relative addressing. Make this parameter optional in order to support targets where this value is not available. Signed-off-by: Sean Cross --- src/unwinder/find_fde/custom.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/unwinder/find_fde/custom.rs b/src/unwinder/find_fde/custom.rs index cf9883d..25da562 100644 --- a/src/unwinder/find_fde/custom.rs +++ b/src/unwinder/find_fde/custom.rs @@ -22,7 +22,7 @@ pub unsafe trait EhFrameFinder { } pub struct FrameInfo { - pub text_base: usize, + pub text_base: Option, pub kind: FrameInfoKind, } @@ -102,13 +102,14 @@ fn find_fde(eh_frame_finder: &T, pc: usize) -> Option fn find_fde_with_eh_frame_hdr( pc: usize, - text_base: usize, + text_base: Option, eh_frame_hdr: usize, ) -> Option { unsafe { - let bases = BaseAddresses::default() - .set_text(text_base as _) - .set_eh_frame_hdr(eh_frame_hdr as _); + let mut bases = BaseAddresses::default().set_eh_frame_hdr(eh_frame_hdr as _); + if let Some(text_base) = text_base { + bases = bases.set_text(text_base as _); + } let eh_frame_hdr = EhFrameHdr::new( get_unlimited_slice(eh_frame_hdr as usize as _), NativeEndian, @@ -145,11 +146,16 @@ fn find_fde_with_eh_frame_hdr( } } -fn find_fde_with_eh_frame(pc: usize, text_base: usize, eh_frame: usize) -> Option { +fn find_fde_with_eh_frame( + pc: usize, + text_base: Option, + eh_frame: usize, +) -> Option { unsafe { - let bases = BaseAddresses::default() - .set_text(text_base as _) - .set_eh_frame(eh_frame as _); + let mut bases = BaseAddresses::default().set_eh_frame(eh_frame as _); + if let Some(text_base) = text_base { + bases = bases.set_text(text_base as _); + } let eh_frame = EhFrame::new(get_unlimited_slice(eh_frame as _), NativeEndian); if let Ok(fde) = eh_frame.fde_for_address(&bases, pc as _, EhFrame::cie_from_offset) { From f5ef1d145ed79293fa07aceb5a26b743f450a4fe Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 6 Aug 2023 12:50:27 +0100 Subject: [PATCH 24/40] Make UnwindTraceFn take `&UnwindContext` only --- src/abi.rs | 2 +- src/panic_handler.rs | 2 +- src/unwinder/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/abi.rs b/src/abi.rs index 737cb0f..9c89f2c 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -78,7 +78,7 @@ pub struct UnwindException { } pub type UnwindTraceFn = - extern "C" fn(ctx: &mut UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode; + extern "C" fn(ctx: &UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode; #[cfg(not(feature = "unwinder"))] #[repr(C)] diff --git a/src/panic_handler.rs b/src/panic_handler.rs index beca6ff..5ba13a6 100644 --- a/src/panic_handler.rs +++ b/src/panic_handler.rs @@ -60,7 +60,7 @@ fn stack_trace() { counter: usize, } extern "C" fn callback( - unwind_ctx: &mut UnwindContext<'_>, + unwind_ctx: &UnwindContext<'_>, arg: *mut c_void, ) -> UnwindReasonCode { let data = unsafe { &mut *(arg as *mut CallbackData) }; diff --git a/src/unwinder/mod.rs b/src/unwinder/mod.rs index 968566b..d650db7 100644 --- a/src/unwinder/mod.rs +++ b/src/unwinder/mod.rs @@ -390,7 +390,7 @@ pub extern "C-unwind" fn _Unwind_Backtrace( let frame = try1!(Frame::from_context(&ctx, signal)); if !skipping { let code = trace( - &mut UnwindContext { + &UnwindContext { frame: frame.as_ref(), ctx: &mut ctx, signal, From 7477bc5b6f4faf276dd444fad98fcdabf8973cf7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 6 Aug 2023 13:15:09 +0100 Subject: [PATCH 25/40] Adjust ABI safety requirement --- src/abi.rs | 22 +++--- src/panic_handler.rs | 5 +- src/unwinder/mod.rs | 158 +++++++++++++++++++++++-------------------- 3 files changed, 97 insertions(+), 88 deletions(-) diff --git a/src/abi.rs b/src/abi.rs index 9c89f2c..ff22f47 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -60,11 +60,11 @@ impl UnwindAction { pub type UnwindExceptionCleanupFn = unsafe extern "C" fn(UnwindReasonCode, *mut UnwindException); -pub type UnwindStopFn = extern "C" fn( +pub type UnwindStopFn = unsafe extern "C" fn( c_int, UnwindAction, u64, - &mut UnwindException, + *mut UnwindException, &mut UnwindContext<'_>, *mut c_void, ) -> UnwindReasonCode; @@ -87,11 +87,11 @@ pub struct UnwindContext<'a> { phantom: core::marker::PhantomData<&'a ()>, } -pub type PersonalityRoutine = extern "C" fn( +pub type PersonalityRoutine = unsafe extern "C" fn( c_int, UnwindAction, u64, - &mut UnwindException, + *mut UnwindException, &mut UnwindContext<'_>, ) -> UnwindReasonCode; @@ -134,17 +134,17 @@ binding! { extern "C" fn _Unwind_GetTextRelBase(unwind_ctx: &UnwindContext<'_>) -> usize; extern "C" fn _Unwind_GetDataRelBase(unwind_ctx: &UnwindContext<'_>) -> usize; extern "C" fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void; - extern "C-unwind" fn _Unwind_RaiseException( - exception: &mut UnwindException, + extern "C-unwind" [unsafe] fn _Unwind_RaiseException( + exception: *mut UnwindException, ) -> UnwindReasonCode; - extern "C-unwind" fn _Unwind_ForcedUnwind( - exception: &mut UnwindException, + extern "C-unwind" [unsafe] fn _Unwind_ForcedUnwind( + exception: *mut UnwindException, stop: UnwindStopFn, stop_arg: *mut c_void, ) -> UnwindReasonCode; - extern "C-unwind" fn _Unwind_Resume(exception: &mut UnwindException) -> !; - extern "C-unwind" fn _Unwind_Resume_or_Rethrow( - exception: &mut UnwindException, + extern "C-unwind" [unsafe] fn _Unwind_Resume(exception: *mut UnwindException) -> !; + extern "C-unwind" [unsafe] fn _Unwind_Resume_or_Rethrow( + exception: *mut UnwindException, ) -> UnwindReasonCode; extern "C" [unsafe] fn _Unwind_DeleteException(exception: *mut UnwindException); extern "C-unwind" fn _Unwind_Backtrace( diff --git a/src/panic_handler.rs b/src/panic_handler.rs index 5ba13a6..1d07768 100644 --- a/src/panic_handler.rs +++ b/src/panic_handler.rs @@ -59,10 +59,7 @@ fn stack_trace() { struct CallbackData { counter: usize, } - extern "C" fn callback( - unwind_ctx: &UnwindContext<'_>, - arg: *mut c_void, - ) -> UnwindReasonCode { + extern "C" fn callback(unwind_ctx: &UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode { let data = unsafe { &mut *(arg as *mut CallbackData) }; data.counter += 1; eprintln!( diff --git a/src/unwinder/mod.rs b/src/unwinder/mod.rs index d650db7..5bcc383 100644 --- a/src/unwinder/mod.rs +++ b/src/unwinder/mod.rs @@ -149,8 +149,8 @@ macro_rules! try2 { #[inline(never)] #[no_mangle] -pub extern "C-unwind" fn _Unwind_RaiseException( - exception: &mut UnwindException, +pub unsafe extern "C-unwind" fn _Unwind_RaiseException( + exception: *mut UnwindException, ) -> UnwindReasonCode { with_context(|saved_ctx| { // Phase 1: Search for handler @@ -159,17 +159,19 @@ pub extern "C-unwind" fn _Unwind_RaiseException( loop { if let Some(frame) = try1!(Frame::from_context(&ctx, signal)) { if let Some(personality) = frame.personality() { - let result = personality( - 1, - UnwindAction::SEARCH_PHASE, - exception.exception_class, - exception, - &mut UnwindContext { - frame: Some(&frame), - ctx: &mut ctx, - signal, - }, - ); + let result = unsafe { + personality( + 1, + UnwindAction::SEARCH_PHASE, + (*exception).exception_class, + exception, + &mut UnwindContext { + frame: Some(&frame), + ctx: &mut ctx, + signal, + }, + ) + }; match result { UnwindReasonCode::CONTINUE_UNWIND => (), @@ -189,8 +191,10 @@ pub extern "C-unwind" fn _Unwind_RaiseException( // Disambiguate normal frame and signal frame. let handler_cfa = ctx[Arch::SP] - signal as usize; - exception.private_1 = None; - exception.private_2 = handler_cfa; + unsafe { + (*exception).private_1 = None; + (*exception).private_2 = handler_cfa; + } let code = raise_exception_phase2(exception, saved_ctx, handler_cfa); match code { @@ -201,7 +205,7 @@ pub extern "C-unwind" fn _Unwind_RaiseException( } fn raise_exception_phase2( - exception: &mut UnwindException, + exception: *mut UnwindException, ctx: &mut Context, handler_cfa: usize, ) -> UnwindReasonCode { @@ -210,22 +214,24 @@ fn raise_exception_phase2( if let Some(frame) = try2!(Frame::from_context(ctx, signal)) { let frame_cfa = ctx[Arch::SP] - signal as usize; if let Some(personality) = frame.personality() { - let code = personality( - 1, - UnwindAction::CLEANUP_PHASE - | if frame_cfa == handler_cfa { - UnwindAction::HANDLER_FRAME - } else { - UnwindAction::empty() + let code = unsafe { + personality( + 1, + UnwindAction::CLEANUP_PHASE + | if frame_cfa == handler_cfa { + UnwindAction::HANDLER_FRAME + } else { + UnwindAction::empty() + }, + (*exception).exception_class, + exception, + &mut UnwindContext { + frame: Some(&frame), + ctx, + signal, }, - exception.exception_class, - exception, - &mut UnwindContext { - frame: Some(&frame), - ctx, - signal, - }, - ); + ) + }; match code { UnwindReasonCode::CONTINUE_UNWIND => (), @@ -247,14 +253,16 @@ fn raise_exception_phase2( #[inline(never)] #[no_mangle] -pub extern "C-unwind" fn _Unwind_ForcedUnwind( - exception: &mut UnwindException, +pub unsafe extern "C-unwind" fn _Unwind_ForcedUnwind( + exception: *mut UnwindException, stop: UnwindStopFn, stop_arg: *mut c_void, ) -> UnwindReasonCode { with_context(|ctx| { - exception.private_1 = Some(stop); - exception.private_2 = stop_arg as _; + unsafe { + (*exception).private_1 = Some(stop); + (*exception).private_2 = stop_arg as _; + } let code = force_unwind_phase2(exception, ctx, stop, stop_arg); match code { @@ -265,7 +273,7 @@ pub extern "C-unwind" fn _Unwind_ForcedUnwind( } fn force_unwind_phase2( - exception: &mut UnwindException, + exception: *mut UnwindException, ctx: &mut Context, stop: UnwindStopFn, stop_arg: *mut c_void, @@ -274,24 +282,26 @@ fn force_unwind_phase2( loop { let frame = try2!(Frame::from_context(ctx, signal)); - let code = stop( - 1, - UnwindAction::FORCE_UNWIND - | UnwindAction::END_OF_STACK - | if frame.is_none() { - UnwindAction::END_OF_STACK - } else { - UnwindAction::empty() + let code = unsafe { + stop( + 1, + UnwindAction::FORCE_UNWIND + | UnwindAction::END_OF_STACK + | if frame.is_none() { + UnwindAction::END_OF_STACK + } else { + UnwindAction::empty() + }, + (*exception).exception_class, + exception, + &mut UnwindContext { + frame: frame.as_ref(), + ctx, + signal, }, - exception.exception_class, - exception, - &mut UnwindContext { - frame: frame.as_ref(), - ctx, - signal, - }, - stop_arg, - ); + stop_arg, + ) + }; match code { UnwindReasonCode::NO_REASON => (), _ => return UnwindReasonCode::FATAL_PHASE2_ERROR, @@ -299,17 +309,19 @@ fn force_unwind_phase2( if let Some(frame) = frame { if let Some(personality) = frame.personality() { - let code = personality( - 1, - UnwindAction::FORCE_UNWIND | UnwindAction::CLEANUP_PHASE, - exception.exception_class, - exception, - &mut UnwindContext { - frame: Some(&frame), - ctx, - signal, - }, - ); + let code = unsafe { + personality( + 1, + UnwindAction::FORCE_UNWIND | UnwindAction::CLEANUP_PHASE, + (*exception).exception_class, + exception, + &mut UnwindContext { + frame: Some(&frame), + ctx, + signal, + }, + ) + }; match code { UnwindReasonCode::CONTINUE_UNWIND => (), @@ -331,15 +343,15 @@ fn force_unwind_phase2( #[inline(never)] #[no_mangle] -pub extern "C-unwind" fn _Unwind_Resume(exception: &mut UnwindException) -> ! { +pub unsafe extern "C-unwind" fn _Unwind_Resume(exception: *mut UnwindException) -> ! { with_context(|ctx| { - let code = match exception.private_1 { + let code = match unsafe { (*exception).private_1 } { None => { - let handler_cfa = exception.private_2; + let handler_cfa = unsafe { (*exception).private_2 }; raise_exception_phase2(exception, ctx, handler_cfa) } Some(stop) => { - let stop_arg = exception.private_2 as _; + let stop_arg = unsafe { (*exception).private_2 as _ }; force_unwind_phase2(exception, ctx, stop, stop_arg) } }; @@ -351,16 +363,16 @@ pub extern "C-unwind" fn _Unwind_Resume(exception: &mut UnwindException) -> ! { #[inline(never)] #[no_mangle] -pub extern "C-unwind" fn _Unwind_Resume_or_Rethrow( - exception: &mut UnwindException, +pub unsafe extern "C-unwind" fn _Unwind_Resume_or_Rethrow( + exception: *mut UnwindException, ) -> UnwindReasonCode { - let stop = match exception.private_1 { - None => return _Unwind_RaiseException(exception), + let stop = match unsafe { (*exception).private_1 } { + None => return unsafe { _Unwind_RaiseException(exception) }, Some(v) => v, }; with_context(|ctx| { - let stop_arg = exception.private_2 as _; + let stop_arg = unsafe { (*exception).private_2 as _ }; let code = force_unwind_phase2(exception, ctx, stop, stop_arg); assert!(code == UnwindReasonCode::INSTALL_CONTEXT); From 8b05b629ae1a8f73cbd70acdf0239c7a9b699827 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 6 Aug 2023 13:20:58 +0100 Subject: [PATCH 26/40] Adjust binding macro --- src/abi.rs | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/abi.rs b/src/abi.rs index ff22f47..7e1529b 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -97,17 +97,24 @@ pub type PersonalityRoutine = unsafe extern "C" fn( #[cfg(not(feature = "unwinder"))] macro_rules! binding { - ($(extern $abi: literal $([$t:tt])? fn $name: ident ($($arg: ident : $arg_ty: ty),*$(,)?) $(-> $ret: ty)?;)*) => { - $( - #[allow(non_snake_case)] - #[inline] - pub $($t)? fn $name($($arg: $arg_ty),*) $(-> $ret)? { - extern $abi { - fn $name($($arg: $arg_ty),*) $(-> $ret)?; - } - unsafe { $name($($arg),*) } + () => {}; + (unsafe extern $abi: literal fn $name: ident ($($arg: ident : $arg_ty: ty),*$(,)?) $(-> $ret: ty)?; $($rest: tt)*) => { + extern $abi { + pub fn $name($($arg: $arg_ty),*) $(-> $ret)?; + } + binding!($($rest)*); + }; + + (extern $abi: literal fn $name: ident ($($arg: ident : $arg_ty: ty),*$(,)?) $(-> $ret: ty)?; $($rest: tt)*) => { + #[allow(non_snake_case)] + #[inline] + pub fn $name($($arg: $arg_ty),*) $(-> $ret)? { + extern $abi { + fn $name($($arg: $arg_ty),*) $(-> $ret)?; } - )* + unsafe { $name($($arg),*) } + } + binding!($($rest)*); }; } @@ -134,19 +141,19 @@ binding! { extern "C" fn _Unwind_GetTextRelBase(unwind_ctx: &UnwindContext<'_>) -> usize; extern "C" fn _Unwind_GetDataRelBase(unwind_ctx: &UnwindContext<'_>) -> usize; extern "C" fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void; - extern "C-unwind" [unsafe] fn _Unwind_RaiseException( + unsafe extern "C-unwind" fn _Unwind_RaiseException( exception: *mut UnwindException, ) -> UnwindReasonCode; - extern "C-unwind" [unsafe] fn _Unwind_ForcedUnwind( + unsafe extern "C-unwind" fn _Unwind_ForcedUnwind( exception: *mut UnwindException, stop: UnwindStopFn, stop_arg: *mut c_void, ) -> UnwindReasonCode; - extern "C-unwind" [unsafe] fn _Unwind_Resume(exception: *mut UnwindException) -> !; - extern "C-unwind" [unsafe] fn _Unwind_Resume_or_Rethrow( + unsafe extern "C-unwind" fn _Unwind_Resume(exception: *mut UnwindException) -> !; + unsafe extern "C-unwind" fn _Unwind_Resume_or_Rethrow( exception: *mut UnwindException, ) -> UnwindReasonCode; - extern "C" [unsafe] fn _Unwind_DeleteException(exception: *mut UnwindException); + unsafe extern "C" fn _Unwind_DeleteException(exception: *mut UnwindException); extern "C-unwind" fn _Unwind_Backtrace( trace: UnwindTraceFn, trace_argument: *mut c_void, From de5dd40a4f898f206387ead5af81c11147a0011a Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 6 Aug 2023 13:27:01 +0100 Subject: [PATCH 27/40] Add ABI-compatibility assertion --- src/abi.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/abi.rs b/src/abi.rs index 7e1529b..12766c1 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -118,7 +118,18 @@ macro_rules! binding { }; } -#[cfg(not(feature = "unwinder"))] +#[cfg(feature = "unwinder")] +macro_rules! binding { + () => {}; + (unsafe extern $abi: literal fn $name: ident ($($arg: ident : $arg_ty: ty),*$(,)?) $(-> $ret: ty)?; $($rest: tt)*) => { + const _: unsafe extern $abi fn($($arg_ty),*) $(-> $ret)? = $name; + }; + + (extern $abi: literal fn $name: ident ($($arg: ident : $arg_ty: ty),*$(,)?) $(-> $ret: ty)?; $($rest: tt)*) => { + const _: extern $abi fn($($arg_ty),*) $(-> $ret)? = $name; + }; +} + binding! { extern "C" fn _Unwind_GetGR(unwind_ctx: &UnwindContext<'_>, index: c_int) -> usize; extern "C" fn _Unwind_GetCFA(unwind_ctx: &UnwindContext<'_>) -> usize; From a421b6d55c96d9c4cb75be9c933eea47e90ec7c4 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 6 Aug 2023 14:30:50 +0100 Subject: [PATCH 28/40] Update ABI user --- src/panicking.rs | 2 +- src/personality.rs | 6 +++--- src/personality_dummy.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/panicking.rs b/src/panicking.rs index 24da451..9c83bfe 100644 --- a/src/panicking.rs +++ b/src/panicking.rs @@ -21,7 +21,7 @@ pub fn begin_panic(exception: E) -> UnwindReasonCode { unsafe { (*ex).exception_class = u64::from_be_bytes(E::CLASS); (*ex).exception_cleanup = Some(exception_cleanup::); - _Unwind_RaiseException(&mut *ex) + _Unwind_RaiseException(ex) } } diff --git a/src/personality.rs b/src/personality.rs index 2dda30a..3bbdb16 100644 --- a/src/personality.rs +++ b/src/personality.rs @@ -136,11 +136,11 @@ fn find_eh_action( } #[lang = "eh_personality"] -fn rust_eh_personality( +unsafe fn rust_eh_personality( version: c_int, actions: UnwindAction, _exception_class: u64, - exception: &mut UnwindException, + exception: *mut UnwindException, unwind_ctx: &mut UnwindContext<'_>, ) -> UnwindReasonCode { if version != 1 { @@ -170,7 +170,7 @@ fn rust_eh_personality( _Unwind_SetGR( unwind_ctx, Arch::UNWIND_DATA_REG.0 .0 as _, - exception as *mut _ as usize, + exception as usize, ); _Unwind_SetGR(unwind_ctx, Arch::UNWIND_DATA_REG.1 .0 as _, 0); _Unwind_SetIP(unwind_ctx, lpad); diff --git a/src/personality_dummy.rs b/src/personality_dummy.rs index 8d9465a..ff026c7 100644 --- a/src/personality_dummy.rs +++ b/src/personality_dummy.rs @@ -2,11 +2,11 @@ use crate::abi::*; use crate::util::*; #[lang = "eh_personality"] -extern "C" fn personality( +unsafe extern "C" fn personality( version: c_int, _actions: UnwindAction, _exception_class: u64, - _exception: &mut UnwindException, + _exception: *mut UnwindException, _ctx: &mut UnwindContext<'_>, ) -> UnwindReasonCode { if version != 1 { From 36895d362c97f230ece3e0b4b17ad0085d77edb8 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 6 Aug 2023 14:35:59 +0100 Subject: [PATCH 29/40] Version bump --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f0ec722..33ac4ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "unwinding" -version = "0.1.7" +version = "0.2.0" authors = ["Gary Guo "] edition = "2018" license = "MIT OR Apache-2.0" From 9704d0bf23b6586e62704c3731927be9d26dcffb Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 28 Oct 2023 00:13:46 +0100 Subject: [PATCH 30/40] Fix warnings --- src/lib.rs | 6 ++++-- src/util.rs | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 97cb357..faa4488 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,8 +3,10 @@ #![feature(naked_functions)] // lang_items is an internal feature. `internal_features` lint is added recently // so also allow unknown lints to prevent warning in older nightly versions. -#![allow(unknown_lints)] -#![allow(internal_features)] +#![cfg_attr( + any(feature = "personality", feature = "personality-dummy"), + allow(internal_features) +)] #![cfg_attr( any(feature = "personality", feature = "personality-dummy"), feature(lang_items) diff --git a/src/util.rs b/src/util.rs index e28a8a0..7c66e81 100644 --- a/src/util.rs +++ b/src/util.rs @@ -25,7 +25,7 @@ pub use libc::c_int; pub type c_int = i32; #[cfg(all( - any(feature = "panicking", feature = "panic-handler-dummy"), + any(feature = "panic", feature = "panic-handler-dummy"), feature = "libc" ))] pub fn abort() -> ! { @@ -33,7 +33,7 @@ pub fn abort() -> ! { } #[cfg(all( - any(feature = "panicking", feature = "panic-handler-dummy"), + any(feature = "panic", feature = "panic-handler-dummy"), not(feature = "libc") ))] pub fn abort() -> ! { From 00a74653285ed18663e41436338d2372e0939736 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 28 Oct 2023 00:13:56 +0100 Subject: [PATCH 31/40] Update gimli version --- Cargo.toml | 2 +- src/lib.rs | 1 + src/unwinder/frame.rs | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 33ac4ec..9e60f08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ repository = "https://github.com/nbdd0121/unwinding/" members = ["cdylib", "example"] [dependencies] -gimli = { version = "0.26.1", default-features = false, features = ["read-core"] } +gimli = { version = "0.28", default-features = false, features = ["read-core"] } libc = { version = "0.2", optional = true } spin = { version = "0.9.8", optional = true, default-features = false, features = ["mutex", "spin_mutex"] } core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' } diff --git a/src/lib.rs b/src/lib.rs index faa4488..44ecc37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![doc = include_str!("../README.md")] #![feature(c_unwind)] #![feature(naked_functions)] +#![feature(non_exhaustive_omitted_patterns_lint)] // lang_items is an internal feature. `internal_features` lint is added recently // so also allow unknown lints to prevent warning in older nightly versions. #![cfg_attr( diff --git a/src/unwinder/frame.rs b/src/unwinder/frame.rs index 8659bfe..9ede0a1 100644 --- a/src/unwinder/frame.rs +++ b/src/unwinder/frame.rs @@ -144,6 +144,7 @@ impl Frame { new_ctx[Arch::SP] = cfa as _; new_ctx[Arch::RA] = 0; + #[warn(non_exhaustive_omitted_patterns)] for (reg, rule) in row.registers() { let value = match *rule { RegisterRule::Undefined | RegisterRule::SameValue => ctx[*reg], @@ -158,6 +159,8 @@ impl Frame { } RegisterRule::ValExpression(expr) => self.evaluate_expression(ctx, expr)?, RegisterRule::Architectural => unreachable!(), + RegisterRule::Constant(value) => value as usize, + _ => unreachable!(), }; new_ctx[*reg] = value; } From ad9086f9bb1dc26bc6e4bb6adf91600f63e3d523 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 28 Oct 2023 00:24:56 +0100 Subject: [PATCH 32/40] Update exception struct to match current version of rustc --- src/panic.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/panic.rs b/src/panic.rs index d61f5e9..b69e958 100644 --- a/src/panic.rs +++ b/src/panic.rs @@ -7,6 +7,8 @@ use crate::abi::*; pub use crate::panic_handler::*; use crate::panicking::Exception; +static CANARY: u8 = 0; + #[repr(transparent)] struct RustPanic(Box, DropGuard); @@ -25,6 +27,8 @@ impl Drop for DropGuard { #[repr(C)] struct ExceptionWithPayload { exception: MaybeUninit, + // See rust/library/panic_unwind/src/gcc.rs for the canary values + canary: *const u8, payload: RustPanic, } @@ -34,12 +38,23 @@ unsafe impl Exception for RustPanic { fn wrap(this: Self) -> *mut UnwindException { Box::into_raw(Box::new(ExceptionWithPayload { exception: MaybeUninit::uninit(), + canary: &CANARY, payload: this, })) as *mut UnwindException } unsafe fn unwrap(ex: *mut UnwindException) -> Self { - let ex = unsafe { Box::from_raw(ex as *mut ExceptionWithPayload) }; + let ex = ex as *mut ExceptionWithPayload; + let canary = unsafe { core::ptr::addr_of!((*ex).canary).read() }; + if !core::ptr::eq(canary, &CANARY) { + // This is a Rust exception but not generated by us. + #[cfg(feature = "panic-handler")] + { + foreign_exception(); + } + crate::util::abort(); + } + let ex = unsafe { Box::from_raw(ex) }; ex.payload } } From fdf70d1e18d9be25ed4f03f9d4c67c3c7f028dcf Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 28 Oct 2023 01:06:27 +0100 Subject: [PATCH 33/40] Add more tests --- .github/workflows/ci.yml | 11 +++------- Cargo.toml | 7 ++++++- example/Cargo.toml | 8 -------- rust-toolchain | 2 ++ test_crates/catch_std_exception/Cargo.toml | 8 ++++++++ test_crates/catch_std_exception/check.sh | 9 +++++++++ test_crates/catch_std_exception/src/main.rs | 7 +++++++ test_crates/std_catch_exception/Cargo.toml | 8 ++++++++ test_crates/std_catch_exception/check.sh | 9 +++++++++ test_crates/std_catch_exception/src/main.rs | 7 +++++++ test_crates/throw_and_catch/Cargo.toml | 8 ++++++++ test_crates/throw_and_catch/check.sh | 10 ++++++++++ .../throw_and_catch}/src/main.rs | 0 tests/compile_tests.rs | 20 +++++++++++++++++++ 14 files changed, 97 insertions(+), 17 deletions(-) delete mode 100644 example/Cargo.toml create mode 100644 rust-toolchain create mode 100644 test_crates/catch_std_exception/Cargo.toml create mode 100755 test_crates/catch_std_exception/check.sh create mode 100644 test_crates/catch_std_exception/src/main.rs create mode 100644 test_crates/std_catch_exception/Cargo.toml create mode 100755 test_crates/std_catch_exception/check.sh create mode 100644 test_crates/std_catch_exception/src/main.rs create mode 100644 test_crates/throw_and_catch/Cargo.toml create mode 100755 test_crates/throw_and_catch/check.sh rename {example => test_crates/throw_and_catch}/src/main.rs (100%) create mode 100644 tests/compile_tests.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1946b16..99e7ec1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,13 +28,8 @@ jobs: with: target: ${{ matrix.target }} - - name: Build example binary + - name: Build library run: cargo build --release $BUILD_STD - - name: Run example binary - run: (cargo run --release $BUILD_STD 2>&1 | tee ../run.log) || true - working-directory: example - - - name: Check log - run: | - grep -Pz 'panicked at example/src/main.rs:36:5:\npanic\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\ndropped: "string"\ncaught\npanicked at example/src/main.rs:46:5:\npanic\npanicked at example/src/main.rs:25:9:\npanic on drop\n( *\d+:.*\n)+thread panicked while processing panic\. aborting\.' run.log + - name: Run tests + run: cargo test --release $BUILD_STD diff --git a/Cargo.toml b/Cargo.toml index 9e60f08..ff64183 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,12 @@ description = "Unwinding library in Rust and for Rust" repository = "https://github.com/nbdd0121/unwinding/" [workspace] -members = ["cdylib", "example"] +members = [ + "cdylib", + "test_crates/throw_and_catch", + "test_crates/catch_std_exception", + "test_crates/std_catch_exception", +] [dependencies] gimli = { version = "0.28", default-features = false, features = ["read-core"] } diff --git a/example/Cargo.toml b/example/Cargo.toml deleted file mode 100644 index 6a6b603..0000000 --- a/example/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "example" -version = "0.1.0" -edition = "2018" - -[dependencies] -unwinding = { path = "../", features = ["system-alloc", "personality", "panic-handler"] } -libc = "0.2" diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/rust-toolchain @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/test_crates/catch_std_exception/Cargo.toml b/test_crates/catch_std_exception/Cargo.toml new file mode 100644 index 0000000..55d4982 --- /dev/null +++ b/test_crates/catch_std_exception/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "catch_std_exception" +version = "0.1.0" +edition = "2018" + +[dependencies] +unwinding = { path = "../../", features = ["panic"] } +libc = "0.2" diff --git a/test_crates/catch_std_exception/check.sh b/test_crates/catch_std_exception/check.sh new file mode 100755 index 0000000..455444b --- /dev/null +++ b/test_crates/catch_std_exception/check.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -o pipefail +trap "rm -f run.log" EXIT +cargo run --release $BUILD_STD 2>&1 | tee run.log +if [ $? -ne 134 ]; then + echo process is not aborted + exit 1 +fi +grep -Pz 'panicked at test_crates/catch_std_exception/src/main.rs:5:9:\nexplicit panic\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace' run.log diff --git a/test_crates/catch_std_exception/src/main.rs b/test_crates/catch_std_exception/src/main.rs new file mode 100644 index 0000000..e4fc9f1 --- /dev/null +++ b/test_crates/catch_std_exception/src/main.rs @@ -0,0 +1,7 @@ +extern crate unwinding; + +fn main() { + let _ = unwinding::panic::catch_unwind(|| { + panic!(); + }); +} diff --git a/test_crates/std_catch_exception/Cargo.toml b/test_crates/std_catch_exception/Cargo.toml new file mode 100644 index 0000000..5501109 --- /dev/null +++ b/test_crates/std_catch_exception/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "std_catch_exception" +version = "0.1.0" +edition = "2018" + +[dependencies] +unwinding = { path = "../../", features = ["panic"] } +libc = "0.2" diff --git a/test_crates/std_catch_exception/check.sh b/test_crates/std_catch_exception/check.sh new file mode 100755 index 0000000..408153a --- /dev/null +++ b/test_crates/std_catch_exception/check.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -o pipefail +trap "rm -f run.log" EXIT +cargo run --release $BUILD_STD 2>&1 | tee run.log +if [ $? -ne 134 ]; then + echo process is not aborted + exit 1 +fi +grep -Pz 'fatal runtime error: Rust cannot catch foreign exceptions' run.log diff --git a/test_crates/std_catch_exception/src/main.rs b/test_crates/std_catch_exception/src/main.rs new file mode 100644 index 0000000..625aede --- /dev/null +++ b/test_crates/std_catch_exception/src/main.rs @@ -0,0 +1,7 @@ +extern crate unwinding; + +fn main() { + let _ = std::panic::catch_unwind(|| { + unwinding::panic::begin_panic(Box::new("test")); + }); +} diff --git a/test_crates/throw_and_catch/Cargo.toml b/test_crates/throw_and_catch/Cargo.toml new file mode 100644 index 0000000..5e87993 --- /dev/null +++ b/test_crates/throw_and_catch/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "throw_and_catch" +version = "0.1.0" +edition = "2018" + +[dependencies] +unwinding = { path = "../..", features = ["system-alloc", "personality", "panic-handler"] } +libc = "0.2" diff --git a/test_crates/throw_and_catch/check.sh b/test_crates/throw_and_catch/check.sh new file mode 100755 index 0000000..17e13fa --- /dev/null +++ b/test_crates/throw_and_catch/check.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -o pipefail +trap "rm -f run.log" EXIT +cargo run --release $BUILD_STD 2>&1 | tee run.log +if [ $? -ne 134 ]; then + echo process is not aborted + exit 1 +fi +grep -Pz 'panicked at test_crates/throw_and_catch/src/main.rs:36:5:\npanic\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\ndropped: "string"\ncaught\npanicked at test_crates/throw_and_catch/src/main.rs:46:5:\npanic\npanicked at test_crates/throw_and_catch/src/main.rs:25:9:\npanic on drop\n( *\d+:.*\n)+thread panicked while processing panic\. aborting\.' run.log + diff --git a/example/src/main.rs b/test_crates/throw_and_catch/src/main.rs similarity index 100% rename from example/src/main.rs rename to test_crates/throw_and_catch/src/main.rs diff --git a/tests/compile_tests.rs b/tests/compile_tests.rs new file mode 100644 index 0000000..26a5697 --- /dev/null +++ b/tests/compile_tests.rs @@ -0,0 +1,20 @@ +use std::process::Command; + +#[test] +fn main() { + let dir = env!("CARGO_MANIFEST_DIR"); + + let tests = [ + "throw_and_catch", + "catch_std_exception", + "std_catch_exception", + ]; + + for test in tests { + let status = Command::new("./check.sh") + .current_dir(format!("{dir}/test_crates/{test}")) + .status() + .unwrap(); + assert!(status.success()); + } +} From ad1b65a9b6f5c58d45abfcac56cfd1c71c4d83ec Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 28 Oct 2023 01:14:25 +0100 Subject: [PATCH 34/40] Version bump and edition upgrade --- .gitignore | 1 - Cargo.lock | 87 ++++++++++++++++++++++ Cargo.toml | 4 +- cdylib/Cargo.toml | 2 +- test_crates/catch_std_exception/Cargo.toml | 2 +- test_crates/std_catch_exception/Cargo.toml | 2 +- test_crates/throw_and_catch/Cargo.toml | 2 +- 7 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index 98ae53c..b3e9e33 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ .vscode/ target -Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4ad1349 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,87 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "catch_std_exception" +version = "0.1.0" +dependencies = [ + "libc", + "unwinding", +] + +[[package]] +name = "compiler_builtins" +version = "0.1.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a6d58e9c3408138099a396a98fd0d0e6cfb25d723594d2ae48b5004513fd5b" + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "rustc-std-workspace-alloc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86" + +[[package]] +name = "rustc-std-workspace-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "std_catch_exception" +version = "0.1.0" +dependencies = [ + "libc", + "unwinding", +] + +[[package]] +name = "throw_and_catch" +version = "0.1.0" +dependencies = [ + "libc", + "unwinding", +] + +[[package]] +name = "unwinding" +version = "0.2.1" +dependencies = [ + "compiler_builtins", + "gimli", + "libc", + "rustc-std-workspace-core", + "spin", +] + +[[package]] +name = "unwinding_dyn" +version = "0.1.0" +dependencies = [ + "libc", + "unwinding", +] diff --git a/Cargo.toml b/Cargo.toml index ff64183..5ab1a8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "unwinding" -version = "0.2.0" +version = "0.2.1" authors = ["Gary Guo "] -edition = "2018" +edition = "2021" license = "MIT OR Apache-2.0" description = "Unwinding library in Rust and for Rust" repository = "https://github.com/nbdd0121/unwinding/" diff --git a/cdylib/Cargo.toml b/cdylib/Cargo.toml index ce3168f..04704e8 100644 --- a/cdylib/Cargo.toml +++ b/cdylib/Cargo.toml @@ -2,7 +2,7 @@ name = "unwinding_dyn" version = "0.1.0" authors = ["Gary Guo "] -edition = "2018" +edition = "2021" [lib] crate-type = ["cdylib", "staticlib"] diff --git a/test_crates/catch_std_exception/Cargo.toml b/test_crates/catch_std_exception/Cargo.toml index 55d4982..f21c600 100644 --- a/test_crates/catch_std_exception/Cargo.toml +++ b/test_crates/catch_std_exception/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "catch_std_exception" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] unwinding = { path = "../../", features = ["panic"] } diff --git a/test_crates/std_catch_exception/Cargo.toml b/test_crates/std_catch_exception/Cargo.toml index 5501109..b44f456 100644 --- a/test_crates/std_catch_exception/Cargo.toml +++ b/test_crates/std_catch_exception/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "std_catch_exception" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] unwinding = { path = "../../", features = ["panic"] } diff --git a/test_crates/throw_and_catch/Cargo.toml b/test_crates/throw_and_catch/Cargo.toml index 5e87993..be500e9 100644 --- a/test_crates/throw_and_catch/Cargo.toml +++ b/test_crates/throw_and_catch/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "throw_and_catch" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] unwinding = { path = "../..", features = ["system-alloc", "personality", "panic-handler"] } From cf89c1934cc9d16606eec2de2d9b25c3079fc5b4 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Wed, 27 Dec 2023 23:43:26 +0800 Subject: [PATCH 35/40] riscv32: align stack pointer to 16-bytes Even though rv32 is only 32-bits, all RISC-V stacks must be aligned to a 16-byte boundary. For discussion on this, see: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/21 As an example of why this is important, the `c.addi16sp` compressed instruction is only able to adjust the stack pointer by 16-byte increments. Signed-off-by: Sean Cross --- src/unwinder/arch/riscv32.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unwinder/arch/riscv32.rs b/src/unwinder/arch/riscv32.rs index 1e8709e..45b8753 100644 --- a/src/unwinder/arch/riscv32.rs +++ b/src/unwinder/arch/riscv32.rs @@ -176,7 +176,7 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p asm!( " mv t0, sp - add sp, sp, -0x188 + add sp, sp, -0x190 sw ra, 0x180(sp) ", code!(save_gp), @@ -186,7 +186,7 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p mv a0, sp jalr t0 lw ra, 0x180(sp) - add sp, sp, 0x188 + add sp, sp, 0x190 ret ", options(noreturn) @@ -197,7 +197,7 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p asm!( " mv t0, sp - add sp, sp, -0x88 + add sp, sp, -0x90 sw ra, 0x80(sp) ", code!(save_gp), @@ -206,7 +206,7 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p mv a0, sp jalr t0 lw ra, 0x80(sp) - add sp, sp, 0x88 + add sp, sp, 0x90 ret ", options(noreturn) From 96888d814ff64cfe0ba2cda46dfb7606238d873b Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 30 Dec 2023 21:31:25 +0000 Subject: [PATCH 36/40] core_intrinsics is now also marked as internal feature, so fix the warning --- src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 44ecc37..23e776e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,12 @@ // lang_items is an internal feature. `internal_features` lint is added recently // so also allow unknown lints to prevent warning in older nightly versions. #![cfg_attr( - any(feature = "personality", feature = "personality-dummy"), + any( + feature = "personality", + feature = "personality-dummy", + feature = "panicking", + feature = "panic-handler-dummy" + ), allow(internal_features) )] #![cfg_attr( From 06699c21b02cce24bef4fe0a63feb5b951f9bff3 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 30 Dec 2023 21:36:11 +0000 Subject: [PATCH 37/40] Stop using naked functions for restore_context --- src/unwinder/arch/aarch64.rs | 4 ++-- src/unwinder/arch/riscv32.rs | 5 +++-- src/unwinder/arch/riscv64.rs | 5 +++-- src/unwinder/arch/x86.rs | 6 ++---- src/unwinder/arch/x86_64.rs | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/unwinder/arch/aarch64.rs b/src/unwinder/arch/aarch64.rs index f65332c..28b740c 100644 --- a/src/unwinder/arch/aarch64.rs +++ b/src/unwinder/arch/aarch64.rs @@ -94,8 +94,7 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p } } -#[naked] -pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { +pub unsafe fn restore_context(ctx: &Context) -> ! { unsafe { asm!( " @@ -136,6 +135,7 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { ldp x0, x1, [x0, 0x00] ret ", + in("x0") ctx, options(noreturn) ); } diff --git a/src/unwinder/arch/riscv32.rs b/src/unwinder/arch/riscv32.rs index 45b8753..bebd390 100644 --- a/src/unwinder/arch/riscv32.rs +++ b/src/unwinder/arch/riscv32.rs @@ -214,8 +214,7 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p } } -#[naked] -pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { +pub unsafe fn restore_context(ctx: &Context) -> ! { #[cfg(target_feature = "d")] unsafe { asm!( @@ -225,6 +224,7 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { lw a0, 0x28(a0) ret ", + in("a0") ctx, options(noreturn) ); } @@ -236,6 +236,7 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { lw a0, 0x28(a0) ret ", + in("a0") ctx, options(noreturn) ); } diff --git a/src/unwinder/arch/riscv64.rs b/src/unwinder/arch/riscv64.rs index a680d70..badc433 100644 --- a/src/unwinder/arch/riscv64.rs +++ b/src/unwinder/arch/riscv64.rs @@ -214,8 +214,7 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p } } -#[naked] -pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { +pub unsafe fn restore_context(ctx: &Context) -> ! { #[cfg(target_feature = "d")] unsafe { asm!( @@ -225,6 +224,7 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { ld a0, 0x50(a0) ret ", + in("a0") ctx, options(noreturn) ); } @@ -236,6 +236,7 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { ld a0, 0x50(a0) ret ", + in("a0") ctx, options(noreturn) ); } diff --git a/src/unwinder/arch/x86.rs b/src/unwinder/arch/x86.rs index 992afb6..e627e7c 100644 --- a/src/unwinder/arch/x86.rs +++ b/src/unwinder/arch/x86.rs @@ -96,13 +96,10 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p } } -#[naked] -pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { +pub unsafe fn restore_context(ctx: &Context) -> ! { unsafe { asm!( " - mov edx, [esp + 4] - /* Restore stack */ mov esp, [edx + 16] @@ -130,6 +127,7 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { ret ", + in("edx") ctx, options(noreturn) ); } diff --git a/src/unwinder/arch/x86_64.rs b/src/unwinder/arch/x86_64.rs index 4387686..c7d9069 100644 --- a/src/unwinder/arch/x86_64.rs +++ b/src/unwinder/arch/x86_64.rs @@ -94,8 +94,7 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p } } -#[naked] -pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { +pub unsafe fn restore_context(ctx: &Context) -> ! { unsafe { asm!( " @@ -134,6 +133,7 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { ret ", + in("rdi") ctx, options(noreturn) ); } From e9eefeed51548ce202c21eebbfde2748ba03265d Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 30 Dec 2023 21:53:33 +0000 Subject: [PATCH 38/40] Use $CARGO instead of cargo in test scripts --- test_crates/catch_std_exception/check.sh | 2 +- test_crates/std_catch_exception/check.sh | 2 +- test_crates/throw_and_catch/check.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test_crates/catch_std_exception/check.sh b/test_crates/catch_std_exception/check.sh index 455444b..9268c8a 100755 --- a/test_crates/catch_std_exception/check.sh +++ b/test_crates/catch_std_exception/check.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -o pipefail trap "rm -f run.log" EXIT -cargo run --release $BUILD_STD 2>&1 | tee run.log +${CARGO:-cargo} run --release $BUILD_STD 2>&1 | tee run.log if [ $? -ne 134 ]; then echo process is not aborted exit 1 diff --git a/test_crates/std_catch_exception/check.sh b/test_crates/std_catch_exception/check.sh index 408153a..e6f54a9 100755 --- a/test_crates/std_catch_exception/check.sh +++ b/test_crates/std_catch_exception/check.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -o pipefail trap "rm -f run.log" EXIT -cargo run --release $BUILD_STD 2>&1 | tee run.log +${CARGO:-cargo} run --release $BUILD_STD 2>&1 | tee run.log if [ $? -ne 134 ]; then echo process is not aborted exit 1 diff --git a/test_crates/throw_and_catch/check.sh b/test_crates/throw_and_catch/check.sh index 17e13fa..252e9d9 100755 --- a/test_crates/throw_and_catch/check.sh +++ b/test_crates/throw_and_catch/check.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -o pipefail trap "rm -f run.log" EXIT -cargo run --release $BUILD_STD 2>&1 | tee run.log +${CARGO:-cargo} run --release $BUILD_STD 2>&1 | tee run.log if [ $? -ne 134 ]; then echo process is not aborted exit 1 From 6720a34c6677e2c150cb3327a0220ff67b1b1d65 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 10 Jan 2024 21:37:59 +0000 Subject: [PATCH 39/40] Fix static_mut_ref warning --- src/unwinder/find_fde/registry.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/unwinder/find_fde/registry.rs b/src/unwinder/find_fde/registry.rs index 5341a35..5b29b10 100644 --- a/src/unwinder/find_fde/registry.rs +++ b/src/unwinder/find_fde/registry.rs @@ -32,7 +32,7 @@ unsafe fn lock_global_state() -> impl ops::DerefMut { #[cfg(feature = "libc")] { static mut MUTEX: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; - unsafe { libc::pthread_mutex_lock(&mut MUTEX) }; + unsafe { libc::pthread_mutex_lock(core::ptr::addr_of_mut!(MUTEX)) }; static mut STATE: GlobalState = GlobalState { object: ptr::null_mut(), @@ -41,20 +41,22 @@ unsafe fn lock_global_state() -> impl ops::DerefMut { struct LockGuard; impl Drop for LockGuard { fn drop(&mut self) { - unsafe { libc::pthread_mutex_unlock(&mut MUTEX) }; + unsafe { libc::pthread_mutex_unlock(core::ptr::addr_of_mut!(MUTEX)) }; } } impl ops::Deref for LockGuard { type Target = GlobalState; + + #[allow(static_mut_ref)] fn deref(&self) -> &GlobalState { - unsafe { &STATE } + unsafe { &*core::ptr::addr_of!(STATE) } } } impl ops::DerefMut for LockGuard { fn deref_mut(&mut self) -> &mut GlobalState { - unsafe { &mut STATE } + unsafe { &mut *core::ptr::addr_of_mut!(STATE) } } } From d7cd46e009ed1dbc762dbaaf4402f57973b300bb Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 29 Feb 2024 00:01:29 +0900 Subject: [PATCH 40/40] Use intrinsics::catch_unwind instead of intrinsics::try intrinsics::try has been renamed in https://github.com/rust-lang/rust/pull/121598. --- src/panicking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panicking.rs b/src/panicking.rs index 9c83bfe..805a210 100644 --- a/src/panicking.rs +++ b/src/panicking.rs @@ -39,7 +39,7 @@ pub fn catch_unwind R>(f: F) -> Result, data_ptr, do_catch::) == 0 { + return if core::intrinsics::catch_unwind(do_call::, data_ptr, do_catch::) == 0 { Ok(ManuallyDrop::into_inner(data.r)) } else { Err(ManuallyDrop::into_inner(data.p))