ntdll: Suspend a thread with its start context explicitly before attaching dlls.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2017-11-30 11:01:47 +01:00
parent 0d3ebfc459
commit 6c61ea6a13
13 changed files with 81 additions and 14 deletions

View file

@ -68,7 +68,7 @@ extern NTSTATUS signal_alloc_thread( TEB **teb ) DECLSPEC_HIDDEN;
extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN; extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_init_thread( TEB *teb ) DECLSPEC_HIDDEN; extern void signal_init_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_init_process(void) DECLSPEC_HIDDEN; extern void signal_init_process(void) DECLSPEC_HIDDEN;
extern NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend ) DECLSPEC_HIDDEN;
extern NTSTATUS signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend ) DECLSPEC_HIDDEN; extern NTSTATUS signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend ) DECLSPEC_HIDDEN;
extern void version_init( const WCHAR *appname ) DECLSPEC_HIDDEN; extern void version_init( const WCHAR *appname ) DECLSPEC_HIDDEN;
extern void debug_init(void) DECLSPEC_HIDDEN; extern void debug_init(void) DECLSPEC_HIDDEN;
@ -85,7 +85,7 @@ extern unsigned int server_cpus DECLSPEC_HIDDEN;
extern BOOL is_wow64 DECLSPEC_HIDDEN; extern BOOL is_wow64 DECLSPEC_HIDDEN;
extern void server_init_process(void) DECLSPEC_HIDDEN; extern void server_init_process(void) DECLSPEC_HIDDEN;
extern NTSTATUS server_init_process_done(void) DECLSPEC_HIDDEN; extern NTSTATUS server_init_process_done(void) DECLSPEC_HIDDEN;
extern size_t server_init_thread( void *entry_point ) DECLSPEC_HIDDEN; extern size_t server_init_thread( void *entry_point, BOOL *suspend ) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN abort_thread( int status ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN abort_thread( int status ) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN terminate_thread( int status ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN terminate_thread( int status ) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN exit_thread( int status ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN exit_thread( int status ) DECLSPEC_HIDDEN;

View file

@ -1470,7 +1470,7 @@ NTSTATUS server_init_process_done(void)
* *
* Send an init thread request. Return 0 if OK. * Send an init thread request. Return 0 if OK.
*/ */
size_t server_init_thread( void *entry_point ) size_t server_init_thread( void *entry_point, BOOL *suspend )
{ {
static const char *cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" }; static const char *cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" };
static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
@ -1511,6 +1511,7 @@ size_t server_init_thread( void *entry_point )
info_size = reply->info_size; info_size = reply->info_size;
server_start_time = reply->server_start; server_start_time = reply->server_start;
server_cpus = reply->all_cpus; server_cpus = reply->all_cpus;
*suspend = reply->suspend;
} }
SERVER_END_REQ; SERVER_END_REQ;

View file

@ -1029,11 +1029,21 @@ static void thread_startup( void *param )
/*********************************************************************** /***********************************************************************
* signal_start_thread * signal_start_thread
*/ */
NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend )
{ {
NTSTATUS status; NTSTATUS status;
CONTEXT context = { 0 };
struct startup_info info = { entry, arg }; struct startup_info info = { entry, arg };
/* build the initial context */
context.ContextFlags = CONTEXT_FULL;
context.R0 = (DWORD)entry;
context.R1 = (DWORD)arg;
context.Sp = (DWORD)NtCurrentTeb()->Tib.StackBase;
context.Pc = (DWORD)call_thread_entry_point;
if (suspend) wait_suspend( &context );
if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase ))) if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase )))
{ {
TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );

View file

@ -900,11 +900,21 @@ static void thread_startup( void *param )
/*********************************************************************** /***********************************************************************
* signal_start_thread * signal_start_thread
*/ */
NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend )
{ {
NTSTATUS status; NTSTATUS status;
CONTEXT context = { 0 };
struct startup_info info = { entry, arg }; struct startup_info info = { entry, arg };
/* build the initial context */
context.ContextFlags = CONTEXT_FULL;
context.X0 = (DWORD_PTR)entry;
context.X1 = (DWORD_PTR)arg;
context.Sp = (DWORD_PTR)NtCurrentTeb()->Tib.StackBase;
context.Pc = (DWORD_PTR)call_thread_entry_point;
if (suspend) wait_suspend( &context );
if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase ))) if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase )))
{ {
TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );

View file

@ -2618,11 +2618,29 @@ static void thread_startup( void *param )
/*********************************************************************** /***********************************************************************
* signal_start_thread * signal_start_thread
*/ */
NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend )
{ {
NTSTATUS status; NTSTATUS status;
CONTEXT context = { 0 };
struct startup_info info = { entry, arg }; struct startup_info info = { entry, arg };
/* build the initial context */
context.ContextFlags = CONTEXT_FULL;
context.SegCs = wine_get_cs();
context.SegDs = wine_get_ds();
context.SegEs = wine_get_es();
context.SegFs = wine_get_fs();
context.SegGs = wine_get_gs();
context.SegSs = wine_get_ss();
context.Eax = (DWORD)entry;
context.Ebx = (DWORD)arg;
context.Esp = (DWORD)NtCurrentTeb()->Tib.StackBase - 16;
context.Eip = (DWORD)call_thread_entry_point;
((void **)context.Esp)[1] = entry;
((void **)context.Esp)[2] = arg;
if (suspend) wait_suspend( &context );
if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase ))) if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase )))
{ {
TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );

View file

@ -1102,11 +1102,21 @@ static void thread_startup( void *param )
/*********************************************************************** /***********************************************************************
* signal_start_thread * signal_start_thread
*/ */
NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend )
{ {
NTSTATUS status; NTSTATUS status;
CONTEXT context = { 0 };
struct startup_info info = { entry, arg }; struct startup_info info = { entry, arg };
/* build the initial context */
context.ContextFlags = CONTEXT_FULL;
context.Gpr1 = (DWORD)NtCurrentTeb()->Tib.StackBase;
context.Gpr3 = (DWORD)entry;
context.Gpr4 = (DWORD)arg;
context.Iar = (DWORD)call_thread_entry_point;
if (suspend) wait_suspend( &context );
if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase ))) if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase )))
{ {
TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );

View file

@ -3160,11 +3160,24 @@ static void thread_startup( void *param )
/*********************************************************************** /***********************************************************************
* signal_start_thread * signal_start_thread
*/ */
NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg ) NTSTATUS signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend )
{ {
NTSTATUS status; NTSTATUS status;
CONTEXT context = { 0 };
struct startup_info info = { entry, arg }; struct startup_info info = { entry, arg };
/* build the initial context */
context.ContextFlags = CONTEXT_FULL;
__asm__( "movw %%cs,%0" : "=m" (context.SegCs) );
__asm__( "movw %%ss,%0" : "=m" (context.SegSs) );
__asm__( "fxsave %0" : "=m" (context.u.FltSave) );
context.Rcx = (ULONG_PTR)entry;
context.Rdx = (ULONG_PTR)arg;
context.Rsp = (ULONG_PTR)NtCurrentTeb()->Tib.StackBase - 0x28;
context.Rip = (ULONG_PTR)call_thread_entry_point;
if (suspend) wait_suspend( &context );
if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase ))) if (!(status = wine_call_on_stack( attach_dlls, (void *)1, NtCurrentTeb()->Tib.StackBase )))
{ {
TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );

View file

@ -272,6 +272,7 @@ HANDLE thread_init(void)
{ {
TEB *teb; TEB *teb;
void *addr; void *addr;
BOOL suspend;
SIZE_T size, info_size; SIZE_T size, info_size;
HANDLE exe_file = 0; HANDLE exe_file = 0;
LARGE_INTEGER now; LARGE_INTEGER now;
@ -359,7 +360,7 @@ HANDLE thread_init(void)
/* setup the server connection */ /* setup the server connection */
server_init_process(); server_init_process();
info_size = server_init_thread( peb ); info_size = server_init_thread( peb, &suspend );
/* create the process heap */ /* create the process heap */
if (!(peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL ))) if (!(peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
@ -496,6 +497,7 @@ void exit_thread( int status )
*/ */
static void start_thread( struct startup_info *info ) static void start_thread( struct startup_info *info )
{ {
BOOL suspend;
NTSTATUS status; NTSTATUS status;
TEB *teb = info->teb; TEB *teb = info->teb;
struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
@ -507,8 +509,8 @@ static void start_thread( struct startup_info *info )
thread_data->pthread_id = pthread_self(); thread_data->pthread_id = pthread_self();
signal_init_thread( teb ); signal_init_thread( teb );
server_init_thread( info->entry_point ); server_init_thread( info->entry_point, &suspend );
status = signal_start_thread( (LPTHREAD_START_ROUTINE)info->entry_point, info->entry_arg ); status = signal_start_thread( (LPTHREAD_START_ROUTINE)info->entry_point, info->entry_arg, suspend );
NtTerminateThread( GetCurrentThread(), status ); NtTerminateThread( GetCurrentThread(), status );
} }

View file

@ -827,7 +827,7 @@ struct init_thread_reply
data_size_t info_size; data_size_t info_size;
int version; int version;
unsigned int all_cpus; unsigned int all_cpus;
char __pad_36[4]; int suspend;
}; };
@ -6475,6 +6475,6 @@ union generic_reply
struct terminate_job_reply terminate_job_reply; struct terminate_job_reply terminate_job_reply;
}; };
#define SERVER_PROTOCOL_VERSION 543 #define SERVER_PROTOCOL_VERSION 544
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View file

@ -807,6 +807,7 @@ struct rawinput_device
data_size_t info_size; /* total size of startup info */ data_size_t info_size; /* total size of startup info */
int version; /* protocol version */ int version; /* protocol version */
unsigned int all_cpus; /* bitset of supported CPUs */ unsigned int all_cpus; /* bitset of supported CPUs */
int suspend; /* is thread suspended? */
@END @END

View file

@ -782,6 +782,7 @@ C_ASSERT( FIELD_OFFSET(struct init_thread_reply, server_start) == 16 );
C_ASSERT( FIELD_OFFSET(struct init_thread_reply, info_size) == 24 ); C_ASSERT( FIELD_OFFSET(struct init_thread_reply, info_size) == 24 );
C_ASSERT( FIELD_OFFSET(struct init_thread_reply, version) == 28 ); C_ASSERT( FIELD_OFFSET(struct init_thread_reply, version) == 28 );
C_ASSERT( FIELD_OFFSET(struct init_thread_reply, all_cpus) == 32 ); C_ASSERT( FIELD_OFFSET(struct init_thread_reply, all_cpus) == 32 );
C_ASSERT( FIELD_OFFSET(struct init_thread_reply, suspend) == 36 );
C_ASSERT( sizeof(struct init_thread_reply) == 40 ); C_ASSERT( sizeof(struct init_thread_reply) == 40 );
C_ASSERT( FIELD_OFFSET(struct terminate_process_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct terminate_process_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct terminate_process_request, exit_code) == 16 ); C_ASSERT( FIELD_OFFSET(struct terminate_process_request, exit_code) == 16 );

View file

@ -1323,7 +1323,6 @@ DECL_HANDLER(init_thread)
if (process->unix_pid != current->unix_pid) if (process->unix_pid != current->unix_pid)
process->unix_pid = -1; /* can happen with linuxthreads */ process->unix_pid = -1; /* can happen with linuxthreads */
init_thread_context( current ); init_thread_context( current );
stop_thread_if_suspended( current );
generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, &req->entry ); generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, &req->entry );
set_thread_affinity( current, current->affinity ); set_thread_affinity( current, current->affinity );
} }
@ -1334,6 +1333,7 @@ DECL_HANDLER(init_thread)
reply->version = SERVER_PROTOCOL_VERSION; reply->version = SERVER_PROTOCOL_VERSION;
reply->server_start = server_start_time; reply->server_start = server_start_time;
reply->all_cpus = supported_cpus & get_prefix_cpu_mask(); reply->all_cpus = supported_cpus & get_prefix_cpu_mask();
reply->suspend = (current->suspend || process->suspend);
return; return;
error: error:

View file

@ -1306,6 +1306,7 @@ static void dump_init_thread_reply( const struct init_thread_reply *req )
fprintf( stderr, ", info_size=%u", req->info_size ); fprintf( stderr, ", info_size=%u", req->info_size );
fprintf( stderr, ", version=%d", req->version ); fprintf( stderr, ", version=%d", req->version );
fprintf( stderr, ", all_cpus=%08x", req->all_cpus ); fprintf( stderr, ", all_cpus=%08x", req->all_cpus );
fprintf( stderr, ", suspend=%d", req->suspend );
} }
static void dump_terminate_process_request( const struct terminate_process_request *req ) static void dump_terminate_process_request( const struct terminate_process_request *req )