Implemented GetThreadSelectorEntry through the server.

diff --git a/server/process.c b/server/process.c
index b2743e1..915ecf6 100644
--- a/server/process.c
+++ b/server/process.c
@@ -149,6 +149,8 @@
     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 @@
         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 737de56..6e84a32 100644
--- a/server/process.h
+++ b/server/process.h
@@ -34,6 +34,8 @@
     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 c9fcd10..9957e4e 100644
--- a/server/request.h
+++ b/server/request.h
@@ -162,6 +162,7 @@
 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 @@
     { (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 d2c5a56..962a7bf 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -520,6 +520,37 @@
     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 @@
         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 89547b5..391125d 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -239,6 +239,8 @@
 
 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 @@
     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 @@
     (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 @@
     (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 @@
     "cancel_timer",
     "get_thread_context",
     "set_thread_context",
+    "get_selector_entry",
 };
 
 /* ### make_requests end ### */