Change save_context to invoke callback instead
This commit is contained in:
parent
6dc1ed4d80
commit
a9bec9e719
@ -59,25 +59,34 @@ impl ops::IndexMut<gimli::Register> for Context {
|
||||
}
|
||||
|
||||
#[naked]
|
||||
pub extern "C-unwind" fn save_context() -> Context {
|
||||
pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
|
||||
// No need to save caller-saved registers here.
|
||||
unsafe {
|
||||
asm!(
|
||||
"
|
||||
stp d8, d9, [x8, 0x140]
|
||||
stp d10, d11, [x8, 0x150]
|
||||
stp d12, d13, [x8, 0x160]
|
||||
stp d14, d15, [x8, 0x170]
|
||||
|
||||
str x19, [x8, 0x98]
|
||||
stp x20, x21, [x8, 0xA0]
|
||||
stp x22, x23, [x8, 0xB0]
|
||||
stp x24, x25, [x8, 0xC0]
|
||||
stp x26, x27, [x8, 0xD0]
|
||||
stp x28, x29, [x8, 0xE0]
|
||||
stp x29, x30, [sp, -16]!
|
||||
sub sp, sp, 512
|
||||
mov x8, x0
|
||||
mov x0, sp
|
||||
stp x30, x0, [x8, 0xF0]
|
||||
|
||||
stp d8, d9, [sp, 0x140]
|
||||
stp d10, d11, [sp, 0x150]
|
||||
stp d12, d13, [sp, 0x160]
|
||||
stp d14, d15, [sp, 0x170]
|
||||
|
||||
str x19, [sp, 0x98]
|
||||
stp x20, x21, [sp, 0xA0]
|
||||
stp x22, x23, [sp, 0xB0]
|
||||
stp x24, x25, [sp, 0xC0]
|
||||
stp x26, x27, [sp, 0xD0]
|
||||
stp x28, x29, [sp, 0xE0]
|
||||
add x2, sp, 528
|
||||
stp x30, x2, [sp, 0xF0]
|
||||
|
||||
blr x8
|
||||
|
||||
add sp, sp, 512
|
||||
ldp x29, x30, [sp], 16
|
||||
ret
|
||||
",
|
||||
options(noreturn)
|
||||
|
@ -61,39 +61,39 @@ impl ops::IndexMut<gimli::Register> for Context {
|
||||
macro_rules! code {
|
||||
(save_gp) => {
|
||||
"
|
||||
sw x0, 0x00(a0)
|
||||
sw ra, 0x04(a0)
|
||||
sw sp, 0x08(a0)
|
||||
sw gp, 0x0C(a0)
|
||||
sw tp, 0x10(a0)
|
||||
sw s0, 0x20(a0)
|
||||
sw s1, 0x24(a0)
|
||||
sw s2, 0x48(a0)
|
||||
sw s3, 0x4C(a0)
|
||||
sw s4, 0x50(a0)
|
||||
sw s5, 0x54(a0)
|
||||
sw s6, 0x58(a0)
|
||||
sw s7, 0x5C(a0)
|
||||
sw s8, 0x60(a0)
|
||||
sw s9, 0x64(a0)
|
||||
sw s10, 0x68(a0)
|
||||
sw s11, 0x6C(a0)
|
||||
sw x0, 0x00(sp)
|
||||
sw ra, 0x04(sp)
|
||||
sw t0, 0x08(sp)
|
||||
sw gp, 0x0C(sp)
|
||||
sw tp, 0x10(sp)
|
||||
sw s0, 0x20(sp)
|
||||
sw s1, 0x24(sp)
|
||||
sw s2, 0x48(sp)
|
||||
sw s3, 0x4C(sp)
|
||||
sw s4, 0x50(sp)
|
||||
sw s5, 0x54(sp)
|
||||
sw s6, 0x58(sp)
|
||||
sw s7, 0x5C(sp)
|
||||
sw s8, 0x60(sp)
|
||||
sw s9, 0x64(sp)
|
||||
sw s10, 0x68(sp)
|
||||
sw s11, 0x6C(sp)
|
||||
"
|
||||
};
|
||||
(save_fp) => {
|
||||
"
|
||||
fsd fs0, 0xC0(a0)
|
||||
fsd fs1, 0xC8(a0)
|
||||
fsd fs2, 0x110(a0)
|
||||
fsd fs3, 0x118(a0)
|
||||
fsd fs4, 0x120(a0)
|
||||
fsd fs5, 0x128(a0)
|
||||
fsd fs6, 0x130(a0)
|
||||
fsd fs7, 0x138(a0)
|
||||
fsd fs8, 0x140(a0)
|
||||
fsd fs9, 0x148(a0)
|
||||
fsd fs10, 0x150(a0)
|
||||
fsd fs11, 0x158(a0)
|
||||
fsd fs0, 0xC0(sp)
|
||||
fsd fs1, 0xC8(sp)
|
||||
fsd fs2, 0x110(sp)
|
||||
fsd fs3, 0x118(sp)
|
||||
fsd fs4, 0x120(sp)
|
||||
fsd fs5, 0x128(sp)
|
||||
fsd fs6, 0x130(sp)
|
||||
fsd fs7, 0x138(sp)
|
||||
fsd fs8, 0x140(sp)
|
||||
fsd fs9, 0x148(sp)
|
||||
fsd fs10, 0x150(sp)
|
||||
fsd fs11, 0x158(sp)
|
||||
"
|
||||
};
|
||||
(restore_gp) => {
|
||||
@ -169,18 +169,48 @@ macro_rules! code {
|
||||
}
|
||||
|
||||
#[naked]
|
||||
pub extern "C-unwind" fn save_context() -> Context {
|
||||
pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
|
||||
// No need to save caller-saved registers here.
|
||||
#[cfg(target_feature = "d")]
|
||||
unsafe {
|
||||
asm!(
|
||||
concat!(code!(save_gp), code!(save_fp), "ret"),
|
||||
"
|
||||
mv t0, sp
|
||||
add sp, sp, -0x188
|
||||
sw ra, 0x180(sp)
|
||||
",
|
||||
code!(save_gp),
|
||||
code!(save_fp),
|
||||
"
|
||||
mv t0, a0
|
||||
mv a0, sp
|
||||
jalr t0
|
||||
lw ra, 0x180(sp)
|
||||
add sp, sp, 0x188
|
||||
ret
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
#[cfg(not(target_feature = "d"))]
|
||||
unsafe {
|
||||
asm!(concat!(code!(save_gp), "ret"), options(noreturn));
|
||||
asm!(
|
||||
"
|
||||
mv t0, sp
|
||||
add sp, sp, -0x88
|
||||
sw ra, 0x80(sp)
|
||||
",
|
||||
code!(save_gp),
|
||||
"
|
||||
mv t0, a0
|
||||
mv a0, sp
|
||||
jalr t0
|
||||
lw ra, 0x80(sp)
|
||||
add sp, sp, 0x88
|
||||
ret
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,14 +219,23 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
|
||||
#[cfg(target_feature = "d")]
|
||||
unsafe {
|
||||
asm!(
|
||||
concat!(code!(restore_fp), code!(restore_gp), "lw a0, 0x28(a0)\nret"),
|
||||
code!(restore_fp),
|
||||
code!(restore_gp),
|
||||
"
|
||||
lw a0, 0x28(a0)
|
||||
ret
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
#[cfg(not(target_feature = "d"))]
|
||||
unsafe {
|
||||
asm!(
|
||||
concat!(code!(restore_gp), "lw a0, 0x28(a0)\nret"),
|
||||
code!(restore_gp),
|
||||
"
|
||||
lw a0, 0x28(a0)
|
||||
ret
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
|
@ -61,39 +61,39 @@ impl ops::IndexMut<gimli::Register> for Context {
|
||||
macro_rules! code {
|
||||
(save_gp) => {
|
||||
"
|
||||
sd x0, 0x00(a0)
|
||||
sd ra, 0x08(a0)
|
||||
sd sp, 0x10(a0)
|
||||
sd gp, 0x18(a0)
|
||||
sd tp, 0x20(a0)
|
||||
sd s0, 0x40(a0)
|
||||
sd s1, 0x48(a0)
|
||||
sd s2, 0x90(a0)
|
||||
sd s3, 0x98(a0)
|
||||
sd s4, 0xA0(a0)
|
||||
sd s5, 0xA8(a0)
|
||||
sd s6, 0xB0(a0)
|
||||
sd s7, 0xB8(a0)
|
||||
sd s8, 0xC0(a0)
|
||||
sd s9, 0xC8(a0)
|
||||
sd s10, 0xD0(a0)
|
||||
sd s11, 0xD8(a0)
|
||||
sd x0, 0x00(sp)
|
||||
sd ra, 0x08(sp)
|
||||
sd t0, 0x10(sp)
|
||||
sd gp, 0x18(sp)
|
||||
sd tp, 0x20(sp)
|
||||
sd s0, 0x40(sp)
|
||||
sd s1, 0x48(sp)
|
||||
sd s2, 0x90(sp)
|
||||
sd s3, 0x98(sp)
|
||||
sd s4, 0xA0(sp)
|
||||
sd s5, 0xA8(sp)
|
||||
sd s6, 0xB0(sp)
|
||||
sd s7, 0xB8(sp)
|
||||
sd s8, 0xC0(sp)
|
||||
sd s9, 0xC8(sp)
|
||||
sd s10, 0xD0(sp)
|
||||
sd s11, 0xD8(sp)
|
||||
"
|
||||
};
|
||||
(save_fp) => {
|
||||
"
|
||||
fsd fs0, 0x140(a0)
|
||||
fsd fs1, 0x148(a0)
|
||||
fsd fs2, 0x190(a0)
|
||||
fsd fs3, 0x198(a0)
|
||||
fsd fs4, 0x1A0(a0)
|
||||
fsd fs5, 0x1A8(a0)
|
||||
fsd fs6, 0x1B0(a0)
|
||||
fsd fs7, 0x1B8(a0)
|
||||
fsd fs8, 0x1C0(a0)
|
||||
fsd fs9, 0x1C8(a0)
|
||||
fsd fs10, 0x1D0(a0)
|
||||
fsd fs11, 0x1D8(a0)
|
||||
fsd fs0, 0x140(sp)
|
||||
fsd fs1, 0x148(sp)
|
||||
fsd fs2, 0x190(sp)
|
||||
fsd fs3, 0x198(sp)
|
||||
fsd fs4, 0x1A0(sp)
|
||||
fsd fs5, 0x1A8(sp)
|
||||
fsd fs6, 0x1B0(sp)
|
||||
fsd fs7, 0x1B8(sp)
|
||||
fsd fs8, 0x1C0(sp)
|
||||
fsd fs9, 0x1C8(sp)
|
||||
fsd fs10, 0x1D0(sp)
|
||||
fsd fs11, 0x1D8(sp)
|
||||
"
|
||||
};
|
||||
(restore_gp) => {
|
||||
@ -169,18 +169,48 @@ macro_rules! code {
|
||||
}
|
||||
|
||||
#[naked]
|
||||
pub extern "C-unwind" fn save_context() -> Context {
|
||||
pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
|
||||
// No need to save caller-saved registers here.
|
||||
#[cfg(target_feature = "d")]
|
||||
unsafe {
|
||||
asm!(
|
||||
concat!(code!(save_gp), code!(save_fp), "ret"),
|
||||
"
|
||||
mv t0, sp
|
||||
add sp, sp, -0x210
|
||||
sd ra, 0x200(sp)
|
||||
",
|
||||
code!(save_gp),
|
||||
code!(save_fp),
|
||||
"
|
||||
mv t0, a0
|
||||
mv a0, sp
|
||||
jalr t0
|
||||
ld ra, 0x200(sp)
|
||||
add sp, sp, 0x210
|
||||
ret
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
#[cfg(not(target_feature = "d"))]
|
||||
unsafe {
|
||||
asm!(concat!(code!(save_gp), "ret"), options(noreturn));
|
||||
asm!(
|
||||
"
|
||||
mv t0, sp
|
||||
add sp, sp, -0x110
|
||||
sd ra, 0x100(sp)
|
||||
",
|
||||
code!(save_gp),
|
||||
"
|
||||
mv t0, a0
|
||||
mv a0, sp
|
||||
jalr t0
|
||||
ld ra, 0x100(sp)
|
||||
add sp, sp, 0x110
|
||||
ret
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,14 +219,23 @@ pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
|
||||
#[cfg(target_feature = "d")]
|
||||
unsafe {
|
||||
asm!(
|
||||
concat!(code!(restore_fp), code!(restore_gp), "ld a0, 0x50(a0)\nret"),
|
||||
code!(restore_fp),
|
||||
code!(restore_gp),
|
||||
"
|
||||
ld a0, 0x50(a0)
|
||||
ret
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
#[cfg(not(target_feature = "d"))]
|
||||
unsafe {
|
||||
asm!(
|
||||
concat!(code!(restore_gp), "ld a0, 0x50(a0)\nret"),
|
||||
code!(restore_gp),
|
||||
"
|
||||
ld a0, 0x50(a0)
|
||||
ret
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
|
@ -56,28 +56,40 @@ impl ops::IndexMut<gimli::Register> for Context {
|
||||
}
|
||||
|
||||
#[naked]
|
||||
pub extern "C-unwind" fn save_context() -> Context {
|
||||
pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
|
||||
// No need to save caller-saved registers here.
|
||||
unsafe {
|
||||
asm!(
|
||||
"
|
||||
mov eax, [esp + 4]
|
||||
mov [eax + 4], ecx
|
||||
mov [eax + 8], edx
|
||||
mov [eax + 12], ebx
|
||||
mov [eax + 20], ebp
|
||||
mov [eax + 24], esi
|
||||
mov [eax + 28], edi
|
||||
sub esp, 44
|
||||
|
||||
mov [esp + 4], ecx
|
||||
mov [esp + 8], edx
|
||||
mov [esp + 12], ebx
|
||||
|
||||
/* Adjust the stack to account for the return address */
|
||||
lea edx, [esp + 4]
|
||||
mov [eax + 16], edx
|
||||
lea eax, [esp + 48]
|
||||
mov [esp + 16], eax
|
||||
|
||||
mov edx, [esp]
|
||||
mov [eax + 32], edx
|
||||
stmxcsr [eax + 36]
|
||||
fnstcw [eax + 40]
|
||||
ret 4
|
||||
mov [esp + 20], ebp
|
||||
mov [esp + 24], esi
|
||||
mov [esp + 28], edi
|
||||
|
||||
/* Return address */
|
||||
mov eax, [esp + 44]
|
||||
mov [esp + 32], eax
|
||||
|
||||
stmxcsr [esp + 36]
|
||||
fnstcw [esp + 40]
|
||||
|
||||
mov eax, [esp + 52]
|
||||
mov ecx, esp
|
||||
push eax
|
||||
push ecx
|
||||
call [esp + 56]
|
||||
|
||||
add esp, 52
|
||||
ret
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
|
@ -58,27 +58,35 @@ impl ops::IndexMut<gimli::Register> for Context {
|
||||
}
|
||||
|
||||
#[naked]
|
||||
pub extern "C-unwind" fn save_context() -> Context {
|
||||
pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
|
||||
// No need to save caller-saved registers here.
|
||||
unsafe {
|
||||
asm!(
|
||||
"
|
||||
mov rax, rdi
|
||||
mov [rax + 0x18], rbx
|
||||
mov [rax + 0x30], rbp
|
||||
sub rsp, 0x98
|
||||
mov [rsp + 0x18], rbx
|
||||
mov [rsp + 0x30], rbp
|
||||
|
||||
/* Adjust the stack to account for the return address */
|
||||
lea rdi, [rsp + 8]
|
||||
mov [rax + 0x38], rdi
|
||||
lea rax, [rsp + 0xA0]
|
||||
mov [rsp + 0x38], rax
|
||||
|
||||
mov [rax + 0x60], r12
|
||||
mov [rax + 0x68], r13
|
||||
mov [rax + 0x70], r14
|
||||
mov [rax + 0x78], r15
|
||||
mov rdx, [rsp]
|
||||
mov [rax + 0x80], rdx
|
||||
stmxcsr [rax + 0x88]
|
||||
fnstcw [rax + 0x90]
|
||||
mov [rsp + 0x60], r12
|
||||
mov [rsp + 0x68], r13
|
||||
mov [rsp + 0x70], r14
|
||||
mov [rsp + 0x78], r15
|
||||
|
||||
/* Return address */
|
||||
mov rax, [rsp + 0x98]
|
||||
mov [rsp + 0x80], rax
|
||||
|
||||
stmxcsr [rsp + 0x88]
|
||||
fnstcw [rsp + 0x90]
|
||||
|
||||
mov rax, rdi
|
||||
mov rdi, rsp
|
||||
call rax
|
||||
add rsp, 0x98
|
||||
ret
|
||||
",
|
||||
options(noreturn)
|
||||
|
@ -16,6 +16,33 @@ use frame::Frame;
|
||||
#[cfg(feature = "fde-custom")]
|
||||
pub use find_fde::custom_eh_frame_finder;
|
||||
|
||||
// Helper function to turn `save_context` which takes function pointer to a closure-taking function.
|
||||
fn with_context<T, F: FnOnce(&mut Context) -> T>(f: F) -> T {
|
||||
use core::mem::ManuallyDrop;
|
||||
|
||||
union Data<T, F> {
|
||||
f: ManuallyDrop<F>,
|
||||
t: ManuallyDrop<T>,
|
||||
}
|
||||
|
||||
extern "C" fn delegate<T, F: FnOnce(&mut Context) -> T>(ctx: &mut Context, ptr: *mut ()) {
|
||||
// SAFETY: This function is called exactly once; it extracts the function, call it and
|
||||
// store the return value. This function is `extern "C"` so we don't need to worry about
|
||||
// unwinding past it.
|
||||
unsafe {
|
||||
let data = &mut *ptr.cast::<Data<T, F>>();
|
||||
let t = ManuallyDrop::take(&mut data.f)(ctx);
|
||||
data.t = ManuallyDrop::new(t);
|
||||
}
|
||||
}
|
||||
|
||||
let mut data = Data {
|
||||
f: ManuallyDrop::new(f),
|
||||
};
|
||||
save_context(delegate::<T, F>, ptr::addr_of_mut!(data).cast());
|
||||
unsafe { ManuallyDrop::into_inner(data.t) }
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct UnwindException {
|
||||
pub exception_class: u64,
|
||||
@ -125,8 +152,7 @@ macro_rules! try2 {
|
||||
pub extern "C-unwind" fn _Unwind_RaiseException(
|
||||
exception: &mut UnwindException,
|
||||
) -> UnwindReasonCode {
|
||||
let saved_ctx = save_context();
|
||||
|
||||
with_context(|saved_ctx| {
|
||||
// Phase 1: Search for handler
|
||||
let mut ctx = saved_ctx.clone();
|
||||
let mut signal = false;
|
||||
@ -166,12 +192,12 @@ pub extern "C-unwind" fn _Unwind_RaiseException(
|
||||
exception.private_1 = None;
|
||||
exception.private_2 = handler_cfa;
|
||||
|
||||
let mut ctx = saved_ctx;
|
||||
let code = raise_exception_phase2(exception, &mut ctx, handler_cfa);
|
||||
let code = raise_exception_phase2(exception, saved_ctx, handler_cfa);
|
||||
match code {
|
||||
UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(&ctx) },
|
||||
UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(saved_ctx) },
|
||||
_ => code,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn raise_exception_phase2(
|
||||
@ -225,16 +251,16 @@ pub extern "C-unwind" fn _Unwind_ForcedUnwind(
|
||||
stop: UnwindStopFn,
|
||||
stop_arg: *mut c_void,
|
||||
) -> UnwindReasonCode {
|
||||
let mut ctx = save_context();
|
||||
|
||||
with_context(|ctx| {
|
||||
exception.private_1 = Some(stop);
|
||||
exception.private_2 = stop_arg as _;
|
||||
|
||||
let code = force_unwind_phase2(exception, &mut ctx, stop, stop_arg);
|
||||
let code = force_unwind_phase2(exception, ctx, stop, stop_arg);
|
||||
match code {
|
||||
UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(&ctx) },
|
||||
UnwindReasonCode::INSTALL_CONTEXT => unsafe { restore_context(ctx) },
|
||||
_ => code,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn force_unwind_phase2(
|
||||
@ -304,21 +330,21 @@ fn force_unwind_phase2(
|
||||
#[inline(never)]
|
||||
#[no_mangle]
|
||||
pub extern "C-unwind" fn _Unwind_Resume(exception: &mut UnwindException) -> ! {
|
||||
let mut ctx = save_context();
|
||||
|
||||
with_context(|ctx| {
|
||||
let code = match exception.private_1 {
|
||||
None => {
|
||||
let handler_cfa = exception.private_2;
|
||||
raise_exception_phase2(exception, &mut ctx, handler_cfa)
|
||||
raise_exception_phase2(exception, ctx, handler_cfa)
|
||||
}
|
||||
Some(stop) => {
|
||||
let stop_arg = exception.private_2 as _;
|
||||
force_unwind_phase2(exception, &mut ctx, stop, stop_arg)
|
||||
force_unwind_phase2(exception, ctx, stop, stop_arg)
|
||||
}
|
||||
};
|
||||
assert!(code == UnwindReasonCode::INSTALL_CONTEXT);
|
||||
|
||||
unsafe { restore_context(&ctx) }
|
||||
unsafe { restore_context(ctx) }
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
@ -331,13 +357,13 @@ pub extern "C-unwind" fn _Unwind_Resume_or_Rethrow(
|
||||
Some(v) => v,
|
||||
};
|
||||
|
||||
let mut ctx = save_context();
|
||||
|
||||
with_context(|ctx| {
|
||||
let stop_arg = exception.private_2 as _;
|
||||
let code = force_unwind_phase2(exception, &mut ctx, stop, stop_arg);
|
||||
let code = force_unwind_phase2(exception, ctx, stop, stop_arg);
|
||||
assert!(code == UnwindReasonCode::INSTALL_CONTEXT);
|
||||
|
||||
unsafe { restore_context(&ctx) }
|
||||
unsafe { restore_context(ctx) }
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -353,7 +379,8 @@ pub extern "C-unwind" fn _Unwind_Backtrace(
|
||||
trace: UnwindTraceFn,
|
||||
trace_argument: *mut c_void,
|
||||
) -> UnwindReasonCode {
|
||||
let mut ctx = save_context();
|
||||
with_context(|ctx| {
|
||||
let mut ctx = ctx.clone();
|
||||
let mut signal = false;
|
||||
let mut skipping = cfg!(feature = "hide-trace");
|
||||
|
||||
@ -385,4 +412,5 @@ pub extern "C-unwind" fn _Unwind_Backtrace(
|
||||
return UnwindReasonCode::END_OF_STACK;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user