[PATCH v2 1/3] ntdll: Allow raising second chance exceptions from signal handlers.
Jinoh Kang
jinoh.kang.kr at gmail.com
Mon Dec 6 08:24:47 CST 2021
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 at 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;
>
>
--
Sincerely,
Jinoh Kang
More information about the wine-devel
mailing list