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 {
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];
// 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()
}
}

View File

@ -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;
}