Handle signal frame
This commit is contained in:
parent
10dccf7dc4
commit
41e805c1cf
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user