From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/signal_x86_64.c | 41 +++++++++++++++++++++++++++--------- dlls/ntdll/tests/exception.c | 6 +++--- 2 files changed, 34 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index ae16bb77dae..63ed4c6a096 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -169,13 +169,20 @@ __ASM_GLOBAL_FUNC( RtlCaptureContext, "ret" );
+struct call_seh_handler_frame +{ + ULONG64 unused[4]; + ULONG64 establisher_frame; +}; + /******************************************************************* * nested_exception_handler */ -EXCEPTION_DISPOSITION WINAPI nested_exception_handler( EXCEPTION_RECORD *rec, void *frame, - CONTEXT *context, void *dispatch ) +EXCEPTION_DISPOSITION WINAPI nested_exception_handler( EXCEPTION_RECORD *rec, struct call_seh_handler_frame *frame, + CONTEXT *context, DISPATCHER_CONTEXT *dispatch ) { if (rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) return ExceptionContinueSearch; + dispatch->EstablisherFrame = frame->establisher_frame; return ExceptionNestedException; }
@@ -187,8 +194,10 @@ EXCEPTION_DISPOSITION WINAPI nested_exception_handler( EXCEPTION_RECORD *rec, vo DWORD WINAPI call_seh_handler( EXCEPTION_RECORD *rec, ULONG_PTR frame, CONTEXT *context, void *dispatch, PEXCEPTION_ROUTINE handler ); __ASM_GLOBAL_FUNC( call_seh_handler, - "subq $0x28, %rsp\n\t" - ".seh_stackalloc 0x28\n\t" + "pushq %rdx\n\t" /* call_seh_handler_frame.establisher_frame <- frame */ + ".seh_pushreg %rdx\n\t" + "subq $0x20, %rsp\n\t" + ".seh_stackalloc 0x20\n\t" ".seh_endprologue\n\t" ".seh_handler nested_exception_handler, @except\n\t" "callq *0x50(%rsp)\n\t" /* handler */ @@ -199,13 +208,19 @@ __ASM_GLOBAL_FUNC( call_seh_handler, static DWORD call_seh_handler( EXCEPTION_RECORD *rec, ULONG_PTR frame, CONTEXT *context, void *dispatch, PEXCEPTION_ROUTINE handler ) { - EXCEPTION_REGISTRATION_RECORD wrapper_frame; + union + { + struct call_seh_handler_frame seh_handler_frame; + EXCEPTION_REGISTRATION_RECORD frame; + } + wrapper_frame; DWORD res;
- wrapper_frame.Handler = (PEXCEPTION_HANDLER)nested_exception_handler; - __wine_push_frame( &wrapper_frame ); + wrapper_frame.frame.Handler = (PEXCEPTION_HANDLER)nested_exception_handler; + wrapper_frame.seh_handler_frame.establisher_frame = frame; + __wine_push_frame( &wrapper_frame.frame ); res = handler( rec, (void *)frame, context, dispatch ); - __wine_pop_frame( &wrapper_frame ); + __wine_pop_frame( &wrapper_frame.frame ); return res; } #endif @@ -223,7 +238,7 @@ NTSTATUS call_seh_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context ) DISPATCHER_CONTEXT dispatch; CONTEXT context; NTSTATUS status; - ULONG_PTR frame; + ULONG_PTR frame, nested_frame; DWORD res;
context = *orig_context; @@ -232,6 +247,7 @@ NTSTATUS call_seh_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context ) dispatch.TargetIp = 0; dispatch.ContextRecord = &context; dispatch.HistoryTable = &table; + nested_frame = 0; for (;;) { status = virtual_unwind( UNW_FLAG_EHANDLER, &dispatch, &context ); @@ -254,7 +270,8 @@ NTSTATUS call_seh_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context ) dispatch.LanguageHandler, rec, dispatch.EstablisherFrame, orig_context, &dispatch ); res = call_seh_handler( rec, dispatch.EstablisherFrame, orig_context, &dispatch, dispatch.LanguageHandler ); - rec->ExceptionFlags &= EXCEPTION_NONCONTINUABLE; + if (dispatch.EstablisherFrame == nested_frame) + rec->ExceptionFlags &= EXCEPTION_NONCONTINUABLE; TRACE( "handler at %p returned %lu\n", dispatch.LanguageHandler, res );
switch (res) @@ -266,6 +283,7 @@ NTSTATUS call_seh_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context ) break; case ExceptionNestedException: rec->ExceptionFlags |= EXCEPTION_NESTED_CALL; + nested_frame = dispatch.EstablisherFrame; TRACE( "nested exception\n" ); break; case ExceptionCollidedUnwind: @@ -283,6 +301,8 @@ NTSTATUS call_seh_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context ) teb_frame->Handler, rec, teb_frame, orig_context, &dispatch, context.Rsp ); res = call_seh_handler( rec, (ULONG_PTR)teb_frame, orig_context, &dispatch, (PEXCEPTION_ROUTINE)teb_frame->Handler ); + if (dispatch.EstablisherFrame == nested_frame) + rec->ExceptionFlags &= EXCEPTION_NONCONTINUABLE; TRACE( "TEB handler at %p returned %lu\n", teb_frame->Handler, res );
switch (res) @@ -294,6 +314,7 @@ NTSTATUS call_seh_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context ) break; case ExceptionNestedException: rec->ExceptionFlags |= EXCEPTION_NESTED_CALL; + nested_frame = dispatch.EstablisherFrame; TRACE( "nested exception\n" ); break; case ExceptionCollidedUnwind: diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 1057cda292a..c071aa36f65 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -5522,7 +5522,7 @@ static DWORD nested_exception_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRAT ok(rec->ExceptionCode == 0xdeadbeef && (!rec->ExceptionFlags || rec->ExceptionFlags == EXCEPTION_SOFTWARE_ORIGINATE), "Got unexpected exception code %#lx, flags %#lx.\n", rec->ExceptionCode, rec->ExceptionFlags); ok(!rec->NumberParameters, "Got unexpected rec->NumberParameters %lu.\n", rec->NumberParameters); - todo_wine ok(frame == (void *)((BYTE *)nested_exception_crash_frame + 8), + ok(frame == (void *)((BYTE *)nested_exception_crash_frame + 8), "Got unexpected frame %p.\n", frame); got_prev_frame_exception = TRUE; return ExceptionContinueExecution; @@ -5551,7 +5551,7 @@ static DWORD nested_exception_handler2(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRA } ok((char *)frame == (char *)nested_exception_initial_frame + 0x10, "got frame %p, nested_exception_initial_frame %p.\n", frame, nested_exception_initial_frame); - todo_wine ok((rec->ExceptionFlags & EXCEPTION_NESTED_CALL), "got %#lx.\n", rec->ExceptionFlags); + ok((rec->ExceptionFlags & EXCEPTION_NESTED_CALL), "got %#lx.\n", rec->ExceptionFlags); ++context->Rip; return ExceptionContinueExecution; } @@ -5576,7 +5576,7 @@ static void test_nested_exception(void) got_nested_exception = got_prev_frame_exception = FALSE; nested_exception_initial_frame = NULL; run_exception_test(nested_exception_handler, NULL, nested_except_code, sizeof(nested_except_code), PAGE_EXECUTE_READ); - todo_wine ok(got_nested_exception, "Did not get nested exception.\n"); + ok(got_nested_exception, "Did not get nested exception.\n"); ok(got_prev_frame_exception, "Did not get nested exception in the previous frame.\n");
nested_exception_initial_frame = NULL;