Using a dedicated exit jmpbuf and removing the need for assembly routines.
When Wine handles an exception in unix code, we return to user mode by jumping to the last syscall frame. This can leave some pthread cancel cleanups registered, in the pthread internal linked list, and at the same time later overwrite the stack frame they were registered for.
In the same way, jumping to the exit frame on thread exit or abort, can also leave some cleanup handlers registered for invalid stack frames.
Depending on the implementation, calling pthread_exit will cause all the registered pthread cleanup handlers to be called, possibly jumping back to now overwritten stack frames and causing segmentation faults.
Exiting a pthread normally, by returning from its procedure, or calling exit(0) for the main thread doesn't run pthread_exit and doesn't call cleanup handlers, avoiding that situation.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52213
### Additional note:
For robustness, we should probably try to execute these cleanup handlers when unwinding the stack frames, as we would otherwise leave pthread objects in a potential problematic state (like a mutex locked, etc).
It is however hard to do so when the handlers are registered from some C code: pthread C implementation is done by calling some internal pthread functions to register the handlers, and they aren't registered as standard unwind handlers.
Only pthread_cancel and pthread_exit can unwind and call / unregister the C handlers, but interrupting that procedure, for instance calling setjmp / longjmp from withing our own handler isn't supported.
From C++ code, pthread cleanup handlers are registered through C++ class constructors / destructors, and it would then be possible to partially unwind and call them at the same time.
-- v10: ntdll: Remove now unnecessary arch-specific exit frame. ntdll: Avoid calling pthread_exit from abort_thread. ntdll: Avoid calling abort_thread from the signal stack. ntdll: Use is_inside_syscall more consistently.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/signal_arm.c | 13 ++++++------- dlls/ntdll/unix/signal_arm64.c | 15 +++++++-------- dlls/ntdll/unix/signal_i386.c | 14 +++++++------- dlls/ntdll/unix/signal_x86_64.c | 16 ++++++++-------- 4 files changed, 28 insertions(+), 30 deletions(-)
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index 681c2e3c0c1..1fc52632147 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -218,10 +218,10 @@ static inline struct arm_thread_data *arm_thread_data(void) return (struct arm_thread_data *)ntdll_get_thread_data()->cpu_data; }
-static BOOL is_inside_syscall( ucontext_t *sigcontext ) +static BOOL is_inside_syscall( void *addr ) { - return ((char *)SP_sig(sigcontext) >= (char *)ntdll_get_thread_data()->kernel_stack && - (char *)SP_sig(sigcontext) <= (char *)arm_thread_data()->syscall_frame); + return ((char *)addr >= (char *)ntdll_get_thread_data()->kernel_stack && + (char *)addr <= (char *)arm_thread_data()->syscall_frame); }
extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, void *dispatcher ); @@ -1216,8 +1216,7 @@ NTSTATUS WINAPI KeUserModeCallback( ULONG id, const void *args, ULONG len, void ULONG_PTR *stack = args_data;
/* if we have no syscall frame, call the callback directly */ - if ((char *)&frame < (char *)ntdll_get_thread_data()->kernel_stack || - (char *)&frame > (char *)arm_thread_data()->syscall_frame) + if (!is_inside_syscall( &frame )) { NTSTATUS (WINAPI *func)(const void *, ULONG) = ((void **)NtCurrentTeb()->Peb->KernelCallbackTable)[id]; return func( args, len ); @@ -1256,7 +1255,7 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec ) struct syscall_frame *frame = arm_thread_data()->syscall_frame; UINT i;
- if (!is_inside_syscall( context ) && !ntdll_get_thread_data()->jmp_buf) return FALSE; + if (!is_inside_syscall( (void *)SP_sig(context) ) && !ntdll_get_thread_data()->jmp_buf) return FALSE;
TRACE( "code=%lx flags=%lx addr=%p pc=%08lx\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, (DWORD)PC_sig(context) ); @@ -1485,7 +1484,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { CONTEXT context;
- if (is_inside_syscall( sigcontext )) + if (is_inside_syscall( (void *)SP_sig(sigcontext) )) { context.ContextFlags = CONTEXT_FULL; NtGetContextThread( GetCurrentThread(), &context ); diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index da78a7a8036..813853cdf70 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -163,10 +163,10 @@ static inline struct arm64_thread_data *arm64_thread_data(void) return (struct arm64_thread_data *)ntdll_get_thread_data()->cpu_data; }
-static BOOL is_inside_syscall( ucontext_t *sigcontext ) +static BOOL is_inside_syscall( void *addr ) { - return ((char *)SP_sig(sigcontext) >= (char *)ntdll_get_thread_data()->kernel_stack && - (char *)SP_sig(sigcontext) <= (char *)arm64_thread_data()->syscall_frame); + return ((char *)addr >= (char *)ntdll_get_thread_data()->kernel_stack && + (char *)addr <= (char *)arm64_thread_data()->syscall_frame); }
extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, void *dispatcher ); @@ -1172,8 +1172,7 @@ NTSTATUS WINAPI KeUserModeCallback( ULONG id, const void *args, ULONG len, void ULONG_PTR *stack = args_data;
/* if we have no syscall frame, call the callback directly */ - if ((char *)&frame < (char *)ntdll_get_thread_data()->kernel_stack || - (char *)&frame > (char *)arm64_thread_data()->syscall_frame) + if (!is_inside_syscall( &frame )) { NTSTATUS (WINAPI *func)(const void *, ULONG) = ((void **)NtCurrentTeb()->Peb->KernelCallbackTable)[id]; return func( args, len ); @@ -1212,7 +1211,7 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec ) struct syscall_frame *frame = arm64_thread_data()->syscall_frame; DWORD i;
- if (!is_inside_syscall( context ) && !ntdll_get_thread_data()->jmp_buf) return FALSE; + if (!is_inside_syscall( (void *)SP_sig(context) ) && !ntdll_get_thread_data()->jmp_buf) return FALSE;
TRACE( "code=%x flags=%x addr=%p pc=%p tid=%04x\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, @@ -1457,7 +1456,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { CONTEXT context;
- if (is_inside_syscall( sigcontext )) + if (is_inside_syscall( (void *)SP_sig(sigcontext) )) { context.ContextFlags = CONTEXT_FULL; NtGetContextThread( GetCurrentThread(), &context ); @@ -1484,7 +1483,7 @@ static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext ) ucontext_t *context = sigcontext; DWORD i;
- if (!is_inside_syscall( sigcontext )) return; + if (!is_inside_syscall( (void *)SP_sig(sigcontext) )) return;
FP_sig(context) = frame->fp; LR_sig(context) = frame->lr; diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 89af605443d..f0847913da0 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -552,10 +552,10 @@ static inline TEB *get_current_teb(void) /*********************************************************************** * is_inside_syscall */ -static BOOL is_inside_syscall( ucontext_t *sigcontext ) +static BOOL is_inside_syscall( void *addr ) { - return ((char *)ESP_sig(sigcontext) >= (char *)ntdll_get_thread_data()->kernel_stack && - (char *)ESP_sig(sigcontext) <= (char *)x86_thread_data()->syscall_frame); + return ((char *)addr >= (char *)ntdll_get_thread_data()->kernel_stack && + (char *)addr <= (char *)x86_thread_data()->syscall_frame); }
@@ -1654,8 +1654,7 @@ NTSTATUS WINAPI KeUserModeCallback( ULONG id, const void *args, ULONG len, void ULONG_PTR *stack = args_data;
/* if we have no syscall frame, call the callback directly */ - if ((char *)&frame < (char *)ntdll_get_thread_data()->kernel_stack || - (char *)&frame > (char *)x86_thread_data()->syscall_frame) + if (!is_inside_syscall( &frame )) { NTSTATUS (WINAPI *func)(const void *, ULONG) = ((void **)NtCurrentTeb()->Peb->KernelCallbackTable)[id]; return func( args, len ); @@ -1771,7 +1770,7 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, void *stack_ptr, struct syscall_frame *frame = x86_thread_data()->syscall_frame; UINT i, *stack;
- if (!is_inside_syscall( sigcontext ) && !ntdll_get_thread_data()->jmp_buf) return FALSE; + if (!is_inside_syscall( (void *)ESP_sig(sigcontext) ) && !ntdll_get_thread_data()->jmp_buf) return FALSE;
TRACE( "code=%lx flags=%lx addr=%p ip=%08lx\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, context->Eip ); @@ -2078,10 +2077,11 @@ static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) */ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { + ucontext_t *ucontext = sigcontext; struct xcontext xcontext;
init_handler( sigcontext ); - if (is_inside_syscall( sigcontext )) + if (is_inside_syscall( (void *)ESP_sig(ucontext) )) { DECLSPEC_ALIGN(64) XSTATE xs; xcontext.c.ContextFlags = CONTEXT_FULL; diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index f8a90d3caec..4453039208e 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -449,10 +449,10 @@ static inline TEB *get_current_teb(void) } #endif
-static BOOL is_inside_syscall( const ucontext_t *sigcontext ) +static BOOL is_inside_syscall( void *addr ) { - return ((char *)RSP_sig(sigcontext) >= (char *)ntdll_get_thread_data()->kernel_stack && - (char *)RSP_sig(sigcontext) <= (char *)amd64_thread_data()->syscall_frame); + return ((char *)addr >= (char *)ntdll_get_thread_data()->kernel_stack && + (char *)addr <= (char *)amd64_thread_data()->syscall_frame); }
@@ -831,7 +831,8 @@ static inline ucontext_t *init_handler( void *sigcontext ) static inline void leave_handler( const ucontext_t *sigcontext ) { #ifdef __linux__ - if (fs32_sel && !is_inside_signal_stack( (void *)RSP_sig(sigcontext )) && !is_inside_syscall(sigcontext)) + if (fs32_sel && !is_inside_signal_stack( (void *)RSP_sig(sigcontext )) && + !is_inside_syscall( (void *)RSP_sig(sigcontext) )) __asm__ volatile( "movw %0,%%fs" :: "r" (fs32_sel) ); #endif } @@ -1711,8 +1712,7 @@ NTSTATUS WINAPI KeUserModeCallback( ULONG id, const void *args, ULONG len, void ULONG_PTR *stack = args_data;
/* if we have no syscall frame, call the callback directly */ - if ((char *)&frame < (char *)ntdll_get_thread_data()->kernel_stack || - (char *)&frame > (char *)amd64_thread_data()->syscall_frame) + if (!is_inside_syscall( &frame )) { NTSTATUS (WINAPI *func)(const void *, ULONG) = ((void **)NtCurrentTeb()->Peb->KernelCallbackTable)[id]; return func( args, len ); @@ -1884,7 +1884,7 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, struct syscall_frame *frame = amd64_thread_data()->syscall_frame; DWORD i;
- if (!is_inside_syscall( sigcontext ) && !ntdll_get_thread_data()->jmp_buf) return FALSE; + if (!is_inside_syscall( (void *)RSP_sig(sigcontext) ) && !ntdll_get_thread_data()->jmp_buf) return FALSE;
TRACE_(seh)( "code=%x flags=%x addr=%p ip=%lx tid=%04x\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, @@ -2189,7 +2189,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) ucontext_t *ucontext = init_handler( sigcontext ); struct xcontext context;
- if (is_inside_syscall( ucontext )) + if (is_inside_syscall( (void *)RSP_sig(ucontext) )) { DECLSPEC_ALIGN(64) XSTATE xs; context.c.ContextFlags = CONTEXT_FULL;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/signal_arm.c | 8 +++++++- dlls/ntdll/unix/signal_arm64.c | 8 +++++++- dlls/ntdll/unix/signal_i386.c | 12 ++++++++++-- dlls/ntdll/unix/signal_x86_64.c | 15 ++++++++++++--- 4 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index 1fc52632147..b15beba672b 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -1471,7 +1471,13 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) */ static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { - abort_thread(0); + UINT_PTR *stack = (void *)SP_sig(sigcontext); + + if (!is_inside_syscall( stack )) stack = (void *)arm_thread_data()->syscall_frame; + + SP_sig(sigcontext) = stack; + REGn_sig(0, sigcontext) = 0; + PC_sig(sigcontext) = (ULONG_PTR)abort_thread; }
diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 813853cdf70..c1c8419a51f 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -1443,7 +1443,13 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) */ static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { - abort_thread(0); + UINT_PTR *stack = (void *)SP_sig(sigcontext); + + if (!is_inside_syscall( stack )) stack = (void *)arm64_thread_data()->syscall_frame; + + SP_sig(sigcontext) = stack; + REGn_sig(0, sigcontext) = 0; + PC_sig(sigcontext) = (ULONG_PTR)abort_thread; }
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index f0847913da0..a380c231d2f 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2065,8 +2065,16 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) */ static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { - init_handler( sigcontext ); - abort_thread(0); + ucontext_t *ucontext = init_handler( sigcontext ); + UINT_PTR *stack = (void *)ESP_sig(ucontext); + + if (!is_inside_syscall( stack )) stack = (void *)x86_thread_data()->syscall_frame; + + *(--stack) = 0; + *(--stack) = 0; + *(--stack) = 0xdeadbabe; /* return address */ + ESP_sig(ucontext) = (DWORD)stack; + EIP_sig(ucontext) = (DWORD)abort_thread; }
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 4453039208e..975a98c109f 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2172,10 +2172,19 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) * * Handler for SIGQUIT. */ -static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext ) +static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { - init_handler( ucontext ); - abort_thread(0); + ucontext_t *ucontext = init_handler( sigcontext ); + UINT_PTR *stack = (void *)RSP_sig(ucontext); + + if (!is_inside_syscall( stack )) stack = (void *)amd64_thread_data()->syscall_frame; + + *(--stack) = 0xdeadbabe; /* return address */ + RDI_sig(ucontext) = 0; + RSP_sig(ucontext) = (UINT_PTR)stack; + RIP_sig(ucontext) = (UINT_PTR)abort_thread; + + leave_handler( sigcontext ); }
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52213 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54346 --- dlls/ntdll/unix/server.c | 12 ++++++++++++ dlls/ntdll/unix/thread.c | 25 +++++++++---------------- dlls/ntdll/unix/unix_private.h | 3 ++- 3 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 275a8fa62ef..900129d6fd0 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -1671,6 +1671,18 @@ void server_init_thread( void *entry_point, BOOL *suspend ) }
+/*********************************************************************** + * server_exit_thread + */ +void server_exit_thread( void ) +{ + close( ntdll_get_thread_data()->wait_fd[0] ); + close( ntdll_get_thread_data()->wait_fd[1] ); + close( ntdll_get_thread_data()->reply_fd ); + close( ntdll_get_thread_data()->request_fd ); +} + + /****************************************************************************** * NtDuplicateObject */ diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 9b0b5f7ce22..feddbe02334 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1077,19 +1077,6 @@ static void contexts_from_server( CONTEXT *context, context_t server_contexts[2] }
-/*********************************************************************** - * pthread_exit_wrapper - */ -static void pthread_exit_wrapper( int status ) -{ - close( ntdll_get_thread_data()->wait_fd[0] ); - close( ntdll_get_thread_data()->wait_fd[1] ); - close( ntdll_get_thread_data()->reply_fd ); - close( ntdll_get_thread_data()->request_fd ); - pthread_exit( UIntToPtr(status) ); -} - - /*********************************************************************** * start_thread * @@ -1409,7 +1396,11 @@ void abort_thread( int status ) { pthread_sigmask( SIG_BLOCK, &server_block_set, NULL ); if (InterlockedDecrement( &nb_threads ) <= 0) abort_process( status ); - signal_exit_thread( status, pthread_exit_wrapper, NtCurrentTeb() ); + + /* pthread_exit isn't safe to call, wait for the process exit instead */ + server_exit_thread(); + select( 0, 0, 0, 0, 0 ); + abort(); }
@@ -1442,7 +1433,9 @@ static DECLSPEC_NORETURN void exit_thread( int status ) virtual_free_teb( teb ); } } - signal_exit_thread( status, pthread_exit_wrapper, NtCurrentTeb() ); + + server_exit_thread(); + pthread_exit( UIntToPtr(status) ); }
@@ -1452,7 +1445,7 @@ static DECLSPEC_NORETURN void exit_thread( int status ) void exit_process( int status ) { pthread_sigmask( SIG_BLOCK, &server_block_set, NULL ); - signal_exit_thread( get_unix_exit_code( status ), process_exit_wrapper, NtCurrentTeb() ); + process_exit_wrapper( get_unix_exit_code( status ) ); }
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index b803b1cef46..e8c1f000cc0 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -197,10 +197,11 @@ extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t * extern int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, int *needs_close, enum server_fd_type *type, unsigned int *options ) DECLSPEC_HIDDEN; extern void wine_server_send_fd( int fd ) DECLSPEC_HIDDEN; -extern void process_exit_wrapper( int status ) DECLSPEC_HIDDEN; +extern void DECLSPEC_NORETURN process_exit_wrapper( int status ) DECLSPEC_HIDDEN; extern size_t server_init_process(void) DECLSPEC_HIDDEN; extern void server_init_process_done(void) DECLSPEC_HIDDEN; extern void server_init_thread( void *entry_point, BOOL *suspend ) DECLSPEC_HIDDEN; +extern void server_exit_thread( void ) DECLSPEC_HIDDEN; extern int server_pipe( int fd[2] ) DECLSPEC_HIDDEN;
extern void fpux_to_fpu( I386_FLOATING_SAVE_AREA *fpu, const XSAVE_FORMAT *fpux ) DECLSPEC_HIDDEN;
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52213 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54346 --- dlls/ntdll/signal_i386.c | 2 - dlls/ntdll/unix/signal_arm.c | 39 +++++------------ dlls/ntdll/unix/signal_arm64.c | 38 +++++----------- dlls/ntdll/unix/signal_i386.c | 66 ++++++---------------------- dlls/ntdll/unix/signal_x86_64.c | 77 ++++++++------------------------- dlls/ntdll/unix/unix_private.h | 1 - 6 files changed, 52 insertions(+), 171 deletions(-)
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index b2f251bf26a..15250f33d9e 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -47,12 +47,10 @@ struct x86_thread_data DWORD dr3; /* 1e8 */ DWORD dr6; /* 1ec */ DWORD dr7; /* 1f0 */ - void *exit_frame; /* 1f4 exit frame pointer */ };
C_ASSERT( sizeof(struct x86_thread_data) <= 16 * sizeof(void *) ); C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, gs ) == 0x1d8 ); -C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, exit_frame ) == 0x1f4 );
static inline struct x86_thread_data *x86_thread_data(void) { diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index b15beba672b..a1664b6ba6f 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -205,13 +205,11 @@ C_ASSERT( sizeof( struct syscall_frame ) == 0x160);
struct arm_thread_data { - void *exit_frame; /* 1d4 exit frame pointer */ - struct syscall_frame *syscall_frame; /* 1d8 frame pointer on syscall entry */ + struct syscall_frame *syscall_frame; /* 1d4 frame pointer on syscall entry */ };
C_ASSERT( sizeof(struct arm_thread_data) <= sizeof(((struct ntdll_thread_data *)0)->cpu_data) ); -C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct arm_thread_data, exit_frame ) == 0x1d4 ); -C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct arm_thread_data, syscall_frame ) == 0x1d8 ); +C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct arm_thread_data, syscall_frame ) == 0x1d4 );
static inline struct arm_thread_data *arm_thread_data(void) { @@ -1169,9 +1167,9 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "str r6, [r5, #0x80]\n\t" #endif "sub sp, sp, #0x160\n\t" /* sizeof(struct syscall_frame) + registers */ - "ldr r5, [r4, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */ + "ldr r5, [r4, #0x1d4]\n\t" /* arm_thread_data()->syscall_frame */ "str r5, [sp, #0x4c]\n\t" /* frame->prev_frame */ - "str sp, [r4, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */ + "str sp, [r4, #0x1d4]\n\t" /* arm_thread_data()->syscall_frame */ "ldr r6, [r5, #0x50]\n\t" /* prev_frame->syscall_table */ "str r6, [sp, #0x50]\n\t" /* frame->syscall_table */ "mov ip, r0\n\t" @@ -1186,9 +1184,9 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, extern void CDECL DECLSPEC_NORETURN user_mode_callback_return( void *ret_ptr, ULONG ret_len, NTSTATUS status, TEB *teb ) DECLSPEC_HIDDEN; __ASM_GLOBAL_FUNC( user_mode_callback_return, - "ldr r4, [r3, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */ + "ldr r4, [r3, #0x1d4]\n\t" /* arm_thread_data()->syscall_frame */ "ldr r5, [r4, #0x4c]\n\t" /* frame->prev_frame */ - "str r5, [r3, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */ + "str r5, [r3, #0x1d4]\n\t" /* arm_thread_data()->syscall_frame */ "add r5, r4, #0x160\n\t" #ifndef __SOFTFP__ "vldm r5, {d8-d15}\n\t" @@ -1631,39 +1629,22 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B */ __ASM_GLOBAL_FUNC( signal_start_thread, __ASM_EHABI(".cantunwind\n\t") - "push {r4-r12,lr}\n\t" - /* store exit frame */ - "str sp, [r3, #0x1d4]\n\t" /* arm_thread_data()->exit_frame */ /* set syscall frame */ - "ldr r6, [r3, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */ + "ldr r6, [r3, #0x1d4]\n\t" /* arm_thread_data()->syscall_frame */ "cbnz r6, 1f\n\t" "sub r6, sp, #0x160\n\t" /* sizeof(struct syscall_frame) */ - "str r6, [r3, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */ + "str r6, [r3, #0x1d4]\n\t" /* arm_thread_data()->syscall_frame */ "1:\tmov sp, r6\n\t" "bl " __ASM_NAME("call_init_thunk") )
-/*********************************************************************** - * signal_exit_thread - */ -__ASM_GLOBAL_FUNC( signal_exit_thread, - __ASM_EHABI(".cantunwind\n\t") - "ldr r3, [r2, #0x1d4]\n\t" /* arm_thread_data()->exit_frame */ - "mov ip, #0\n\t" - "str ip, [r2, #0x1d4]\n\t" - "cmp r3, ip\n\t" - "it ne\n\t" - "movne sp, r3\n\t" - "blx r1" ) - - /*********************************************************************** * __wine_syscall_dispatcher */ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_EHABI(".cantunwind\n\t") "mrc p15, 0, r1, c13, c0, 2\n\t" /* NtCurrentTeb() */ - "ldr r1, [r1, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */ + "ldr r1, [r1, #0x1d4]\n\t" /* arm_thread_data()->syscall_frame */ "add r0, r1, #0x10\n\t" "stm r0, {r4-r12,lr}\n\t" "add r2, sp, #0x10\n\t" @@ -1741,7 +1722,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, __ASM_EHABI(".cantunwind\n\t") "mrc p15, 0, r1, c13, c0, 2\n\t" /* NtCurrentTeb() */ - "ldr r1, [r1, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */ + "ldr r1, [r1, #0x1d4]\n\t" /* arm_thread_data()->syscall_frame */ "add ip, r1, #0x10\n\t" "stm ip, {r4-r12,lr}\n\t" "str sp, [r1, #0x38]\n\t" diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index c1c8419a51f..7763d5477d6 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -150,13 +150,11 @@ C_ASSERT( sizeof( struct syscall_frame ) == 0x330 );
struct arm64_thread_data { - void *exit_frame; /* 02f0 exit frame pointer */ - struct syscall_frame *syscall_frame; /* 02f8 frame pointer on syscall entry */ + struct syscall_frame *syscall_frame; /* 02f0 frame pointer on syscall entry */ };
C_ASSERT( sizeof(struct arm64_thread_data) <= sizeof(((struct ntdll_thread_data *)0)->cpu_data) ); -C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct arm64_thread_data, exit_frame ) == 0x2f0 ); -C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct arm64_thread_data, syscall_frame ) == 0x2f8 ); +C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct arm64_thread_data, syscall_frame ) == 0x2f0 );
static inline struct arm64_thread_data *arm64_thread_data(void) { @@ -1118,9 +1116,9 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "ldr x6, [x18]\n\t" /* teb->Tib.ExceptionList */ "stp x5, x6, [x29, #0xb0]\n\t"
- "ldr x7, [x18, #0x2f8]\n\t" /* arm64_thread_data()->syscall_frame */ + "ldr x7, [x18, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */ "sub x5, sp, #0x330\n\t" /* sizeof(struct syscall_frame) */ - "str x5, [x18, #0x2f8]\n\t" /* arm64_thread_data()->syscall_frame */ + "str x5, [x18, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */ "ldr x8, [x7, #0x118]\n\t" /* prev_frame->syscall_table */ "ldp x0, x1, [x17]\n\t" /* id, args */ "ldr x2, [x17, #0x10]\n\t" /* len */ @@ -1135,9 +1133,9 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, extern void CDECL DECLSPEC_NORETURN user_mode_callback_return( void *ret_ptr, ULONG ret_len, NTSTATUS status, TEB *teb ) DECLSPEC_HIDDEN; __ASM_GLOBAL_FUNC( user_mode_callback_return, - "ldr x4, [x3, #0x2f8]\n\t" /* arm64_thread_data()->syscall_frame */ + "ldr x4, [x3, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */ "ldr x5, [x4, #0x110]\n\t" /* prev_frame */ - "str x5, [x3, #0x2f8]\n\t" /* arm64_thread_data()->syscall_frame */ + "str x5, [x3, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */ "add x29, x4, #0x330\n\t" /* sizeof(struct syscall_frame) */ "ldp x5, x6, [x29, #0xb0]\n\t" "str x6, [x3]\n\t" /* teb->Tib.ExceptionList */ @@ -1672,30 +1670,14 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B * signal_start_thread */ __ASM_GLOBAL_FUNC( signal_start_thread, - "stp x29, x30, [sp,#-16]!\n\t" - /* store exit frame */ - "mov x29, sp\n\t" - "str x29, [x3, #0x2f0]\n\t" /* arm64_thread_data()->exit_frame */ /* set syscall frame */ - "ldr x8, [x3, #0x2f8]\n\t" /* arm64_thread_data()->syscall_frame */ + "ldr x8, [x3, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */ "cbnz x8, 1f\n\t" "sub x8, sp, #0x330\n\t" /* sizeof(struct syscall_frame) */ - "str x8, [x3, #0x2f8]\n\t" /* arm64_thread_data()->syscall_frame */ + "str x8, [x3, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */ "1:\tmov sp, x8\n\t" "bl " __ASM_NAME("call_init_thunk") )
-/*********************************************************************** - * signal_exit_thread - */ -__ASM_GLOBAL_FUNC( signal_exit_thread, - "stp x29, x30, [sp,#-16]!\n\t" - "ldr x3, [x2, #0x2f0]\n\t" /* arm64_thread_data()->exit_frame */ - "str xzr, [x2, #0x2f0]\n\t" - "cbz x3, 1f\n\t" - "mov sp, x3\n" - "1:\tldp x29, x30, [sp], #16\n\t" - "br x1" ) -
/*********************************************************************** * __wine_syscall_dispatcher @@ -1717,7 +1699,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "ldr x30, [sp, #80]\n\t" "ldp x0, x1, [sp], #96\n\t"
- "ldr x10, [x18, #0x2f8]\n\t" /* arm64_thread_data()->syscall_frame */ + "ldr x10, [x18, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */ "stp x18, x19, [x10, #0x90]\n\t" "stp x20, x21, [x10, #0xa0]\n\t" "stp x22, x23, [x10, #0xb0]\n\t" @@ -1837,7 +1819,7 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, "ldp x2, x30,[sp, #16]\n\t" "ldp x0, x1, [sp], #32\n\t"
- "ldr x10, [x18, #0x2f8]\n\t" /* arm64_thread_data()->syscall_frame */ + "ldr x10, [x18, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */ "stp x18, x19, [x10, #0x90]\n\t" "stp x20, x21, [x10, #0xa0]\n\t" "stp x22, x23, [x10, #0xb0]\n\t" diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index a380c231d2f..2caa7f47aee 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -480,14 +480,12 @@ struct x86_thread_data UINT dr3; /* 1e8 */ UINT dr6; /* 1ec */ UINT dr7; /* 1f0 */ - void *exit_frame; /* 1f4 exit frame pointer */ - struct syscall_frame *syscall_frame; /* 1f8 frame pointer on syscall entry */ + struct syscall_frame *syscall_frame; /* 1f4 frame pointer on syscall entry */ };
C_ASSERT( sizeof(struct x86_thread_data) <= sizeof(((struct ntdll_thread_data *)0)->cpu_data) ); C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, gs ) == 0x1d8 ); -C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, exit_frame ) == 0x1f4 ); -C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, syscall_frame ) == 0x1f8 ); +C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, syscall_frame ) == 0x1f4 );
/* flags to control the behavior of the syscall dispatcher */ #define SYSCALL_HAVE_XSAVE 1 @@ -1593,13 +1591,13 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "subl $0x384,%esp\n\t" /* sizeof(struct syscall_frame) + ebp */ "andl $~63,%esp\n\t" "movl %ebp,0x380(%esp)\n\t" - "movl 0x1f8(%edx),%ecx\n\t" /* x86_thread_data()->syscall_frame */ + "movl 0x1f4(%edx),%ecx\n\t" /* x86_thread_data()->syscall_frame */ "movl (%ecx),%eax\n\t" /* frame->syscall_flags */ "movl %eax,(%esp)\n\t" "movl 0x38(%ecx),%eax\n\t" /* frame->syscall_table */ "movl %eax,0x38(%esp)\n\t" "movl %ecx,0x3c(%esp)\n\t" /* frame->prev_frame */ - "movl %esp,0x1f8(%edx)\n\t" /* x86_thread_data()->syscall_frame */ + "movl %esp,0x1f4(%edx)\n\t" /* x86_thread_data()->syscall_frame */ "movl 8(%ebp),%ecx\n\t" /* func */ "movl 12(%ebp),%esp\n\t" /* stack */ "xorl %ebp,%ebp\n\t" @@ -1613,9 +1611,9 @@ extern void CDECL DECLSPEC_NORETURN user_mode_callback_return( void *ret_ptr, UL NTSTATUS status, TEB *teb ) DECLSPEC_HIDDEN; __ASM_GLOBAL_FUNC( user_mode_callback_return, "movl 16(%esp),%edx\n" /* teb */ - "movl 0x1f8(%edx),%eax\n\t" /* x86_thread_data()->syscall_frame */ + "movl 0x1f4(%edx),%eax\n\t" /* x86_thread_data()->syscall_frame */ "movl 0x3c(%eax),%ecx\n\t" /* frame->prev_frame */ - "movl %ecx,0x1f8(%edx)\n\t" /* x86_thread_data()->syscall_frame */ + "movl %ecx,0x1f4(%edx)\n\t" /* x86_thread_data()->syscall_frame */ "movl 0x380(%eax),%ebp\n\t" /* call_user_mode_callback ebp */ __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") @@ -2487,65 +2485,29 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B * signal_start_thread */ __ASM_GLOBAL_FUNC( signal_start_thread, - "pushl %ebp\n\t" - __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") - __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") "movl %esp,%ebp\n\t" __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") - "pushl %ebx\n\t" - __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t") - "pushl %esi\n\t" - __ASM_CFI(".cfi_rel_offset %esi,-8\n\t") - "pushl %edi\n\t" - __ASM_CFI(".cfi_rel_offset %edi,-12\n\t") - /* store exit frame */ - "movl 20(%ebp),%ecx\n\t" /* teb */ - "movl %ebp,0x1f4(%ecx)\n\t" /* x86_thread_data()->exit_frame */ + "movl 16(%ebp),%ecx\n\t" /* teb */ /* set syscall frame */ - "movl 0x1f8(%ecx),%eax\n\t" /* x86_thread_data()->syscall_frame */ + "movl 0x1f4(%ecx),%eax\n\t" /* x86_thread_data()->syscall_frame */ "orl %eax,%eax\n\t" "jnz 1f\n\t" "leal -0x380(%esp),%eax\n\t" /* sizeof(struct syscall_frame) */ "andl $~63,%eax\n\t" - "movl %eax,0x1f8(%ecx)\n" /* x86_thread_data()->syscall_frame */ + "movl %eax,0x1f4(%ecx)\n" /* x86_thread_data()->syscall_frame */ "1:\tmovl %eax,%esp\n\t" "pushl %ecx\n\t" /* teb */ - "pushl 16(%ebp)\n\t" /* suspend */ - "pushl 12(%ebp)\n\t" /* arg */ - "pushl 8(%ebp)\n\t" /* entry */ + "pushl 12(%ebp)\n\t" /* suspend */ + "pushl 8(%ebp)\n\t" /* arg */ + "pushl 4(%ebp)\n\t" /* entry */ "call " __ASM_NAME("call_init_thunk") )
-/*********************************************************************** - * signal_exit_thread - */ -__ASM_GLOBAL_FUNC( signal_exit_thread, - "movl 8(%esp),%ecx\n\t" - "movl 12(%esp),%esi\n\t" - "xorl %edx,%edx\n\t" - /* fetch exit frame */ - "xchgl %edx,0x1f4(%esi)\n\t" /* x86_thread_data()->exit_frame */ - "testl %edx,%edx\n\t" - "jnz 1f\n\t" - "jmp *%ecx\n\t" - /* switch to exit frame stack */ - "1:\tmovl 4(%esp),%eax\n\t" - "movl %edx,%ebp\n\t" - __ASM_CFI(".cfi_def_cfa %ebp,4\n\t") - __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") - __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t") - __ASM_CFI(".cfi_rel_offset %esi,-8\n\t") - __ASM_CFI(".cfi_rel_offset %edi,-12\n\t") - "leal -20(%ebp),%esp\n\t" - "pushl %eax\n\t" - "call *%ecx" ) - - /*********************************************************************** * __wine_syscall_dispatcher */ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, - "movl %fs:0x1f8,%ecx\n\t" /* x86_thread_data()->syscall_frame */ + "movl %fs:0x1f4,%ecx\n\t" /* x86_thread_data()->syscall_frame */ "movw $0,0x02(%ecx)\n\t" /* frame->restore_flags */ "popl 0x08(%ecx)\n\t" /* frame->eip */ __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t") @@ -2737,7 +2699,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, * __wine_unix_call_dispatcher */ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, - "movl %fs:0x1f8,%ecx\n\t" /* x86_thread_data()->syscall_frame */ + "movl %fs:0x1f4,%ecx\n\t" /* x86_thread_data()->syscall_frame */ "movw $0,0x02(%ecx)\n\t" /* frame->restore_flags */ "popl 0x08(%ecx)\n\t" /* frame->eip */ __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t") diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 975a98c109f..f785342734b 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -424,16 +424,14 @@ struct amd64_thread_data DWORD_PTR dr3; /* 0308 */ DWORD_PTR dr6; /* 0310 */ DWORD_PTR dr7; /* 0318 */ - void *exit_frame; /* 0320 exit frame pointer */ - struct syscall_frame *syscall_frame; /* 0328 syscall frame pointer */ - void *pthread_teb; /* 0330 thread data for pthread */ - DWORD fs; /* 0338 WOW TEB selector */ + struct syscall_frame *syscall_frame; /* 0320 syscall frame pointer */ + void *pthread_teb; /* 0328 thread data for pthread */ + DWORD fs; /* 0330 WOW TEB selector */ };
C_ASSERT( sizeof(struct amd64_thread_data) <= sizeof(((struct ntdll_thread_data *)0)->cpu_data) ); -C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct amd64_thread_data, exit_frame ) == 0x320 ); -C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct amd64_thread_data, syscall_frame ) == 0x328 ); -C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct amd64_thread_data, pthread_teb ) == 0x330 ); +C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct amd64_thread_data, syscall_frame ) == 0x320 ); +C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct amd64_thread_data, pthread_teb ) == 0x328 );
static inline struct amd64_thread_data *amd64_thread_data(void) { @@ -1620,7 +1618,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "subq $0x410,%rsp\n\t" /* sizeof(struct syscall_frame) + ebp + exception */ "andq $~63,%rsp\n\t" "movq %rbp,0x400(%rsp)\n\t" - "movq 0x328(%r11),%r10\n\t" /* amd64_thread_data()->syscall_frame */ + "movq 0x320(%r11),%r10\n\t" /* amd64_thread_data()->syscall_frame */ "movq (%r11),%rax\n\t" /* NtCurrentTeb()->Tib.ExceptionList */ "movq %rax,0x408(%rsp)\n\t" "movq 0xa8(%r10),%rax\n\t" /* prev_frame->syscall_table */ @@ -1628,11 +1626,11 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "movl 0xb0(%r10),%r14d\n\t" /* prev_frame->syscall_flags */ "movl %r14d,0xb0(%rsp)\n\t" /* frame->syscall_flags */ "movq %r10,0xa0(%rsp)\n\t" /* frame->prev_frame */ - "movq %rsp,0x328(%r11)\n\t" /* amd64_thread_data()->syscall_frame */ + "movq %rsp,0x320(%r11)\n\t" /* amd64_thread_data()->syscall_frame */ #ifdef __linux__ "testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */ "jz 1f\n\t" - "movw 0x338(%r11),%fs\n" /* amd64_thread_data()->fs */ + "movw 0x330(%r11),%fs\n" /* amd64_thread_data()->fs */ "1:\n\t" #endif "movq %rcx,%r9\n\t" /* func */ @@ -1650,9 +1648,9 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, extern void CDECL DECLSPEC_NORETURN user_mode_callback_return( void *ret_ptr, ULONG ret_len, NTSTATUS status, TEB *teb ) DECLSPEC_HIDDEN; __ASM_GLOBAL_FUNC( user_mode_callback_return, - "movq 0x328(%r9),%r10\n\t" /* amd64_thread_data()->syscall_frame */ + "movq 0x320(%r9),%r10\n\t" /* amd64_thread_data()->syscall_frame */ "movq 0xa0(%r10),%r11\n\t" /* frame->prev_frame */ - "movq %r11,0x328(%r9)\n\t" /* amd64_thread_data()->syscall_frame = prev_frame */ + "movq %r11,0x320(%r9)\n\t" /* amd64_thread_data()->syscall_frame = prev_frame */ "movq 0x400(%r10),%rbp\n\t" /* call_user_mode_callback rbp */ __ASM_CFI(".cfi_def_cfa_register %rbp\n\t") __ASM_CFI(".cfi_rel_offset %rbx,-0x08\n\t") @@ -2603,65 +2601,26 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B * signal_start_thread */ __ASM_GLOBAL_FUNC( signal_start_thread, - "subq $56,%rsp\n\t" - __ASM_SEH(".seh_stackalloc 56\n\t") - __ASM_SEH(".seh_endprologue\n\t") - __ASM_CFI(".cfi_adjust_cfa_offset 56\n\t") - "movq %rbp,48(%rsp)\n\t" - __ASM_CFI(".cfi_rel_offset %rbp,48\n\t") - "movq %rbx,40(%rsp)\n\t" - __ASM_CFI(".cfi_rel_offset %rbx,40\n\t") - "movq %r12,32(%rsp)\n\t" - __ASM_CFI(".cfi_rel_offset %r12,32\n\t") - "movq %r13,24(%rsp)\n\t" - __ASM_CFI(".cfi_rel_offset %r13,24\n\t") - "movq %r14,16(%rsp)\n\t" - __ASM_CFI(".cfi_rel_offset %r14,16\n\t") - "movq %r15,8(%rsp)\n\t" - __ASM_CFI(".cfi_rel_offset %r15,8\n\t") - /* store exit frame */ - "movq %rsp,0x320(%rcx)\n\t" /* amd64_thread_data()->exit_frame */ /* set syscall frame */ - "movq 0x328(%rcx),%rax\n\t" /* amd64_thread_data()->syscall_frame */ + "movq 0x320(%rcx),%rax\n\t" /* amd64_thread_data()->syscall_frame */ "orq %rax,%rax\n\t" "jnz 1f\n\t" "leaq -0x400(%rsp),%rax\n\t" /* sizeof(struct syscall_frame) */ "andq $~63,%rax\n\t" - "movq %rax,0x328(%rcx)\n" /* amd64_thread_data()->syscall_frame */ + "movq %rax,0x320(%rcx)\n" /* amd64_thread_data()->syscall_frame */ "1:\tmovq %rax,%rsp\n\t" "call " __ASM_NAME("call_init_thunk"))
-/*********************************************************************** - * signal_exit_thread - */ -__ASM_GLOBAL_FUNC( signal_exit_thread, - /* fetch exit frame */ - "xorl %ecx,%ecx\n\t" - "xchgq %rcx,0x320(%rdx)\n\t" /* amd64_thread_data()->exit_frame */ - "testq %rcx,%rcx\n\t" - "jnz 1f\n\t" - "jmp *%rsi\n" - /* switch to exit frame stack */ - "1:\tmovq %rcx,%rsp\n\t" - __ASM_CFI(".cfi_adjust_cfa_offset 56\n\t") - __ASM_CFI(".cfi_rel_offset %rbp,48\n\t") - __ASM_CFI(".cfi_rel_offset %rbx,40\n\t") - __ASM_CFI(".cfi_rel_offset %r12,32\n\t") - __ASM_CFI(".cfi_rel_offset %r13,24\n\t") - __ASM_CFI(".cfi_rel_offset %r14,16\n\t") - __ASM_CFI(".cfi_rel_offset %r15,8\n\t") - "call *%rsi" ) - /*********************************************************************** * __wine_syscall_dispatcher */ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, #ifdef __APPLE__ "movq %gs:0x30,%rcx\n\t" - "movq 0x328(%rcx),%rcx\n\t" + "movq 0x320(%rcx),%rcx\n\t" #else - "movq %gs:0x328,%rcx\n\t" /* amd64_thread_data()->syscall_frame */ + "movq %gs:0x320,%rcx\n\t" /* amd64_thread_data()->syscall_frame */ #endif "popq 0x70(%rcx)\n\t" /* frame->rip */ __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") @@ -2742,7 +2701,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, #ifdef __linux__ "testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */ "jz 2f\n\t" - "movq %gs:0x330,%rsi\n\t" /* amd64_thread_data()->pthread_teb */ + "movq %gs:0x328,%rsi\n\t" /* amd64_thread_data()->pthread_teb */ "testl $8,%r14d\n\t" /* SYSCALL_HAVE_WRFSGSBASE */ "jz 1f\n\t" "wrfsbase %rsi\n\t" @@ -2884,9 +2843,9 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, "movq %rcx,%r10\n\t" #ifdef __APPLE__ "movq %gs:0x30,%rcx\n\t" - "movq 0x328(%rcx),%rcx\n\t" + "movq 0x320(%rcx),%rcx\n\t" #else - "movq %gs:0x328,%rcx\n\t" /* amd64_thread_data()->syscall_frame */ + "movq %gs:0x320,%rcx\n\t" /* amd64_thread_data()->syscall_frame */ #endif "popq 0x70(%rcx)\n\t" /* frame->rip */ __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") @@ -2928,7 +2887,7 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, "testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */ "jz 2f\n\t" "movw %fs,0x7e(%rcx)\n\t" - "movq %gs:0x330,%rsi\n\t" /* amd64_thread_data()->pthread_teb */ + "movq %gs:0x328,%rsi\n\t" /* amd64_thread_data()->pthread_teb */ "testl $8,%r14d\n\t" /* SYSCALL_HAVE_WRFSGSBASE */ "jz 1f\n\t" "wrfsbase %rsi\n\t" diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index e8c1f000cc0..5f3576ce326 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -266,7 +266,6 @@ extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN; extern void signal_init_process(void) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN signal_start_thread( PRTL_THREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB *teb ) DECLSPEC_HIDDEN; -extern void DECLSPEC_NORETURN signal_exit_thread( int status, void (*func)(int), TEB *teb ) DECLSPEC_HIDDEN; extern SYSTEM_SERVICE_TABLE KeServiceDescriptorTable[4] DECLSPEC_HIDDEN; extern void __wine_syscall_dispatcher(void) DECLSPEC_HIDDEN; extern void WINAPI DECLSPEC_NORETURN __wine_syscall_dispatcher_return( void *frame, ULONG_PTR retval ) DECLSPEC_HIDDEN;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=131789
Your paranoid android.
=== debian11 (32 bit report) ===
user32: win.c:10983: Test failed: GetForegroundWindow() = 00210148
As a simpler approach, I've changed this to avoid calling `pthread_exit` only in the `abort_thread` case. Instead, it calls `select` to block indefinitely and wait for the process to exit.
This should hopefully happen soon enough, as `abort_thread` is most often called from `SIGQUIT` when `wineserver` terminates a process. Then it is maybe not, for the cases where `abort_thread` is called on thread or process init errors, but these should not generally happen anyway, or in the case where `NtTerminateThread` is called.
This leaks any thread resources and stack until the process exit, but I think that was already the case as it doesn't go through the `exit_thread` cooperative cleanup.
In general, this should hopefully solve most crashes, and the only ones remaining would be caused by `exit_thread` being called from a thread which has faulted in a syscall and left some cleanup handlers registered. I guess we can consider that this isn't supposed to happen.
On Tue Apr 11 16:44:00 2023 +0000, Rémi Bernon wrote:
As a simpler approach, I've changed this to avoid calling `pthread_exit` only in the `abort_thread` case. Instead, it calls `select` to block indefinitely and wait for the process to exit. This should hopefully happen soon enough, as `abort_thread` is most often called from `SIGQUIT` when `wineserver` terminates a process. Then it is maybe not, for the cases where `abort_thread` is called on thread or process init errors, but these should not generally happen anyway, or in the case where `NtTerminateThread` is called. This leaks any thread resources and stack until the process exit, but I think that was already the case as it doesn't go through the `exit_thread` cooperative cleanup. In general, this should hopefully solve most crashes, and the only ones remaining would be caused by `exit_thread` being called from a thread which has faulted in a syscall and left some cleanup handlers registered. I guess we can consider that this isn't supposed to happen.
Maybe I should've kept the longjmp? Its removal doesn't seem to be causing much trouble but I'm not sure exactly which unwind it was there for.
In any case would something like that (blocking the threads) be better than returning from their functions?
Looking at this again, trying to simply unwind the syscall frames (ie: without avoiding the pthread_exit call), it does not seem to be fully solving the issue.
I used `_Unwind_ForcedUnwind` the same way I previously did here, and it allows me to unwind syscall frames, by interleaving `_Unwind_ForcedUnwind` with `NtCallbackReturn` calls when appropriate. It even unwinds and execute handlers installed using `pthread_cleanup_push` / `pthread_cleanup_pop`, as long as the code is compiled with `-fexceptions`.
*However*, `pthread_cond_t` cleanup handlers are still causing trouble and crashes once the stack unwind is complete and `pthread_exit` is called. The reason is that, even though the glibc is probably compiled with `-fexceptions`, the condition variable cleanup handlers are not installed using `pthread_cleanup_push` but an internal version of them, which always using pthread thread-local cleanup handler linked list instead of personality routines. The thread-local cleanup handler list is not flushed by `_Unwind_ForcedUnwind` and only `pthread_cancel` / `pthread_exit` can, without offering the ability to interleave their unwinding with a custom code.
A possible solution would be to get rid of the thread-local unwind handlers by calling this internal pthread function, but it's much uglier than all the other solutions explored here:
```c struct _pthread_cleanup_buffer buffer = {0}; _pthread_cleanup_pop( &buffer, FALSE ); ```
Another possibility, would be to give up the unwinding control and leave `pthread_exit` do it, but expose personality routines for the syscall dispatchers to unwind the frames. I don't know how to write custom personality routines and hook them where pthread would find them though.
On Fri Oct 20 14:34:02 2023 +0000, Alexandre Julliard wrote:
Right now `TerminateThread` potentially crashes the entire process,
which I think is a bit too much of a broken state? Not necessarily, TerminateThread is essentially a useless API. Still, if we can avoid the crashes it's preferable, but I don't think returning from the thread function is an improvement, and having to create an extra thread just for that purpose is ugly.
Fwiw I think the extra thread could be useful for other purposes, and also remove some specific logic from the code.
For instance I believe the mac port needs an extra thread already, as the main thread is used for macOS main loop, having this on Linux too would make it consistent. I could even imagine using the thread on Linux for some similar thing than macOS, for instance for DBus or host input polling.
I also understand that because the main thread does not have its initial stack created by us, we have some specific logic later to set its syscall_frame early and switch the stack to it in `signal_start_thread`, to the contrary to other threads which start from their kernel stack already.