ntdll: Move the threading initialization functions to the Unix library.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
3e59649c9e
commit
3e9f8c87e5
|
@ -69,10 +69,12 @@ static LDT_ENTRY ldt_make_entry( const void *base, unsigned int limit, unsigned
|
|||
*/
|
||||
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_fs() )) first_ldt_entry += 512;
|
||||
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;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -53,6 +53,12 @@ C_SRCS = \
|
|||
unix/debug.c \
|
||||
unix/loader.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 \
|
||||
version.c \
|
||||
virtual.c \
|
||||
|
|
|
@ -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 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_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;
|
||||
|
||||
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
|
||||
|
@ -80,15 +79,9 @@ extern LPCSTR debugstr_ObjectAttributes(const OBJECT_ATTRIBUTES *oa) DECLSPEC_HI
|
|||
/* init routines */
|
||||
extern SIZE_T signal_stack_size 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_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 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 debug_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 void server_init_process(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 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;
|
||||
|
|
|
@ -127,7 +127,7 @@ static DECLSPEC_NORETURN void server_protocol_error( const char *err, ... )
|
|||
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
|
||||
vfprintf( stderr, err, 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() );
|
||||
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) );
|
||||
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;
|
||||
/* we stole another reply, wait for the real one */
|
||||
signaled = wait_select_reply( cookie );
|
||||
|
@ -714,7 +714,7 @@ void server_init_process(void)
|
|||
void server_init_process_done(void)
|
||||
{
|
||||
#ifdef __i386__
|
||||
extern struct ldt_copy __wine_ldt_copy;
|
||||
extern struct ldt_copy *__wine_ldt_copy;
|
||||
#endif
|
||||
PEB *peb = NtCurrentTeb()->Peb;
|
||||
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 );
|
||||
#ifdef __i386__
|
||||
req->ldt_copy = wine_server_client_ptr( &__wine_ldt_copy );
|
||||
req->ldt_copy = wine_server_client_ptr( __wine_ldt_copy );
|
||||
#endif
|
||||
req->entry = wine_server_client_ptr( entry );
|
||||
req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI);
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/library.h"
|
||||
#include "wine/exception.h"
|
||||
#include "ntdll_misc.h"
|
||||
#include "wine/debug.h"
|
||||
|
@ -64,8 +63,6 @@
|
|||
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||
|
||||
static pthread_key_t teb_key;
|
||||
|
||||
/***********************************************************************
|
||||
* 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 )
|
||||
{
|
||||
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
|
||||
*/
|
||||
|
@ -1163,16 +1120,6 @@ __ASM_GLOBAL_FUNC( start_thread,
|
|||
"mov r0, sp\n\t"
|
||||
"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
|
||||
*/
|
||||
|
@ -1239,39 +1186,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
|
|||
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.@)
|
||||
*/
|
||||
|
@ -1293,7 +1207,7 @@ void WINAPI DbgUserBreakPoint(void)
|
|||
*/
|
||||
TEB * WINAPI NtCurrentTeb(void)
|
||||
{
|
||||
return pthread_getspecific( teb_key );
|
||||
return unix_funcs->NtCurrentTeb();
|
||||
}
|
||||
|
||||
#endif /* __arm__ */
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/library.h"
|
||||
#include "wine/exception.h"
|
||||
#include "ntdll_misc.h"
|
||||
#include "wine/debug.h"
|
||||
|
@ -67,8 +66,6 @@
|
|||
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||
|
||||
static pthread_key_t teb_key;
|
||||
|
||||
/* layering violation: the setjmp buffer is defined in msvcrt, but used by RtlUnwindEx */
|
||||
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 )
|
||||
{
|
||||
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
|
||||
*/
|
||||
|
@ -2208,14 +2160,6 @@ __ASM_GLOBAL_FUNC( start_thread,
|
|||
"ldr x0, [x0, #0x8]\n\t" /* context->X0 */
|
||||
"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
|
||||
*/
|
||||
|
@ -2281,39 +2225,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
|
|||
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.@)
|
||||
*/
|
||||
|
@ -2329,7 +2240,7 @@ __ASM_STDCALL_FUNC( DbgUserBreakPoint, 0, "brk #0; ret")
|
|||
*/
|
||||
TEB * WINAPI NtCurrentTeb(void)
|
||||
{
|
||||
return pthread_getspecific( teb_key );
|
||||
return unix_funcs->NtCurrentTeb();
|
||||
}
|
||||
|
||||
#endif /* __aarch64__ */
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "wine/library.h"
|
||||
#include "ntdll_misc.h"
|
||||
#include "wine/exception.h"
|
||||
#include "wine/debug.h"
|
||||
|
@ -182,30 +181,6 @@ __ASM_GLOBAL_FUNC( rt_sigreturn,
|
|||
"int $0x80" );
|
||||
#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__)
|
||||
|
||||
#include <machine/frame.h>
|
||||
|
@ -470,8 +445,6 @@ struct stack_layout
|
|||
|
||||
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 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),
|
||||
(unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit,
|
||||
NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
unix_funcs->abort_thread(1);
|
||||
}
|
||||
|
||||
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),
|
||||
(unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
unix_funcs->abort_thread(1);
|
||||
}
|
||||
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),
|
||||
(unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
unix_funcs->abort_thread(1);
|
||||
}
|
||||
case -1: /* overflow */
|
||||
exception_code = EXCEPTION_STACK_OVERFLOW;
|
||||
|
@ -2264,7 +2237,7 @@ static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
|||
{
|
||||
WORD 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
|
||||
*/
|
||||
|
@ -2870,27 +2535,6 @@ __ASM_GLOBAL_FUNC( start_thread,
|
|||
"movl %esi,(%esp)\n\t"
|
||||
"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;
|
||||
__ASM_GLOBAL_FUNC( call_thread_entry,
|
||||
"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.@)
|
||||
*/
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/library.h"
|
||||
#include "wine/exception.h"
|
||||
#include "ntdll_misc.h"
|
||||
#include "wine/debug.h"
|
||||
|
@ -61,8 +60,6 @@
|
|||
WINE_DEFAULT_DEBUG_CHANNEL(seh);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||
|
||||
static pthread_key_t teb_key;
|
||||
|
||||
/***********************************************************************
|
||||
* 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 )
|
||||
{
|
||||
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
|
||||
*/
|
||||
|
@ -1218,39 +1180,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
|
|||
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.@)
|
||||
*/
|
||||
|
@ -1272,7 +1201,7 @@ void WINAPI DbgUserBreakPoint(void)
|
|||
*/
|
||||
TEB * WINAPI NtCurrentTeb(void)
|
||||
{
|
||||
return pthread_getspecific( teb_key );
|
||||
return unix_funcs->NtCurrentTeb();
|
||||
}
|
||||
|
||||
#endif /* __powerpc__ */
|
||||
|
|
|
@ -65,7 +65,6 @@
|
|||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/library.h"
|
||||
#include "wine/exception.h"
|
||||
#include "wine/list.h"
|
||||
#include "ntdll_misc.h"
|
||||
|
@ -123,9 +122,6 @@ struct MSVCRT_JUMP_BUFFER
|
|||
*/
|
||||
#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 RBX_sig(context) ((context)->uc_mcontext.gregs[REG_RBX])
|
||||
#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",
|
||||
GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_sig(sigcontext),
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
unix_funcs->abort_thread(1);
|
||||
}
|
||||
|
||||
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),
|
||||
(ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
unix_funcs->abort_thread(1);
|
||||
}
|
||||
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),
|
||||
(ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
|
||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
unix_funcs->abort_thread(1);
|
||||
}
|
||||
case -1: /* 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 )
|
||||
{
|
||||
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
|
||||
*/
|
||||
|
@ -4150,27 +4007,6 @@ __ASM_GLOBAL_FUNC( start_thread,
|
|||
"movq %rsp,%rdi\n\t"
|
||||
"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
|
||||
*/
|
||||
|
@ -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.@)
|
||||
*/
|
||||
|
|
|
@ -71,6 +71,8 @@ static RTL_BITMAP tls_expansion_bitmap;
|
|||
static RTL_BITMAP fls_bitmap;
|
||||
static int nb_threads = 1;
|
||||
|
||||
struct ldt_copy *__wine_ldt_copy = NULL;
|
||||
|
||||
static RTL_CRITICAL_SECTION peb_lock;
|
||||
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
|
||||
{
|
||||
|
@ -243,6 +245,10 @@ TEB *thread_init(void)
|
|||
/* allocate and initialize the PEB and initial 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->FastPebLock = &peb_lock;
|
||||
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.@)
|
||||
*/
|
||||
|
@ -332,8 +314,7 @@ void WINAPI RtlExitUserThread( ULONG status )
|
|||
if (InterlockedDecrement( &nb_threads ) <= 0)
|
||||
{
|
||||
LdrShutdownProcess();
|
||||
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
|
||||
signal_exit_process( get_unix_exit_code( status ));
|
||||
unix_funcs->exit_process( status );
|
||||
}
|
||||
|
||||
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->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 );
|
||||
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;
|
||||
}
|
||||
if (self) abort_thread( exit_code );
|
||||
if (self) unix_funcs->abort_thread( exit_code );
|
||||
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.@)
|
||||
* ZwQueryInformationThread (NTDLL.@)
|
||||
|
@ -894,7 +885,7 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
|
|||
return status;
|
||||
|
||||
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:
|
||||
{
|
||||
|
|
|
@ -984,7 +984,9 @@ static HMODULE load_ntdll(void)
|
|||
static struct unix_funcs unix_funcs =
|
||||
{
|
||||
NtClose,
|
||||
NtCurrentTeb,
|
||||
NtDuplicateObject,
|
||||
NtSetLdtEntries,
|
||||
get_main_args,
|
||||
get_paths,
|
||||
get_dll_path,
|
||||
|
@ -998,6 +1000,14 @@ static struct unix_funcs unix_funcs =
|
|||
mmap_remove_reserved_area,
|
||||
mmap_is_in_reserved_area,
|
||||
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,
|
||||
wine_server_call,
|
||||
server_send_fd,
|
||||
|
|
|
@ -190,7 +190,7 @@ static DECLSPEC_NORETURN void server_protocol_error( const char *err, ... )
|
|||
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
|
||||
vfprintf( stderr, err, 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() );
|
||||
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 (errno == EPIPE) NtTerminateThread( GetCurrentThread(), 0 );
|
||||
if (errno == EPIPE) abort_thread(0);
|
||||
if (errno == EFAULT) return STATUS_ACCESS_VIOLATION;
|
||||
server_protocol_perror( "write" );
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ static void read_reply_data( void *buffer, size_t size )
|
|||
server_protocol_perror("read");
|
||||
}
|
||||
/* 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 >= 0) server_protocol_error( "partial write %d\n", ret );
|
||||
if (errno == EINTR) continue;
|
||||
if (errno == EPIPE) NtTerminateThread( GetCurrentThread(), 0 );
|
||||
if (errno == EPIPE) abort_thread(0);
|
||||
server_protocol_perror( "sendmsg" );
|
||||
}
|
||||
}
|
||||
|
@ -441,7 +441,7 @@ static int receive_fd( obj_handle_t *handle )
|
|||
server_protocol_perror("recvmsg");
|
||||
}
|
||||
/* the server closed the connection; time to die... */
|
||||
for (;;) NtTerminateThread( GetCurrentThread(), 0 );
|
||||
abort_thread(0);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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 );
|
||||
}
|
|
@ -75,11 +75,30 @@ extern void CDECL server_init_process(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,
|
||||
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 *build_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 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 */
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "wine/port.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
# include <sys/mman.h>
|
||||
|
@ -62,9 +63,20 @@ struct reserved_area
|
|||
|
||||
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 */
|
||||
|
||||
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
|
||||
#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)
|
||||
{
|
||||
const struct preload_info **preload_info = dlsym( RTLD_DEFAULT, "wine_main_preload_info" );
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
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_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) );
|
||||
}
|
||||
|
|
|
@ -24,16 +24,20 @@
|
|||
#include "wine/server.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
struct ldt_copy;
|
||||
|
||||
/* increment this when you change the function table */
|
||||
#define NTDLL_UNIXLIB_VERSION 11
|
||||
#define NTDLL_UNIXLIB_VERSION 12
|
||||
|
||||
struct unix_funcs
|
||||
{
|
||||
/* Nt* functions */
|
||||
NTSTATUS (WINAPI *NtClose)( HANDLE handle );
|
||||
TEB * (WINAPI *NtCurrentTeb)(void);
|
||||
NTSTATUS (WINAPI *NtDuplicateObject)( HANDLE source_process, HANDLE source,
|
||||
HANDLE dest_process, HANDLE *dest,
|
||||
ACCESS_MASK access, ULONG attributes, ULONG options );
|
||||
NTSTATUS (WINAPI *NtSetLdtEntries)( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 );
|
||||
|
||||
/* environment functions */
|
||||
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),
|
||||
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 */
|
||||
unsigned int (CDECL *server_call_unlocked)( void *req_ptr );
|
||||
unsigned int (CDECL *server_call)( void *req_ptr );
|
||||
|
|
|
@ -2284,9 +2284,6 @@ TEB *virtual_alloc_first_teb(void)
|
|||
teb->Tib.StackBase = (void *)~0ul;
|
||||
teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
|
||||
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
|
||||
signal_init_threading();
|
||||
signal_alloc_thread( teb );
|
||||
signal_init_thread( teb );
|
||||
use_locks = TRUE;
|
||||
return teb;
|
||||
}
|
||||
|
@ -2337,7 +2334,7 @@ NTSTATUS virtual_alloc_teb( TEB **ret_teb )
|
|||
teb->Tib.ExceptionList = (void *)~0UL;
|
||||
teb->StaticUnicodeString.Buffer = 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 );
|
||||
*(TEB **)teb = next_free_teb;
|
||||
|
@ -2357,7 +2354,7 @@ void virtual_free_teb( TEB *teb )
|
|||
SIZE_T size;
|
||||
sigset_t sigset;
|
||||
|
||||
signal_free_thread( teb );
|
||||
unix_funcs->free_thread( teb );
|
||||
if (teb->DeallocationStack)
|
||||
{
|
||||
size = 0;
|
||||
|
|
Loading…
Reference in New Issue