diff --git a/include/server.h b/include/server.h index 30d4e9748d3..ff40699a8ad 100644 --- a/include/server.h +++ b/include/server.h @@ -148,6 +148,8 @@ struct boot_done_request /* Initialize a process; called from the new process context */ struct init_process_request { + IN void* ldt_copy; /* addr of LDT copy */ + IN void* ldt_flags; /* addr of LDT flags */ OUT int start_flags; /* flags from startup info */ OUT int hstdin; /* handle for stdin */ OUT int hstdout; /* handle for stdout */ @@ -1031,6 +1033,17 @@ struct set_thread_context_request }; +/* Fetch a selector entry for a thread */ +struct get_selector_entry_request +{ + IN int handle; /* thread handle */ + IN int entry; /* LDT entry */ + OUT unsigned int base; /* selector base */ + OUT unsigned int limit; /* selector limit */ + OUT unsigned char flags; /* selector flags */ +}; + + /* Everything below this line is generated automatically by tools/make_requests */ /* ### make_requests begin ### */ @@ -1128,6 +1141,7 @@ enum request REQ_CANCEL_TIMER, REQ_GET_THREAD_CONTEXT, REQ_SET_THREAD_CONTEXT, + REQ_GET_SELECTOR_ENTRY, REQ_NB_REQUESTS }; diff --git a/memory/selector.c b/memory/selector.c index 40a760f5194..e52c3980d33 100644 --- a/memory/selector.c +++ b/memory/selector.c @@ -5,16 +5,18 @@ */ #include +#include "winerror.h" #include "wine/winbase16.h" #include "ldt.h" #include "miscemu.h" #include "selectors.h" #include "stackframe.h" #include "process.h" +#include "server.h" #include "debugtools.h" #include "toolhelp.h" -DEFAULT_DEBUG_CHANNEL(selector) +DEFAULT_DEBUG_CHANNEL(selector); /*********************************************************************** @@ -604,28 +606,74 @@ void WINAPI UnMapLS( SEGPTR sptr ) /*********************************************************************** * GetThreadSelectorEntry (KERNEL32) - * FIXME: add #ifdef i386 for non x86 */ -BOOL WINAPI GetThreadSelectorEntry( HANDLE hthread, DWORD sel, - LPLDT_ENTRY ldtent) +BOOL WINAPI GetThreadSelectorEntry( HANDLE hthread, DWORD sel, LPLDT_ENTRY ldtent) { - ldt_entry ldtentry; +#ifdef __i386__ + struct get_selector_entry_request *req = get_req_buffer(); - LDT_GetEntry(SELECTOR_TO_ENTRY(sel),&ldtentry); - ldtent->BaseLow = ldtentry.base & 0x0000ffff; - ldtent->HighWord.Bits.BaseMid = (ldtentry.base & 0x00ff0000) >> 16; - ldtent->HighWord.Bits.BaseHi = (ldtentry.base & 0xff000000) >> 24; - ldtent->LimitLow = ldtentry.limit & 0x0000ffff; - ldtent->HighWord.Bits.LimitHi = (ldtentry.limit & 0x00ff0000) >> 16; - ldtent->HighWord.Bits.Dpl = 3; - ldtent->HighWord.Bits.Sys = 0; - ldtent->HighWord.Bits.Pres = 1; - ldtent->HighWord.Bits.Type = 0x10|(ldtentry.type << 2); - if (!ldtentry.read_only) - ldtent->HighWord.Bits.Type|=0x2; - ldtent->HighWord.Bits.Granularity = ldtentry.limit_in_pages; - ldtent->HighWord.Bits.Default_Big = ldtentry.seg_32bit; + if (!(sel & 4)) /* GDT selector */ + { + WORD seg; + sel &= ~3; /* ignore RPL */ + if (!sel) /* null selector */ + { + memset( ldtent, 0, sizeof(*ldtent) ); + return TRUE; + } + ldtent->BaseLow = 0; + ldtent->HighWord.Bits.BaseMid = 0; + ldtent->HighWord.Bits.BaseHi = 0; + ldtent->LimitLow = 0xffff; + ldtent->HighWord.Bits.LimitHi = 0xf; + ldtent->HighWord.Bits.Dpl = 3; + ldtent->HighWord.Bits.Sys = 0; + ldtent->HighWord.Bits.Pres = 1; + ldtent->HighWord.Bits.Granularity = 1; + ldtent->HighWord.Bits.Default_Big = 1; + ldtent->HighWord.Bits.Type = 0x12; + /* it has to be one of the system GDT selectors */ + GET_DS(seg); + if (sel == (seg & ~3)) return TRUE; + GET_SS(seg); + if (sel == (seg & ~3)) return TRUE; + GET_CS(seg); + if (sel == (seg & ~3)) + { + ldtent->HighWord.Bits.Type |= 8; /* code segment */ + return TRUE; + } + SetLastError( ERROR_NOACCESS ); + return FALSE; + } + + req->handle = hthread; + req->entry = sel >> __AHSHIFT; + if (server_call( REQ_GET_SELECTOR_ENTRY )) return FALSE; + + if (!(req->flags & LDT_FLAGS_ALLOCATED)) + { + SetLastError( ERROR_MR_MID_NOT_FOUND ); /* sic */ + return FALSE; + } + if (req->flags & LDT_FLAGS_BIG) req->limit >>= 12; + ldtent->BaseLow = req->base & 0x0000ffff; + ldtent->HighWord.Bits.BaseMid = (req->base & 0x00ff0000) >> 16; + ldtent->HighWord.Bits.BaseHi = (req->base & 0xff000000) >> 24; + ldtent->LimitLow = req->limit & 0x0000ffff; + ldtent->HighWord.Bits.LimitHi = (req->limit & 0x000f0000) >> 16; + ldtent->HighWord.Bits.Dpl = 3; + ldtent->HighWord.Bits.Sys = 0; + ldtent->HighWord.Bits.Pres = 1; + ldtent->HighWord.Bits.Granularity = (req->flags & LDT_FLAGS_BIG) !=0; + ldtent->HighWord.Bits.Default_Big = (req->flags & LDT_FLAGS_32BIT) != 0; + ldtent->HighWord.Bits.Type = ((req->flags & LDT_FLAGS_TYPE) << 2) | 0x10; + if (!(req->flags & LDT_FLAGS_READONLY)) ldtent->HighWord.Bits.Type |= 0x2; return TRUE; +#else + SetLastError( ERROR_NOT_IMPLEMENTED ); + return FALSE; +#endif } diff --git a/scheduler/process.c b/scheduler/process.c index 89671aa1fd3..7927a10c6bd 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -254,6 +254,8 @@ static BOOL PROCESS_CreateEnvDB(void) /* Retrieve startup info from the server */ + req->ldt_copy = ldt_copy; + req->ldt_flags = ldt_flags_copy; if (server_call( REQ_INIT_PROCESS )) return FALSE; startup->dwFlags = req->start_flags; startup->wShowWindow = req->cmd_show; diff --git a/server/process.c b/server/process.c index b2743e12033..915ecf63baf 100644 --- a/server/process.c +++ b/server/process.c @@ -149,6 +149,8 @@ struct thread *create_process( int fd, struct process *parent, process->console_out = NULL; process->init_event = NULL; process->info = NULL; + process->ldt_copy = NULL; + process->ldt_flags = NULL; gettimeofday( &process->start_time, NULL ); if ((process->next = first_process) != NULL) process->next->prev = process; first_process = process; @@ -539,6 +541,8 @@ DECL_HANDLER(init_process) fatal_protocol_error( current, "init_process: called twice\n" ); return; } + current->process->ldt_copy = req->ldt_copy; + current->process->ldt_flags = req->ldt_flags; current->process->info = NULL; req->start_flags = info->start_flags; req->hstdin = info->hstdin; diff --git a/server/process.h b/server/process.h index 737de561bc7..6e84a32657e 100644 --- a/server/process.h +++ b/server/process.h @@ -34,6 +34,8 @@ struct process struct object *console_in; /* console input */ struct object *console_out; /* console output */ struct event *init_event; /* event for init done */ + void *ldt_copy; /* pointer to LDT copy in client addr space */ + void *ldt_flags; /* pointer to LDT flags in client addr space */ struct new_process_request *info; /* startup info (freed after startup) */ }; diff --git a/server/request.h b/server/request.h index c9fcd10ccfb..9957e4e9deb 100644 --- a/server/request.h +++ b/server/request.h @@ -162,6 +162,7 @@ DECL_HANDLER(set_timer); DECL_HANDLER(cancel_timer); DECL_HANDLER(get_thread_context); DECL_HANDLER(set_thread_context); +DECL_HANDLER(get_selector_entry); #ifdef WANT_REQUEST_HANDLERS @@ -261,6 +262,7 @@ static const struct handler { { (void(*)())req_cancel_timer, sizeof(struct cancel_timer_request) }, { (void(*)())req_get_thread_context, sizeof(struct get_thread_context_request) }, { (void(*)())req_set_thread_context, sizeof(struct set_thread_context_request) }, + { (void(*)())req_get_selector_entry, sizeof(struct get_selector_entry_request) }, }; #endif /* WANT_REQUEST_HANDLERS */ diff --git a/server/thread.c b/server/thread.c index d2c5a56e5a3..962a7bf76ae 100644 --- a/server/thread.c +++ b/server/thread.c @@ -520,6 +520,37 @@ static int thread_queue_apc( struct thread *thread, void *func, void *param ) return 1; } +/* retrieve an LDT selector entry */ +static void get_selector_entry( struct thread *thread, int entry, + unsigned int *base, unsigned int *limit, + unsigned char *flags ) +{ + if (!thread->process->ldt_copy || !thread->process->ldt_flags) + { + set_error( STATUS_ACCESS_DENIED ); + return; + } + if (entry >= 8192) + { + set_error( STATUS_INVALID_PARAMETER ); /* FIXME */ + return; + } + suspend_thread( thread, 0 ); + if (thread->attached) + { + unsigned char flags_buf[4]; + int *addr = (int *)thread->process->ldt_copy + 2 * entry; + if (read_thread_int( thread, addr, base ) == -1) goto done; + if (read_thread_int( thread, addr + 1, limit ) == -1) goto done; + addr = (int *)thread->process->ldt_flags + (entry >> 2); + if (read_thread_int( thread, addr, (int *)flags_buf ) == -1) goto done; + *flags = flags_buf[entry & 3]; + } + else set_error( STATUS_ACCESS_DENIED ); + done: + resume_thread( thread ); +} + /* kill a thread on the spot */ void kill_thread( struct thread *thread, int exit_code ) { @@ -689,3 +720,14 @@ DECL_HANDLER(get_apcs) current->apc_count = 0; } } + +/* fetch a selector entry for a thread */ +DECL_HANDLER(get_selector_entry) +{ + struct thread *thread; + if ((thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION ))) + { + get_selector_entry( thread, req->entry, &req->base, &req->limit, &req->flags ); + release_object( thread ); + } +} diff --git a/server/trace.c b/server/trace.c index 89547b50f67..391125dda3d 100644 --- a/server/trace.c +++ b/server/trace.c @@ -239,6 +239,8 @@ static void dump_boot_done_request( const struct boot_done_request *req ) static void dump_init_process_request( const struct init_process_request *req ) { + fprintf( stderr, " ldt_copy=%p,", req->ldt_copy ); + fprintf( stderr, " ldt_flags=%p", req->ldt_flags ); } static void dump_init_process_reply( const struct init_process_request *req ) @@ -1167,6 +1169,19 @@ static void dump_set_thread_context_request( const struct set_thread_context_req dump_context( &req->context ); } +static void dump_get_selector_entry_request( const struct get_selector_entry_request *req ) +{ + fprintf( stderr, " handle=%d,", req->handle ); + fprintf( stderr, " entry=%d", req->entry ); +} + +static void dump_get_selector_entry_reply( const struct get_selector_entry_request *req ) +{ + fprintf( stderr, " base=%08x,", req->base ); + fprintf( stderr, " limit=%08x,", req->limit ); + fprintf( stderr, " flags=%02x", req->flags ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_new_thread_request, @@ -1260,6 +1275,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_cancel_timer_request, (dump_func)dump_get_thread_context_request, (dump_func)dump_set_thread_context_request, + (dump_func)dump_get_selector_entry_request, }; static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -1355,6 +1371,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)0, (dump_func)dump_get_thread_context_reply, (dump_func)0, + (dump_func)dump_get_selector_entry_reply, }; static const char * const req_names[REQ_NB_REQUESTS] = { @@ -1450,6 +1467,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "cancel_timer", "get_thread_context", "set_thread_context", + "get_selector_entry", }; /* ### make_requests end ### */ diff --git a/tools/make_requests b/tools/make_requests index 9a8e6c9fd3a..8e608ccf52c 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -11,6 +11,7 @@ "int" => "%d", "long" => "%ld", "char" => "%c", + "unsigned char" => "%02x", "unsigned int" => "%08x", "void*" => "%p", "time_t" => "%ld",