ntdll: Move the threading initialization functions to the Unix library.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2020-06-01 12:52:05 +02:00
parent 3e59649c9e
commit 3e9f8c87e5
22 changed files with 1521 additions and 887 deletions

View File

@ -69,10 +69,12 @@ static LDT_ENTRY ldt_make_entry( const void *base, unsigned int limit, unsigned
*/ */
void init_selectors(void) void init_selectors(void)
{ {
const struct ldt_copy **ldt_copy_ptr;
if (!is_gdt_sel( get_gs() )) first_ldt_entry += 512; if (!is_gdt_sel( get_gs() )) first_ldt_entry += 512;
if (!is_gdt_sel( get_fs() )) first_ldt_entry += 512; if (!is_gdt_sel( get_fs() )) first_ldt_entry += 512;
RtlSetBits( &ldt_bitmap, 0, first_ldt_entry ); RtlSetBits( &ldt_bitmap, 0, first_ldt_entry );
ldt_copy = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "__wine_ldt_copy" ); ldt_copy_ptr = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "__wine_ldt_copy" );
if (ldt_copy_ptr) ldt_copy = *ldt_copy_ptr;
} }
/*********************************************************************** /***********************************************************************

View File

@ -53,6 +53,12 @@ C_SRCS = \
unix/debug.c \ unix/debug.c \
unix/loader.c \ unix/loader.c \
unix/server.c \ unix/server.c \
unix/signal_arm.c \
unix/signal_arm64.c \
unix/signal_i386.c \
unix/signal_powerpc.c \
unix/signal_x86_64.c \
unix/thread.c \
unix/virtual.c \ unix/virtual.c \
version.c \ version.c \
virtual.c \ virtual.c \

View File

@ -66,7 +66,6 @@ extern NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) DECLSPEC
extern NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) DECLSPEC_HIDDEN; extern NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) DECLSPEC_HIDDEN;
extern NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self ) DECLSPEC_HIDDEN; extern NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self ) DECLSPEC_HIDDEN;
extern NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int flags, BOOL *self ) DECLSPEC_HIDDEN; extern NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int flags, BOOL *self ) DECLSPEC_HIDDEN;
extern NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len ) DECLSPEC_HIDDEN;
extern LONG WINAPI call_unhandled_exception_filter( PEXCEPTION_POINTERS eptr ) DECLSPEC_HIDDEN; extern LONG WINAPI call_unhandled_exception_filter( PEXCEPTION_POINTERS eptr ) DECLSPEC_HIDDEN;
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
@ -80,15 +79,9 @@ extern LPCSTR debugstr_ObjectAttributes(const OBJECT_ATTRIBUTES *oa) DECLSPEC_HI
/* init routines */ /* init routines */
extern SIZE_T signal_stack_size DECLSPEC_HIDDEN; extern SIZE_T signal_stack_size DECLSPEC_HIDDEN;
extern SIZE_T signal_stack_mask DECLSPEC_HIDDEN; extern SIZE_T signal_stack_mask DECLSPEC_HIDDEN;
extern void signal_init_threading(void) DECLSPEC_HIDDEN;
extern NTSTATUS signal_alloc_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_process(void) DECLSPEC_HIDDEN; extern void signal_init_process(void) DECLSPEC_HIDDEN;
extern void signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend ) DECLSPEC_HIDDEN; extern void signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend ) DECLSPEC_HIDDEN;
extern void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend ) DECLSPEC_HIDDEN; extern void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend ) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN signal_exit_thread( int status ) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN signal_exit_process( int status ) DECLSPEC_HIDDEN;
extern void version_init(void) DECLSPEC_HIDDEN; extern void version_init(void) DECLSPEC_HIDDEN;
extern void debug_init(void) DECLSPEC_HIDDEN; extern void debug_init(void) DECLSPEC_HIDDEN;
extern TEB *thread_init(void) DECLSPEC_HIDDEN; extern TEB *thread_init(void) DECLSPEC_HIDDEN;
@ -116,8 +109,6 @@ extern BOOL is_wow64 DECLSPEC_HIDDEN;
extern NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_info ) DECLSPEC_HIDDEN; extern NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_info ) DECLSPEC_HIDDEN;
extern void server_init_process(void) DECLSPEC_HIDDEN; extern void server_init_process(void) DECLSPEC_HIDDEN;
extern void server_init_process_done(void) DECLSPEC_HIDDEN; extern void server_init_process_done(void) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN abort_thread( int status ) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN exit_thread( int status ) DECLSPEC_HIDDEN;
extern sigset_t server_block_set DECLSPEC_HIDDEN; extern sigset_t server_block_set DECLSPEC_HIDDEN;
extern void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN; extern void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN;
extern void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN; extern void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN;

View File

@ -127,7 +127,7 @@ static DECLSPEC_NORETURN void server_protocol_error( const char *err, ... )
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() ); fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
vfprintf( stderr, err, args ); vfprintf( stderr, err, args );
va_end( args ); va_end( args );
abort_thread(1); for (;;) unix_funcs->abort_thread(1);
} }
@ -138,7 +138,7 @@ static DECLSPEC_NORETURN void server_protocol_perror( const char *err )
{ {
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() ); fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
perror( err ); perror( err );
abort_thread(1); for (;;) unix_funcs->abort_thread(1);
} }
@ -205,7 +205,7 @@ static int wait_select_reply( void *cookie )
ret = read( ntdll_get_thread_data()->wait_fd[0], &reply, sizeof(reply) ); ret = read( ntdll_get_thread_data()->wait_fd[0], &reply, sizeof(reply) );
if (ret == sizeof(reply)) if (ret == sizeof(reply))
{ {
if (!reply.cookie) abort_thread( reply.signaled ); /* thread got killed */ if (!reply.cookie) unix_funcs->abort_thread( reply.signaled ); /* thread got killed */
if (wine_server_get_ptr(reply.cookie) == cookie) return reply.signaled; if (wine_server_get_ptr(reply.cookie) == cookie) return reply.signaled;
/* we stole another reply, wait for the real one */ /* we stole another reply, wait for the real one */
signaled = wait_select_reply( cookie ); signaled = wait_select_reply( cookie );
@ -714,7 +714,7 @@ void server_init_process(void)
void server_init_process_done(void) void server_init_process_done(void)
{ {
#ifdef __i386__ #ifdef __i386__
extern struct ldt_copy __wine_ldt_copy; extern struct ldt_copy *__wine_ldt_copy;
#endif #endif
PEB *peb = NtCurrentTeb()->Peb; PEB *peb = NtCurrentTeb()->Peb;
IMAGE_NT_HEADERS *nt = RtlImageNtHeader( peb->ImageBaseAddress ); IMAGE_NT_HEADERS *nt = RtlImageNtHeader( peb->ImageBaseAddress );
@ -737,7 +737,7 @@ void server_init_process_done(void)
{ {
req->module = wine_server_client_ptr( peb->ImageBaseAddress ); req->module = wine_server_client_ptr( peb->ImageBaseAddress );
#ifdef __i386__ #ifdef __i386__
req->ldt_copy = wine_server_client_ptr( &__wine_ldt_copy ); req->ldt_copy = wine_server_client_ptr( __wine_ldt_copy );
#endif #endif
req->entry = wine_server_client_ptr( entry ); req->entry = wine_server_client_ptr( entry );
req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI); req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI);

View File

@ -55,7 +55,6 @@
#define WIN32_NO_STATUS #define WIN32_NO_STATUS
#include "windef.h" #include "windef.h"
#include "winternl.h" #include "winternl.h"
#include "wine/library.h"
#include "wine/exception.h" #include "wine/exception.h"
#include "ntdll_misc.h" #include "ntdll_misc.h"
#include "wine/debug.h" #include "wine/debug.h"
@ -64,8 +63,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(seh); WINE_DEFAULT_DEBUG_CHANNEL(seh);
WINE_DECLARE_DEBUG_CHANNEL(relay); WINE_DECLARE_DEBUG_CHANNEL(relay);
static pthread_key_t teb_key;
/*********************************************************************** /***********************************************************************
* signal context platform-specific definitions * signal context platform-specific definitions
*/ */
@ -921,7 +918,7 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/ */
static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{ {
abort_thread(0); unix_funcs->abort_thread(0);
} }
@ -952,46 +949,6 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
} }
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_8A__)
/* Win32/ARM applications expect the TEB pointer to be in the TPIDRURW register. */
__asm__ __volatile__( "mcr p15, 0, %0, c13, c0, 2" : : "r" (teb) );
#endif
pthread_setspecific( teb_key, teb );
}
/********************************************************************** /**********************************************************************
* signal_init_process * signal_init_process
*/ */
@ -1163,16 +1120,6 @@ __ASM_GLOBAL_FUNC( start_thread,
"mov r0, sp\n\t" "mov r0, sp\n\t"
"b " __ASM_NAME("set_cpu_context") ) "b " __ASM_NAME("set_cpu_context") )
extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), TEB *teb );
__ASM_GLOBAL_FUNC( call_thread_exit_func,
".arm\n\t"
"ldr r3, [r2, #0x1d4]\n\t" /* teb->SystemReserved2 */
"mov ip, #0\n\t"
"str ip, [r2, #0x1d4]\n\t"
"cmp r3, ip\n\t"
"movne sp, r3\n\t"
"blx r1" )
/*********************************************************************** /***********************************************************************
* init_thread_context * init_thread_context
*/ */
@ -1239,39 +1186,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
start_thread( entry, NtCurrentTeb()->Peb, suspend, kernel32_start_process, NtCurrentTeb() ); start_thread( entry, NtCurrentTeb()->Peb, suspend, kernel32_start_process, NtCurrentTeb() );
} }
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status )
{
call_thread_exit_func( status, exit_thread, NtCurrentTeb() );
}
/***********************************************************************
* signal_exit_process
*/
void signal_exit_process( int status )
{
call_thread_exit_func( status, exit, NtCurrentTeb() );
}
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/********************************************************************** /**********************************************************************
* DbgBreakPoint (NTDLL.@) * DbgBreakPoint (NTDLL.@)
*/ */
@ -1293,7 +1207,7 @@ void WINAPI DbgUserBreakPoint(void)
*/ */
TEB * WINAPI NtCurrentTeb(void) TEB * WINAPI NtCurrentTeb(void)
{ {
return pthread_getspecific( teb_key ); return unix_funcs->NtCurrentTeb();
} }
#endif /* __arm__ */ #endif /* __arm__ */

View File

@ -58,7 +58,6 @@
#define WIN32_NO_STATUS #define WIN32_NO_STATUS
#include "windef.h" #include "windef.h"
#include "winternl.h" #include "winternl.h"
#include "wine/library.h"
#include "wine/exception.h" #include "wine/exception.h"
#include "ntdll_misc.h" #include "ntdll_misc.h"
#include "wine/debug.h" #include "wine/debug.h"
@ -67,8 +66,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(seh); WINE_DEFAULT_DEBUG_CHANNEL(seh);
WINE_DECLARE_DEBUG_CHANNEL(relay); WINE_DECLARE_DEBUG_CHANNEL(relay);
static pthread_key_t teb_key;
/* layering violation: the setjmp buffer is defined in msvcrt, but used by RtlUnwindEx */ /* layering violation: the setjmp buffer is defined in msvcrt, but used by RtlUnwindEx */
struct MSVCRT_JUMP_BUFFER struct MSVCRT_JUMP_BUFFER
{ {
@ -1261,7 +1258,7 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/ */
static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{ {
abort_thread(0); unix_funcs->abort_thread(0);
} }
@ -1307,51 +1304,6 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
} }
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
stack_t ss;
ss.ss_sp = (char *)teb + teb_size;
ss.ss_size = signal_stack_size;
ss.ss_flags = 0;
if (sigaltstack( &ss, NULL ) == -1) perror( "sigaltstack" );
/* Win64/ARM applications expect the TEB pointer to be in the x18 platform register. */
__asm__ __volatile__( "mov x18, %0" : : "r" (teb) );
pthread_setspecific( teb_key, teb );
}
/********************************************************************** /**********************************************************************
* signal_init_process * signal_init_process
*/ */
@ -2208,14 +2160,6 @@ __ASM_GLOBAL_FUNC( start_thread,
"ldr x0, [x0, #0x8]\n\t" /* context->X0 */ "ldr x0, [x0, #0x8]\n\t" /* context->X0 */
"br x17" ) "br x17" )
extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), TEB *teb );
__ASM_GLOBAL_FUNC( call_thread_exit_func,
"ldr x3, [x2, #0x300]\n\t" /* arm64_thread_data()->exit_frame */
"str xzr, [x2, #0x300]\n\t"
"cbz x3, 1f\n\t"
"mov sp, x3\n"
"1:\tblr x1" )
/*********************************************************************** /***********************************************************************
* init_thread_context * init_thread_context
*/ */
@ -2281,39 +2225,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
start_thread( entry, NtCurrentTeb()->Peb, suspend, kernel32_start_process, NtCurrentTeb() ); start_thread( entry, NtCurrentTeb()->Peb, suspend, kernel32_start_process, NtCurrentTeb() );
} }
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status )
{
call_thread_exit_func( status, exit_thread, NtCurrentTeb() );
}
/***********************************************************************
* signal_exit_process
*/
void signal_exit_process( int status )
{
call_thread_exit_func( status, exit, NtCurrentTeb() );
}
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/********************************************************************** /**********************************************************************
* DbgBreakPoint (NTDLL.@) * DbgBreakPoint (NTDLL.@)
*/ */
@ -2329,7 +2240,7 @@ __ASM_STDCALL_FUNC( DbgUserBreakPoint, 0, "brk #0; ret")
*/ */
TEB * WINAPI NtCurrentTeb(void) TEB * WINAPI NtCurrentTeb(void)
{ {
return pthread_getspecific( teb_key ); return unix_funcs->NtCurrentTeb();
} }
#endif /* __aarch64__ */ #endif /* __aarch64__ */

View File

@ -52,7 +52,6 @@
#include "ntstatus.h" #include "ntstatus.h"
#define WIN32_NO_STATUS #define WIN32_NO_STATUS
#include "windef.h" #include "windef.h"
#include "wine/library.h"
#include "ntdll_misc.h" #include "ntdll_misc.h"
#include "wine/exception.h" #include "wine/exception.h"
#include "wine/debug.h" #include "wine/debug.h"
@ -182,30 +181,6 @@ __ASM_GLOBAL_FUNC( rt_sigreturn,
"int $0x80" ); "int $0x80" );
#endif #endif
struct modify_ldt_s
{
unsigned int entry_number;
void *base_addr;
unsigned int limit;
unsigned int seg_32bit : 1;
unsigned int contents : 2;
unsigned int read_exec_only : 1;
unsigned int limit_in_pages : 1;
unsigned int seg_not_present : 1;
unsigned int usable : 1;
unsigned int garbage : 25;
};
static inline int modify_ldt( int func, struct modify_ldt_s *ptr, unsigned long count )
{
return syscall( 123 /* SYS_modify_ldt */, func, ptr, count );
}
static inline int set_thread_area( struct modify_ldt_s *ptr )
{
return syscall( 243 /* SYS_set_thread_area */, ptr );
}
#elif defined (__BSDI__) #elif defined (__BSDI__)
#include <machine/frame.h> #include <machine/frame.h>
@ -470,8 +445,6 @@ struct stack_layout
typedef int (*wine_signal_handler)(unsigned int sig); typedef int (*wine_signal_handler)(unsigned int sig);
static const size_t teb_size = 4096; /* we reserve one page for the TEB */
static ULONG first_ldt_entry = 32; static ULONG first_ldt_entry = 32;
static wine_signal_handler handlers[256]; static wine_signal_handler handlers[256];
@ -1832,7 +1805,7 @@ static struct stack_layout *setup_exception_record( ucontext_t *sigcontext, void
GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
(unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit, (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
NtCurrentTeb()->Tib.StackBase ); NtCurrentTeb()->Tib.StackBase );
abort_thread(1); unix_funcs->abort_thread(1);
} }
if (stack - 1 > stack || /* check for overflow in subtraction */ if (stack - 1 > stack || /* check for overflow in subtraction */
@ -1852,7 +1825,7 @@ static struct stack_layout *setup_exception_record( ucontext_t *sigcontext, void
diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
(unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1); unix_funcs->abort_thread(1);
} }
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit) else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
{ {
@ -1866,7 +1839,7 @@ static struct stack_layout *setup_exception_record( ucontext_t *sigcontext, void
diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext),
(unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1); unix_funcs->abort_thread(1);
} }
case -1: /* overflow */ case -1: /* overflow */
exception_code = EXCEPTION_STACK_OVERFLOW; exception_code = EXCEPTION_STACK_OVERFLOW;
@ -2264,7 +2237,7 @@ static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{ {
WORD fs, gs; WORD fs, gs;
init_handler( sigcontext, &fs, &gs ); init_handler( sigcontext, &fs, &gs );
abort_thread(0); unix_funcs->abort_thread(0);
} }
@ -2297,314 +2270,6 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
} }
/***********************************************************************
* LDT support
*/
#define LDT_SIZE 8192
#define LDT_FLAGS_DATA 0x13 /* Data segment */
#define LDT_FLAGS_CODE 0x1b /* Code segment */
#define LDT_FLAGS_32BIT 0x40 /* Segment is 32-bit (code or stack) */
#define LDT_FLAGS_ALLOCATED 0x80 /* Segment is allocated */
struct ldt_copy
{
void *base[LDT_SIZE];
unsigned int limit[LDT_SIZE];
unsigned char flags[LDT_SIZE];
} __wine_ldt_copy;
static WORD gdt_fs_sel;
static RTL_CRITICAL_SECTION ldt_section;
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &ldt_section,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": ldt_section") }
};
static RTL_CRITICAL_SECTION ldt_section = { &critsect_debug, -1, 0, 0, 0, 0 };
static const LDT_ENTRY null_entry;
static inline void *ldt_get_base( LDT_ENTRY ent )
{
return (void *)(ent.BaseLow |
(ULONG_PTR)ent.HighWord.Bits.BaseMid << 16 |
(ULONG_PTR)ent.HighWord.Bits.BaseHi << 24);
}
static inline unsigned int ldt_get_limit( LDT_ENTRY ent )
{
unsigned int limit = ent.LimitLow | (ent.HighWord.Bits.LimitHi << 16);
if (ent.HighWord.Bits.Granularity) limit = (limit << 12) | 0xfff;
return limit;
}
static LDT_ENTRY ldt_make_entry( void *base, unsigned int limit, unsigned char flags )
{
LDT_ENTRY entry;
entry.BaseLow = (WORD)(ULONG_PTR)base;
entry.HighWord.Bits.BaseMid = (BYTE)((ULONG_PTR)base >> 16);
entry.HighWord.Bits.BaseHi = (BYTE)((ULONG_PTR)base >> 24);
if ((entry.HighWord.Bits.Granularity = (limit >= 0x100000))) limit >>= 12;
entry.LimitLow = (WORD)limit;
entry.HighWord.Bits.LimitHi = limit >> 16;
entry.HighWord.Bits.Dpl = 3;
entry.HighWord.Bits.Pres = 1;
entry.HighWord.Bits.Type = flags;
entry.HighWord.Bits.Sys = 0;
entry.HighWord.Bits.Reserved_0 = 0;
entry.HighWord.Bits.Default_Big = (flags & LDT_FLAGS_32BIT) != 0;
return entry;
}
static void ldt_set_entry( WORD sel, LDT_ENTRY entry )
{
int index = sel >> 3;
#ifdef linux
struct modify_ldt_s ldt_info = { index };
ldt_info.base_addr = ldt_get_base( entry );
ldt_info.limit = entry.LimitLow | (entry.HighWord.Bits.LimitHi << 16);
ldt_info.seg_32bit = entry.HighWord.Bits.Default_Big;
ldt_info.contents = (entry.HighWord.Bits.Type >> 2) & 3;
ldt_info.read_exec_only = !(entry.HighWord.Bits.Type & 2);
ldt_info.limit_in_pages = entry.HighWord.Bits.Granularity;
ldt_info.seg_not_present = !entry.HighWord.Bits.Pres;
ldt_info.usable = entry.HighWord.Bits.Sys;
if (modify_ldt( 0x11, &ldt_info, sizeof(ldt_info) ) < 0) perror( "modify_ldt" );
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__)
/* The kernel will only let us set LDTs with user priority level */
if (entry.HighWord.Bits.Pres && entry.HighWord.Bits.Dpl != 3) entry.HighWord.Bits.Dpl = 3;
if (i386_set_ldt(index, (union descriptor *)&entry, 1) < 0)
{
perror("i386_set_ldt");
fprintf( stderr, "Did you reconfigure the kernel with \"options USER_LDT\"?\n" );
exit(1);
}
#elif defined(__svr4__) || defined(_SCO_DS)
struct ssd ldt_mod;
ldt_mod.sel = sel;
ldt_mod.bo = (unsigned long)ldt_get_base( entry );
ldt_mod.ls = entry.LimitLow | (entry.HighWord.Bits.LimitHi << 16);
ldt_mod.acc1 = entry.HighWord.Bytes.Flags1;
ldt_mod.acc2 = entry.HighWord.Bytes.Flags2 >> 4;
if (sysi86(SI86DSCR, &ldt_mod) == -1) perror("sysi86");
#elif defined(__APPLE__)
if (i386_set_ldt(index, (union ldt_entry *)&entry, 1) < 0) perror("i386_set_ldt");
#elif defined(__GNU__)
if (i386_set_ldt(mach_thread_self(), sel, (descriptor_list_t)&entry, 1) != KERN_SUCCESS)
perror("i386_set_ldt");
#else
fprintf( stderr, "No LDT support on this platform\n" );
exit(1);
#endif
__wine_ldt_copy.base[index] = ldt_get_base( entry );
__wine_ldt_copy.limit[index] = ldt_get_limit( entry );
__wine_ldt_copy.flags[index] = (entry.HighWord.Bits.Type |
(entry.HighWord.Bits.Default_Big ? LDT_FLAGS_32BIT : 0) |
LDT_FLAGS_ALLOCATED);
}
static void ldt_set_fs( WORD sel, TEB *teb )
{
if (sel == gdt_fs_sel)
{
#ifdef __linux__
struct modify_ldt_s ldt_info = { sel >> 3 };
ldt_info.base_addr = teb;
ldt_info.limit = teb_size - 1;
ldt_info.seg_32bit = 1;
if (set_thread_area( &ldt_info ) < 0) perror( "set_thread_area" );
#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
i386_set_fsbase( teb );
#endif
}
set_fs( sel );
}
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
THREAD_DESCRIPTOR_INFORMATION *info = data;
NTSTATUS status = STATUS_SUCCESS;
if (len < sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
if (info->Selector >> 16) return STATUS_UNSUCCESSFUL;
if (is_gdt_sel( info->Selector ))
{
if (!(info->Selector & ~3))
info->Entry = null_entry;
else if ((info->Selector | 3) == get_cs())
info->Entry = ldt_make_entry( 0, ~0u, LDT_FLAGS_CODE | LDT_FLAGS_32BIT );
else if ((info->Selector | 3) == get_ds())
info->Entry = ldt_make_entry( 0, ~0u, LDT_FLAGS_DATA | LDT_FLAGS_32BIT );
else if ((info->Selector | 3) == get_fs())
info->Entry = ldt_make_entry( NtCurrentTeb(), 0xfff, LDT_FLAGS_DATA | LDT_FLAGS_32BIT );
else
return STATUS_UNSUCCESSFUL;
}
else
{
SERVER_START_REQ( get_selector_entry )
{
req->handle = wine_server_obj_handle( handle );
req->entry = info->Selector >> 3;
status = wine_server_call( req );
if (!status)
{
if (reply->flags)
info->Entry = ldt_make_entry( (void *)reply->base, reply->limit, reply->flags );
else
status = STATUS_UNSUCCESSFUL;
}
}
SERVER_END_REQ;
}
if (status == STATUS_SUCCESS && ret_len)
/* yes, that's a bit strange, but it's the way it is */
*ret_len = sizeof(info->Entry);
return status;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
sigset_t sigset;
if (sel1 >> 16 || sel2 >> 16) return STATUS_INVALID_LDT_DESCRIPTOR;
if (sel1 && (sel1 >> 3) < first_ldt_entry) return STATUS_INVALID_LDT_DESCRIPTOR;
if (sel2 && (sel2 >> 3) < first_ldt_entry) return STATUS_INVALID_LDT_DESCRIPTOR;
server_enter_uninterrupted_section( &ldt_section, &sigset );
if (sel1) ldt_set_entry( sel1, entry1 );
if (sel2) ldt_set_entry( sel2, entry2 );
server_leave_uninterrupted_section( &ldt_section, &sigset );
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
#ifdef __linux__
/* the preloader may have allocated it already */
gdt_fs_sel = get_fs();
if (!gdt_fs_sel || !is_gdt_sel( gdt_fs_sel ))
{
struct modify_ldt_s ldt_info = { -1 };
ldt_info.seg_32bit = 1;
ldt_info.usable = 1;
if (set_thread_area( &ldt_info ) >= 0) gdt_fs_sel = (ldt_info.entry_number << 3) | 3;
else gdt_fs_sel = 0;
}
#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__)
gdt_fs_sel = GSEL( GUFS_SEL, SEL_UPL );
#endif
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2;
if (!gdt_fs_sel)
{
static int first_thread = 1;
sigset_t sigset;
int idx;
LDT_ENTRY entry = ldt_make_entry( teb, teb_size - 1, LDT_FLAGS_DATA | LDT_FLAGS_32BIT );
if (first_thread) /* no locking for first thread */
{
/* leave some space if libc is using the LDT for %gs */
if (!is_gdt_sel( get_gs() )) first_ldt_entry = 512;
idx = first_ldt_entry;
ldt_set_entry( (idx << 3) | 7, entry );
first_thread = 0;
}
else
{
server_enter_uninterrupted_section( &ldt_section, &sigset );
for (idx = first_ldt_entry; idx < LDT_SIZE; idx++)
{
if (__wine_ldt_copy.flags[idx]) continue;
ldt_set_entry( (idx << 3) | 7, entry );
break;
}
server_leave_uninterrupted_section( &ldt_section, &sigset );
if (idx == LDT_SIZE) return STATUS_TOO_MANY_THREADS;
}
thread_data->fs = (idx << 3) | 7;
}
else thread_data->fs = gdt_fs_sel;
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2;
sigset_t sigset;
if (gdt_fs_sel) return;
server_enter_uninterrupted_section( &ldt_section, &sigset );
__wine_ldt_copy.flags[thread_data->fs >> 3] = 0;
server_leave_uninterrupted_section( &ldt_section, &sigset );
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
const WORD fpu_cw = 0x27f;
struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2;
stack_t ss;
ss.ss_sp = (char *)teb + teb_size;
ss.ss_size = signal_stack_size;
ss.ss_flags = 0;
if (sigaltstack(&ss, NULL) == -1) perror( "sigaltstack" );
ldt_set_fs( thread_data->fs, teb );
thread_data->gs = get_gs();
#ifdef __GNUC__
__asm__ volatile ("fninit; fldcw %0" : : "m" (fpu_cw));
#else
FIXME("FPU setup not implemented for this platform.\n");
#endif
}
/********************************************************************** /**********************************************************************
* signal_init_process * signal_init_process
*/ */
@ -2870,27 +2535,6 @@ __ASM_GLOBAL_FUNC( start_thread,
"movl %esi,(%esp)\n\t" "movl %esi,(%esp)\n\t"
"call " __ASM_NAME("set_cpu_context") ) "call " __ASM_NAME("set_cpu_context") )
extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int) );
__ASM_GLOBAL_FUNC( call_thread_exit_func,
"movl 8(%esp),%ecx\n\t"
/* fetch exit frame */
"movl %fs:0x1f4,%edx\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 $0,%fs:0x1f4\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" )
extern void call_thread_entry(void) DECLSPEC_HIDDEN; extern void call_thread_entry(void) DECLSPEC_HIDDEN;
__ASM_GLOBAL_FUNC( call_thread_entry, __ASM_GLOBAL_FUNC( call_thread_entry,
"pushl %ebp\n\t" "pushl %ebp\n\t"
@ -3015,22 +2659,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
} }
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status )
{
call_thread_exit_func( status, exit_thread );
}
/***********************************************************************
* signal_exit_process
*/
void signal_exit_process( int status )
{
call_thread_exit_func( status, exit );
}
/********************************************************************** /**********************************************************************
* DbgBreakPoint (NTDLL.@) * DbgBreakPoint (NTDLL.@)
*/ */

View File

@ -53,7 +53,6 @@
#define WIN32_NO_STATUS #define WIN32_NO_STATUS
#include "windef.h" #include "windef.h"
#include "winternl.h" #include "winternl.h"
#include "wine/library.h"
#include "wine/exception.h" #include "wine/exception.h"
#include "ntdll_misc.h" #include "ntdll_misc.h"
#include "wine/debug.h" #include "wine/debug.h"
@ -61,8 +60,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(seh); WINE_DEFAULT_DEBUG_CHANNEL(seh);
WINE_DECLARE_DEBUG_CHANNEL(relay); WINE_DECLARE_DEBUG_CHANNEL(relay);
static pthread_key_t teb_key;
/*********************************************************************** /***********************************************************************
* signal context platform-specific definitions * signal context platform-specific definitions
*/ */
@ -982,7 +979,7 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/ */
static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{ {
abort_thread(0); unix_funcs->abort_thread(0);
} }
@ -1013,41 +1010,6 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
} }
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
pthread_setspecific( teb_key, teb );
}
/********************************************************************** /**********************************************************************
* signal_init_process * signal_init_process
*/ */
@ -1218,39 +1180,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
switch_to_stack( thread_startup, &info, NtCurrentTeb()->Tib.StackBase ); switch_to_stack( thread_startup, &info, NtCurrentTeb()->Tib.StackBase );
} }
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status )
{
exit_thread( status );
}
/***********************************************************************
* signal_exit_process
*/
void signal_exit_process( int status )
{
exit( status );
}
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/********************************************************************** /**********************************************************************
* DbgBreakPoint (NTDLL.@) * DbgBreakPoint (NTDLL.@)
*/ */
@ -1272,7 +1201,7 @@ void WINAPI DbgUserBreakPoint(void)
*/ */
TEB * WINAPI NtCurrentTeb(void) TEB * WINAPI NtCurrentTeb(void)
{ {
return pthread_getspecific( teb_key ); return unix_funcs->NtCurrentTeb();
} }
#endif /* __powerpc__ */ #endif /* __powerpc__ */

View File

@ -65,7 +65,6 @@
#define WIN32_NO_STATUS #define WIN32_NO_STATUS
#include "windef.h" #include "windef.h"
#include "winternl.h" #include "winternl.h"
#include "wine/library.h"
#include "wine/exception.h" #include "wine/exception.h"
#include "wine/list.h" #include "wine/list.h"
#include "ntdll_misc.h" #include "ntdll_misc.h"
@ -123,9 +122,6 @@ struct MSVCRT_JUMP_BUFFER
*/ */
#ifdef linux #ifdef linux
#include <asm/prctl.h>
static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_prctl, func, ptr ); }
#define RAX_sig(context) ((context)->uc_mcontext.gregs[REG_RAX]) #define RAX_sig(context) ((context)->uc_mcontext.gregs[REG_RAX])
#define RBX_sig(context) ((context)->uc_mcontext.gregs[REG_RBX]) #define RBX_sig(context) ((context)->uc_mcontext.gregs[REG_RBX])
#define RCX_sig(context) ((context)->uc_mcontext.gregs[REG_RCX]) #define RCX_sig(context) ((context)->uc_mcontext.gregs[REG_RCX])
@ -2646,7 +2642,7 @@ static struct stack_layout *setup_exception( ucontext_t *sigcontext )
ERR( "nested exception on signal stack in thread %04x eip %016lx esp %016lx stack %p-%p\n", ERR( "nested exception on signal stack in thread %04x eip %016lx esp %016lx stack %p-%p\n",
GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_sig(sigcontext), GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_sig(sigcontext),
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1); unix_funcs->abort_thread(1);
} }
if (stack - 1 > stack || /* check for overflow in subtraction */ if (stack - 1 > stack || /* check for overflow in subtraction */
@ -2665,7 +2661,7 @@ static struct stack_layout *setup_exception( ucontext_t *sigcontext )
diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext),
(ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, (ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1); unix_funcs->abort_thread(1);
} }
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit) else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
{ {
@ -2679,7 +2675,7 @@ static struct stack_layout *setup_exception( ucontext_t *sigcontext )
diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext),
(ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, (ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1); unix_funcs->abort_thread(1);
} }
case -1: /* overflow */ case -1: /* overflow */
exception_code = EXCEPTION_STACK_OVERFLOW; exception_code = EXCEPTION_STACK_OVERFLOW;
@ -3075,7 +3071,7 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/ */
static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext ) static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext )
{ {
abort_thread(0); unix_funcs->abort_thread(0);
} }
@ -3106,145 +3102,6 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
} }
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
#ifdef __APPLE__
/**********************************************************************
* mac_thread_gsbase
*/
static void *mac_thread_gsbase(void)
{
struct thread_identifier_info tiinfo;
unsigned int info_count = THREAD_IDENTIFIER_INFO_COUNT;
static int gsbase_offset = -1;
void *ret;
kern_return_t kr = thread_info(mach_thread_self(), THREAD_IDENTIFIER_INFO, (thread_info_t) &tiinfo, &info_count);
if (kr == KERN_SUCCESS)
{
TRACE("pthread_self() %p thread ID %llx gsbase %llx\n", pthread_self(), tiinfo.thread_id, tiinfo.thread_handle);
return (void*)tiinfo.thread_handle;
}
if (gsbase_offset < 0)
{
/* Search for the array of TLS slots within the pthread data structure.
That's what the macOS pthread implementation uses for gsbase. */
const void* const sentinel1 = (const void*)0x2bffb6b4f11228ae;
const void* const sentinel2 = (const void*)0x0845a7ff6ab76707;
int rc;
pthread_key_t key;
const void** p = (const void**)pthread_self();
int i;
gsbase_offset = 0;
if ((rc = pthread_key_create(&key, NULL)))
{
ERR("failed to create sentinel key for gsbase search: %d\n", rc);
return NULL;
}
pthread_setspecific(key, sentinel1);
for (i = key + 1; i < 2000; i++) /* arbitrary limit */
{
if (p[i] == sentinel1)
{
pthread_setspecific(key, sentinel2);
if (p[i] == sentinel2)
{
gsbase_offset = (i - key) * sizeof(*p);
break;
}
pthread_setspecific(key, sentinel1);
}
}
pthread_key_delete(key);
}
if (gsbase_offset)
{
ret = (char*)pthread_self() + gsbase_offset;
TRACE("pthread_self() %p + offset 0x%08x -> gsbase %p\n", pthread_self(), gsbase_offset, ret);
}
else
{
ret = NULL;
ERR("failed to locate gsbase; won't be able to poke ThreadLocalStoragePointer into pthread TLS; expect crashes\n");
}
return ret;
}
#endif
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
const WORD fpu_cw = 0x27f;
stack_t ss;
#if defined __linux__
arch_prctl( ARCH_SET_GS, teb );
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
amd64_set_gsbase( teb );
#elif defined(__NetBSD__)
sysarch( X86_64_SET_GSBASE, &teb );
#elif defined (__APPLE__)
__asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
:
: "r" (teb->Tib.Self), "n" (FIELD_OFFSET(TEB, Tib.Self)));
__asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
:
: "r" (teb->ThreadLocalStoragePointer), "n" (FIELD_OFFSET(TEB, ThreadLocalStoragePointer)));
/* alloc_tls_slot() needs to poke a value to an address relative to each
thread's gsbase. Have each thread record its gsbase pointer into its
TEB so alloc_tls_slot() can find it. */
teb->Reserved5[0] = mac_thread_gsbase();
#else
# error Please define setting %gs for your architecture
#endif
ss.ss_sp = (char *)teb + teb_size;
ss.ss_size = signal_stack_size;
ss.ss_flags = 0;
if (sigaltstack(&ss, NULL) == -1) perror( "sigaltstack" );
#ifdef __GNUC__
__asm__ volatile ("fninit; fldcw %0" : : "m" (fpu_cw));
#else
FIXME("FPU setup not implemented for this platform.\n");
#endif
}
/********************************************************************** /**********************************************************************
* signal_init_process * signal_init_process
*/ */
@ -4150,27 +4007,6 @@ __ASM_GLOBAL_FUNC( start_thread,
"movq %rsp,%rdi\n\t" "movq %rsp,%rdi\n\t"
"call " __ASM_NAME("set_cpu_context") ) "call " __ASM_NAME("set_cpu_context") )
extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int) );
__ASM_GLOBAL_FUNC( call_thread_exit_func,
/* fetch exit frame */
"movq %gs:0x30,%rax\n\t"
"movq 0x330(%rax),%rdx\n\t" /* amd64_thread_data()->exit_frame */
"testq %rdx,%rdx\n\t"
"jnz 1f\n\t"
"jmp *%rsi\n"
/* switch to exit frame stack */
"1:\tmovq $0,0x330(%rax)\n\t"
"movq %rdx,%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" )
/*********************************************************************** /***********************************************************************
* init_thread_context * init_thread_context
*/ */
@ -4245,39 +4081,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
} }
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status )
{
call_thread_exit_func( status, exit_thread );
}
/***********************************************************************
* signal_exit_process
*/
void signal_exit_process( int status )
{
call_thread_exit_func( status, exit );
}
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/********************************************************************** /**********************************************************************
* DbgBreakPoint (NTDLL.@) * DbgBreakPoint (NTDLL.@)
*/ */

View File

@ -71,6 +71,8 @@ static RTL_BITMAP tls_expansion_bitmap;
static RTL_BITMAP fls_bitmap; static RTL_BITMAP fls_bitmap;
static int nb_threads = 1; static int nb_threads = 1;
struct ldt_copy *__wine_ldt_copy = NULL;
static RTL_CRITICAL_SECTION peb_lock; static RTL_CRITICAL_SECTION peb_lock;
static RTL_CRITICAL_SECTION_DEBUG critsect_debug = static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
{ {
@ -243,6 +245,10 @@ TEB *thread_init(void)
/* allocate and initialize the PEB and initial TEB */ /* allocate and initialize the PEB and initial TEB */
teb = virtual_alloc_first_teb(); teb = virtual_alloc_first_teb();
unix_funcs->init_threading( &nb_threads, &__wine_ldt_copy );
unix_funcs->alloc_thread( teb );
unix_funcs->init_thread( teb );
peb = teb->Peb; peb = teb->Peb;
peb->FastPebLock = &peb_lock; peb->FastPebLock = &peb_lock;
peb->TlsBitmap = &tls_bitmap; peb->TlsBitmap = &tls_bitmap;
@ -286,30 +292,6 @@ TEB *thread_init(void)
} }
/***********************************************************************
* abort_thread
*/
void abort_thread( int status )
{
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
if (InterlockedDecrement( &nb_threads ) <= 0) _exit( get_unix_exit_code( status ));
signal_exit_thread( status );
}
/***********************************************************************
* exit_thread
*/
void exit_thread( 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) );
}
/*********************************************************************** /***********************************************************************
* RtlExitUserThread (NTDLL.@) * RtlExitUserThread (NTDLL.@)
*/ */
@ -332,8 +314,7 @@ void WINAPI RtlExitUserThread( ULONG status )
if (InterlockedDecrement( &nb_threads ) <= 0) if (InterlockedDecrement( &nb_threads ) <= 0)
{ {
LdrShutdownProcess(); LdrShutdownProcess();
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL ); unix_funcs->exit_process( status );
signal_exit_process( get_unix_exit_code( status ));
} }
LdrShutdownThread(); LdrShutdownThread();
@ -352,7 +333,7 @@ void WINAPI RtlExitUserThread( ULONG status )
} }
} }
signal_exit_thread( status ); for (;;) unix_funcs->exit_thread( status );
} }
@ -372,7 +353,7 @@ static void start_thread( struct startup_info *info )
thread_data->debug_info = &debug_info; thread_data->debug_info = &debug_info;
thread_data->pthread_id = pthread_self(); thread_data->pthread_id = pthread_self();
signal_init_thread( teb ); unix_funcs->init_thread( teb );
unix_funcs->server_init_thread( info->entry_point, &suspend, NULL, NULL, NULL ); unix_funcs->server_init_thread( info->entry_point, &suspend, NULL, NULL, NULL );
signal_start_thread( (LPTHREAD_START_ROUTINE)info->entry_point, info->entry_arg, suspend ); signal_start_thread( (LPTHREAD_START_ROUTINE)info->entry_point, info->entry_arg, suspend );
} }
@ -667,7 +648,7 @@ NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
} }
SERVER_END_REQ; SERVER_END_REQ;
} }
if (self) abort_thread( exit_code ); if (self) unix_funcs->abort_thread( exit_code );
return ret; return ret;
} }
@ -786,6 +767,16 @@ NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int fla
} }
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return unix_funcs->NtSetLdtEntries( sel1, entry1, sel2, entry2 );
}
/****************************************************************************** /******************************************************************************
* NtQueryInformationThread (NTDLL.@) * NtQueryInformationThread (NTDLL.@)
* ZwQueryInformationThread (NTDLL.@) * ZwQueryInformationThread (NTDLL.@)
@ -894,7 +885,7 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
return status; return status;
case ThreadDescriptorTableEntry: case ThreadDescriptorTableEntry:
return get_thread_ldt_entry( handle, data, length, ret_len ); return unix_funcs->get_thread_ldt_entry( handle, data, length, ret_len );
case ThreadAmILastThread: case ThreadAmILastThread:
{ {

View File

@ -984,7 +984,9 @@ static HMODULE load_ntdll(void)
static struct unix_funcs unix_funcs = static struct unix_funcs unix_funcs =
{ {
NtClose, NtClose,
NtCurrentTeb,
NtDuplicateObject, NtDuplicateObject,
NtSetLdtEntries,
get_main_args, get_main_args,
get_paths, get_paths,
get_dll_path, get_dll_path,
@ -998,6 +1000,14 @@ static struct unix_funcs unix_funcs =
mmap_remove_reserved_area, mmap_remove_reserved_area,
mmap_is_in_reserved_area, mmap_is_in_reserved_area,
mmap_enum_reserved_areas, mmap_enum_reserved_areas,
init_threading,
alloc_thread,
free_thread,
init_thread,
abort_thread,
exit_thread,
exit_process,
get_thread_ldt_entry,
server_call_unlocked, server_call_unlocked,
wine_server_call, wine_server_call,
server_send_fd, server_send_fd,

View File

@ -190,7 +190,7 @@ static DECLSPEC_NORETURN void server_protocol_error( const char *err, ... )
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() ); fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
vfprintf( stderr, err, args ); vfprintf( stderr, err, args );
va_end( args ); va_end( args );
exit(1); abort_thread(1);
} }
@ -201,7 +201,7 @@ static DECLSPEC_NORETURN void server_protocol_perror( const char *err )
{ {
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() ); fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
perror( err ); perror( err );
exit(1); abort_thread(1);
} }
@ -237,7 +237,7 @@ static unsigned int send_request( const struct __server_request_info *req )
} }
if (ret >= 0) server_protocol_error( "partial write %d\n", ret ); if (ret >= 0) server_protocol_error( "partial write %d\n", ret );
if (errno == EPIPE) NtTerminateThread( GetCurrentThread(), 0 ); if (errno == EPIPE) abort_thread(0);
if (errno == EFAULT) return STATUS_ACCESS_VIOLATION; if (errno == EFAULT) return STATUS_ACCESS_VIOLATION;
server_protocol_perror( "write" ); server_protocol_perror( "write" );
} }
@ -266,7 +266,7 @@ static void read_reply_data( void *buffer, size_t size )
server_protocol_perror("read"); server_protocol_perror("read");
} }
/* the server closed the connection; time to die... */ /* the server closed the connection; time to die... */
for (;;) NtTerminateThread( GetCurrentThread(), 0 ); abort_thread(0);
} }
@ -379,7 +379,7 @@ void CDECL server_send_fd( int fd )
if ((ret = sendmsg( fd_socket, &msghdr, 0 )) == sizeof(data)) return; if ((ret = sendmsg( fd_socket, &msghdr, 0 )) == sizeof(data)) return;
if (ret >= 0) server_protocol_error( "partial write %d\n", ret ); if (ret >= 0) server_protocol_error( "partial write %d\n", ret );
if (errno == EINTR) continue; if (errno == EINTR) continue;
if (errno == EPIPE) NtTerminateThread( GetCurrentThread(), 0 ); if (errno == EPIPE) abort_thread(0);
server_protocol_perror( "sendmsg" ); server_protocol_perror( "sendmsg" );
} }
} }
@ -441,7 +441,7 @@ static int receive_fd( obj_handle_t *handle )
server_protocol_perror("recvmsg"); server_protocol_perror("recvmsg");
} }
/* the server closed the connection; time to die... */ /* the server closed the connection; time to die... */
for (;;) NtTerminateThread( GetCurrentThread(), 0 ); abort_thread(0);
} }

View File

@ -0,0 +1,157 @@
/*
* ARM signal handling routines
*
* Copyright 2002 Marcus Meissner, SuSE Linux AG
* Copyright 2010-2013, 2015 André Hentschel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#ifdef __arm__
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYSCALL_H
# include <syscall.h>
#else
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winnt.h"
#include "winternl.h"
#include "wine/exception.h"
#include "wine/asm.h"
#include "unix_private.h"
#include "wine/debug.h"
static pthread_key_t teb_key;
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_8A__)
/* Win32/ARM applications expect the TEB pointer to be in the TPIDRURW register. */
__asm__ __volatile__( "mcr p15, 0, %0, c13, c0, 2" : : "r" (teb) );
#endif
pthread_setspecific( teb_key, teb );
}
extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), TEB *teb );
__ASM_GLOBAL_FUNC( call_thread_exit_func,
".arm\n\t"
"ldr r3, [r2, #0x1d4]\n\t" /* teb->SystemReserved2 */
"mov ip, #0\n\t"
"str ip, [r2, #0x1d4]\n\t"
"cmp r3, ip\n\t"
"movne sp, r3\n\t"
"blx r1" )
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status, void (*func)(int) )
{
call_thread_exit_func( status, func, NtCurrentTeb() );
}
/**********************************************************************
* NtCurrentTeb (NTDLL.@)
*/
TEB * WINAPI NtCurrentTeb(void)
{
return pthread_getspecific( teb_key );
}
#endif /* __arm__ */

View File

@ -0,0 +1,166 @@
/*
* ARM64 signal handling routines
*
* Copyright 2010-2013 André Hentschel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#ifdef __aarch64__
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYSCALL_H
# include <syscall.h>
#else
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#ifdef HAVE_LIBUNWIND
# define UNW_LOCAL_ONLY
# include <libunwind.h>
#endif
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winnt.h"
#include "winternl.h"
#include "wine/exception.h"
#include "wine/asm.h"
#include "unix_private.h"
#include "wine/debug.h"
static pthread_key_t teb_key;
static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
stack_t ss;
ss.ss_sp = (char *)teb + teb_size;
ss.ss_size = signal_stack_size;
ss.ss_flags = 0;
if (sigaltstack( &ss, NULL ) == -1) perror( "sigaltstack" );
/* Win64/ARM applications expect the TEB pointer to be in the x18 platform register. */
__asm__ __volatile__( "mov x18, %0" : : "r" (teb) );
pthread_setspecific( teb_key, teb );
}
extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), TEB *teb );
__ASM_GLOBAL_FUNC( call_thread_exit_func,
"ldr x3, [x2, #0x300]\n\t" /* arm64_thread_data()->exit_frame */
"str xzr, [x2, #0x300]\n\t"
"cbz x3, 1f\n\t"
"mov sp, x3\n"
"1:\tblr x1" )
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status, void (*func)(int) )
{
call_thread_exit_func( status, func, NtCurrentTeb() );
}
/**********************************************************************
* NtCurrentTeb (NTDLL.@)
*/
TEB * WINAPI NtCurrentTeb(void)
{
return pthread_getspecific( teb_key );
}
#endif /* __aarch64__ */

View File

@ -0,0 +1,508 @@
/*
* i386 signal handling routines
*
* Copyright 1999 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#ifdef __i386__
#include "config.h"
#include "wine/port.h"
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYSCALL_H
# include <syscall.h>
#else
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "wine/asm.h"
#include "wine/exception.h"
#include "unix_private.h"
#include "wine/debug.h"
/***********************************************************************
* signal context platform-specific definitions
*/
#ifdef __linux__
struct modify_ldt_s
{
unsigned int entry_number;
void *base_addr;
unsigned int limit;
unsigned int seg_32bit : 1;
unsigned int contents : 2;
unsigned int read_exec_only : 1;
unsigned int limit_in_pages : 1;
unsigned int seg_not_present : 1;
unsigned int usable : 1;
unsigned int garbage : 25;
};
static inline int modify_ldt( int func, struct modify_ldt_s *ptr, unsigned long count )
{
return syscall( 123 /* SYS_modify_ldt */, func, ptr, count );
}
static inline int set_thread_area( struct modify_ldt_s *ptr )
{
return syscall( 243 /* SYS_set_thread_area */, ptr );
}
#elif defined (__BSDI__)
#include <machine/frame.h>
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#include <machine/trap.h>
#include <machine/segments.h>
#include <machine/sysarch.h>
#elif defined (__OpenBSD__)
#include <machine/segments.h>
#include <machine/sysarch.h>
#elif defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
#if defined(_SCO_DS) || defined(__sun)
#include <sys/regset.h>
#endif
#elif defined (__APPLE__)
#include <i386/user_ldt.h>
#elif defined(__NetBSD__)
#include <machine/segments.h>
#include <machine/sysarch.h>
#elif defined(__GNU__)
#include <mach/i386/mach_i386.h>
#include <mach/mach_traps.h>
#else
#error You must define the signal context functions for your platform
#endif /* linux */
static const size_t teb_size = 4096; /* we reserve one page for the TEB */
static ULONG first_ldt_entry = 32;
struct x86_thread_data
{
DWORD fs; /* 1d4 TEB selector */
DWORD gs; /* 1d8 libc selector; update winebuild if you move this! */
DWORD dr0; /* 1dc debug registers */
DWORD dr1; /* 1e0 */
DWORD dr2; /* 1e4 */
DWORD dr3; /* 1e8 */
DWORD dr6; /* 1ec */
DWORD dr7; /* 1f0 */
void *exit_frame; /* 1f4 exit frame pointer */
/* the ntdll_thread_data structure follows here */
};
C_ASSERT( offsetof( TEB, SystemReserved2 ) + offsetof( struct x86_thread_data, gs ) == 0x1d8 );
C_ASSERT( offsetof( TEB, SystemReserved2 ) + offsetof( struct x86_thread_data, exit_frame ) == 0x1f4 );
static inline WORD get_cs(void) { WORD res; __asm__( "movw %%cs,%0" : "=r" (res) ); return res; }
static inline WORD get_ds(void) { WORD res; __asm__( "movw %%ds,%0" : "=r" (res) ); return res; }
static inline WORD get_fs(void) { WORD res; __asm__( "movw %%fs,%0" : "=r" (res) ); return res; }
static inline WORD get_gs(void) { WORD res; __asm__( "movw %%gs,%0" : "=r" (res) ); return res; }
static inline void set_fs( WORD val ) { __asm__( "mov %0,%%fs" :: "r" (val)); }
/***********************************************************************
* is_gdt_sel
*/
static inline int is_gdt_sel( WORD sel )
{
return !(sel & 4);
}
/***********************************************************************
* LDT support
*/
#define LDT_SIZE 8192
#define LDT_FLAGS_DATA 0x13 /* Data segment */
#define LDT_FLAGS_CODE 0x1b /* Code segment */
#define LDT_FLAGS_32BIT 0x40 /* Segment is 32-bit (code or stack) */
#define LDT_FLAGS_ALLOCATED 0x80 /* Segment is allocated */
struct ldt_copy
{
void *base[LDT_SIZE];
unsigned int limit[LDT_SIZE];
unsigned char flags[LDT_SIZE];
} __wine_ldt_copy;
static WORD gdt_fs_sel;
static RTL_CRITICAL_SECTION ldt_section;
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &ldt_section,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": ldt_section") }
};
static RTL_CRITICAL_SECTION ldt_section = { &critsect_debug, -1, 0, 0, 0, 0 };
static const LDT_ENTRY null_entry;
static inline void *ldt_get_base( LDT_ENTRY ent )
{
return (void *)(ent.BaseLow |
(ULONG_PTR)ent.HighWord.Bits.BaseMid << 16 |
(ULONG_PTR)ent.HighWord.Bits.BaseHi << 24);
}
static inline unsigned int ldt_get_limit( LDT_ENTRY ent )
{
unsigned int limit = ent.LimitLow | (ent.HighWord.Bits.LimitHi << 16);
if (ent.HighWord.Bits.Granularity) limit = (limit << 12) | 0xfff;
return limit;
}
static LDT_ENTRY ldt_make_entry( void *base, unsigned int limit, unsigned char flags )
{
LDT_ENTRY entry;
entry.BaseLow = (WORD)(ULONG_PTR)base;
entry.HighWord.Bits.BaseMid = (BYTE)((ULONG_PTR)base >> 16);
entry.HighWord.Bits.BaseHi = (BYTE)((ULONG_PTR)base >> 24);
if ((entry.HighWord.Bits.Granularity = (limit >= 0x100000))) limit >>= 12;
entry.LimitLow = (WORD)limit;
entry.HighWord.Bits.LimitHi = limit >> 16;
entry.HighWord.Bits.Dpl = 3;
entry.HighWord.Bits.Pres = 1;
entry.HighWord.Bits.Type = flags;
entry.HighWord.Bits.Sys = 0;
entry.HighWord.Bits.Reserved_0 = 0;
entry.HighWord.Bits.Default_Big = (flags & LDT_FLAGS_32BIT) != 0;
return entry;
}
static void ldt_set_entry( WORD sel, LDT_ENTRY entry )
{
int index = sel >> 3;
#ifdef linux
struct modify_ldt_s ldt_info = { index };
ldt_info.base_addr = ldt_get_base( entry );
ldt_info.limit = entry.LimitLow | (entry.HighWord.Bits.LimitHi << 16);
ldt_info.seg_32bit = entry.HighWord.Bits.Default_Big;
ldt_info.contents = (entry.HighWord.Bits.Type >> 2) & 3;
ldt_info.read_exec_only = !(entry.HighWord.Bits.Type & 2);
ldt_info.limit_in_pages = entry.HighWord.Bits.Granularity;
ldt_info.seg_not_present = !entry.HighWord.Bits.Pres;
ldt_info.usable = entry.HighWord.Bits.Sys;
if (modify_ldt( 0x11, &ldt_info, sizeof(ldt_info) ) < 0) perror( "modify_ldt" );
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__)
/* The kernel will only let us set LDTs with user priority level */
if (entry.HighWord.Bits.Pres && entry.HighWord.Bits.Dpl != 3) entry.HighWord.Bits.Dpl = 3;
if (i386_set_ldt(index, (union descriptor *)&entry, 1) < 0)
{
perror("i386_set_ldt");
fprintf( stderr, "Did you reconfigure the kernel with \"options USER_LDT\"?\n" );
exit(1);
}
#elif defined(__svr4__) || defined(_SCO_DS)
struct ssd ldt_mod;
ldt_mod.sel = sel;
ldt_mod.bo = (unsigned long)ldt_get_base( entry );
ldt_mod.ls = entry.LimitLow | (entry.HighWord.Bits.LimitHi << 16);
ldt_mod.acc1 = entry.HighWord.Bytes.Flags1;
ldt_mod.acc2 = entry.HighWord.Bytes.Flags2 >> 4;
if (sysi86(SI86DSCR, &ldt_mod) == -1) perror("sysi86");
#elif defined(__APPLE__)
if (i386_set_ldt(index, (union ldt_entry *)&entry, 1) < 0) perror("i386_set_ldt");
#elif defined(__GNU__)
if (i386_set_ldt(mach_thread_self(), sel, (descriptor_list_t)&entry, 1) != KERN_SUCCESS)
perror("i386_set_ldt");
#else
fprintf( stderr, "No LDT support on this platform\n" );
exit(1);
#endif
__wine_ldt_copy.base[index] = ldt_get_base( entry );
__wine_ldt_copy.limit[index] = ldt_get_limit( entry );
__wine_ldt_copy.flags[index] = (entry.HighWord.Bits.Type |
(entry.HighWord.Bits.Default_Big ? LDT_FLAGS_32BIT : 0) |
LDT_FLAGS_ALLOCATED);
}
static void ldt_set_fs( WORD sel, TEB *teb )
{
if (sel == gdt_fs_sel)
{
#ifdef __linux__
struct modify_ldt_s ldt_info = { sel >> 3 };
ldt_info.base_addr = teb;
ldt_info.limit = teb_size - 1;
ldt_info.seg_32bit = 1;
if (set_thread_area( &ldt_info ) < 0) perror( "set_thread_area" );
#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
i386_set_fsbase( teb );
#endif
}
set_fs( sel );
}
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
THREAD_DESCRIPTOR_INFORMATION *info = data;
NTSTATUS status = STATUS_SUCCESS;
if (len < sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
if (info->Selector >> 16) return STATUS_UNSUCCESSFUL;
if (is_gdt_sel( info->Selector ))
{
if (!(info->Selector & ~3))
info->Entry = null_entry;
else if ((info->Selector | 3) == get_cs())
info->Entry = ldt_make_entry( 0, ~0u, LDT_FLAGS_CODE | LDT_FLAGS_32BIT );
else if ((info->Selector | 3) == get_ds())
info->Entry = ldt_make_entry( 0, ~0u, LDT_FLAGS_DATA | LDT_FLAGS_32BIT );
else if ((info->Selector | 3) == get_fs())
info->Entry = ldt_make_entry( NtCurrentTeb(), 0xfff, LDT_FLAGS_DATA | LDT_FLAGS_32BIT );
else
return STATUS_UNSUCCESSFUL;
}
else
{
SERVER_START_REQ( get_selector_entry )
{
req->handle = wine_server_obj_handle( handle );
req->entry = info->Selector >> 3;
status = wine_server_call( req );
if (!status)
{
if (reply->flags)
info->Entry = ldt_make_entry( (void *)reply->base, reply->limit, reply->flags );
else
status = STATUS_UNSUCCESSFUL;
}
}
SERVER_END_REQ;
}
if (status == STATUS_SUCCESS && ret_len)
/* yes, that's a bit strange, but it's the way it is */
*ret_len = sizeof(info->Entry);
return status;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
sigset_t sigset;
if (sel1 >> 16 || sel2 >> 16) return STATUS_INVALID_LDT_DESCRIPTOR;
if (sel1 && (sel1 >> 3) < first_ldt_entry) return STATUS_INVALID_LDT_DESCRIPTOR;
if (sel2 && (sel2 >> 3) < first_ldt_entry) return STATUS_INVALID_LDT_DESCRIPTOR;
server_enter_uninterrupted_section( &ldt_section, &sigset );
if (sel1) ldt_set_entry( sel1, entry1 );
if (sel2) ldt_set_entry( sel2, entry2 );
server_leave_uninterrupted_section( &ldt_section, &sigset );
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
#ifdef __linux__
/* the preloader may have allocated it already */
gdt_fs_sel = get_fs();
if (!gdt_fs_sel || !is_gdt_sel( gdt_fs_sel ))
{
struct modify_ldt_s ldt_info = { -1 };
ldt_info.seg_32bit = 1;
ldt_info.usable = 1;
if (set_thread_area( &ldt_info ) >= 0) gdt_fs_sel = (ldt_info.entry_number << 3) | 3;
else gdt_fs_sel = 0;
}
#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__)
gdt_fs_sel = GSEL( GUFS_SEL, SEL_UPL );
#endif
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2;
if (!gdt_fs_sel)
{
static int first_thread = 1;
sigset_t sigset;
int idx;
LDT_ENTRY entry = ldt_make_entry( teb, teb_size - 1, LDT_FLAGS_DATA | LDT_FLAGS_32BIT );
if (first_thread) /* no locking for first thread */
{
/* leave some space if libc is using the LDT for %gs */
if (!is_gdt_sel( get_gs() )) first_ldt_entry = 512;
idx = first_ldt_entry;
ldt_set_entry( (idx << 3) | 7, entry );
first_thread = 0;
}
else
{
server_enter_uninterrupted_section( &ldt_section, &sigset );
for (idx = first_ldt_entry; idx < LDT_SIZE; idx++)
{
if (__wine_ldt_copy.flags[idx]) continue;
ldt_set_entry( (idx << 3) | 7, entry );
break;
}
server_leave_uninterrupted_section( &ldt_section, &sigset );
if (idx == LDT_SIZE) return STATUS_TOO_MANY_THREADS;
}
thread_data->fs = (idx << 3) | 7;
}
else thread_data->fs = gdt_fs_sel;
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2;
sigset_t sigset;
if (gdt_fs_sel) return;
server_enter_uninterrupted_section( &ldt_section, &sigset );
__wine_ldt_copy.flags[thread_data->fs >> 3] = 0;
server_leave_uninterrupted_section( &ldt_section, &sigset );
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
const WORD fpu_cw = 0x27f;
struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2;
stack_t ss;
ss.ss_sp = (char *)teb + teb_size;
ss.ss_size = signal_stack_size;
ss.ss_flags = 0;
if (sigaltstack(&ss, NULL) == -1) perror( "sigaltstack" );
ldt_set_fs( thread_data->fs, teb );
thread_data->gs = get_gs();
#ifdef __GNUC__
__asm__ volatile ("fninit; fldcw %0" : : "m" (fpu_cw));
#else
FIXME("FPU setup not implemented for this platform.\n");
#endif
}
/***********************************************************************
* signal_exit_thread
*/
__ASM_GLOBAL_FUNC( signal_exit_thread,
"movl 8(%esp),%ecx\n\t"
/* fetch exit frame */
"movl %fs:0x1f4,%edx\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 $0,%fs:0x1f4\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" )
/**********************************************************************
* NtCurrentTeb (NTDLL.@)
*/
__ASM_STDCALL_FUNC( NtCurrentTeb, 0, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" )
#endif /* __i386__ */

View File

@ -0,0 +1,140 @@
/*
* PowerPC signal handling routines
*
* Copyright 2002 Marcus Meissner, SuSE Linux AG
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#ifdef __powerpc__
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYSCALL_H
# include <syscall.h>
#else
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "wine/exception.h"
#include "wine/asm.h"
#include "unix_private.h"
#include "wine/debug.h"
static pthread_key_t teb_key;
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
pthread_setspecific( teb_key, teb );
}
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status, void (*func)(int) )
{
func( status );
}
/**********************************************************************
* NtCurrentTeb (NTDLL.@)
*/
TEB * WINAPI NtCurrentTeb(void)
{
return pthread_getspecific( teb_key );
}
#endif /* __powerpc__ */

View File

@ -0,0 +1,278 @@
/*
* x86-64 signal handling routines
*
* Copyright 1999, 2005 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#ifdef __x86_64__
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_MACHINE_SYSARCH_H
# include <machine/sysarch.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYSCALL_H
# include <syscall.h>
#else
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#ifdef HAVE_LIBUNWIND
# define UNW_LOCAL_ONLY
# include <libunwind.h>
#endif
#ifdef __APPLE__
# include <mach/mach.h>
#endif
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "wine/exception.h"
#include "wine/list.h"
#include "wine/asm.h"
#include "unix_private.h"
#include "wine/debug.h"
/***********************************************************************
* signal context platform-specific definitions
*/
#ifdef linux
#include <asm/prctl.h>
static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_prctl, func, ptr ); }
#endif
enum i386_trap_code
{
TRAP_x86_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */
TRAP_x86_DIVIDE = 0, /* Division by zero exception */
TRAP_x86_TRCTRAP = 1, /* Single-step exception */
TRAP_x86_NMI = 2, /* NMI interrupt */
TRAP_x86_BPTFLT = 3, /* Breakpoint exception */
TRAP_x86_OFLOW = 4, /* Overflow exception */
TRAP_x86_BOUND = 5, /* Bound range exception */
TRAP_x86_PRIVINFLT = 6, /* Invalid opcode exception */
TRAP_x86_DNA = 7, /* Device not available exception */
TRAP_x86_DOUBLEFLT = 8, /* Double fault exception */
TRAP_x86_FPOPFLT = 9, /* Coprocessor segment overrun */
TRAP_x86_TSSFLT = 10, /* Invalid TSS exception */
TRAP_x86_SEGNPFLT = 11, /* Segment not present exception */
TRAP_x86_STKFLT = 12, /* Stack fault */
TRAP_x86_PROTFLT = 13, /* General protection fault */
TRAP_x86_PAGEFLT = 14, /* Page fault */
TRAP_x86_ARITHTRAP = 16, /* Floating point exception */
TRAP_x86_ALIGNFLT = 17, /* Alignment check exception */
TRAP_x86_MCHK = 18, /* Machine check exception */
TRAP_x86_CACHEFLT = 19 /* Cache flush exception */
};
static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
#ifdef __APPLE__
/**********************************************************************
* mac_thread_gsbase
*/
static void *mac_thread_gsbase(void)
{
struct thread_identifier_info tiinfo;
unsigned int info_count = THREAD_IDENTIFIER_INFO_COUNT;
static int gsbase_offset = -1;
kern_return_t kr = thread_info(mach_thread_self(), THREAD_IDENTIFIER_INFO, (thread_info_t) &tiinfo, &info_count);
if (kr == KERN_SUCCESS) return (void*)tiinfo.thread_handle;
if (gsbase_offset < 0)
{
/* Search for the array of TLS slots within the pthread data structure.
That's what the macOS pthread implementation uses for gsbase. */
const void* const sentinel1 = (const void*)0x2bffb6b4f11228ae;
const void* const sentinel2 = (const void*)0x0845a7ff6ab76707;
int rc;
pthread_key_t key;
const void** p = (const void**)pthread_self();
int i;
gsbase_offset = 0;
if ((rc = pthread_key_create(&key, NULL))) return NULL;
pthread_setspecific(key, sentinel1);
for (i = key + 1; i < 2000; i++) /* arbitrary limit */
{
if (p[i] == sentinel1)
{
pthread_setspecific(key, sentinel2);
if (p[i] == sentinel2)
{
gsbase_offset = (i - key) * sizeof(*p);
break;
}
pthread_setspecific(key, sentinel1);
}
}
pthread_key_delete(key);
}
if (gsbase_offset) return (char*)pthread_self() + gsbase_offset;
return NULL;
}
#endif
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
const WORD fpu_cw = 0x27f;
stack_t ss;
#if defined __linux__
arch_prctl( ARCH_SET_GS, teb );
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
amd64_set_gsbase( teb );
#elif defined(__NetBSD__)
sysarch( X86_64_SET_GSBASE, &teb );
#elif defined (__APPLE__)
__asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
:
: "r" (teb->Tib.Self), "n" (FIELD_OFFSET(TEB, Tib.Self)));
__asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
:
: "r" (teb->ThreadLocalStoragePointer), "n" (FIELD_OFFSET(TEB, ThreadLocalStoragePointer)));
/* alloc_tls_slot() needs to poke a value to an address relative to each
thread's gsbase. Have each thread record its gsbase pointer into its
TEB so alloc_tls_slot() can find it. */
teb->Reserved5[0] = mac_thread_gsbase();
#else
# error Please define setting %gs for your architecture
#endif
ss.ss_sp = (char *)teb + teb_size;
ss.ss_size = signal_stack_size;
ss.ss_flags = 0;
if (sigaltstack(&ss, NULL) == -1) perror( "sigaltstack" );
#ifdef __GNUC__
__asm__ volatile ("fninit; fldcw %0" : : "m" (fpu_cw));
#else
FIXME("FPU setup not implemented for this platform.\n");
#endif
}
/***********************************************************************
* signal_exit_thread
*/
__ASM_GLOBAL_FUNC( signal_exit_thread,
/* fetch exit frame */
"movq %gs:0x30,%rax\n\t"
"movq 0x330(%rax),%rdx\n\t" /* amd64_thread_data()->exit_frame */
"testq %rdx,%rdx\n\t"
"jnz 1f\n\t"
"jmp *%rsi\n"
/* switch to exit frame stack */
"1:\tmovq $0,0x330(%rax)\n\t"
"movq %rdx,%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" )
#endif /* __x86_64__ */

150
dlls/ntdll/unix/thread.c Normal file
View File

@ -0,0 +1,150 @@
/*
* NT threads support
*
* Copyright 1996, 2003 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <limits.h>
#include <stdarg.h>
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#ifdef HAVE_SYS_TIMES_H
#include <sys/times.h>
#endif
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
#endif
#define NONAMELESSUNION
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "winternl.h"
#include "ddk/wdm.h"
#include "wine/server.h"
#include "wine/debug.h"
#include "wine/exception.h"
#include "unix_private.h"
#ifndef PTHREAD_STACK_MIN
#define PTHREAD_STACK_MIN 16384
#endif
static int *nb_threads;
static inline int get_unix_exit_code( NTSTATUS status )
{
/* prevent a nonzero exit code to end up truncated to zero in unix */
if (status && !(status & 0xff)) return 1;
return status;
}
/***********************************************************************
* 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) );
}
/***********************************************************************
* init_threading
*/
void CDECL init_threading( int *nb_threads_ptr, struct ldt_copy **ldt_copy )
{
#ifdef __i386__
extern struct ldt_copy __wine_ldt_copy;
*ldt_copy = &__wine_ldt_copy;
#endif
nb_threads = nb_threads_ptr;
signal_init_threading();
}
/***********************************************************************
* alloc_thread
*/
NTSTATUS CDECL alloc_thread( TEB *teb )
{
return signal_alloc_thread( teb );
}
/***********************************************************************
* free_thread
*/
void CDECL free_thread( TEB *teb )
{
signal_free_thread( teb );
}
/***********************************************************************
* init_thread
*/
void CDECL init_thread( TEB *teb )
{
signal_init_thread( teb );
}
/***********************************************************************
* abort_thread
*/
void CDECL abort_thread( int status )
{
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
if (InterlockedDecrement( nb_threads ) <= 0) _exit( get_unix_exit_code( status ));
signal_exit_thread( status, pthread_exit_wrapper );
}
/***********************************************************************
* exit_thread
*/
void CDECL exit_thread( int status )
{
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
signal_exit_thread( status, pthread_exit_wrapper );
}
/***********************************************************************
* exit_process
*/
void CDECL exit_process( int status )
{
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
signal_exit_thread( get_unix_exit_code( status ), exit );
}

View File

@ -75,11 +75,30 @@ extern void CDECL server_init_process(void) DECLSPEC_HIDDEN;
extern void CDECL server_init_process_done(void) DECLSPEC_HIDDEN; extern void CDECL server_init_process_done(void) DECLSPEC_HIDDEN;
extern size_t CDECL server_init_thread( void *entry_point, BOOL *suspend, unsigned int *cpus, extern size_t CDECL server_init_thread( void *entry_point, BOOL *suspend, unsigned int *cpus,
BOOL *wow64, timeout_t *start_time ) DECLSPEC_HIDDEN; BOOL *wow64, timeout_t *start_time ) DECLSPEC_HIDDEN;
extern void CDECL init_threading( int *nb_threads, struct ldt_copy **ldt_copy ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL alloc_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void CDECL free_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void CDECL init_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void CDECL DECLSPEC_NORETURN abort_thread( int status ) DECLSPEC_HIDDEN;
extern void CDECL DECLSPEC_NORETURN exit_thread( int status ) DECLSPEC_HIDDEN;
extern void CDECL DECLSPEC_NORETURN exit_process( int status ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len ) DECLSPEC_HIDDEN;
extern const char *data_dir DECLSPEC_HIDDEN; extern const char *data_dir DECLSPEC_HIDDEN;
extern const char *build_dir DECLSPEC_HIDDEN; extern const char *build_dir DECLSPEC_HIDDEN;
extern const char *config_dir DECLSPEC_HIDDEN; extern const char *config_dir DECLSPEC_HIDDEN;
extern sigset_t server_block_set DECLSPEC_HIDDEN;
extern SIZE_T signal_stack_size DECLSPEC_HIDDEN;
extern SIZE_T signal_stack_mask DECLSPEC_HIDDEN;
extern void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN;
extern void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN;
extern void start_server( BOOL debug ) DECLSPEC_HIDDEN; extern void start_server( BOOL debug ) DECLSPEC_HIDDEN;
extern void signal_init_threading(void) DECLSPEC_HIDDEN;
extern NTSTATUS signal_alloc_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 DECLSPEC_NORETURN signal_exit_thread( int status, void (*func)(int) ) DECLSPEC_HIDDEN;
#endif /* __NTDLL_UNIX_PRIVATE_H */ #endif /* __NTDLL_UNIX_PRIVATE_H */

View File

@ -26,6 +26,7 @@
#include "wine/port.h" #include "wine/port.h"
#include <assert.h> #include <assert.h>
#include <signal.h>
#include <stdarg.h> #include <stdarg.h>
#ifdef HAVE_SYS_MMAN_H #ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h> # include <sys/mman.h>
@ -62,9 +63,20 @@ struct reserved_area
static struct list reserved_areas = LIST_INIT(reserved_areas); static struct list reserved_areas = LIST_INIT(reserved_areas);
static const UINT page_shift = 12;
static const UINT_PTR page_mask = 0xfff;
static const unsigned int granularity_mask = 0xffff; /* reserved areas have 64k granularity */ static const unsigned int granularity_mask = 0xffff; /* reserved areas have 64k granularity */
extern IMAGE_NT_HEADERS __wine_spec_nt_header; SIZE_T signal_stack_size = 0;
SIZE_T signal_stack_mask = 0;
static SIZE_T signal_stack_align;
#define ROUND_ADDR(addr,mask) \
((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask)))
#define ROUND_SIZE(addr,size) \
(((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)
#ifndef MAP_NORESERVE #ifndef MAP_NORESERVE
#define MAP_NORESERVE 0 #define MAP_NORESERVE 0
@ -367,6 +379,7 @@ int CDECL mmap_enum_reserved_areas( int (CDECL *enum_func)(void *base, SIZE_T si
void virtual_init(void) void virtual_init(void)
{ {
const struct preload_info **preload_info = dlsym( RTLD_DEFAULT, "wine_main_preload_info" ); const struct preload_info **preload_info = dlsym( RTLD_DEFAULT, "wine_main_preload_info" );
size_t size;
int i; int i;
if (preload_info && *preload_info) if (preload_info && *preload_info)
@ -374,4 +387,11 @@ void virtual_init(void)
mmap_add_reserved_area( (*preload_info)[i].addr, (*preload_info)[i].size ); mmap_add_reserved_area( (*preload_info)[i].addr, (*preload_info)[i].size );
mmap_init( preload_info ? *preload_info : NULL ); mmap_init( preload_info ? *preload_info : NULL );
size = ROUND_SIZE( 0, sizeof(TEB) ) + max( MINSIGSTKSZ, 8192 );
/* find the first power of two not smaller than size */
signal_stack_align = page_shift;
while ((1u << signal_stack_align) < size) signal_stack_align++;
signal_stack_mask = (1 << signal_stack_align) - 1;
signal_stack_size = (1 << signal_stack_align) - ROUND_SIZE( 0, sizeof(TEB) );
} }

View File

@ -24,16 +24,20 @@
#include "wine/server.h" #include "wine/server.h"
#include "wine/debug.h" #include "wine/debug.h"
struct ldt_copy;
/* increment this when you change the function table */ /* increment this when you change the function table */
#define NTDLL_UNIXLIB_VERSION 11 #define NTDLL_UNIXLIB_VERSION 12
struct unix_funcs struct unix_funcs
{ {
/* Nt* functions */ /* Nt* functions */
NTSTATUS (WINAPI *NtClose)( HANDLE handle ); NTSTATUS (WINAPI *NtClose)( HANDLE handle );
TEB * (WINAPI *NtCurrentTeb)(void);
NTSTATUS (WINAPI *NtDuplicateObject)( HANDLE source_process, HANDLE source, NTSTATUS (WINAPI *NtDuplicateObject)( HANDLE source_process, HANDLE source,
HANDLE dest_process, HANDLE *dest, HANDLE dest_process, HANDLE *dest,
ACCESS_MASK access, ULONG attributes, ULONG options ); ACCESS_MASK access, ULONG attributes, ULONG options );
NTSTATUS (WINAPI *NtSetLdtEntries)( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 );
/* environment functions */ /* environment functions */
void (CDECL *get_main_args)( int *argc, char **argv[], char **envp[] ); void (CDECL *get_main_args)( int *argc, char **argv[], char **envp[] );
@ -56,6 +60,16 @@ struct unix_funcs
int (CDECL *mmap_enum_reserved_areas)( int (CDECL *enum_func)(void *base, SIZE_T size, void *arg), int (CDECL *mmap_enum_reserved_areas)( int (CDECL *enum_func)(void *base, SIZE_T size, void *arg),
void *arg, int top_down ); void *arg, int top_down );
/* thread/process functions */
void (CDECL *init_threading)( int *nb_threads, struct ldt_copy **ldt_copy );
NTSTATUS (CDECL *alloc_thread)( TEB *teb );
void (CDECL *free_thread)( TEB *teb );
void (CDECL *init_thread)( TEB *teb );
void (CDECL *abort_thread)( int status );
void (CDECL *exit_thread)( int status );
void (CDECL *exit_process)( int status );
NTSTATUS (CDECL *get_thread_ldt_entry)( HANDLE handle, void *data, ULONG len, ULONG *ret_len );
/* server functions */ /* server functions */
unsigned int (CDECL *server_call_unlocked)( void *req_ptr ); unsigned int (CDECL *server_call_unlocked)( void *req_ptr );
unsigned int (CDECL *server_call)( void *req_ptr ); unsigned int (CDECL *server_call)( void *req_ptr );

View File

@ -2284,9 +2284,6 @@ TEB *virtual_alloc_first_teb(void)
teb->Tib.StackBase = (void *)~0ul; teb->Tib.StackBase = (void *)~0ul;
teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
signal_init_threading();
signal_alloc_thread( teb );
signal_init_thread( teb );
use_locks = TRUE; use_locks = TRUE;
return teb; return teb;
} }
@ -2337,7 +2334,7 @@ NTSTATUS virtual_alloc_teb( TEB **ret_teb )
teb->Tib.ExceptionList = (void *)~0UL; teb->Tib.ExceptionList = (void *)~0UL;
teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
if ((status = signal_alloc_thread( teb ))) if ((status = unix_funcs->alloc_thread( teb )))
{ {
server_enter_uninterrupted_section( &csVirtual, &sigset ); server_enter_uninterrupted_section( &csVirtual, &sigset );
*(TEB **)teb = next_free_teb; *(TEB **)teb = next_free_teb;
@ -2357,7 +2354,7 @@ void virtual_free_teb( TEB *teb )
SIZE_T size; SIZE_T size;
sigset_t sigset; sigset_t sigset;
signal_free_thread( teb ); unix_funcs->free_thread( teb );
if (teb->DeallocationStack) if (teb->DeallocationStack)
{ {
size = 0; size = 0;