From: Vibhav Pant vibhavp@gmail.com
--- dlls/msvcr100/msvcr100.spec | 2 +- dlls/msvcr110/msvcr110.spec | 2 +- dlls/msvcr120/msvcr120.spec | 2 +- dlls/msvcr80/msvcr80.spec | 2 +- dlls/msvcr90/msvcr90.spec | 2 +- dlls/msvcrt/except.c | 254 +++++++++++++++++++++++++++++++++++ dlls/msvcrt/except_arm.c | 8 ++ dlls/msvcrt/except_arm64.c | 29 ++++ dlls/msvcrt/except_arm64ec.c | 30 +++++ dlls/msvcrt/msvcrt.spec | 2 +- dlls/ucrtbase/ucrtbase.spec | 2 +- 11 files changed, 328 insertions(+), 7 deletions(-)
diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index d5949728840..95885b79162 100644 --- a/dlls/msvcr100/msvcr100.spec +++ b/dlls/msvcr100/msvcr100.spec @@ -712,7 +712,7 @@ @ cdecl __AdjustPointer(ptr ptr) @ stub __BuildCatchObject @ stub __BuildCatchObjectHelper -@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) ntdll.__C_specific_handler +@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) msvcrt.__C_specific_handler @ cdecl __CppXcptFilter(long ptr) @ stub __CxxCallUnwindDelDtor @ stub __CxxCallUnwindDtor diff --git a/dlls/msvcr110/msvcr110.spec b/dlls/msvcr110/msvcr110.spec index 9e45d08432f..b221cce714b 100644 --- a/dlls/msvcr110/msvcr110.spec +++ b/dlls/msvcr110/msvcr110.spec @@ -872,7 +872,7 @@ @ cdecl __AdjustPointer(ptr ptr) @ stub __BuildCatchObject @ stub __BuildCatchObjectHelper -@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) ntdll.__C_specific_handler +@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) msvcrt.__C_specific_handler @ cdecl __CppXcptFilter(long ptr) @ cdecl __CxxDetectRethrow(ptr) @ cdecl __CxxExceptionFilter(ptr ptr long ptr) diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec index 42494e4e39f..b7f89645888 100644 --- a/dlls/msvcr120/msvcr120.spec +++ b/dlls/msvcr120/msvcr120.spec @@ -857,7 +857,7 @@ @ cdecl __AdjustPointer(ptr ptr) @ stub __BuildCatchObject @ stub __BuildCatchObjectHelper -@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) ntdll.__C_specific_handler +@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) msvcrt.__C_specific_handler @ cdecl __CppXcptFilter(long ptr) @ cdecl __CxxDetectRethrow(ptr) @ cdecl __CxxExceptionFilter(ptr ptr long ptr) diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index 0e5084c6c6e..a1a38586126 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -198,7 +198,7 @@ @ cdecl __AdjustPointer(ptr ptr) @ stub __BuildCatchObject @ stub __BuildCatchObjectHelper -@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) ntdll.__C_specific_handler +@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) msvcrt.__C_specific_handler @ cdecl __CppXcptFilter(long ptr) @ stub __CxxCallUnwindDelDtor @ stub __CxxCallUnwindDtor diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index 97c6427bd80..cd09aaea497 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -189,7 +189,7 @@ @ cdecl __AdjustPointer(ptr ptr) @ stub __BuildCatchObject @ stub __BuildCatchObjectHelper -@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) ntdll.__C_specific_handler +@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) msvcrt.__C_specific_handler @ cdecl __CppXcptFilter(long ptr) @ stub __CxxCallUnwindDelDtor @ stub __CxxCallUnwindDtor diff --git a/dlls/msvcrt/except.c b/dlls/msvcrt/except.c index 383c67f7437..1b10387a810 100644 --- a/dlls/msvcrt/except.c +++ b/dlls/msvcrt/except.c @@ -43,6 +43,9 @@ #include "cppexcept.h"
WINE_DEFAULT_DEBUG_CHANNEL(seh); +#ifndef __i386__ +WINE_DECLARE_DEBUG_CHANNEL(unwind); +#endif
#if _MSVCR_VER>=70 && _MSVCR_VER<=71 static MSVCRT_security_error_handler security_error_handler; @@ -1077,3 +1080,254 @@ int* CDECL __processing_throw(void) }
#endif /* _MSVCR_VER>=140 */ + +#ifndef __i386__ +#define DUMP_SCOPE_TABLE(base,table) do { \ + for (unsigned int i = 0; i < table->Count; i++) \ + TRACE( " %u: %p-%p handler %p target %p\n", i, \ + (char *)base + table->ScopeRecord[i].BeginAddress, \ + (char *)base + table->ScopeRecord[i].EndAddress, \ + (char *)base + table->ScopeRecord[i].HandlerAddress, \ + (char *)base + table->ScopeRecord[i].JumpTarget ); \ +} while(0) + +LONG __C_ExecuteExceptionFilter( EXCEPTION_POINTERS *ptrs, void *frame, PEXCEPTION_FILTER filter, BYTE *nonvolatile ); +#endif + +/* msvcrt's __C_specific_handler will call the destructor on the exception object while handling C++ exceptions, unlike ntdll. */ + +#if defined(__aarch64__) || defined(__arm64ec__) + +#ifdef __arm64ec__ +#define __C_specific_handler __C_specific_handler_arm64 +#endif + +EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec, void *frame, + ARM64_NT_CONTEXT *context, + DISPATCHER_CONTEXT_ARM64 *dispatch ) +{ + const SCOPE_TABLE *table = dispatch->HandlerData; + ULONG_PTR base = dispatch->ImageBase; + ULONG_PTR pc = dispatch->ControlPc; + unsigned int i; + void *handler; + + TRACE( "%p %p %p %p pc %Ix\n", rec, frame, context, dispatch, pc ); + if (TRACE_ON(unwind)) DUMP_SCOPE_TABLE( base, table ); + + if (dispatch->ControlPcIsUnwound) pc -= 4; + + if (rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (table->ScopeRecord[i].JumpTarget) continue; + + if (rec->ExceptionFlags & EXCEPTION_TARGET_UNWIND && + dispatch->TargetPc >= base + table->ScopeRecord[i].BeginAddress && + dispatch->TargetPc < base + table->ScopeRecord[i].EndAddress) + { + break; + } + handler = (void *)(base + table->ScopeRecord[i].HandlerAddress); + dispatch->ScopeIndex = i + 1; + TRACE( "scope %u calling __finally %p frame %p\n", i, handler, frame ); + __C_ExecuteExceptionFilter( ULongToPtr(TRUE), frame, handler, dispatch->NonVolatileRegisters ); + } + } + else + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (!table->ScopeRecord[i].JumpTarget) continue; + + if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER) + { + EXCEPTION_POINTERS ptrs = { rec, (CONTEXT *)context }; + + handler = (void *)(base + table->ScopeRecord[i].HandlerAddress); + TRACE( "scope %u calling filter %p ptrs %p frame %p\n", i, handler, &ptrs, frame ); + switch (__C_ExecuteExceptionFilter( &ptrs, frame, handler, dispatch->NonVolatileRegisters )) + { + case EXCEPTION_EXECUTE_HANDLER: + break; + case EXCEPTION_CONTINUE_SEARCH: + continue; + case EXCEPTION_CONTINUE_EXECUTION: + return ExceptionContinueExecution; + } + } + /* Call the destructor if we're handling a C++ exception. */ + if (is_cxx_exception(rec)) __DestructExceptionObject( rec ); + + TRACE( "unwinding to target %Ix\n", base + table->ScopeRecord[i].JumpTarget ); + RtlUnwindEx( frame, (char *)base + table->ScopeRecord[i].JumpTarget, + rec, ULongToPtr(rec->ExceptionCode), (CONTEXT *)dispatch->ContextRecord, + dispatch->HistoryTable ); + } + } + return ExceptionContinueSearch; +} + +#ifdef __arm64ec__ +#undef __C_specific_handler +#endif + +#endif /* __aarch64__ || __arm64ec__ */ + +#ifdef __arm__ + +EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec, void *frame, + CONTEXT *context, DISPATCHER_CONTEXT *dispatch ) +{ + const SCOPE_TABLE *table = dispatch->HandlerData; + ULONG_PTR base = dispatch->ImageBase; + ULONG_PTR pc = dispatch->ControlPc; + unsigned int i; + void *handler; + + TRACE( "%p %p %p %p pc %Ix\n", rec, frame, context, dispatch, pc ); + if (TRACE_ON(unwind)) DUMP_SCOPE_TABLE( base, table ); + + if (dispatch->ControlPcIsUnwound) pc -= 2; + + if (rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (table->ScopeRecord[i].JumpTarget) continue; + + if (rec->ExceptionFlags & EXCEPTION_TARGET_UNWIND && + dispatch->TargetPc >= base + table->ScopeRecord[i].BeginAddress && + dispatch->TargetPc < base + table->ScopeRecord[i].EndAddress) + { + break; + } + handler = (void *)(base + table->ScopeRecord[i].HandlerAddress); + dispatch->ScopeIndex = i + 1; + TRACE( "scope %u calling __finally %p frame %p\n", i, handler, frame ); + __C_ExecuteExceptionFilter( ULongToPtr(TRUE), frame, handler, dispatch->NonVolatileRegisters ); + } + } + else + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (!table->ScopeRecord[i].JumpTarget) continue; + + if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER) + { + EXCEPTION_POINTERS ptrs = { rec, context }; + + handler = (void *)(base + table->ScopeRecord[i].HandlerAddress); + TRACE( "scope %u calling filter %p ptrs %p frame %p\n", i, handler, &ptrs, frame ); + switch (__C_ExecuteExceptionFilter( &ptrs, frame, handler, dispatch->NonVolatileRegisters )) + { + case EXCEPTION_EXECUTE_HANDLER: + break; + case EXCEPTION_CONTINUE_SEARCH: + continue; + case EXCEPTION_CONTINUE_EXECUTION: + return ExceptionContinueExecution; + } + } + /* Call the destructor if we're handling a C++ exception. */ + if (is_cxx_exception( rec )) __DestructExceptionObject( rec ); + + TRACE( "unwinding to target %lx\n", base + table->ScopeRecord[i].JumpTarget ); + RtlUnwindEx( frame, (char *)base + table->ScopeRecord[i].JumpTarget, + rec, ULongToPtr(rec->ExceptionCode), dispatch->ContextRecord, + dispatch->HistoryTable ); + } + } + return ExceptionContinueSearch; +} + +#endif /* __arm__ */ + +#ifdef __x86_64__ + +EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec, void *frame, CONTEXT *context, + DISPATCHER_CONTEXT *dispatch ) +{ + const SCOPE_TABLE *table = dispatch->HandlerData; + ULONG_PTR base = dispatch->ImageBase; + ULONG_PTR pc = dispatch->ControlPc; + unsigned int i; + +#ifdef __arm64ec__ + if (RtlIsEcCode( pc )) + return __C_specific_handler_arm64( rec, frame, (ARM64_NT_CONTEXT *)context, + (DISPATCHER_CONTEXT_ARM64 *)dispatch ); +#endif + + TRACE( "%p %p %p %p pc %Ix\n", rec, frame, context, dispatch, pc ); + if (TRACE_ON(unwind)) DUMP_SCOPE_TABLE( base, table ); + + if (rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (table->ScopeRecord[i].JumpTarget) continue; + + if (rec->ExceptionFlags & EXCEPTION_TARGET_UNWIND && + dispatch->TargetIp >= base + table->ScopeRecord[i].BeginAddress && + dispatch->TargetIp < base + table->ScopeRecord[i].EndAddress) + { + break; + } + else + { + PTERMINATION_HANDLER handler = (void *)(base + table->ScopeRecord[i].HandlerAddress); + dispatch->ScopeIndex = i + 1; + TRACE( "scope %u calling __finally %p frame %p\n", i, handler, frame ); + handler( TRUE, frame ); + } + } + } + else + { + for (i = dispatch->ScopeIndex; i < table->Count; i++) + { + if (pc < base + table->ScopeRecord[i].BeginAddress) continue; + if (pc >= base + table->ScopeRecord[i].EndAddress) continue; + if (!table->ScopeRecord[i].JumpTarget) continue; + + if (table->ScopeRecord[i].HandlerAddress != EXCEPTION_EXECUTE_HANDLER) + { + EXCEPTION_POINTERS ptrs = { rec, context }; + PEXCEPTION_FILTER filter = (void *)(base + table->ScopeRecord[i].HandlerAddress); + + TRACE( "scope %u calling filter %p ptrs %p frame %p\n", i, filter, &ptrs, frame ); + switch (filter( &ptrs, frame )) + { + case EXCEPTION_EXECUTE_HANDLER: + break; + case EXCEPTION_CONTINUE_SEARCH: + continue; + case EXCEPTION_CONTINUE_EXECUTION: + return ExceptionContinueExecution; + } + } + if (is_cxx_exception( rec )) __DestructExceptionObject( rec ); + + TRACE( "unwinding to target %Ix\n", base + table->ScopeRecord[i].JumpTarget ); + RtlUnwindEx( frame, (char *)base + table->ScopeRecord[i].JumpTarget, + rec, ULongToPtr(rec->ExceptionCode), dispatch->ContextRecord, + dispatch->HistoryTable ); + } + } + return ExceptionContinueSearch; +} + +#endif /* __x86_64__ */ \ No newline at end of file diff --git a/dlls/msvcrt/except_arm.c b/dlls/msvcrt/except_arm.c index b2bf94d5338..f54a93784ef 100644 --- a/dlls/msvcrt/except_arm.c +++ b/dlls/msvcrt/except_arm.c @@ -94,4 +94,12 @@ int handle_fpieee_flt( __msvcrt_ulong exception_code, EXCEPTION_POINTERS *ep, return EXCEPTION_CONTINUE_SEARCH; }
+__ASM_GLOBAL_FUNC( __C_ExecuteExceptionFilter, + "push {r3-r11,lr}\n\t" + ".seh_save_regs_w {r3-r11,lr}\n\t" + ".seh_endprologue\n\t" + "ldm r3, {r4-r11}\n\t" + "blx r2\n\t" + "pop {r3-r11,pc}\n\t" ); + #endif /* __arm__ */ diff --git a/dlls/msvcrt/except_arm64.c b/dlls/msvcrt/except_arm64.c index 6d515f8b150..81b0bf5b6ec 100644 --- a/dlls/msvcrt/except_arm64.c +++ b/dlls/msvcrt/except_arm64.c @@ -125,4 +125,33 @@ int handle_fpieee_flt( __msvcrt_ulong exception_code, EXCEPTION_POINTERS *ep, return EXCEPTION_CONTINUE_SEARCH; }
+__ASM_GLOBAL_FUNC( __C_ExecuteExceptionFilter, + "stp x29, x30, [sp, #-96]!\n\t" + ".seh_save_fplr_x 96\n\t" + "stp x19, x20, [sp, #16]\n\t" + ".seh_save_regp x19, 16\n\t" + "stp x21, x22, [sp, #32]\n\t" + ".seh_save_regp x21, 32\n\t" + "stp x23, x24, [sp, #48]\n\t" + ".seh_save_regp x23, 48\n\t" + "stp x25, x26, [sp, #64]\n\t" + ".seh_save_regp x25, 64\n\t" + "stp x27, x28, [sp, #80]\n\t" + ".seh_save_regp x27, 80\n\t" + ".seh_endprologue\n\t" + "ldp x19, x20, [x3, #0]\n\t" /* nonvolatile regs */ + "ldp x21, x22, [x3, #16]\n\t" + "ldp x23, x24, [x3, #32]\n\t" + "ldp x25, x26, [x3, #48]\n\t" + "ldp x27, x28, [x3, #64]\n\t" + "ldr x1, [x3, #80]\n\t" /* x29 = frame */ + "blr x2\n\t" /* filter */ + "ldp x19, x20, [sp, #16]\n\t" + "ldp x21, x22, [sp, #32]\n\t" + "ldp x23, x24, [sp, #48]\n\t" + "ldp x25, x26, [sp, #64]\n\t" + "ldp x27, x28, [sp, #80]\n\t" + "ldp x29, x30, [sp], #96\n\t" + "ret" ); + #endif /* __aarch64__ */ diff --git a/dlls/msvcrt/except_arm64ec.c b/dlls/msvcrt/except_arm64ec.c index b2e723f79b3..fe1d79610a2 100644 --- a/dlls/msvcrt/except_arm64ec.c +++ b/dlls/msvcrt/except_arm64ec.c @@ -166,4 +166,34 @@ void __cdecl __crtCapturePreviousContext( CONTEXT *ctx ) } #endif
+LONG __attribute__((naked)) __C_ExecuteExceptionFilter( EXCEPTION_POINTERS *ptrs, void *frame, + PEXCEPTION_FILTER filter, BYTE *nonvolatile ) +{ + asm( ".seh_proc _C_ExecuteExceptionFilter\n\t" + "stp x29, x30, [sp, #-80]!\n\t" + ".seh_save_fplr_x 80\n\t" + "stp x19, x20, [sp, #16]\n\t" + ".seh_save_regp x19, 16\n\t" + "stp x21, x22, [sp, #32]\n\t" + ".seh_save_regp x21, 32\n\t" + "stp x25, x26, [sp, #48]\n\t" + ".seh_save_regp x25, 48\n\t" + "str x27, [sp, #64]\n\t" + ".seh_save_reg x27, 64\n\t" + ".seh_endprologue\n\t" + "ldp x19, x20, [x3, #0]\n\t" /* nonvolatile regs */ + "ldp x21, x22, [x3, #16]\n\t" + "ldp x25, x26, [x3, #48]\n\t" + "ldr x27, [x3, #64]\n\t" + "ldr x1, [x3, #80]\n\t" /* x29 = frame */ + "blr x2\n\t" /* filter */ + "ldp x19, x20, [sp, #16]\n\t" + "ldp x21, x22, [sp, #32]\n\t" + "ldp x25, x26, [sp, #48]\n\t" + "ldr x27, [sp, #64]\n\t" + "ldp x29, x30, [sp], #80\n\t" + "ret\n\t" + ".seh_endproc" ); +} + #endif /* __arm64ec__ */ diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index 27cd61376e4..c308c1711a7 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -174,7 +174,7 @@ @ extern _HUGE MSVCRT__HUGE @ cdecl _Strftime(ptr long str ptr ptr) @ cdecl _XcptFilter(long ptr) -@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) ntdll.__C_specific_handler +@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) @ cdecl __CppXcptFilter(long ptr) # stub __CxxCallUnwindDelDtor # stub __CxxCallUnwindDtor diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec index f2e5102b616..1f738637317 100644 --- a/dlls/ucrtbase/ucrtbase.spec +++ b/dlls/ucrtbase/ucrtbase.spec @@ -48,7 +48,7 @@ @ cdecl __AdjustPointer(ptr ptr) @ stub __BuildCatchObject @ stub __BuildCatchObjectHelper -@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) ntdll.__C_specific_handler +@ stdcall -arch=!i386 __C_specific_handler(ptr long ptr ptr) msvcrt.__C_specific_handler @ cdecl __CxxDetectRethrow(ptr) @ cdecl __CxxExceptionFilter(ptr ptr long ptr) @ cdecl -norelay __CxxFrameHandler(ptr ptr ptr ptr)