/************************************************************* * __wine_exception_handler (NTDLL.@) * * Exception handler for exception blocks declared in Wine code. */ DWORD __wine_exception_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame, CONTEXT *context, LPVOID pdispatcher ) { __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL)) return ExceptionContinueSearch; if (wine_frame->u.filter) { EXCEPTION_POINTERS ptrs; ptrs.ExceptionRecord = record; ptrs.ContextRecord = context; switch(wine_frame->u.filter( &ptrs )) { case EXCEPTION_CONTINUE_SEARCH: return ExceptionContinueSearch; case EXCEPTION_CONTINUE_EXECUTION: return ExceptionContinueExecution; case EXCEPTION_EXECUTE_HANDLER: break; default: MESSAGE( "Invalid return value from exception filter\n" ); assert( FALSE ); } } /* hack to make GetExceptionCode() work in handler */ wine_frame->ExceptionCode = record->ExceptionCode; wine_frame->ExceptionRecord = wine_frame; RtlUnwind( frame, 0, record, 0 ); __wine_pop_frame( frame ); longjmp( wine_frame->jmp, 1 ); }
VOID longjmp ( IN jmp_buf JumpBuffer, IN int ReturnValue ) /*++ Routine Description: This function executes a long jump operation by virtually unwinding to the caller of the corresponding call to set jump and then calling unwind to transfer control to the jump target. Arguments: JumpBuffer - Supplies the address of a jump buffer that contains the virtual frame pointer and target address. N.B. This is an array of double to force quadword alignment. ReturnValue - Supplies the value that is to be returned to the caller of set jump. Return Value: None. --*/ { PULONG JumpArray; // // If the specified return value is zero, then set it to one. // if (ReturnValue == 0) { ReturnValue = 1; } // // Unwind to the caller of set jump and return the specified value. // There is no return from unwind. // JumpArray = (PULONG)&JumpBuffer[0]; RtlUnwind((PVOID)JumpArray[0], (PVOID)JumpArray[1], NULL, (PVOID)ReturnValue); }
/******************************************************************* * longjmp (MSVCRT.@) */ void __cdecl MSVCRT_longjmp(struct MSVCRT___JUMP_BUFFER *jmp, int retval) { EXCEPTION_RECORD rec; if (!retval) retval = 1; if (jmp->Frame) { rec.ExceptionCode = STATUS_LONGJUMP; rec.ExceptionFlags = 0; rec.ExceptionRecord = NULL; rec.ExceptionAddress = NULL; rec.NumberParameters = 1; rec.ExceptionInformation[0] = (DWORD_PTR)jmp; RtlUnwind((void *)jmp->Frame, (void *)jmp->Pc, &rec, IntToPtr(retval)); } longjmp_set_regs(jmp, retval); }
void longjmpex( jmp_buf jb, int ret ) { EXCEPTION_RECORD er; _JUMPEXDATA *jd = (_JUMPEXDATA *)jb; er.ExceptionCode = 0xE5670123; er.ExceptionFlags = 0x00000002; er.ExceptionRecord = 0L; er.ExceptionAddress = 0L; er.NumberParameters = 1L; er.ExceptionInformation[0] = jd->sp; if( !_ProcSetsFP( RtlLookupFunctionEntry( jd->pc ) ) ) RtlUnwind( (void *)jd->sp, (void *)jd->pc, &er, (void *)ret ); else RtlUnwindRfp( jd->fp, jd->pc, &er, ret ); } /* longjmp() */
void __stdcall _UnwindNestedFrames( EHRegistrationNode *pRN, // Unwind up to (but not including) this frame EHExceptionRecord *pExcept // The exception that initiated this unwind ) { EHTRACE_ENTER; void* pReturnPoint; EHRegistrationNode *pDispatcherRN; // Magic! __asm { // // Save the dispatcher's marker node // // NOTE: RtlUnwind will trash the callee-save regs EBX, ESI, and EDI. // We explicitly use them here in the inline-asm so they get preserved // and restored by the function prologue/epilogue. // mov esi, dword ptr FS:[0] // use ESI mov pDispatcherRN, esi } __asm mov pReturnPoint, offset ReturnPoint RtlUnwind(pRN, pReturnPoint, (PEXCEPTION_RECORD)pExcept, nullptr); ReturnPoint: PER_FLAGS(pExcept) &= ~EXCEPTION_UNWINDING; // Clear the 'Unwinding' flag // in case exception is rethrown __asm { // // Re-link the dispatcher's marker node // mov edi, dword ptr FS:[0] // Get the current head (use EDI) mov ebx, pDispatcherRN // Get the saved head (use EBX) mov [ebx], edi // Link saved head to current head mov dword ptr FS:[0], ebx // Make saved head current head } EHTRACE_EXIT; return; }
void CPPLIB( PdUnwind ) // UNWIND USING PROCEDURE DESCRIPTORS ( FsExcRec* exc_rec ) // - exception record { DISPATCH_EXC* dispatch; // - dispatch control RW_DTREG* rw; // - R/W block being dispatched void* frame; // - frame for rtn. (SP or FP) void* pc; // - PC for continuation (after the setjmp) _CONTEXT ctx; // - context for function unsigned save_area[3*2]; // - save area RtlCaptureContext( &ctx ); pc = CPPLIB( PdCtx )( &ctx, save_area ); if( pc ) { dispatch = exc_rec->dispatch; rw = dispatch->rw; frame = (void*)( (char*)rw - rw->base.ro->fun.rw_offset ); if( procSetsFP( dispatch->pdata ) ) { RtlUnwindRfp( frame, pc, exc_rec, save_area ); } else { RtlUnwind( frame, pc, exc_rec, save_area ); } } }
void _global_unwind2(PEXCEPTION_FRAME frame) { RtlUnwind(frame, 0, 0, 0); }