Handle signal frame

This commit is contained in:
Gary Guo 2021-08-27 18:33:06 +01:00
parent 10dccf7dc4
commit 41e805c1cf
2 changed files with 37 additions and 14 deletions

View File

@ -17,7 +17,7 @@ pub struct Frame {
} }
impl Frame { impl Frame {
pub fn from_context(ctx: &Context) -> Result<Option<Self>, gimli::Error> { pub fn from_context(ctx: &Context, signal: bool) -> Result<Option<Self>, gimli::Error> {
let mut ra = ctx[Arch::RA]; let mut ra = ctx[Arch::RA];
// Reached end of stack // 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 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 _) { let fde_result = match find_fde::get_finder().find_fde(ra as _) {
Some(v) => v, Some(v) => v,
@ -153,4 +155,8 @@ impl Frame {
pub fn initial_address(&self) -> usize { pub fn initial_address(&self) -> usize {
self.fde_result.fde.initial_address() as _ self.fde_result.fde.initial_address() as _
} }
pub fn is_signal_trampoline(&self) -> bool {
self.fde_result.fde.is_signal_trampoline()
}
} }

View File

@ -25,6 +25,7 @@ pub struct UnwindException {
pub struct UnwindContext<'a> { pub struct UnwindContext<'a> {
frame: Option<&'a Frame>, frame: Option<&'a Frame>,
ctx: &'a mut Context, ctx: &'a mut Context,
signal: bool,
} }
#[no_mangle] #[no_mangle]
@ -52,7 +53,7 @@ pub extern "C" fn _Unwind_GetIPInfo(
unwind_ctx: &UnwindContext<'_>, unwind_ctx: &UnwindContext<'_>,
ip_before_insn: &mut c_int, ip_before_insn: &mut c_int,
) -> usize { ) -> usize {
*ip_before_insn = 0; *ip_before_insn = unwind_ctx.signal as _;
unwind_ctx.ctx[Arch::RA] unwind_ctx.ctx[Arch::RA]
} }
@ -124,8 +125,9 @@ pub extern "C-unwind" fn _Unwind_RaiseException(
// Phase 1: Search for handler // Phase 1: Search for handler
let mut ctx = saved_ctx.clone(); let mut ctx = saved_ctx.clone();
let handler_cfa = loop { let mut signal = false;
if let Some(frame) = try1!(Frame::from_context(&ctx)) { loop {
if let Some(frame) = try1!(Frame::from_context(&ctx, signal)) {
if let Some(personality) = frame.personality() { if let Some(personality) = frame.personality() {
let result = personality( let result = personality(
1, 1,
@ -135,25 +137,30 @@ pub extern "C-unwind" fn _Unwind_RaiseException(
&mut UnwindContext { &mut UnwindContext {
frame: Some(&frame), frame: Some(&frame),
ctx: &mut ctx, ctx: &mut ctx,
signal,
}, },
); );
match result { match result {
UnwindReasonCode::CONTINUE_UNWIND => (), UnwindReasonCode::CONTINUE_UNWIND => (),
UnwindReasonCode::HANDLER_FOUND => { UnwindReasonCode::HANDLER_FOUND => {
exception.private_1 = None; break;
exception.private_2 = ctx[Arch::SP];
break ctx[Arch::SP];
} }
_ => return UnwindReasonCode::FATAL_PHASE1_ERROR, _ => return UnwindReasonCode::FATAL_PHASE1_ERROR,
} }
} }
ctx = try1!(frame.unwind(&ctx)); ctx = try1!(frame.unwind(&ctx));
signal = frame.is_signal_trampoline();
} else { } else {
return UnwindReasonCode::END_OF_STACK; 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 mut ctx = saved_ctx;
let code = raise_exception_phase2(exception, &mut ctx, handler_cfa); let code = raise_exception_phase2(exception, &mut ctx, handler_cfa);
@ -168,14 +175,15 @@ fn raise_exception_phase2(
ctx: &mut Context, ctx: &mut Context,
handler_cfa: usize, handler_cfa: usize,
) -> UnwindReasonCode { ) -> UnwindReasonCode {
let mut signal = false;
loop { loop {
if let Some(frame) = try2!(Frame::from_context(ctx)) { if let Some(frame) = try2!(Frame::from_context(ctx, signal)) {
let is_handler = ctx[Arch::SP] == handler_cfa; let frame_cfa = ctx[Arch::SP] - signal as usize;
if let Some(personality) = frame.personality() { if let Some(personality) = frame.personality() {
let code = personality( let code = personality(
1, 1,
UnwindAction::CLEANUP_PHASE UnwindAction::CLEANUP_PHASE
| if is_handler { | if frame_cfa == handler_cfa {
UnwindAction::HANDLER_FRAME UnwindAction::HANDLER_FRAME
} else { } else {
UnwindAction::empty() UnwindAction::empty()
@ -185,6 +193,7 @@ fn raise_exception_phase2(
&mut UnwindContext { &mut UnwindContext {
frame: Some(&frame), frame: Some(&frame),
ctx, ctx,
signal,
}, },
); );
@ -196,6 +205,7 @@ fn raise_exception_phase2(
} }
*ctx = try2!(frame.unwind(ctx)); *ctx = try2!(frame.unwind(ctx));
signal = frame.is_signal_trampoline();
} else { } else {
return UnwindReasonCode::FATAL_PHASE2_ERROR; return UnwindReasonCode::FATAL_PHASE2_ERROR;
} }
@ -228,8 +238,9 @@ fn force_unwind_phase2(
stop: UnwindStopFn, stop: UnwindStopFn,
stop_arg: *mut c_void, stop_arg: *mut c_void,
) -> UnwindReasonCode { ) -> UnwindReasonCode {
let mut signal = false;
loop { loop {
let frame = try2!(Frame::from_context(ctx)); let frame = try2!(Frame::from_context(ctx, signal));
let code = stop( let code = stop(
1, 1,
@ -245,6 +256,7 @@ fn force_unwind_phase2(
&mut UnwindContext { &mut UnwindContext {
frame: frame.as_ref(), frame: frame.as_ref(),
ctx, ctx,
signal,
}, },
stop_arg, stop_arg,
); );
@ -263,6 +275,7 @@ fn force_unwind_phase2(
&mut UnwindContext { &mut UnwindContext {
frame: Some(&frame), frame: Some(&frame),
ctx, ctx,
signal,
}, },
); );
@ -274,6 +287,7 @@ fn force_unwind_phase2(
} }
*ctx = try2!(frame.unwind(ctx)); *ctx = try2!(frame.unwind(ctx));
signal = frame.is_signal_trampoline();
} else { } else {
return UnwindReasonCode::END_OF_STACK; return UnwindReasonCode::END_OF_STACK;
} }
@ -333,15 +347,17 @@ pub extern "C-unwind" fn _Unwind_Backtrace(
trace_argument: *mut c_void, trace_argument: *mut c_void,
) -> UnwindReasonCode { ) -> UnwindReasonCode {
let mut ctx = save_context(); let mut ctx = save_context();
let mut signal = false;
let mut skipping = cfg!(feature = "hide-trace"); let mut skipping = cfg!(feature = "hide-trace");
loop { loop {
let frame = try1!(Frame::from_context(&ctx)); let frame = try1!(Frame::from_context(&ctx, signal));
if !skipping { if !skipping {
let code = trace( let code = trace(
&mut UnwindContext { &mut UnwindContext {
frame: frame.as_ref(), frame: frame.as_ref(),
ctx: &mut ctx, ctx: &mut ctx,
signal,
}, },
trace_argument, trace_argument,
); );
@ -357,6 +373,7 @@ pub extern "C-unwind" fn _Unwind_Backtrace(
} }
} }
ctx = try1!(frame.unwind(&ctx)); ctx = try1!(frame.unwind(&ctx));
signal = frame.is_signal_trampoline();
} else { } else {
return UnwindReasonCode::END_OF_STACK; return UnwindReasonCode::END_OF_STACK;
} }