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@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;