123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- mod arch;
- 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 arch::*;
- use find_fde::FDEFinder;
- use frame::Frame;
- #[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 struct UnwindContext<'a> {
- frame: Option<&'a Frame>,
- ctx: &'a mut Context,
- signal: bool,
- }
- #[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 = unwind_ctx.signal as _;
- 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,
- }
- }};
- }
- #[inline(never)]
- #[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 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;
- }
- _ => return UnwindReasonCode::FATAL_PHASE1_ERROR,
- }
- }
- 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;
- 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 {
- let mut signal = false;
- loop {
- 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()
- },
- exception.exception_class,
- exception,
- &mut UnwindContext {
- frame: Some(&frame),
- ctx,
- signal,
- },
- );
- match code {
- UnwindReasonCode::CONTINUE_UNWIND => (),
- UnwindReasonCode::INSTALL_CONTEXT => break,
- _ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
- }
- }
- *ctx = try2!(frame.unwind(ctx));
- signal = frame.is_signal_trampoline();
- } else {
- return UnwindReasonCode::FATAL_PHASE2_ERROR;
- }
- }
- UnwindReasonCode::INSTALL_CONTEXT
- }
- #[inline(never)]
- #[no_mangle]
- pub extern "C-unwind" fn _Unwind_ForcedUnwind(
- 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 {
- let mut signal = false;
- 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()
- },
- exception.exception_class,
- exception,
- &mut UnwindContext {
- frame: frame.as_ref(),
- ctx,
- signal,
- },
- 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,
- signal,
- },
- );
- match code {
- UnwindReasonCode::CONTINUE_UNWIND => (),
- UnwindReasonCode::INSTALL_CONTEXT => break,
- _ => return UnwindReasonCode::FATAL_PHASE2_ERROR,
- }
- }
- *ctx = try2!(frame.unwind(ctx));
- signal = frame.is_signal_trampoline();
- } else {
- return UnwindReasonCode::END_OF_STACK;
- }
- }
- UnwindReasonCode::INSTALL_CONTEXT
- }
- #[inline(never)]
- #[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) }
- }
- #[inline(never)]
- #[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 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;
- }
- }
- ctx = try1!(frame.unwind(&ctx));
- signal = frame.is_signal_trampoline();
- } else {
- return UnwindReasonCode::END_OF_STACK;
- }
- }
- }
|