123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- 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::*;
- #[repr(transparent)]
- #[derive(Clone, Copy, PartialEq, Eq)]
- pub struct UnwindReasonCode(c_int);
- #[allow(unused)]
- impl UnwindReasonCode {
- pub const NO_REASON: Self = Self(0);
- pub const FOREIGN_EXCEPTION_CAUGHT: Self = Self(1);
- pub const FATAL_PHASE2_ERROR: Self = Self(2);
- pub const FATAL_PHASE1_ERROR: Self = Self(3);
- pub const NORMAL_STOP: Self = Self(4);
- pub const END_OF_STACK: Self = Self(5);
- pub const HANDLER_FOUND: Self = Self(6);
- pub const INSTALL_CONTEXT: Self = Self(7);
- pub const CONTINUE_UNWIND: Self = Self(8);
- }
- #[repr(transparent)]
- #[derive(Clone, Copy, PartialEq, Eq)]
- pub struct UnwindAction(c_int);
- impl UnwindAction {
- pub const SEARCH_PHASE: Self = Self(1);
- pub const CLEANUP_PHASE: Self = Self(2);
- pub const HANDLER_FRAME: Self = Self(4);
- pub const FORCE_UNWIND: Self = Self(8);
- pub const END_OF_STACK: Self = Self(16);
- }
- impl ops::BitOr for UnwindAction {
- type Output = Self;
- #[inline]
- fn bitor(self, rhs: Self) -> Self {
- Self(self.0 | rhs.0)
- }
- }
- impl UnwindAction {
- #[inline]
- pub const fn empty() -> Self {
- Self(0)
- }
- #[inline]
- pub const fn contains(&self, other: Self) -> bool {
- self.0 & other.0 != 0
- }
- }
- pub type UnwindExceptionCleanupFn = unsafe extern "C" fn(UnwindReasonCode, *mut UnwindException);
- pub type UnwindStopFn = unsafe extern "C" fn(
- c_int,
- UnwindAction,
- u64,
- &mut UnwindException,
- &mut UnwindContext<'_>,
- *mut c_void,
- ) -> UnwindReasonCode;
- #[repr(C)]
- pub struct UnwindException {
- pub exception_class: u64,
- pub exception_cleanup: Option<UnwindExceptionCleanupFn>,
- private_1: Option<UnwindStopFn>,
- private_2: usize,
- private_unused: [usize; Arch::UNWIND_PRIVATE_DATA_SIZE - 2],
- }
- pub type UnwindTraceFn =
- unsafe extern "C" fn(ctx: &mut UnwindContext<'_>, arg: *mut c_void) -> UnwindReasonCode;
- pub struct UnwindContext<'a> {
- frame: Option<&'a Frame>,
- ctx: &'a mut Context,
- }
- pub type PersonalityRoutine = extern "C" fn(
- c_int,
- UnwindAction,
- u64,
- &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 unsafe 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 = unsafe { force_unwind_phase2(exception, &mut ctx, stop, stop_arg) };
- match code {
- UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(&ctx) },
- _ => code,
- }
- }
- unsafe 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 = 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,
- },
- 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 _;
- unsafe { 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 = unsafe { 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) };
- }
- }
- #[no_mangle]
- pub unsafe 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 = unsafe {
- 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;
- }
- }
- }
|