void sigsegv_handler(int signal, siginfo_t *info, void *raw_context) { #ifndef _M_GENERIC if (signal != SIGSEGV) { // We are not interested in other signals - handle it as usual. return; } ucontext_t *context = (ucontext_t *)raw_context; int sicode = info->si_code; if (sicode != SEGV_MAPERR && sicode != SEGV_ACCERR) { // Huh? Return. return; } void *fault_memory_ptr = (void *)info->si_addr; // Get all the information we can out of the context. mcontext_t *ctx = &context->uc_mcontext; #ifdef _M_X64 u8 *fault_instruction_ptr = (u8 *)CREG_RIP(ctx); #else u8 *fault_instruction_ptr = (u8 *)CREG_EIP(ctx); #endif if (!JitInterface::IsInCodeSpace(fault_instruction_ptr)) { // Let's not prevent debugging. return; } u64 bad_address = (u64)fault_memory_ptr; u64 memspace_bottom = (u64)Memory::base; if (bad_address < memspace_bottom) { PanicAlertT("Exception handler - access below memory space. %08llx%08llx", bad_address >> 32, bad_address); }
if (bad_address < memspace_bottom) { PanicAlertT("Exception handler - access below memory space. %08llx%08llx", bad_address >> 32, bad_address); } u32 em_address = (u32)(bad_address - memspace_bottom); // Backpatch time. // Seems we'll need to disassemble to get access_type - that work is probably // best done and debugged on the Windows side. int access_type = 0; CONTEXT fake_ctx; #ifdef _M_X64 fake_ctx.Rax = CREG_RAX(ctx); fake_ctx.Rip = CREG_RIP(ctx); #else fake_ctx.Eax = CREG_EAX(ctx); fake_ctx.Eip = CREG_EIP(ctx); #endif const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, access_type, em_address, &fake_ctx); if (new_rip) { #ifdef _M_X64 CREG_RAX(ctx) = fake_ctx.Rax; CREG_RIP(ctx) = fake_ctx.Rip; #else CREG_EAX(ctx) = fake_ctx.Eax; CREG_EIP(ctx) = fake_ctx.Eip; #endif }