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 ---
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;
__fastfail() is used by the Visual C++ runtime and Windows system libraries to signal that the in-process state is corrupted and unrecoverable.
If __fastfail() is invoked, the NT kernel raises a second-chance non-continuable exception STATUS_STACK_BUFFER_OVERRUN. This quickly terminates the process, bypassing all in-process exception handlers (since they all rely on the potentially corrupted process state).
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/ntdll/unix/signal_arm.c | 14 ++++++++++++-- dlls/ntdll/unix/signal_arm64.c | 11 +++++++++++ dlls/ntdll/unix/signal_i386.c | 7 +++++++ dlls/ntdll/unix/signal_x86_64.c | 7 +++++++ 4 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index dbc2770f72e..1816e210644 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -809,13 +809,23 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) switch (get_trap_code(signal, context)) { case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */ - if (*(WORD *)PC_sig(context) == 0xdefe) /* breakpoint */ + switch (*(WORD *)PC_sig(context)) { + case 0xdefb: /* __fastfail */ + rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec.ExceptionFlags = EH_NONCONTINUABLE; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = REGn_sig(0, context); + setup_exception( context, &rec, FALSE ); + return; + case 0xdefe: /* breakpoint */ rec.ExceptionCode = EXCEPTION_BREAKPOINT; rec.NumberParameters = 1; break; + default: + rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; } - rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break; case TRAP_ARM_PAGEFLT: /* Page fault */ rec.NumberParameters = 2; diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index ef70d4df44b..fe80732c03d 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -905,6 +905,17 @@ static void bus_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { EXCEPTION_RECORD rec = { 0 }; + ucontext_t *context = sigcontext; + + if ((get_fault_esr( context ) & 0xfe00ffffU) == 0xf200f003U) + { + rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec.ExceptionFlags = EH_NONCONTINUABLE; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = REGn_sig( 0, context ); + setup_exception( sigcontext, &rec, FALSE ); + return; + }
switch (siginfo->si_code) { diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index e18aed2c222..6d448b99223 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1660,6 +1660,13 @@ static BOOL handle_interrupt( unsigned int interrupt, ucontext_t *sigcontext, vo
switch(interrupt) { + case 0x29: + rec->ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec->ExceptionFlags = EH_NONCONTINUABLE; + rec->NumberParameters = 1; + rec->ExceptionInformation[0] = context->Ecx; + setup_raise_exception( sigcontext, stack, rec, xcontext, FALSE ); + return TRUE; case 0x2d: if (!is_wow64) { diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index ff4a40c7933..39bf1bcc835 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2441,6 +2441,13 @@ static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *r
switch (ERROR_sig(sigcontext) >> 3) { + case 0x29: + rec->ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + rec->ExceptionFlags = EH_NONCONTINUABLE; + rec->NumberParameters = 1; + rec->ExceptionInformation[0] = context->Rcx; + setup_raise_exception( sigcontext, rec, xcontext, FALSE ); + return TRUE; case 0x2c: rec->ExceptionCode = STATUS_ASSERTION_FAILURE; break;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=103453
Your paranoid android.
=== debiant2 (32 bit WoW report) ===
ntdll: change.c:241: Test failed: should be ready change.c:247: Test failed: action wrong change.c:277: Test failed: should be ready change.c:280: Test failed: info not set change.c:293: Test failed: status set too soon change.c:294: Test failed: info set too soon
Today, the UDF instruction handler code assumes Thumb mode code, and cannot recognise the UDF.W form or equivalent instructions in ARM mode encoding.
Fix this by generalising the UDF instruction parser code.
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/ntdll/unix/signal_arm.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index 1816e210644..f4987f902e0 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -359,6 +359,35 @@ static inline WORD get_error_code( const ucontext_t *sigcontext ) }
+/*********************************************************************** + * get_udf_immediate + * + * Get the immediate operand if the PC is at a UDF instruction. + */ +static inline int get_udf_immediate( const ucontext_t *sigcontext ) +{ + if (CPSR_sig(sigcontext) & 0x20) + { + WORD thumb_insn = *(WORD *)PC_sig(sigcontext); + if ((thumb_insn >> 8) == 0xde) return thumb_insn & 0xff; + if ((thumb_insn & 0xfff0) == 0xf7f0) /* udf.w */ + { + WORD ext = *(WORD *)(PC_sig(sigcontext) + 2); + if ((ext & 0xf000) == 0xa000) return ((thumb_insn & 0xf) << 12) | (ext & 0x0fff); + } + } + else + { + DWORD arm_insn = *(DWORD *)PC_sig(sigcontext); + if ((arm_insn & 0xfff000f0) == 0xe7f000f0) + { + return ((arm_insn >> 4) & 0xfff0) | (arm_insn & 0xf); + } + } + return -1; +} + + /*********************************************************************** * save_context * @@ -809,16 +838,16 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) switch (get_trap_code(signal, context)) { case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */ - switch (*(WORD *)PC_sig(context)) + switch (get_udf_immediate( context )) { - case 0xdefb: /* __fastfail */ + case 0xfb: /* __fastfail */ rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; rec.ExceptionFlags = EH_NONCONTINUABLE; rec.NumberParameters = 1; rec.ExceptionInformation[0] = REGn_sig(0, context); setup_exception( context, &rec, FALSE ); return; - case 0xdefe: /* breakpoint */ + case 0xfe: /* breakpoint */ rec.ExceptionCode = EXCEPTION_BREAKPOINT; rec.NumberParameters = 1; break;
Do I understand correctly that the main purpose of these patches is to provide the debugger an opportunity to see (and potentially handle) second chance exception? As it probably doesn't matter too much how exactly the process will fail after second chance exception in the absence of debugger. In any case, that probably deserves some debugger tests? The majority of existing debugger tests is in ntdll/tests/exception.c:test_debugger().
On 12/6/21 16:55, Jinoh Kang wrote:
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
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,
{ CONTEXT *context = &xcontext->c; size_t stack_size;BOOL first_chance )
@@ -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;
On 12/6/21 23:18, Paul Gofman wrote:
Do I understand correctly that the main purpose of these patches is to provide the debugger an opportunity to see (and potentially handle) second chance exception?
Yes, certainly.
As it probably doesn't matter too much how exactly the process will fail after second chance exception in the absence of debugger.
Other than the TerminateProcess() exit code, yes.
In any case, that probably deserves some debugger tests?
I'm already working on the tests. The reason why I posted the implementation first is twofold:
1. I'd like to hear some feedback first, in case I did something obviously wrong or before my work go completely south.
2. Frankly, I dont't have direct access to Windows 7/8 test machines, so... 😅
The majority of existing debugger tests is in ntdll/tests/exception.c:test_debugger().
On 12/6/21 16:55, Jinoh Kang wrote:
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
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;
On 12/6/21 17:24, Jinoh Kang wrote:
- Frankly, I dont't have direct access to Windows 7/8 test machines, so... 😅
You can request access at testbot.winehq.org for manually submitting patches for test without sending them to wine-devel. I think most of us don't have a full collection of Win versions locally. I usually develop tests checking with a local Win10 and the run tests on testbot for all the machines.
On 12/6/21 23:28, Paul Gofman wrote:
On 12/6/21 17:24, Jinoh Kang wrote:
- Frankly, I dont't have direct access to Windows 7/8 test machines, so... 😅
You can request access at testbot.winehq.org for manually submitting patches for test without sending them to wine-devel.
I thought that testbot was only available to CodeWeavers / WineHQ employees. Thanks for the information!
I think most of us don't have a full collection of Win versions locally. I usually develop tests checking with a local Win10 and the run tests on testbot for all the machines.
Maybe I could set up the test environment myself if I got my hands on Windows 7/8 ISO. Don't have an idea where to get them, though.
On 12/6/21 23:18, Paul Gofman wrote:
Do I understand correctly that the main purpose of these patches is to provide the debugger an opportunity to see (and potentially handle) second chance exception? As it probably doesn't matter too much how exactly the process will fail after second chance exception in the absence of debugger. In any case, that probably deserves some debugger tests? The majority of existing debugger tests is in ntdll/tests/exception.c:test_debugger().
Since second chance exceptions are inherently nonrecoverable, perhaps it should be placed at the end in the debuggee?
Or maybe write a dedicated function that tests just this one.
P.S. the change test fail seems to be a uncaught regression from earlier commits.