From 41e805c1cfa1e0a853007e670491448e458c15e3 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 27 Aug 2021 18:33:06 +0100 Subject: [PATCH] Handle signal frame --- src/unwinder/frame.rs | 10 ++++++++-- src/unwinder/mod.rs | 41 +++++++++++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/unwinder/frame.rs b/src/unwinder/frame.rs index 387d006..15c9088 100644 --- a/src/unwinder/frame.rs +++ b/src/unwinder/frame.rs @@ -17,7 +17,7 @@ pub struct Frame { } impl Frame { - pub fn from_context(ctx: &Context) -> Result, gimli::Error> { + pub fn from_context(ctx: &Context, signal: bool) -> Result, gimli::Error> { let mut ra = ctx[Arch::RA]; // Reached end of stack @@ -26,7 +26,9 @@ impl Frame { } // RA points to the *next* instruction, so move it back 1 byte for the call instruction. - ra -= 1; + if !signal { + ra -= 1; + } let fde_result = match find_fde::get_finder().find_fde(ra as _) { Some(v) => v, @@ -153,4 +155,8 @@ impl Frame { pub fn initial_address(&self) -> usize { self.fde_result.fde.initial_address() as _ } + + pub fn is_signal_trampoline(&self) -> bool { + self.fde_result.fde.is_signal_trampoline() + } } diff --git a/src/unwinder/mod.rs b/src/unwinder/mod.rs index b49450e..73b760c 100644 --- a/src/unwinder/mod.rs +++ b/src/unwinder/mod.rs @@ -25,6 +25,7 @@ pub struct UnwindException { pub struct UnwindContext<'a> { frame: Option<&'a Frame>, ctx: &'a mut Context, + signal: bool, } #[no_mangle] @@ -52,7 +53,7 @@ pub extern "C" fn _Unwind_GetIPInfo( unwind_ctx: &UnwindContext<'_>, ip_before_insn: &mut c_int, ) -> usize { - *ip_before_insn = 0; + *ip_before_insn = unwind_ctx.signal as _; unwind_ctx.ctx[Arch::RA] } @@ -124,8 +125,9 @@ pub extern "C-unwind" fn _Unwind_RaiseException( // Phase 1: Search for handler let mut ctx = saved_ctx.clone(); - let handler_cfa = loop { - if let Some(frame) = try1!(Frame::from_context(&ctx)) { + 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, @@ -135,25 +137,30 @@ pub extern "C-unwind" fn _Unwind_RaiseException( &mut UnwindContext { frame: Some(&frame), ctx: &mut ctx, + signal, }, ); match result { UnwindReasonCode::CONTINUE_UNWIND => (), UnwindReasonCode::HANDLER_FOUND => { - exception.private_1 = None; - exception.private_2 = ctx[Arch::SP]; - break ctx[Arch::SP]; + 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); @@ -168,14 +175,15 @@ fn raise_exception_phase2( ctx: &mut Context, handler_cfa: usize, ) -> UnwindReasonCode { + let mut signal = false; loop { - if let Some(frame) = try2!(Frame::from_context(ctx)) { - let is_handler = ctx[Arch::SP] == handler_cfa; + 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 is_handler { + | if frame_cfa == handler_cfa { UnwindAction::HANDLER_FRAME } else { UnwindAction::empty() @@ -185,6 +193,7 @@ fn raise_exception_phase2( &mut UnwindContext { frame: Some(&frame), ctx, + signal, }, ); @@ -196,6 +205,7 @@ fn raise_exception_phase2( } *ctx = try2!(frame.unwind(ctx)); + signal = frame.is_signal_trampoline(); } else { return UnwindReasonCode::FATAL_PHASE2_ERROR; } @@ -228,8 +238,9 @@ fn force_unwind_phase2( stop: UnwindStopFn, stop_arg: *mut c_void, ) -> UnwindReasonCode { + let mut signal = false; loop { - let frame = try2!(Frame::from_context(ctx)); + let frame = try2!(Frame::from_context(ctx, signal)); let code = stop( 1, @@ -245,6 +256,7 @@ fn force_unwind_phase2( &mut UnwindContext { frame: frame.as_ref(), ctx, + signal, }, stop_arg, ); @@ -263,6 +275,7 @@ fn force_unwind_phase2( &mut UnwindContext { frame: Some(&frame), ctx, + signal, }, ); @@ -274,6 +287,7 @@ fn force_unwind_phase2( } *ctx = try2!(frame.unwind(ctx)); + signal = frame.is_signal_trampoline(); } else { return UnwindReasonCode::END_OF_STACK; } @@ -333,15 +347,17 @@ pub extern "C-unwind" fn _Unwind_Backtrace( 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)); + 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, ); @@ -357,6 +373,7 @@ pub extern "C-unwind" fn _Unwind_Backtrace( } } ctx = try1!(frame.unwind(&ctx)); + signal = frame.is_signal_trampoline(); } else { return UnwindReasonCode::END_OF_STACK; }