From e1c7c1ae60c9a646dde3516a9559886a70db37f5 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 26 Aug 2021 12:08:37 +0100 Subject: [PATCH] Refactor --- Cargo.toml | 3 +- src/abi.rs | 361 +---------------------- src/lib.rs | 5 +- src/panic_handler.rs | 6 +- src/{ => unwinder}/find_fde/mod.rs | 0 src/{ => unwinder}/find_fde/phdr.rs | 2 +- src/{ => unwinder}/find_fde/registry.rs | 0 src/{ => unwinder}/frame.rs | 2 +- src/unwinder/mod.rs | 362 ++++++++++++++++++++++++ 9 files changed, 383 insertions(+), 358 deletions(-) rename src/{ => unwinder}/find_fde/mod.rs (100%) rename src/{ => unwinder}/find_fde/phdr.rs (99%) rename src/{ => unwinder}/find_fde/registry.rs (100%) rename src/{ => unwinder}/frame.rs (98%) create mode 100644 src/unwinder/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 6f064a3..f171efb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ spin = { version = "0.9", default-features = false, features = ["mutex", "spin_m [features] alloc = [] +unwinder = [] fde-phdr = ["libc"] fde-registry = ["alloc"] dwarf-expr = [] @@ -25,7 +26,7 @@ panic = ["alloc"] panic-handler = ["print", "panic"] panic-handler-dummy = [] system-alloc = [] -default = ["dwarf-expr", "hide-trace", "fde-phdr", "fde-registry"] +default = ["unwinder", "dwarf-expr", "hide-trace", "fde-phdr", "fde-registry"] [profile.dev] # Must be turned on due to Rust bug https://github.com/rust-lang/rust/issues/50007 diff --git a/src/abi.rs b/src/abi.rs index 8299f34..000bbaf 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -1,13 +1,12 @@ use core::ffi::c_void; use core::ops; -use core::ptr; -use gimli::Register; use crate::arch::*; -use crate::find_fde::{self, FDEFinder}; -use crate::frame::Frame; use crate::util::*; +#[cfg(feature = "unwinder")] +use crate::unwinder::*; + #[repr(transparent)] #[derive(Clone, Copy, PartialEq, Eq)] pub struct UnwindReasonCode(pub c_int); @@ -69,34 +68,28 @@ pub type UnwindStopFn = extern "C" fn( *mut c_void, ) -> UnwindReasonCode; +#[cfg(not(feature = "unwinder"))] #[repr(C)] pub struct UnwindException { pub exception_class: u64, pub exception_cleanup: Option, - private_1: Option, - private_2: usize, - private_unused: [usize; Arch::UNWIND_PRIVATE_DATA_SIZE - 2], + private: [usize; Arch::UNWIND_PRIVATE_DATA_SIZE], } impl UnwindException { #[inline] pub fn new() -> UnwindException { - UnwindException { - exception_class: 0, - exception_cleanup: None, - private_1: None, - private_2: 0, - private_unused: [0; Arch::UNWIND_PRIVATE_DATA_SIZE - 2], - } + unsafe { core::mem::zeroed() } } } pub type UnwindTraceFn = extern "C" fn(ctx: &mut UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode; +#[cfg(not(feature = "unwinder"))] pub struct UnwindContext<'a> { - frame: Option<&'a Frame>, - ctx: &'a mut Context, + opaque: usize, + phantom: core::marker::PhantomData<&'a ()>, } pub type PersonalityRoutine = extern "C" fn( @@ -106,339 +99,3 @@ pub type PersonalityRoutine = extern "C" fn( &mut UnwindException, &mut UnwindContext<'_>, ) -> UnwindReasonCode; - -#[no_mangle] -pub extern "C" fn _Unwind_GetGR(unwind_ctx: &UnwindContext<'_>, index: c_int) -> usize { - unwind_ctx.ctx[Register(index as u16)] -} - -#[no_mangle] -pub extern "C" fn _Unwind_GetCFA(unwind_ctx: &UnwindContext<'_>) -> usize { - unwind_ctx.ctx[Arch::SP] -} - -#[no_mangle] -pub extern "C" fn _Unwind_SetGR(unwind_ctx: &mut UnwindContext<'_>, index: c_int, value: usize) { - unwind_ctx.ctx[Register(index as u16)] = value; -} - -#[no_mangle] -pub extern "C" fn _Unwind_GetIP(unwind_ctx: &UnwindContext<'_>) -> usize { - unwind_ctx.ctx[Arch::RA] -} - -#[no_mangle] -pub extern "C" fn _Unwind_GetIPInfo( - unwind_ctx: &UnwindContext<'_>, - ip_before_insn: &mut c_int, -) -> usize { - *ip_before_insn = 0; - unwind_ctx.ctx[Arch::RA] -} - -#[no_mangle] -pub extern "C" fn _Unwind_SetIP(unwind_ctx: &mut UnwindContext<'_>, value: usize) { - unwind_ctx.ctx[Arch::RA] = value; -} - -#[no_mangle] -pub extern "C" fn _Unwind_GetLanguageSpecificData(unwind_ctx: &UnwindContext<'_>) -> *mut c_void { - unwind_ctx - .frame - .map(|f| f.lsda() as *mut c_void) - .unwrap_or(ptr::null_mut()) -} - -#[no_mangle] -pub extern "C" fn _Unwind_GetRegionStart(unwind_ctx: &UnwindContext<'_>) -> usize { - unwind_ctx.frame.map(|f| f.initial_address()).unwrap_or(0) -} - -#[no_mangle] -pub extern "C" fn _Unwind_GetTextRelBase(unwind_ctx: &UnwindContext<'_>) -> usize { - unwind_ctx - .frame - .map(|f| f.bases().eh_frame.text.unwrap() as _) - .unwrap_or(0) -} - -#[no_mangle] -pub extern "C" fn _Unwind_GetDataRelBase(unwind_ctx: &UnwindContext<'_>) -> usize { - unwind_ctx - .frame - .map(|f| f.bases().eh_frame.data.unwrap() as _) - .unwrap_or(0) -} - -#[no_mangle] -pub extern "C" fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void { - find_fde::get_finder() - .find_fde(pc as usize - 1) - .map(|r| r.fde.initial_address() as usize as _) - .unwrap_or(ptr::null_mut()) -} - -macro_rules! try1 { - ($e: expr) => {{ - match $e { - Ok(v) => v, - Err(_) => return UnwindReasonCode::FATAL_PHASE1_ERROR, - } - }}; -} - -macro_rules! try2 { - ($e: expr) => {{ - match $e { - Ok(v) => v, - Err(_) => return UnwindReasonCode::FATAL_PHASE2_ERROR, - } - }}; -} - -#[no_mangle] -pub extern "C-unwind" fn _Unwind_RaiseException( - exception: &mut UnwindException, -) -> UnwindReasonCode { - let saved_ctx = save_context(); - - // Phase 1: Search for handler - let mut ctx = saved_ctx.clone(); - let handler_cfa = loop { - if let Some(frame) = try1!(Frame::from_context(&ctx)) { - 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, - }, - ); - - match result { - UnwindReasonCode::CONTINUE_UNWIND => (), - UnwindReasonCode::HANDLER_FOUND => { - exception.private_1 = None; - exception.private_2 = ctx[Arch::SP]; - break ctx[Arch::SP]; - } - _ => return UnwindReasonCode::FATAL_PHASE1_ERROR, - } - } - - ctx = try1!(frame.unwind(&ctx)); - } else { - return UnwindReasonCode::END_OF_STACK; - } - }; - - 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, - } -} - -fn raise_exception_phase2( - exception: &mut UnwindException, - ctx: &mut Context, - handler_cfa: usize, -) -> UnwindReasonCode { - loop { - if let Some(frame) = try2!(Frame::from_context(ctx)) { - let is_handler = ctx[Arch::SP] == handler_cfa; - if let Some(personality) = frame.personality() { - let code = personality( - 1, - UnwindAction::CLEANUP_PHASE - | if is_handler { - UnwindAction::HANDLER_FRAME - } else { - UnwindAction::empty() - }, - exception.exception_class, - exception, - &mut UnwindContext { - frame: Some(&frame), - ctx, - }, - ); - - match code { - UnwindReasonCode::CONTINUE_UNWIND => (), - UnwindReasonCode::INSTALL_CONTEXT => break, - _ => return UnwindReasonCode::FATAL_PHASE2_ERROR, - } - } - - *ctx = try2!(frame.unwind(ctx)); - } else { - return UnwindReasonCode::FATAL_PHASE2_ERROR; - } - } - - UnwindReasonCode::INSTALL_CONTEXT -} - -#[no_mangle] -pub extern "C-unwind" fn _Unwind_ForceUnwind( - exception: &mut UnwindException, - stop: UnwindStopFn, - stop_arg: *mut c_void, -) -> UnwindReasonCode { - let mut ctx = save_context(); - - 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, - } -} - -fn force_unwind_phase2( - exception: &mut UnwindException, - ctx: &mut Context, - stop: UnwindStopFn, - stop_arg: *mut c_void, -) -> UnwindReasonCode { - loop { - let frame = try2!(Frame::from_context(ctx)); - - let code = 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, - }, - stop_arg, - ); - match code { - UnwindReasonCode::NO_REASON => (), - _ => return UnwindReasonCode::FATAL_PHASE2_ERROR, - } - - 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, - }, - ); - - match code { - UnwindReasonCode::CONTINUE_UNWIND => (), - UnwindReasonCode::INSTALL_CONTEXT => break, - _ => return UnwindReasonCode::FATAL_PHASE2_ERROR, - } - } - - *ctx = try2!(frame.unwind(ctx)); - } else { - return UnwindReasonCode::END_OF_STACK; - } - } - - UnwindReasonCode::INSTALL_CONTEXT -} - -#[no_mangle] -pub extern "C-unwind" fn _Unwind_Resume(exception: &mut UnwindException) -> ! { - let mut ctx = save_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) } -} - -#[no_mangle] -pub extern "C-unwind" fn _Unwind_Resume_or_Rethrow( - exception: &mut UnwindException, -) -> UnwindReasonCode { - let stop = match exception.private_1 { - None => return _Unwind_RaiseException(exception), - Some(v) => v, - }; - - let mut ctx = save_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) } -} - -#[no_mangle] -pub unsafe extern "C" fn _Unwind_DeleteException(exception: *mut UnwindException) { - if let Some(cleanup) = unsafe { (*exception).exception_cleanup } { - unsafe { cleanup(UnwindReasonCode::FOREIGN_EXCEPTION_CAUGHT, exception) }; - } -} - -#[inline(never)] -#[no_mangle] -pub extern "C-unwind" fn _Unwind_Backtrace( - trace: UnwindTraceFn, - trace_argument: *mut c_void, -) -> UnwindReasonCode { - let mut ctx = save_context(); - let mut skipping = cfg!(feature = "hide-trace"); - - loop { - let frame = try1!(Frame::from_context(&ctx)); - if !skipping { - let code = trace( - &mut UnwindContext { - frame: frame.as_ref(), - ctx: &mut ctx, - }, - 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; - } - } - ctx = try1!(frame.unwind(&ctx)); - } else { - return UnwindReasonCode::END_OF_STACK; - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 00ba6b0..0d2b7a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,11 +17,12 @@ #[cfg(feature = "alloc")] extern crate alloc; +#[cfg(feature = "unwinder")] +mod unwinder; + pub mod abi; mod arch; -mod find_fde; -mod frame; mod util; #[cfg(feature = "print")] diff --git a/src/panic_handler.rs b/src/panic_handler.rs index a7dbcd1..508ad8c 100644 --- a/src/panic_handler.rs +++ b/src/panic_handler.rs @@ -65,7 +65,11 @@ fn stack_trace() { ) -> UnwindReasonCode { let data = unsafe { &mut *(arg as *mut CallbackData) }; data.counter += 1; - eprintln!("{:4}:{:#19x} - ", data.counter, _Unwind_GetIP(unwind_ctx)); + eprintln!( + "{:4}:{:#19x} - ", + data.counter, + _Unwind_GetIP(unwind_ctx) + ); UnwindReasonCode::NO_REASON } let mut data = CallbackData { counter: 0 }; diff --git a/src/find_fde/mod.rs b/src/unwinder/find_fde/mod.rs similarity index 100% rename from src/find_fde/mod.rs rename to src/unwinder/find_fde/mod.rs diff --git a/src/find_fde/phdr.rs b/src/unwinder/find_fde/phdr.rs similarity index 99% rename from src/find_fde/phdr.rs rename to src/unwinder/find_fde/phdr.rs index f691bc8..e61ee78 100644 --- a/src/find_fde/phdr.rs +++ b/src/unwinder/find_fde/phdr.rs @@ -1,4 +1,4 @@ -use crate::find_fde::FDESearchResult; +use super::FDESearchResult; use crate::util::*; use core::ffi::c_void; diff --git a/src/find_fde/registry.rs b/src/unwinder/find_fde/registry.rs similarity index 100% rename from src/find_fde/registry.rs rename to src/unwinder/find_fde/registry.rs diff --git a/src/frame.rs b/src/unwinder/frame.rs similarity index 98% rename from src/frame.rs rename to src/unwinder/frame.rs index 9cd846f..0061702 100644 --- a/src/frame.rs +++ b/src/unwinder/frame.rs @@ -3,9 +3,9 @@ use gimli::{ UninitializedUnwindContext, UnwindTableRow, Value, }; +use super::find_fde::{self, FDEFinder, FDESearchResult}; use crate::abi::PersonalityRoutine; use crate::arch::*; -use crate::find_fde::{self, FDEFinder, FDESearchResult}; use crate::util::*; #[derive(Debug)] diff --git a/src/unwinder/mod.rs b/src/unwinder/mod.rs new file mode 100644 index 0000000..92d4aac --- /dev/null +++ b/src/unwinder/mod.rs @@ -0,0 +1,362 @@ +mod find_fde; +mod frame; + +use core::ffi::c_void; +use core::ptr; +use gimli::Register; + +use crate::abi::*; +use crate::arch::*; +use crate::util::*; +use find_fde::FDEFinder; +use frame::Frame; + +#[repr(C)] +pub struct UnwindException { + pub exception_class: u64, + pub exception_cleanup: Option, + private_1: Option, + private_2: usize, + private_unused: [usize; Arch::UNWIND_PRIVATE_DATA_SIZE - 2], +} + +pub struct UnwindContext<'a> { + frame: Option<&'a Frame>, + ctx: &'a mut Context, +} + +#[no_mangle] +pub extern "C" fn _Unwind_GetGR(unwind_ctx: &UnwindContext<'_>, index: c_int) -> usize { + unwind_ctx.ctx[Register(index as u16)] +} + +#[no_mangle] +pub extern "C" fn _Unwind_GetCFA(unwind_ctx: &UnwindContext<'_>) -> usize { + unwind_ctx.ctx[Arch::SP] +} + +#[no_mangle] +pub extern "C" fn _Unwind_SetGR(unwind_ctx: &mut UnwindContext<'_>, index: c_int, value: usize) { + unwind_ctx.ctx[Register(index as u16)] = value; +} + +#[no_mangle] +pub extern "C" fn _Unwind_GetIP(unwind_ctx: &UnwindContext<'_>) -> usize { + unwind_ctx.ctx[Arch::RA] +} + +#[no_mangle] +pub extern "C" fn _Unwind_GetIPInfo( + unwind_ctx: &UnwindContext<'_>, + ip_before_insn: &mut c_int, +) -> usize { + *ip_before_insn = 0; + unwind_ctx.ctx[Arch::RA] +} + +#[no_mangle] +pub extern "C" fn _Unwind_SetIP(unwind_ctx: &mut UnwindContext<'_>, value: usize) { + unwind_ctx.ctx[Arch::RA] = value; +} + +#[no_mangle] +pub extern "C" fn _Unwind_GetLanguageSpecificData(unwind_ctx: &UnwindContext<'_>) -> *mut c_void { + unwind_ctx + .frame + .map(|f| f.lsda() as *mut c_void) + .unwrap_or(ptr::null_mut()) +} + +#[no_mangle] +pub extern "C" fn _Unwind_GetRegionStart(unwind_ctx: &UnwindContext<'_>) -> usize { + unwind_ctx.frame.map(|f| f.initial_address()).unwrap_or(0) +} + +#[no_mangle] +pub extern "C" fn _Unwind_GetTextRelBase(unwind_ctx: &UnwindContext<'_>) -> usize { + unwind_ctx + .frame + .map(|f| f.bases().eh_frame.text.unwrap() as _) + .unwrap_or(0) +} + +#[no_mangle] +pub extern "C" fn _Unwind_GetDataRelBase(unwind_ctx: &UnwindContext<'_>) -> usize { + unwind_ctx + .frame + .map(|f| f.bases().eh_frame.data.unwrap() as _) + .unwrap_or(0) +} + +#[no_mangle] +pub extern "C" fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void { + find_fde::get_finder() + .find_fde(pc as usize - 1) + .map(|r| r.fde.initial_address() as usize as _) + .unwrap_or(ptr::null_mut()) +} + +macro_rules! try1 { + ($e: expr) => {{ + match $e { + Ok(v) => v, + Err(_) => return UnwindReasonCode::FATAL_PHASE1_ERROR, + } + }}; +} + +macro_rules! try2 { + ($e: expr) => {{ + match $e { + Ok(v) => v, + Err(_) => return UnwindReasonCode::FATAL_PHASE2_ERROR, + } + }}; +} + +#[no_mangle] +pub extern "C-unwind" fn _Unwind_RaiseException( + exception: &mut UnwindException, +) -> UnwindReasonCode { + let saved_ctx = save_context(); + + // Phase 1: Search for handler + let mut ctx = saved_ctx.clone(); + let handler_cfa = loop { + if let Some(frame) = try1!(Frame::from_context(&ctx)) { + 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, + }, + ); + + match result { + UnwindReasonCode::CONTINUE_UNWIND => (), + UnwindReasonCode::HANDLER_FOUND => { + exception.private_1 = None; + exception.private_2 = ctx[Arch::SP]; + break ctx[Arch::SP]; + } + _ => return UnwindReasonCode::FATAL_PHASE1_ERROR, + } + } + + ctx = try1!(frame.unwind(&ctx)); + } else { + return UnwindReasonCode::END_OF_STACK; + } + }; + + 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, + } +} + +fn raise_exception_phase2( + exception: &mut UnwindException, + ctx: &mut Context, + handler_cfa: usize, +) -> UnwindReasonCode { + loop { + if let Some(frame) = try2!(Frame::from_context(ctx)) { + let is_handler = ctx[Arch::SP] == handler_cfa; + if let Some(personality) = frame.personality() { + let code = personality( + 1, + UnwindAction::CLEANUP_PHASE + | if is_handler { + UnwindAction::HANDLER_FRAME + } else { + UnwindAction::empty() + }, + exception.exception_class, + exception, + &mut UnwindContext { + frame: Some(&frame), + ctx, + }, + ); + + match code { + UnwindReasonCode::CONTINUE_UNWIND => (), + UnwindReasonCode::INSTALL_CONTEXT => break, + _ => return UnwindReasonCode::FATAL_PHASE2_ERROR, + } + } + + *ctx = try2!(frame.unwind(ctx)); + } else { + return UnwindReasonCode::FATAL_PHASE2_ERROR; + } + } + + UnwindReasonCode::INSTALL_CONTEXT +} + +#[no_mangle] +pub extern "C-unwind" fn _Unwind_ForceUnwind( + exception: &mut UnwindException, + stop: UnwindStopFn, + stop_arg: *mut c_void, +) -> UnwindReasonCode { + let mut ctx = save_context(); + + 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, + } +} + +fn force_unwind_phase2( + exception: &mut UnwindException, + ctx: &mut Context, + stop: UnwindStopFn, + stop_arg: *mut c_void, +) -> UnwindReasonCode { + loop { + let frame = try2!(Frame::from_context(ctx)); + + let code = 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, + }, + stop_arg, + ); + match code { + UnwindReasonCode::NO_REASON => (), + _ => return UnwindReasonCode::FATAL_PHASE2_ERROR, + } + + 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, + }, + ); + + match code { + UnwindReasonCode::CONTINUE_UNWIND => (), + UnwindReasonCode::INSTALL_CONTEXT => break, + _ => return UnwindReasonCode::FATAL_PHASE2_ERROR, + } + } + + *ctx = try2!(frame.unwind(ctx)); + } else { + return UnwindReasonCode::END_OF_STACK; + } + } + + UnwindReasonCode::INSTALL_CONTEXT +} + +#[no_mangle] +pub extern "C-unwind" fn _Unwind_Resume(exception: &mut UnwindException) -> ! { + let mut ctx = save_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) } +} + +#[no_mangle] +pub extern "C-unwind" fn _Unwind_Resume_or_Rethrow( + exception: &mut UnwindException, +) -> UnwindReasonCode { + let stop = match exception.private_1 { + None => return _Unwind_RaiseException(exception), + Some(v) => v, + }; + + let mut ctx = save_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) } +} + +#[no_mangle] +pub unsafe extern "C" fn _Unwind_DeleteException(exception: *mut UnwindException) { + if let Some(cleanup) = unsafe { (*exception).exception_cleanup } { + unsafe { cleanup(UnwindReasonCode::FOREIGN_EXCEPTION_CAUGHT, exception) }; + } +} + +#[inline(never)] +#[no_mangle] +pub extern "C-unwind" fn _Unwind_Backtrace( + trace: UnwindTraceFn, + trace_argument: *mut c_void, +) -> UnwindReasonCode { + let mut ctx = save_context(); + let mut skipping = cfg!(feature = "hide-trace"); + + loop { + let frame = try1!(Frame::from_context(&ctx)); + if !skipping { + let code = trace( + &mut UnwindContext { + frame: frame.as_ref(), + ctx: &mut ctx, + }, + 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; + } + } + ctx = try1!(frame.unwind(&ctx)); + } else { + return UnwindReasonCode::END_OF_STACK; + } + } +}