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(a)gmail.com>
---
Notes:
v1 -> v2: proper patch splitting
dlls/ntdll/unix/signal_arm.c | 18 ++++++++++++------
dlls/ntdll/unix/signal_arm64.c | 22 ++++++++++++++--------
dlls/ntdll/unix/signal_i386.c | 21 ++++++++++++++-------
dlls/ntdll/unix/signal_x86_64.c | 18 ++++++++++++------
dlls/ntdll/unix/thread.c | 28 +++++++++++++++++++---------
dlls/ntdll/unix/unix_private.h | 1 +
6 files changed, 72 insertions(+), 36 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..e18aed2c222 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--;
@@ -1482,7 +1489,7 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
struct xcontext xcontext;
void *stack = setup_exception_record( sigcontext, rec, &xcontext );
- setup_raise_exception( sigcontext, stack, rec, &xcontext );
+ setup_raise_exception( sigcontext, stack, rec, &xcontext, TRUE );
}
/* stack layout when calling an user apc function.
@@ -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