Module: wine Branch: master Commit: cf08bbaa0f95f40b972b330e1ee687e2cac0501c URL: https://gitlab.winehq.org/wine/wine/-/commit/cf08bbaa0f95f40b972b330e1ee687e...
Author: Alexandre Julliard julliard@winehq.org Date: Mon Mar 25 18:05:39 2024 +0100
ntdll: Use a common wrapper to call unwind handlers on x86-64.
---
dlls/ntdll/signal_x86_64.c | 133 +++++++++++++++++---------------------------- 1 file changed, 49 insertions(+), 84 deletions(-)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 021c4c30daf..78afadbe387 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -391,6 +391,9 @@ struct unwind_exception_frame * save space when .seh handler is used. */ DISPATCHER_CONTEXT *dispatch; }; +C_ASSERT( sizeof(struct unwind_exception_frame) == 0x28 ); +C_ASSERT( offsetof(struct unwind_exception_frame, dispatch) == 0x20 ); +
/********************************************************************** * unwind_exception_handler @@ -418,30 +421,26 @@ DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR return ExceptionCollidedUnwind; }
-/*********************************************************************** - * unwind_handler_call_wrapper + +/********************************************************************** + * call_unwind_handler */ #ifdef __WINE_PE_BUILD -DWORD WINAPI unwind_handler_call_wrapper( EXCEPTION_RECORD *rec, void *frame, - CONTEXT *context, DISPATCHER_CONTEXT *dispatch ); - -C_ASSERT( sizeof(struct unwind_exception_frame) == 0x28 ); -C_ASSERT( offsetof(struct unwind_exception_frame, dispatch) == 0x20 ); -C_ASSERT( offsetof(DISPATCHER_CONTEXT, LanguageHandler) == 0x30 ); - -__ASM_GLOBAL_FUNC( unwind_handler_call_wrapper, +DWORD WINAPI call_unwind_handler( EXCEPTION_RECORD *rec, ULONG_PTR frame, + CONTEXT *context, void *dispatch, PEXCEPTION_ROUTINE handler ); +__ASM_GLOBAL_FUNC( call_unwind_handler, "subq $0x28,%rsp\n\t" ".seh_stackalloc 0x28\n\t" ".seh_endprologue\n\t" + ".seh_handler unwind_exception_handler, @except, @unwind\n\t" "movq %r9,0x20(%rsp)\n\t" /* unwind_exception_frame->dispatch */ - "callq *0x30(%r9)\n\t" /* dispatch->LanguageHandler */ + "callq *0x50(%rsp)\n\t" /* handler */ "nop\n\t" /* avoid epilogue so handler is called */ "addq $0x28, %rsp\n\t" - "ret\n\t" - ".seh_handler " __ASM_NAME("unwind_exception_handler") ", @except, @unwind\n\t" ) + "ret" ) #else -static DWORD unwind_handler_call_wrapper( EXCEPTION_RECORD *rec, void *frame, - CONTEXT *context, DISPATCHER_CONTEXT *dispatch ) +static DWORD call_unwind_handler( EXCEPTION_RECORD *rec, ULONG_PTR frame, + CONTEXT *context, void *dispatch, PEXCEPTION_ROUTINE handler ) { struct unwind_exception_frame wrapper_frame; DWORD res; @@ -449,68 +448,12 @@ static DWORD unwind_handler_call_wrapper( EXCEPTION_RECORD *rec, void *frame, wrapper_frame.frame.Handler = unwind_exception_handler; wrapper_frame.dispatch = dispatch; __wine_push_frame( &wrapper_frame.frame ); - res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); + res = handler( rec, (void *)frame, context, dispatch ); __wine_pop_frame( &wrapper_frame.frame ); return res; } #endif
-/********************************************************************** - * call_unwind_handler - * - * Call a single unwind handler. - */ -DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch ) -{ - DWORD res; - - TRACE( "calling handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n", - dispatch->LanguageHandler, rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); - res = unwind_handler_call_wrapper( rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); - TRACE( "handler %p returned %lx\n", dispatch->LanguageHandler, res ); - - switch (res) - { - case ExceptionContinueSearch: - case ExceptionCollidedUnwind: - break; - default: - raise_status( STATUS_INVALID_DISPOSITION, rec ); - break; - } - - return res; -} - - -/********************************************************************** - * call_teb_unwind_handler - * - * Call a single unwind handler from the TEB chain. - */ -static DWORD call_teb_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch, - EXCEPTION_REGISTRATION_RECORD *teb_frame ) -{ - DWORD res; - - TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n", - teb_frame->Handler, rec, teb_frame, dispatch->ContextRecord, dispatch ); - res = teb_frame->Handler( rec, teb_frame, dispatch->ContextRecord, (EXCEPTION_REGISTRATION_RECORD**)dispatch ); - TRACE( "handler at %p returned %lu\n", teb_frame->Handler, res ); - - switch (res) - { - case ExceptionContinueSearch: - case ExceptionCollidedUnwind: - break; - default: - raise_status( STATUS_INVALID_DISPOSITION, rec ); - break; - } - - return res; -} -
/********************************************************************** * call_consolidate_callback @@ -691,7 +634,7 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec CONTEXT new_context; NTSTATUS status; ULONG_PTR frame; - DWORD i; + DWORD i, res;
RtlCaptureContext( context ); new_context = *context; @@ -744,40 +687,62 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec raise_status( STATUS_INVALID_UNWIND_TARGET, rec ); } if (dispatch.EstablisherFrame == (ULONG64)end_frame) rec->ExceptionFlags |= EXCEPTION_TARGET_UNWIND; - if (call_unwind_handler( rec, &dispatch ) == ExceptionCollidedUnwind) + TRACE( "calling handler %p (rec=%p, frame=%I64x context=%p, dispatch=%p)\n", + dispatch.LanguageHandler, rec, dispatch.EstablisherFrame, + dispatch.ContextRecord, &dispatch ); + res = call_unwind_handler( rec, dispatch.EstablisherFrame, dispatch.ContextRecord, + &dispatch, dispatch.LanguageHandler ); + TRACE( "handler %p returned %lx\n", dispatch.LanguageHandler, res ); + + switch (res) { + case ExceptionContinueSearch: + rec->ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND; + break; + case ExceptionCollidedUnwind: new_context = *context; RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase, dispatch.ControlPc, dispatch.FunctionEntry, &new_context, NULL, &frame, NULL ); rec->ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND; goto unwind_done; + default: + raise_status( STATUS_INVALID_DISPOSITION, rec ); + break; } - rec->ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND; } else /* hack: call builtin handlers registered in the tib list */ { - DWORD64 backup_frame = dispatch.EstablisherFrame; while (is_valid_frame( (ULONG_PTR)teb_frame ) && (ULONG64)teb_frame < new_context.Rsp && (ULONG64)teb_frame < (ULONG64)end_frame) { - TRACE( "found builtin frame %p handler %p\n", teb_frame, teb_frame->Handler ); - dispatch.EstablisherFrame = (ULONG64)teb_frame; - if (call_teb_unwind_handler( rec, &dispatch, teb_frame ) == ExceptionCollidedUnwind) + TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n", + teb_frame->Handler, rec, teb_frame, dispatch.ContextRecord, &dispatch ); + res = call_unwind_handler( rec, (ULONG_PTR)teb_frame, dispatch.ContextRecord, &dispatch, + (PEXCEPTION_ROUTINE)teb_frame->Handler ); + TRACE( "handler at %p returned %lu\n", teb_frame->Handler, res ); + teb_frame = __wine_pop_frame( teb_frame ); + + switch (res) { - teb_frame = __wine_pop_frame( teb_frame ); + case ExceptionContinueSearch: + rec->ExceptionFlags &= ~EXCEPTION_COLLIDED_UNWIND; + break; + case ExceptionCollidedUnwind: new_context = *context; RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase, - dispatch.ControlPc, dispatch.FunctionEntry, - &new_context, NULL, &frame, NULL ); + dispatch.ControlPc, dispatch.FunctionEntry, + &new_context, &dispatch.HandlerData, + &frame, NULL ); rec->ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND; goto unwind_done; + default: + raise_status( STATUS_INVALID_DISPOSITION, rec ); + break; } - teb_frame = __wine_pop_frame( teb_frame ); } if ((ULONG64)teb_frame == (ULONG64)end_frame && (ULONG64)end_frame < new_context.Rsp) break; - dispatch.EstablisherFrame = backup_frame; }
if (dispatch.EstablisherFrame == (ULONG64)end_frame) break;