[RFC-v3] Add windows Thread Information Block

Pierre Muller
2009-07-03T16:11:55Z

[-- Attachment #1: Type: text/plain, Size: 1104 bytes --]

Here is a new version of this patch:

- It does add a convenience variable name "$_tlb"
for "thread local base" as this is the only value that needs
to be fetch especially.
Maybe "_tib" is better, in the sense that it "talks" more to
windows used debuggers? But this is really only a pointer and not the
block itself. Any better idea?

I tried to create a type that really fits
the Windows OS layout, but as this structure is not documented really
and has changed between OS version, there can be no
assurance that all fields are OK in all versions...
It works both native and remotely.

I didn't check if it works OK, if endianess are different
but the extra field in extract_unsigned_integer should take care
of this.

As Christopher reported problems trying to apply my previous
version, I attach it this time, hoping that this will avoid troubles.

Pedro, I didn't change the TARGET_OBJECT type,
and I really want to know if this is really required,
as it seems to be a lot of work and I can't see the benefit...

Pierre Muller
Pascal language support maintainer for GDB

[-- Attachment #2: windows-tlb2.patch --]
[-- Type: application/octet-stream, Size: 26262 bytes --]

2009-07-03 Pierre Muller <muller@ics.u-strasbg.fr>

* windows-nat.c: Include target.h.
(thread_info): Add THREAD_LOCAL_BASE field.
(windows_add_thread): Add TLB argument of type 'void *'.
(fake_create_process): Adapt windows_add_thread call.
(get_windows_debug_event): Idem.
(windows_xfer_partial): Handle TARGET_OBJECT_OSDATA type.
(_initialize_windows_nat): Replace info_w32_cmdlist
initialization by a call to init_w32_command_list.
(info_w32_command, info_w32_cmdlist): Removed from here...
to windows-tdep.c file.
* windows-tdep.h (info_w32_cmdlist): Declare.
(init_w32_command_list): New external function
declaration.
* windows-tdep.c: Add several headers.
(info_w32_cmdlist): to here, made global.
(thread_information_32): New struct.
(thread_information_64): New struct.
(TIB_NAME): New char array.
(MAX_TIB32, MAX_TIB64, FULL_TIB_SIZE): New constants.
(maint_display_all_tib): New static variable.
(windows_get_tlb_type): New function.
(tlb_value_read, tlb_value_write): New functions.
(tlb_value_funcs): New static struct.
(tlb_make_value): New function.
(display_one_tib): New function.
(display_tib): New function.
(info_w32_command): Moved from windows-nat.c.
(init_w32_command_list): New function.
(_initialize_windows_tdep): New function.
New "maint set/show show-all-tib" command
New "$_tlb" internal variable.

gdbserver/ChangeLog entry:

2009-07-01 Pierre Muller <muller@ics.u-strasbg.fr>

* gdbserver/win32-low.h (win32_thread_info): Add THREAD_LOCAL_BASE
field.
* gdbserver/win32-low.c (child_add_thread): Add TLB argument.
(get_child_debug_event): Adapt to child_add_thread change.
(win32_qxfer_osdata): New function.
(win32_target_op): Set qxfer_osdata field to win32_qxfer_osdata.

Index: windows-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/windows-nat.c,v
retrieving revision 1.196
diff -u -p -r1.196 windows-nat.c
--- windows-nat.c 2 Jul 2009 17:21:07 -0000 1.196
+++ windows-nat.c 3 Jul 2009 15:53:20 -0000
@@ -57,6 +57,7 @@
#include "solist.h"
#include "solib.h"
#include "xml-support.h"
+#include "target.h"

#include "i386-tdep.h"
#include "i387-tdep.h"
@@ -155,6 +156,7 @@ typedef struct thread_info_struct
struct thread_info_struct *next;
DWORD id;
HANDLE h;
+ CORE_ADDR thread_local_base;
char *name;
int suspended;
int reload_context;
@@ -284,7 +286,7 @@ thread_rec (DWORD id, int get_context)

/* Add a thread to the thread list. */
static thread_info *
-windows_add_thread (ptid_t ptid, HANDLE h)
+windows_add_thread (ptid_t ptid, HANDLE h, void *tlb)
{
thread_info *th;
DWORD id;
@@ -299,6 +301,7 @@ windows_add_thread (ptid_t ptid, HANDLE
th = XZALLOC (thread_info);
th->id = id;
th->h = h;
+ th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb;
th->next = thread_head.next;
thread_head.next = th;
add_thread (ptid);
@@ -984,15 +987,6 @@ display_selectors (char * args, int from
}
}

-static struct cmd_list_element *info_w32_cmdlist = NULL;
-
-static void
-info_w32_command (char *args, int from_tty)
-{
- help_list (info_w32_cmdlist, "info w32 ", class_info, gdb_stdout);
-}
-
-
#define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \
printf_unfiltered ("gdb: Target exception %s at %s\n", x, \
host_address_to_string (\
@@ -1181,9 +1175,11 @@ fake_create_process (void)
/* We can not debug anything in that case. */
}
main_thread_id = current_event.dwThreadId;
- current_thread = windows_add_thread (ptid_build (current_event.dwProcessId, 0,
- current_event.dwThreadId),
- current_event.u.CreateThread.hThread);
+ current_thread = windows_add_thread (
+ ptid_build (current_event.dwProcessId, 0,
+ current_event.dwThreadId),
+ current_event.u.CreateThread.hThread,
+ current_event.u.CreateThread.lpThreadLocalBase);
return main_thread_id;
}

@@ -1357,7 +1353,8 @@ get_windows_debug_event (struct target_o
retval = current_event.dwThreadId;
th = windows_add_thread (ptid_build (current_event.dwProcessId, 0,
current_event.dwThreadId),
- current_event.u.CreateThread.hThread);
+ current_event.u.CreateThread.hThread,
+ current_event.u.CreateThread.lpThreadLocalBase);
break;

case EXIT_THREAD_DEBUG_EVENT:
@@ -1390,7 +1387,8 @@ get_windows_debug_event (struct target_o
/* Add the main thread */
th = windows_add_thread (ptid_build (current_event.dwProcessId, 0,
current_event.dwThreadId),
- current_event.u.CreateProcessInfo.hThread);
+ current_event.u.CreateProcessInfo.hThread,
+ current_event.u.CreateProcessInfo.lpThreadLocalBase);
retval = current_event.dwThreadId;
break;

@@ -2103,6 +2101,11 @@ windows_xfer_partial (struct target_ops
const char *annex, gdb_byte *readbuf,
const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
{
+ ULONGEST val;
+ thread_info *th;
+ char info_type[20];
+ char *type_end;
+
switch (object)
{
case TARGET_OBJECT_MEMORY:
@@ -2114,6 +2117,31 @@ windows_xfer_partial (struct target_ops
len, 1/*write*/, NULL, ops);
return -1;

+ case TARGET_OBJECT_OSDATA:
+ memset (info_type, 0, sizeof (info_type));
+ val = 0;
+ sscanf (annex, "%s %llu", info_type, &val);
+ if (strcmp (info_type, "tlb") == 0 && readbuf)
+ {
+ th = thread_rec (val, 0);
+ if (th == NULL)
+ return -1;
+
+ if (len == 8)
+ {
+ uint64_t tlb = th->thread_local_base;
+ memcpy ((void *)readbuf, (void *) &tlb, len);
+ return len;
+ }
+ else if (len == 4)
+ {
+ uint32_t tlb = th->thread_local_base;
+ memcpy ((void *)readbuf, (void *) &tlb, len);
+ return len;
+ }
+ }
+ return -1;
+
case TARGET_OBJECT_LIBRARIES:
return windows_xfer_shared_libraries (ops, object, annex, readbuf,
writebuf, offset, len);
@@ -2271,9 +2299,7 @@ Show whether to display kernel exception
NULL, /* FIXME: i18n: */
&setlist, &showlist);

- add_prefix_cmd ("w32", class_info, info_w32_command,
- _("Print information specific to Win32 debugging."),
- &info_w32_cmdlist, "info w32 ", 0, &infolist);
+ init_w32_command_list ();

add_cmd ("selector", class_info, display_selectors,
_("Display selectors infos."),
Index: windows-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/windows-tdep.c,v
retrieving revision 1.4
diff -u -p -r1.4 windows-tdep.c
--- windows-tdep.c 2 Jul 2009 17:21:07 -0000 1.4
+++ windows-tdep.c 3 Jul 2009 15:53:22 -0000
@@ -19,6 +19,356 @@
#include "windows-tdep.h"
#include "gdb_obstack.h"
#include "xml-support.h"
+#include "gdbarch.h"
+#include "target.h"
+#include "value.h"
+#include "inferior.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+struct cmd_list_element *info_w32_cmdlist;
+
+typedef struct thread_information_block_32
+ {
+ uint32_t current_seh; /* %fs:0x0000 */
+ uint32_t current_top_of_stack; /* %fs:0x0004 */
+ uint32_t current_bottom_of_stack; /* %fs:0x0008 */
+ uint32_t sub_system_tib; /* %fs:0x000c */
+ uint32_t fiber_data; /* %fs:0x0010 */
+ uint32_t arbitrary_data_slot; /* %fs:0x0014 */
+ uint32_t linear_address_tib; /* %fs:0x0018 */
+ uint32_t environment_pointer; /* %fs:0x001c */
+ uint32_t process_id; /* %fs:0x0020 */
+ uint32_t current_thread_id; /* %fs:0x0024 */
+ uint32_t thread_local_storage; /* %fs:0x0028 */
+ uint32_t active_rpc_handle; /* %fs:0x002c */
+ uint32_t process_environment_block; /* %fs:0x0030 */
+ uint32_t last_error_number; /* %fs:0x0034 */
+ }
+thread_information_32;
+
+typedef struct thread_information_block_64
+ {
+ uint64_t current_seh; /* %gs:0x0000 */
+ uint64_t current_top_of_stack; /* %gs:0x0008 */
+ uint64_t current_bottom_of_stack; /* %gs:0x0010 */
+ uint64_t sub_system_tib; /* %gs:0x0018 */
+ uint64_t fiber_data; /* %gs:0x0020 */
+ uint64_t arbitrary_data_slot; /* %gs:0x0028 */
+ uint64_t linear_address_tib; /* %gs:0x0030 */
+ }
+thread_information_64;
+
+
+static const
+char* TIB_NAME[] =
+ {
+ " current_seh ", /* %fs:0x0000 */
+ " current_top_of_stack ", /* %fs:0x0004 */
+ " current_bottom_of_stack ", /* %fs:0x0008 */
+ " sub_system_tib ", /* %fs:0x000c */
+ " fiber_data ", /* %fs:0x0010 */
+ " arbitrary_data_slot ", /* %fs:0x0014 */
+ " linear_address_tib ", /* %fs:0x0018 */
+ " environment_pointer ", /* %fs:0x001c */
+ " process_id ", /* %fs:0x0020 */
+ " current_thread_id ", /* %fs:0x0024 */
+ " thread_local_storage ", /* %fs:0x0028 */
+ " active_rpc_handle ", /* %fs:0x002c */
+ " process_environment_block ", /* %fs:0x0030 */
+ " last_error_number " /* %fs:0x0034 */
+ };
+
+static const int
+MAX_TIB32 = sizeof (thread_information_32) / sizeof (uint32_t);
+static const int
+MAX_TIB64 = sizeof (thread_information_64) / sizeof (uint64_t);
+static const int
+FULL_TIB_SIZE = 0x1000;
+
+static int maint_display_all_tib = 0;
+
+/* Define ThreadLocalBase pointer type */
+struct type *
+windows_get_tlb_type (struct gdbarch *gdbarch)
+{
+ struct type *dword_ptr_type, *void_ptr_type;
+ struct type *peb_ldr_type, *peb_ldr_ptr_type;
+ struct type *peb_type, *peb_ptr_type, *list_type, *list_ptr_type;
+ struct type *module_list_ptr_type;
+ struct type *tib_type, *seh_type, *tib_ptr_type, *seh_ptr_type;
+
+ dword_ptr_type = arch_integer_type (gdbarch, gdbarch_ptr_bit (gdbarch),
+ 1, "DWORD_PTR");
+ void_ptr_type = lookup_pointer_type (builtin_type (gdbarch)->builtin_void);
+
+ /* list entry */
+
+ list_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+ TYPE_NAME (list_type) = xstrdup ("list");
+
+ list_ptr_type = arch_type (gdbarch, TYPE_CODE_PTR,
+ TYPE_LENGTH (void_ptr_type), NULL);
+
+ module_list_ptr_type = void_ptr_type;
+
+ append_composite_type_field (list_type, "forward_list", module_list_ptr_type);
+ append_composite_type_field (list_type, "backward_list",
+ module_list_ptr_type);
+
+ /* Structured Exception Handler */
+
+ seh_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+ TYPE_NAME (seh_type) = xstrdup ("seh");
+
+ seh_ptr_type = arch_type (gdbarch, TYPE_CODE_PTR,
+ TYPE_LENGTH (void_ptr_type), NULL);
+ TYPE_TARGET_TYPE (seh_ptr_type) = seh_type;
+
+ append_composite_type_field (seh_type, "next_seh", seh_ptr_type);
+ append_composite_type_field (seh_type, "handler", void_ptr_type);
+
+ /* struct _PEB_LDR_DATA */
+ /* FIXME: 64bit layout is unknown. */
+ peb_ldr_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+ TYPE_NAME (peb_ldr_type) = xstrdup ("peb_ldr_data");
+
+ append_composite_type_field (peb_ldr_type, "length", dword_ptr_type);
+ append_composite_type_field (peb_ldr_type, "initialized", dword_ptr_type);
+ append_composite_type_field (peb_ldr_type, "ss_handle", void_ptr_type);
+ append_composite_type_field (peb_ldr_type, "in_load_order", list_type);
+ append_composite_type_field (peb_ldr_type, "in_memory_order", list_type);
+ append_composite_type_field (peb_ldr_type, "in_init_order", list_type);
+ append_composite_type_field (peb_ldr_type, "entry_in_progress",
+ void_ptr_type);
+ peb_ldr_ptr_type = arch_type (gdbarch, TYPE_CODE_PTR,
+ TYPE_LENGTH (void_ptr_type), NULL);
+ TYPE_TARGET_TYPE (peb_ldr_ptr_type) = peb_ldr_type;
+
+
+ /* struct process environment block */
+ peb_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+ TYPE_NAME (peb_type) = xstrdup ("peb");
+
+ /* 4 first byte contain several flags. */
+ /* FIXME: 64bit layout is unknown. */
+ append_composite_type_field (peb_type, "flags", dword_ptr_type);
+ append_composite_type_field (peb_type, "mutant", void_ptr_type);
+ append_composite_type_field (peb_type, "image_base_address", void_ptr_type);
+ append_composite_type_field (peb_type, "ldr", peb_ldr_ptr_type);
+ append_composite_type_field (peb_type, "process_parameters", void_ptr_type);
+ append_composite_type_field (peb_type, "sub_system_data", void_ptr_type);
+ append_composite_type_field (peb_type, "process_heap", void_ptr_type);
+ append_composite_type_field (peb_type, "fast_peb_lock", void_ptr_type);
+ peb_ptr_type = arch_type (gdbarch, TYPE_CODE_PTR,
+ TYPE_LENGTH (void_ptr_type), NULL);
+ TYPE_TARGET_TYPE (peb_ptr_type) = peb_type;
+
+
+ /* struct thread information block */
+ tib_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+ TYPE_NAME (tib_type) = xstrdup ("tib");
+
+ /* uint32_t current_seh; %fs:0x0000 */
+ append_composite_type_field (tib_type, "current_seh", seh_ptr_type);
+ /* uint32_t current_top_of_stack; %fs:0x0004 */
+ append_composite_type_field (tib_type, "current_top_of_stack", void_ptr_type);
+ /* uint32_t current_bottom_of_stack; %fs:0x0008 */
+ append_composite_type_field (tib_type, "current_bottom_of_stack",
+ void_ptr_type);
+ /* uint32_t sub_system_tib; %fs:0x000c */
+ append_composite_type_field (tib_type, "sub_system_tib", void_ptr_type);
+
+ /* uint32_t fiber_data; %fs:0x0010 */
+ append_composite_type_field (tib_type, "fiber_data", void_ptr_type);
+ /* uint32_t arbitrary_data_slot; %fs:0x0014 */
+ append_composite_type_field (tib_type, "arbitrary_data_slot", void_ptr_type);
+ /* uint32_t linear_address_tib; %fs:0x0018 */
+ append_composite_type_field (tib_type, "linear_address_tib", void_ptr_type);
+ /* uint32_t environment_pointer; %fs:0x001c */
+ append_composite_type_field (tib_type, "environment_pointer", void_ptr_type);
+ /* uint32_t process_id; %fs:0x0020 */
+ append_composite_type_field (tib_type, "process_id", dword_ptr_type);
+ /* uint32_t current_thread_id; %fs:0x0024 */
+ append_composite_type_field (tib_type, "thread_id", dword_ptr_type);
+ /* uint32_t thread_local_storage; %fs:0x0028 */
+ append_composite_type_field (tib_type, "thread_local_storage", void_ptr_type);
+ /* uint32_t active_rpc_handle; %fs:0x002c */
+ append_composite_type_field (tib_type, "active_rpc_handle", dword_ptr_type);
+ /* uint32_t process_environment_block; %fs:0x0030 */
+ append_composite_type_field (tib_type, "process_environment_block",
+ peb_ptr_type);
+ /* uint32_t last_error_number; %fs:0x0034 */
+ append_composite_type_field (tib_type, "last_error_number", dword_ptr_type);
+
+ tib_ptr_type = arch_type (gdbarch, TYPE_CODE_PTR,
+ TYPE_LENGTH (void_ptr_type), NULL);
+ TYPE_TARGET_TYPE (tib_ptr_type) = tib_type;
+
+ return tib_ptr_type;
+}
+/* The $_tlb convenience variable is a bit special. We don't know
+ for sure the type of the value until we actually have a chance to
+ fetch the data. The type can change depending on gdbarch, so it it
+ also dependent on which thread you have selected.
+
+ 1. making $_tlb be an internalvar that creates a new value on
+ access.
+
+ 2. making the value of $_tlbi be an lval_computed value. */
+
+/* This function implements the lval_computed support for reading a
+ $_tlb value. */
+
+static void
+tlb_value_read (struct value *v)
+{
+ LONGEST transferred;
+ char annex[20];
+ /* This needs to be changed if multi-process support is added. */
+ strcpy (annex, "tlb ");
+ strcat (annex, pulongest (ptid_get_tid (inferior_ptid)));
+
+ transferred =
+ target_read (&current_target, TARGET_OBJECT_OSDATA,
+ annex,
+ value_contents_all_raw (v),
+ value_offset (v),
+ TYPE_LENGTH (value_type (v)));
+
+ if (transferred != TYPE_LENGTH (value_type (v)))
+ error (_("Unable to read tlb"));
+}
+
+/* This function implements the lval_computed support for writing a
+ $_siginfo value. */
+
+static void
+tlb_value_write (struct value *v, struct value *fromval)
+{
+ error (_("Impossible to change tlb"));
+}
+
+static struct lval_funcs tlb_value_funcs =
+ {
+ tlb_value_read,
+ tlb_value_write
+ };
+
+
+/* Return a new value with the correct type for the tlb object of
+ the current thread using architecture GDBARCH. Return a void value
+ if there's no object available. */
+
+static struct value *
+tlb_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+{
+ if (target_has_stack
+ && !ptid_equal (inferior_ptid, null_ptid))
+ {
+ struct type *type = windows_get_tlb_type (gdbarch);
+ return allocate_computed_value (type, &tlb_value_funcs, NULL);
+ }
+
+ return allocate_value (builtin_type (gdbarch)->builtin_void);
+}
+
+
+/* Display thread information block of a given thread. */
+static int
+display_one_tib (ULONGEST ThreadId)
+{
+#define PTID_STRING_SIZE 40
+ char annex[PTID_STRING_SIZE];
+ char *annex_end = annex + PTID_STRING_SIZE;
+ gdb_byte *tib = NULL;
+ gdb_byte *index;
+ CORE_ADDR thread_local_base;
+ ULONGEST i, val, max, max_name, size, tib_size;
+ ULONGEST sizeof_ptr = gdbarch_ptr_bit (target_gdbarch);
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+
+ if (sizeof_ptr == 64)
+ {
+ size = sizeof (uint64_t);
+ tib_size = sizeof (thread_information_64);
+ max = MAX_TIB64;
+ }
+ else
+ {
+ size = sizeof (uint32_t);
+ tib_size = sizeof (thread_information_32);
+ max = MAX_TIB32;
+ }
+
+ max_name = max;
+
+ if (maint_display_all_tib)
+ {
+ tib_size = FULL_TIB_SIZE;
+ max = tib_size / size;
+ }
+
+ tib = alloca (tib_size);
+
+ /* This needs to be changed if multi-process support is added. */
+ strcpy (annex, "tlb ");
+ strcat (annex, pulongest (ThreadId));
+
+ if (target_read (&current_target, TARGET_OBJECT_OSDATA,
+ annex, tib, 0, size) != size)
+ {
+ printf_filtered ("Unable to get thread local base for ThreadId %s\n",
+ pulongest (ThreadId));
+ return -1;
+ }
+ thread_local_base = extract_unsigned_integer (tib, size, byte_order);
+
+ if (target_read (&current_target, TARGET_OBJECT_MEMORY,
+ annex, tib, thread_local_base, tib_size) != tib_size)
+ {
+ printf_filtered ("Unable to read thread information block for ThreadId %s at address %s\n",
+ pulongest (ThreadId), paddress (target_gdbarch, thread_local_base));
+ return -1;
+ }
+
+ printf_filtered ("Thread Information Block %s at %s\n",
+ pulongest (ThreadId),
+ paddress (target_gdbarch, thread_local_base));
+
+ index = (gdb_byte *) tib;
+
+ /* All fields have the size of a pointer, this allows to iterate
+ using the same for loop for both layouts. */
+ for (i = 0; i < max; i++)
+ {
+ val = extract_unsigned_integer (index, size, byte_order);
+ if (i < max_name)
+ printf_filtered ("%s is 0x%s\n", TIB_NAME [i], phex (val, size));
+ else if (val != 0)
+ printf_filtered ("TIB[0x%s] is 0x%s\n", phex (i*size, 2),
+ phex (val, size));
+ index += size;
+ }
+ return 1;
+}
+
+/* Display thread information block of a thread specified by ARGS.
+ If ARGS is empty, display thread information block of current_thread
+ if current_thread is non NULL.
+ Otherwise ARGS is parsed and converted to a integer that should
+ be the windows ThreadID (not the internal GDB thread ID). */
+static void
+display_tib (char * args, int from_tty)
+{
+ if (args)
+ {
+ ULONGEST id = (ULONGEST) parse_and_eval_long (args);
+ display_one_tib (id);
+ }
+ else if (!ptid_equal (inferior_ptid, null_ptid))
+ display_one_tib (ptid_get_tid (inferior_ptid));
+}

void
windows_xfer_shared_library (const char* so_name, CORE_ADDR load_addr,
@@ -36,3 +386,51 @@ windows_xfer_shared_library (const char*
obstack_grow_str (obstack, paddress (gdbarch, load_addr + 0x1000));
obstack_grow_str (obstack, "\"/></library>");
}
+
+static void
+info_w32_command (char *args, int from_tty)
+{
+ help_list (info_w32_cmdlist, "info w32 ", class_info, gdb_stdout);
+}
+
+static int w32_prefix_command_valid = 0;
+void
+init_w32_command_list (void)
+{
+ if (!w32_prefix_command_valid)
+ {
+ add_prefix_cmd ("w32", class_info, info_w32_command,
+ _("Print information specific to Win32 debugging."),
+ &info_w32_cmdlist, "info w32 ", 0, &infolist);
+ w32_prefix_command_valid = 1;
+ }
+}
+
+void
+_initialize_windows_tdep (void)
+{
+ init_w32_command_list ();
+ add_cmd ("thread-information-block", class_info, display_tib,
+ _("Display thread information block."),
+ &info_w32_cmdlist);
+ add_alias_cmd ("tib", "thread-information-block", class_info, 1,
+ &info_w32_cmdlist);
+
+ add_setshow_boolean_cmd ("show-all-tib", class_maintenance,
+ &maint_display_all_tib, _("\
+Set whether to display all non-zero fields of thread information block."), _("\
+Show whether to display all non-zero fields of thread information block."), _("\
+Use \"on\" to enable, \"off\" to disable.\n\
+If enabled, all non-zero fields of thread information block are displayed,\n\
+even if its meaning is unknown."),
+ NULL,
+ NULL,
+ &maintenance_set_cmdlist,
+ &maintenance_show_cmdlist);
+
+ /* Explicitly create without lookup, since that tries to create a
+ value with a void typed value, and when we get here, gdbarch
+ isn't initialized yet. At this point, we're quite sure there
+ isn't another convenience variable of the same name. */
+ create_internalvar_type_lazy ("_tlb", tlb_make_value);
+}
Index: windows-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/windows-tdep.h,v
retrieving revision 1.3
diff -u -p -r1.3 windows-tdep.h
--- windows-tdep.h 2 Jul 2009 17:21:07 -0000 1.3
+++ windows-tdep.h 3 Jul 2009 15:53:22 -0000
@@ -21,6 +21,10 @@
struct obstack;
struct gdbarch;

+extern struct cmd_list_element *info_w32_cmdlist;
+
+extern void init_w32_command_list (void);
+
extern void windows_xfer_shared_library (const char* so_name,
CORE_ADDR load_addr,
struct gdbarch *gdbarch,
Index: gdbserver/win32-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v
retrieving revision 1.37
diff -u -p -r1.37 win32-low.c
--- gdbserver/win32-low.c 30 Jun 2009 16:35:25 -0000 1.37
+++ gdbserver/win32-low.c 3 Jul 2009 15:53:23 -0000
@@ -175,7 +175,7 @@ thread_rec (ptid_t ptid, int get_context

/* Add a thread to the thread list. */
static win32_thread_info *
-child_add_thread (DWORD pid, DWORD tid, HANDLE h)
+child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
{
win32_thread_info *th;
ptid_t ptid = ptid_build (pid, tid, 0);
@@ -186,6 +186,7 @@ child_add_thread (DWORD pid, DWORD tid,
th = xcalloc (1, sizeof (*th));
th->tid = tid;
th->h = h;
+ th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb;

add_thread (ptid, th);
set_inferior_regcache_data ((struct thread_info *)
@@ -1427,7 +1428,8 @@ get_child_debug_event (struct target_wai
/* Record the existence of this thread. */
child_add_thread (current_event.dwProcessId,
current_event.dwThreadId,
- current_event.u.CreateThread.hThread);
+ current_event.u.CreateThread.hThread,
+ current_event.u.CreateThread.lpThreadLocalBase);
break;

case EXIT_THREAD_DEBUG_EVENT:
@@ -1455,7 +1457,8 @@ get_child_debug_event (struct target_wai
/* Add the main thread. */
child_add_thread (current_event.dwProcessId,
main_thread_id,
- current_event.u.CreateProcessInfo.hThread);
+ current_event.u.CreateProcessInfo.hThread,
+ current_event.u.CreateProcessInfo.lpThreadLocalBase);

ourstatus->value.related_pid = debug_event_ptid (&current_event);
#ifdef _WIN32_WCE
@@ -1723,6 +1726,42 @@ wince_hostio_last_error (char *buf)
}
#endif

+/* Read/Write Windows OS information. */
+int
+win32_qxfer_osdata (const char *info_type,
+ unsigned char *readbuf, unsigned const char *writebuf,
+ CORE_ADDR offset, int len)
+
+{
+ if (strncmp (info_type, "tlb ", 4) == 0 && readbuf)
+ {
+ unsigned long long tid;
+ char type_name[20];
+ ptid_t ptid;
+ win32_thread_info *th;
+ sscanf (info_type, "%s %llu", type_name, &tid);
+ ptid = ptid_build (current_process_id, tid, 0);
+ th = thread_rec (ptid, 0);
+ if (th == NULL)
+ return 0;
+ len--;
+ if (len == 8)
+ {
+ uint64_t tlb = th->thread_local_base;
+ memcpy (readbuf, &tlb, len);
+ return len;
+ }
+ else if (len == 4)
+ {
+ uint32_t tlb = th->thread_local_base;
+ memcpy (readbuf, &tlb, len);
+ return len;
+ }
+ }
+ return -1;
+}
+
+
static struct target_ops win32_target_ops = {
win32_create_inferior,
win32_attach,
@@ -1751,6 +1790,7 @@ static struct target_ops win32_target_op
#else
hostio_last_error_from_errno,
#endif
+ win32_qxfer_osdata,
};

/* Initialize the Win32 backend. */
Index: gdbserver/win32-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v
retrieving revision 1.10
diff -u -p -r1.10 win32-low.h
--- gdbserver/win32-low.h 30 Jun 2009 16:35:25 -0000 1.10
+++ gdbserver/win32-low.h 3 Jul 2009 15:53:23 -0000
@@ -28,6 +28,9 @@ typedef struct win32_thread_info
/* The handle to the thread. */
HANDLE h;

+ /* Thread Information Block address. */
+ CORE_ADDR thread_local_base;
+
/* Non zero if SuspendThread was called on this thread. */
int suspended;