use super::windows_bindings::Windows::Win32::{
Foundation::EXCEPTION_STACK_OVERFLOW,
System::Diagnostics::Debug::{AddVectoredExceptionHandler, CONTEXT, EXCEPTION_POINTERS},
};
use crate::rt::{guard, Context, ContextStack};
use std::sync::Once;
unsafe extern "system" fn vectored_handler(exception_info: *mut EXCEPTION_POINTERS) -> i32 {
const EXCEPTION_CONTINUE_SEARCH: i32 = 0;
const EXCEPTION_CONTINUE_EXECUTION: i32 = -1;
let info = &*exception_info;
let rec = &(*info.ExceptionRecord);
let context = &mut (*info.ContextRecord);
#[cfg(target_arch = "x86_64")]
let fault_sp = context.Rsp as usize;
#[cfg(target_arch = "aarch64")]
let fault_sp = context.Sp as usize;
if rec.ExceptionCode == EXCEPTION_STACK_OVERFLOW && guard::current().contains(&fault_sp) {
eprintln!(
"\ncoroutine in thread '{}' has overflowed its stack\n",
std::thread::current().name().unwrap_or("<unknown>")
);
let env = ContextStack::current();
let cur = env.top();
cur.err = Some(Box::new(crate::Error::StackErr));
context_init(env.pop_context(cur as *mut _), context);
EXCEPTION_CONTINUE_EXECUTION
} else {
EXCEPTION_CONTINUE_SEARCH
}
}
unsafe fn init() {
AddVectoredExceptionHandler(1, Some(vectored_handler));
}
pub fn init_once() {
static INIT_ONCE: Once = Once::new();
INIT_ONCE.call_once(|| unsafe {
init();
})
}
#[cfg(target_arch = "x86_64")]
unsafe fn context_init(parent: &mut Context, context: &mut CONTEXT) {
let [rbx, rsp, rbp, _, r12, r13, r14, r15, _, _, _, stack_base, stack_limit, dealloc_stack, ..] =
parent.regs.regs.gpr;
let rip = *(rsp as *const usize);
let rsp = rsp + std::mem::size_of::<usize>();
context.Rbx = rbx as u64;
context.Rsp = rsp as u64;
context.Rbp = rbp as u64;
context.R12 = r12 as u64;
context.R13 = r13 as u64;
context.R14 = r14 as u64;
context.R15 = r15 as u64;
context.Rip = rip as u64;
let teb: usize;
unsafe {
std::arch::asm!(
"mov {0}, gs:[0x30]",
out(reg) teb
);
}
*((teb + 0x08) as *mut usize) = stack_base;
*((teb + 0x10) as *mut usize) = stack_limit;
*((teb + 0x1478) as *mut usize) = dealloc_stack;
}
#[cfg(target_arch = "aarch64")]
unsafe fn context_init(parent: &mut Context, context: &mut CONTEXT) {
const X19: usize = 0;
const FP: usize = 10;
const LR: usize = 11;
const SP: usize = 12;
const D_BASE: usize = 14; const STACK_BASE: usize = 22;
const STACK_LIMIT: usize = 23;
const STACK_DEALLOC: usize = 24;
let gpr = &parent.regs.regs.gpr;
let regs = &mut context.Anonymous.Anonymous;
regs.X19 = gpr[X19] as u64;
regs.X20 = gpr[X19 + 1] as u64;
regs.X21 = gpr[X19 + 2] as u64;
regs.X22 = gpr[X19 + 3] as u64;
regs.X23 = gpr[X19 + 4] as u64;
regs.X24 = gpr[X19 + 5] as u64;
regs.X25 = gpr[X19 + 6] as u64;
regs.X26 = gpr[X19 + 7] as u64;
regs.X27 = gpr[X19 + 8] as u64;
regs.X28 = gpr[X19 + 9] as u64;
regs.Fp = gpr[FP] as u64;
regs.Lr = gpr[LR] as u64;
context.Sp = gpr[SP] as u64;
context.Pc = gpr[LR] as u64;
let d_src = (gpr.as_ptr() as *const u64).add(D_BASE);
for i in 0..8 {
let bits = *d_src.add(i);
context.V[8 + i].Anonymous.Low = bits;
context.V[8 + i].Anonymous.High = 0;
}
let teb: usize;
core::arch::asm!("mov {0}, x18", out(reg) teb);
*((teb + 0x08) as *mut usize) = gpr[STACK_BASE];
*((teb + 0x10) as *mut usize) = gpr[STACK_LIMIT];
*((teb + 0x1478) as *mut usize) = gpr[STACK_DEALLOC];
}