[PATCH 1/3] ntdll: Allow raising second chance exceptions from signal handlers.

Jinoh Kang jinoh.kang.kr at gmail.com
Mon Dec 6 07:46:25 CST 2021


This is required to implement some instructions that raise second chance
exceptions directly, such as those emitted from the __fastfail()
intrinsic function.

Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---
 dlls/ntdll/unix/signal_arm.c    | 18 ++++++++++++------
 dlls/ntdll/unix/signal_arm64.c  | 22 ++++++++++++++--------
 dlls/ntdll/unix/signal_i386.c   | 19 +++++++++++++------
 dlls/ntdll/unix/signal_x86_64.c | 18 ++++++++++++------
 dlls/ntdll/unix/thread.c        | 28 +++++++++++++++++++---------
 dlls/ntdll/unix/unix_private.h  |  1 +
 6 files changed, 71 insertions(+), 35 deletions(-)

diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c
index ebc08984adf..dbc2770f72e 100644
--- a/dlls/ntdll/unix/signal_arm.c
+++ b/dlls/ntdll/unix/signal_arm.c
@@ -576,7 +576,7 @@ __ASM_GLOBAL_FUNC( raise_func_trampoline,
  *
  * Modify the signal context to call the exception raise function.
  */
-static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
+static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, BOOL first_chance )
 {
     struct
     {
@@ -591,13 +591,19 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
     rec->ExceptionAddress = (void *)PC_sig(sigcontext);
     save_context( &context, sigcontext );
 
-    status = send_debug_event( rec, &context, TRUE );
+    status = send_debug_event( rec, &context, first_chance );
     if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
     {
         restore_context( &context, sigcontext );
         return;
     }
 
+    if (!first_chance)
+    {
+        handle_second_chance_exception( rec );
+        return;
+    }
+
     stack = virtual_setup_exception( stack_ptr, sizeof(*stack), rec );
     stack->rec = *rec;
     stack->context = context;
@@ -834,7 +840,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         break;
     }
     if (handle_syscall_fault( context, &rec )) return;
-    setup_exception( context, &rec );
+    setup_exception( context, &rec, TRUE );
 }
 
 
@@ -858,7 +864,7 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         rec.NumberParameters = 1;
         break;
     }
-    setup_exception( sigcontext, &rec );
+    setup_exception( sigcontext, &rec, TRUE );
 }
 
 
@@ -915,7 +921,7 @@ static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
         break;
     }
-    setup_exception( sigcontext, &rec );
+    setup_exception( sigcontext, &rec, TRUE );
 }
 
 
@@ -944,7 +950,7 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
 {
     EXCEPTION_RECORD rec = { EXCEPTION_WINE_ASSERTION, EH_NONCONTINUABLE };
 
-    setup_exception( sigcontext, &rec );
+    setup_exception( sigcontext, &rec, TRUE );
 }
 
 
diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c
index 680a14223c6..ef70d4df44b 100644
--- a/dlls/ntdll/unix/signal_arm64.c
+++ b/dlls/ntdll/unix/signal_arm64.c
@@ -618,7 +618,7 @@ __ASM_GLOBAL_FUNC( raise_func_trampoline,
  *
  * Modify the signal context to call the exception raise function.
  */
-static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
+static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, BOOL first_chance )
 {
     struct
     {
@@ -634,13 +634,19 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
     rec->ExceptionAddress = (void *)PC_sig(sigcontext);
     save_context( &context, sigcontext );
 
-    status = send_debug_event( rec, &context, TRUE );
+    status = send_debug_event( rec, &context, first_chance );
     if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
     {
         restore_context( &context, sigcontext );
         return;
     }
 
+    if (!first_chance)
+    {
+        handle_second_chance_exception( rec );
+        return;
+    }
+
     stack = virtual_setup_exception( stack_ptr, (sizeof(*stack) + 15) & ~15, rec );
     stack->rec = *rec;
     stack->context = context;
@@ -861,7 +867,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
                                               (void *)SP_sig(context) );
     if (!rec.ExceptionCode) return;
     if (handle_syscall_fault( context, &rec )) return;
-    setup_exception( context, &rec );
+    setup_exception( context, &rec, TRUE );
 }
 
 
@@ -874,7 +880,7 @@ static void ill_handler( int signal, siginfo_t *siginfo, void *sigcontext )
 {
     EXCEPTION_RECORD rec = { EXCEPTION_ILLEGAL_INSTRUCTION };
 
-    setup_exception( sigcontext, &rec );
+    setup_exception( sigcontext, &rec, TRUE );
 }
 
 
@@ -887,7 +893,7 @@ static void bus_handler( int signal, siginfo_t *siginfo, void *sigcontext )
 {
     EXCEPTION_RECORD rec = { EXCEPTION_DATATYPE_MISALIGNMENT };
 
-    setup_exception( sigcontext, &rec );
+    setup_exception( sigcontext, &rec, TRUE );
 }
 
 
@@ -911,7 +917,7 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         rec.NumberParameters = 1;
         break;
     }
-    setup_exception( sigcontext, &rec );
+    setup_exception( sigcontext, &rec, TRUE );
 }
 
 
@@ -968,7 +974,7 @@ static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
         break;
     }
-    setup_exception( sigcontext, &rec );
+    setup_exception( sigcontext, &rec, TRUE );
 }
 
 
@@ -997,7 +1003,7 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
 {
     EXCEPTION_RECORD rec = { EXCEPTION_WINE_ASSERTION, EH_NONCONTINUABLE };
 
-    setup_exception( sigcontext, &rec );
+    setup_exception( sigcontext, &rec, TRUE );
 }
 
 
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c
index bf3abc1a587..1986c4728bf 100644
--- a/dlls/ntdll/unix/signal_i386.c
+++ b/dlls/ntdll/unix/signal_i386.c
@@ -1400,7 +1400,8 @@ static void *setup_exception_record( ucontext_t *sigcontext, EXCEPTION_RECORD *r
  * Change context to setup a call to a raise exception function.
  */
 static void setup_raise_exception( ucontext_t *sigcontext, void *stack_ptr,
-                                   EXCEPTION_RECORD *rec, struct xcontext *xcontext )
+                                   EXCEPTION_RECORD *rec, struct xcontext *xcontext,
+                                   BOOL first_chance )
 {
     CONTEXT *context = &xcontext->c;
     size_t stack_size;
@@ -1420,7 +1421,7 @@ static void setup_raise_exception( ucontext_t *sigcontext, void *stack_ptr,
 
 C_ASSERT( (offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout)) );
 
-    NTSTATUS status = send_debug_event( rec, context, TRUE );
+    NTSTATUS status = send_debug_event( rec, context, first_chance );
 
     if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
     {
@@ -1428,6 +1429,12 @@ C_ASSERT( (offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout))
         return;
     }
 
+    if (!first_chance)
+    {
+        handle_second_chance_exception( rec );
+        return;
+    }
+
     /* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */
     if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Eip--;
 
@@ -1675,7 +1682,7 @@ static BOOL handle_interrupt( unsigned int interrupt, ucontext_t *sigcontext, vo
         rec->ExceptionInformation[0] = context->Eax;
         rec->ExceptionInformation[1] = context->Ecx;
         rec->ExceptionInformation[2] = context->Edx;
-        setup_raise_exception( sigcontext, stack, rec, xcontext );
+        setup_raise_exception( sigcontext, stack, rec, xcontext, TRUE );
         return TRUE;
     default:
         return FALSE;
@@ -1848,7 +1855,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         break;
     }
     if (handle_syscall_fault( ucontext, stack, &rec, &xcontext.c )) return;
-    setup_raise_exception( ucontext, stack, &rec, &xcontext );
+    setup_raise_exception( ucontext, stack, &rec, &xcontext, TRUE );
 }
 
 
@@ -1894,7 +1901,7 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         rec.ExceptionInformation[2] = 0; /* FIXME */
         break;
     }
-    setup_raise_exception( sigcontext, stack, &rec, &xcontext );
+    setup_raise_exception( sigcontext, stack, &rec, &xcontext, TRUE );
 }
 
 
@@ -1939,7 +1946,7 @@ static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
         break;
     }
-    setup_raise_exception( sigcontext, stack, &rec, &xcontext );
+    setup_raise_exception( sigcontext, stack, &rec, &xcontext, TRUE );
 }
 
 
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 9e9a96db832..ff4a40c7933 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -2110,7 +2110,7 @@ NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size )
 /***********************************************************************
  *           setup_raise_exception
  */
-static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, struct xcontext *xcontext )
+static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, struct xcontext *xcontext, BOOL first_chance )
 {
     void *stack_ptr = (void *)(RSP_sig(sigcontext) & ~15);
     CONTEXT *context = &xcontext->c;
@@ -2136,13 +2136,19 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec
         context->EFlags &= ~0x100;  /* clear single-step flag */
     }
 
-    status = send_debug_event( rec, context, TRUE );
+    status = send_debug_event( rec, context, first_chance );
     if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
     {
         restore_context( xcontext, sigcontext );
         return;
     }
 
+    if (!first_chance)
+    {
+        handle_second_chance_exception( rec );
+        return;
+    }
+
     /* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */
     if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Rip--;
 
@@ -2193,7 +2199,7 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
 
     rec->ExceptionAddress = (void *)RIP_sig(sigcontext);
     save_context( &context, sigcontext );
-    setup_raise_exception( sigcontext, rec, &context );
+    setup_raise_exception( sigcontext, rec, &context, TRUE );
 }
 
 
@@ -2461,7 +2467,7 @@ static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *r
     default:
         return FALSE;
     }
-    setup_raise_exception( sigcontext, rec, xcontext );
+    setup_raise_exception( sigcontext, rec, xcontext, TRUE );
     return TRUE;
 }
 
@@ -2614,7 +2620,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         break;
     }
     if (handle_syscall_fault( sigcontext, &rec, &context.c )) return;
-    setup_raise_exception( sigcontext, &rec, &context );
+    setup_raise_exception( sigcontext, &rec, &context, TRUE );
 }
 
 
@@ -2658,7 +2664,7 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         rec.ExceptionInformation[0] = 0;
         break;
     }
-    setup_raise_exception( sigcontext, &rec, &context );
+    setup_raise_exception( sigcontext, &rec, &context, TRUE );
 }
 
 
diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c
index 455272e07e0..d7204b2fd3b 100644
--- a/dlls/ntdll/unix/thread.c
+++ b/dlls/ntdll/unix/thread.c
@@ -87,6 +87,24 @@ static inline int get_unix_exit_code( NTSTATUS status )
 }
 
 
+/***********************************************************************
+ *           handle_second_chance_exception
+ *
+ * Handle a second chance exception.
+ */
+void handle_second_chance_exception( EXCEPTION_RECORD *rec )
+{
+    if (rec->ExceptionFlags & EH_STACK_INVALID)
+        ERR_(seh)("Exception frame is not in stack limits => unable to dispatch exception.\n");
+    else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
+        ERR_(seh)("Process attempted to continue execution after noncontinuable exception.\n");
+    else
+        ERR_(seh)("Unhandled exception code %x flags %x addr %p\n",
+                  rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
+
+    NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
+}
+
 /***********************************************************************
  *           fpux_to_fpu
  *
@@ -1509,15 +1527,7 @@ NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL
 
     if (first_chance) return call_user_exception_dispatcher( rec, context );
 
-    if (rec->ExceptionFlags & EH_STACK_INVALID)
-        ERR_(seh)("Exception frame is not in stack limits => unable to dispatch exception.\n");
-    else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
-        ERR_(seh)("Process attempted to continue execution after noncontinuable exception.\n");
-    else
-        ERR_(seh)("Unhandled exception code %x flags %x addr %p\n",
-                  rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
-
-    NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
+    handle_second_chance_exception( rec );
     return STATUS_SUCCESS;
 }
 
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 0dcb09ad641..d5414474d2e 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -172,6 +172,7 @@ extern void server_init_process_done(void) DECLSPEC_HIDDEN;
 extern void server_init_thread( void *entry_point, BOOL *suspend ) DECLSPEC_HIDDEN;
 extern int server_pipe( int fd[2] ) DECLSPEC_HIDDEN;
 
+void handle_second_chance_exception( EXCEPTION_RECORD *rec );
 extern void fpux_to_fpu( I386_FLOATING_SAVE_AREA *fpu, const XSAVE_FORMAT *fpux ) DECLSPEC_HIDDEN;
 extern void fpu_to_fpux( XSAVE_FORMAT *fpux, const I386_FLOATING_SAVE_AREA *fpu ) DECLSPEC_HIDDEN;
 extern void *get_cpu_area( USHORT machine ) DECLSPEC_HIDDEN;
-- 
2.31.1




More information about the wine-devel mailing list