public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PING] [RFC-v3] Add windows Thread Information Block
       [not found]           ` <20090703194220.GA30668@ednor.casa.cgf.cx>
@ 2010-03-10 17:14             ` Pierre Muller
  2010-03-10 17:26               ` Pedro Alves
                                 ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Pierre Muller @ 2010-03-10 17:14 UTC (permalink / raw)
  To: gdb-patches

Despite all my efforts,
I never managed to get advices on the non-windows part of
this patch :(
 
  I appended at the bottom of this email an
updated patch.
  To refresh memories,
this patch enables looking at the 'Thread Local Base'
an internal Windows structure describing the current thread
and some process wide features.
  The main problem was about my use of TARGET_OBJECT_OSDATA
to get this information from the gdbserver, which did not seem
to be compatible with the general usage of TARGET_OBJECT_OSDATA.

  I would really like to get new feedback on that
issue.

Pierre Muller
  

> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Christopher Faylor
> Envoyé : Friday, July 03, 2009 9:42 PM
> À : gdb-patches@sourceware.org
> Objet : Re: [RFC-v3] Add windows Thread Information Block
> 
> On Fri, Jul 03, 2009 at 06:11:41PM +0200, Pierre Muller wrote:
> >
> >  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...
> 
> Approved (for the parts that I can approve).
> 
> cgf


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

	* windows-nat.c (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.207
diff -u -p -r1.207 windows-nat.c
--- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
+++ windows-nat.c	10 Mar 2010 16:51:00 -0000
@@ -191,6 +191,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;
@@ -320,7 +321,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;
@@ -335,6 +336,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);
@@ -1074,15 +1076,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 (\
@@ -1271,9 +1264,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;
 }
 
@@ -1447,7 +1442,9 @@ 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:
@@ -1481,7 +1478,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;
 
@@ -2243,6 +2241,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:
@@ -2254,6 +2257,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);
@@ -2315,8 +2343,10 @@ init_windows_ops (void)
   windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
   windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
 
+#ifndef __USE_OLD_CYGWIN_API_
   i386_use_watchpoints (&windows_ops);
 
+#endif
   i386_dr_low.set_control = cygwin_set_dr7;
   i386_dr_low.set_addr = cygwin_set_dr;
   i386_dr_low.reset_addr = NULL;
@@ -2343,8 +2373,10 @@ _initialize_windows_nat (void)
   init_windows_ops ();
 
 #ifdef __CYGWIN__
+#ifdef __USEWIDE
   cygwin_internal (CW_SET_DOS_FILE_WARNING, 0);
 #endif
+#endif
 
   c = add_com ("dll-symbols", class_files, dll_symbol_command,
 	       _("Load dll library symbols from FILE."));
@@ -2415,9 +2447,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.5
diff -u -p -r1.5 windows-tdep.c
--- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
+++ windows-tdep.c	10 Mar 2010 16:51:01 -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.4
diff -u -p -r1.4 windows-tdep.h
--- windows-tdep.h	1 Jan 2010 07:31:46 -0000	1.4
+++ windows-tdep.h	10 Mar 2010 16:51:01 -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.43
diff -u -p -r1.43 win32-low.c
--- gdbserver/win32-low.c	20 Jan 2010 22:55:38 -0000	1.43
+++ gdbserver/win32-low.c	10 Mar 2010 16:51:01 -0000
@@ -178,7 +178,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);
@@ -189,6 +189,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 *)
@@ -1449,7 +1450,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:
@@ -1479,7 +1481,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
@@ -1750,6 +1753,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,
@@ -1778,6 +1817,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.12
diff -u -p -r1.12 win32-low.h
--- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
+++ gdbserver/win32-low.h	10 Mar 2010 16:51:01 -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;
 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING] [RFC-v3] Add windows Thread Information Block
  2010-03-10 17:14             ` [PING] [RFC-v3] Add windows Thread Information Block Pierre Muller
@ 2010-03-10 17:26               ` Pedro Alves
  2010-03-10 22:23                 ` Pierre Muller
  2010-03-10 18:48               ` [PING] [RFC-v3] Add windows " Mark Kettenis
  2010-03-11  0:24               ` Pedro Alves
  2 siblings, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2010-03-10 17:26 UTC (permalink / raw)
  To: gdb-patches; +Cc: Pierre Muller

On Wednesday 10 March 2010 17:14:19, Pierre Muller wrote:
> Despite all my efforts,
> I never managed to get advices on the non-windows part of
> this patch :(
>  
>   I appended at the bottom of this email an
> updated patch.
>   To refresh memories,
> this patch enables looking at the 'Thread Local Base'
> an internal Windows structure describing the current thread
> and some process wide features.
>   The main problem was about my use of TARGET_OBJECT_OSDATA
> to get this information from the gdbserver, which did not seem
> to be compatible with the general usage of TARGET_OBJECT_OSDATA.
> 
>   I would really like to get new feedback on that
> issue.

Sorry, I already explained long ago that TARGET_OBJECT_OSDATA
is being misused here.  Why the resistence to change that?
There's another bit you haven't addressed yet:

> +	  if (len == 8)
> +	    {
> +	      uint64_t tlb = th->thread_local_base;
> +	      memcpy ((void *)readbuf, (void *) &tlb, len);
> +	      return len;
> +	    }
> +          else if (len == 4)

As I explained before, for partial xfers you should not
design the protocol relying on `len' being exactly 4 or 8.
Also, this is just transfering a number, why make that
target-endian dependant (see memcpy above) ?

> 
> Pierre Muller
>   
> 
> > -----Message d'origine-----
> > De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> > owner@sourceware.org] De la part de Christopher Faylor
> > Envoyé : Friday, July 03, 2009 9:42 PM
> > À : gdb-patches@sourceware.org
> > Objet : Re: [RFC-v3] Add windows Thread Information Block
> > 
> > On Fri, Jul 03, 2009 at 06:11:41PM +0200, Pierre Muller wrote:
> > >
> > >  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...
> > 
> > Approved (for the parts that I can approve).
> > 
> > cgf
> 
> 
> 2009-07-03  Pierre Muller  <muller@ics.u-strasbg.fr>
> 
> 	* windows-nat.c (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.207
> diff -u -p -r1.207 windows-nat.c
> --- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
> +++ windows-nat.c	10 Mar 2010 16:51:00 -0000
> @@ -191,6 +191,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;
> @@ -320,7 +321,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;
> @@ -335,6 +336,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);
> @@ -1074,15 +1076,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 (\
> @@ -1271,9 +1264,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;
>  }
>  
> @@ -1447,7 +1442,9 @@ 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:
> @@ -1481,7 +1478,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;
>  
> @@ -2243,6 +2241,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:
> @@ -2254,6 +2257,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);
> @@ -2315,8 +2343,10 @@ init_windows_ops (void)
>    windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
>    windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
>  
> +#ifndef __USE_OLD_CYGWIN_API_
>    i386_use_watchpoints (&windows_ops);
>  
> +#endif
>    i386_dr_low.set_control = cygwin_set_dr7;
>    i386_dr_low.set_addr = cygwin_set_dr;
>    i386_dr_low.reset_addr = NULL;
> @@ -2343,8 +2373,10 @@ _initialize_windows_nat (void)
>    init_windows_ops ();
>  
>  #ifdef __CYGWIN__
> +#ifdef __USEWIDE
>    cygwin_internal (CW_SET_DOS_FILE_WARNING, 0);
>  #endif
> +#endif
>  
>    c = add_com ("dll-symbols", class_files, dll_symbol_command,
>  	       _("Load dll library symbols from FILE."));
> @@ -2415,9 +2447,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.5
> diff -u -p -r1.5 windows-tdep.c
> --- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
> +++ windows-tdep.c	10 Mar 2010 16:51:01 -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.4
> diff -u -p -r1.4 windows-tdep.h
> --- windows-tdep.h	1 Jan 2010 07:31:46 -0000	1.4
> +++ windows-tdep.h	10 Mar 2010 16:51:01 -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.43
> diff -u -p -r1.43 win32-low.c
> --- gdbserver/win32-low.c	20 Jan 2010 22:55:38 -0000	1.43
> +++ gdbserver/win32-low.c	10 Mar 2010 16:51:01 -0000
> @@ -178,7 +178,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);
> @@ -189,6 +189,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 *)
> @@ -1449,7 +1450,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:
> @@ -1479,7 +1481,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
> @@ -1750,6 +1753,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,
> @@ -1778,6 +1817,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.12
> diff -u -p -r1.12 win32-low.h
> --- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
> +++ gdbserver/win32-low.h	10 Mar 2010 16:51:01 -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;
>  
> 
> 


-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING] [RFC-v3] Add windows Thread Information Block
  2010-03-10 17:14             ` [PING] [RFC-v3] Add windows Thread Information Block Pierre Muller
  2010-03-10 17:26               ` Pedro Alves
@ 2010-03-10 18:48               ` Mark Kettenis
  2010-03-10 22:25                 ` Pierre Muller
  2010-03-11  0:24               ` Pedro Alves
  2 siblings, 1 reply; 34+ messages in thread
From: Mark Kettenis @ 2010-03-10 18:48 UTC (permalink / raw)
  To: pierre.muller; +Cc: gdb-patches

> From: "Pierre Muller" <pierre.muller@ics-cnrs.unistra.fr>
> Date: Wed, 10 Mar 2010 18:14:19 +0100
> 
> Despite all my efforts,
> I never managed to get advices on the non-windows part of
> this patch :(

Which non-windows part of this patch?

> 2009-07-03  Pierre Muller  <muller@ics.u-strasbg.fr>
> 
> 	* windows-nat.c (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.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* RE: [PING] [RFC-v3] Add windows Thread Information Block
  2010-03-10 17:26               ` Pedro Alves
@ 2010-03-10 22:23                 ` Pierre Muller
  2010-03-10 23:30                   ` Daniel Jacobowitz
  2010-03-11  0:00                   ` Pedro Alves
  0 siblings, 2 replies; 34+ messages in thread
From: Pierre Muller @ 2010-03-10 22:23 UTC (permalink / raw)
  To: 'Pedro Alves', gdb-patches

> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Pedro Alves
> Envoyé : Wednesday, March 10, 2010 6:26 PM
> À : gdb-patches@sourceware.org
> Cc : Pierre Muller
> Objet : Re: [PING] [RFC-v3] Add windows Thread Information Block
> 
> On Wednesday 10 March 2010 17:14:19, Pierre Muller wrote:
> > Despite all my efforts,
> > I never managed to get advices on the non-windows part of
> > this patch :(
> >
> >   I appended at the bottom of this email an
> > updated patch.
> >   To refresh memories,
> > this patch enables looking at the 'Thread Local Base'
> > an internal Windows structure describing the current thread
> > and some process wide features.
> >   The main problem was about my use of TARGET_OBJECT_OSDATA
> > to get this information from the gdbserver, which did not seem
> > to be compatible with the general usage of TARGET_OBJECT_OSDATA.
> >
> >   I would really like to get new feedback on that
> > issue.
> 
> Sorry, I already explained long ago that TARGET_OBJECT_OSDATA
> is being misused here.  
  OK, I start to remember now,
you said that TARGET_OBJECT_DATA should use xml syntax for 
all data transmission, what that it?

> Why the resistence to change that?
It's not resistance, its just that I have no xml knowledge,
and I still don't really understand why 
xml should be required for all TARGET_OBJECT_DATA.

  
> There's another bit you haven't addressed yet:
> 
> > +	  if (len == 8)
> > +	    {
> > +	      uint64_t tlb = th->thread_local_base;
> > +	      memcpy ((void *)readbuf, (void *) &tlb, len);
> > +	      return len;
> > +	    }
> > +          else if (len == 4)
> 
> As I explained before, for partial xfers you should not
> design the protocol relying on `len' being exactly 4 or 8.
> Also, this is just transfering a number, why make that
> target-endian dependant (see memcpy above) ?

  My code does assume that there is a unique call that
will fetch either 4 bytes (for windows 32 bit inferior)
or 8 bytes for (windows 64 bit inferior) in a unique call,
which avoids the static struct used in the linux counter part...
(I could have added a check that offset is zero).

  Anyhow, if you insist on using xml, you will need to 
help me on how to handle and extract the relevant data from
the generated xml.
 
Pierre Muller

^ permalink raw reply	[flat|nested] 34+ messages in thread

* RE: [PING] [RFC-v3] Add windows Thread Information Block
  2010-03-10 18:48               ` [PING] [RFC-v3] Add windows " Mark Kettenis
@ 2010-03-10 22:25                 ` Pierre Muller
  0 siblings, 0 replies; 34+ messages in thread
From: Pierre Muller @ 2010-03-10 22:25 UTC (permalink / raw)
  To: 'Mark Kettenis'; +Cc: gdb-patches

> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Mark Kettenis
> Envoyé : Wednesday, March 10, 2010 7:48 PM
> À : pierre.muller@ics-cnrs.unistra.fr
> Cc : gdb-patches@sourceware.org
> Objet : Re: [PING] [RFC-v3] Add windows Thread Information Block
> 
> > From: "Pierre Muller" <pierre.muller@ics-cnrs.unistra.fr>
> > Date: Wed, 10 Mar 2010 18:14:19 +0100
> >
> > Despite all my efforts,
> > I never managed to get advices on the non-windows part of
> > this patch :(
> 
> Which non-windows part of this patch?

As you can see by my emails with Pedro,
the problem is aon the usage of TARGET_OBJECT_OSDATA
type for xfer_partial calls.


Pierre

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING] [RFC-v3] Add windows Thread Information Block
  2010-03-10 22:23                 ` Pierre Muller
@ 2010-03-10 23:30                   ` Daniel Jacobowitz
  2010-03-11  0:11                     ` Pedro Alves
  2010-03-11  0:00                   ` Pedro Alves
  1 sibling, 1 reply; 34+ messages in thread
From: Daniel Jacobowitz @ 2010-03-10 23:30 UTC (permalink / raw)
  To: Pierre Muller; +Cc: 'Pedro Alves', gdb-patches

On Wed, Mar 10, 2010 at 11:22:51PM +0100, Pierre Muller wrote:
>   OK, I start to remember now,
> you said that TARGET_OBJECT_DATA should use xml syntax for 
> all data transmission, what that it?

My two cents... the issue isn't that you aren't using XML, but that
you're using TARGET_OBJECT_OSDATA.  That's for information about the
operating system, like the list of all running processes, not about
the current process.

Pedro, this raises an interesting question.  Suppose Pierre added a
new qXfer object.  How would he indicate to a remote target which
process's object was requested?  This may be something already
handled, but I don't know the answer.

-- 
Daniel Jacobowitz
CodeSourcery

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING] [RFC-v3] Add windows Thread Information Block
  2010-03-10 22:23                 ` Pierre Muller
  2010-03-10 23:30                   ` Daniel Jacobowitz
@ 2010-03-11  0:00                   ` Pedro Alves
  2010-03-11  8:13                     ` Pierre Muller
       [not found]                     ` <002101cac0f2$a2298890$e67c99b0$%muller@ics-cnrs.unistra.fr>
  1 sibling, 2 replies; 34+ messages in thread
From: Pedro Alves @ 2010-03-11  0:00 UTC (permalink / raw)
  To: gdb-patches; +Cc: Pierre Muller

On Wednesday 10 March 2010 22:22:51, Pierre Muller wrote:

> > Sorry, I already explained long ago that TARGET_OBJECT_OSDATA
> > is being misused here.  
>   OK, I start to remember now,
> you said that TARGET_OBJECT_DATA should use xml syntax for 
> all data transmission, what that it?

Basically repeating from
<http://sourceware.org/ml/gdb-patches/2009-07/msg00011.html>:

TARGET_OBJECT_OSDATA is meant be used through the
get_osdata interface, which assumes the target returns
xml encoded tabular form data.  See gdb/osdata.c, and 
the "info os" command (use and implementation).  You
can try "info os processes" against linux native or
gdbserver to see it in action.  The basic idea of this
object, is to be able to fetch tables of operating system
related data, like the list of running processes, or the
list of running threads, which are the present uses.

> > Why the resistence to change that?
> It's not resistance, its just that I have no xml knowledge,
> and I still don't really understand why 
> xml should be required for all TARGET_OBJECT_DATA.

See above.

> > There's another bit you haven't addressed yet:
> > 
> > > +     if (len == 8)
> > > +       {
> > > +         uint64_t tlb = th->thread_local_base;
> > > +         memcpy ((void *)readbuf, (void *) &tlb, len);
> > > +         return len;
> > > +       }
> > > +          else if (len == 4)
> > 
> > As I explained before, for partial xfers you should not
> > design the protocol relying on `len' being exactly 4 or 8.
> > Also, this is just transfering a number, why make that
> > target-endian dependant (see memcpy above) ?
> 
>   My code does assume that there is a unique call that
> will fetch either 4 bytes (for windows 32 bit inferior)
> or 8 bytes for (windows 64 bit inferior) in a unique call,
> which avoids the static struct used in the linux counter part...
> (I could have added a check that offset is zero).
> 
>   Anyhow, if you insist on using xml, you will need to 
> help me on how to handle and extract the relevant data from
> the generated xml.

I never insisted you used xml...  I do insist however,
that everything that goes through TARGET_OBJECT_OSDATA
respects the get_osdata interface, and that, is
tabular/xml based transfer of data.

Basically repeating from:
<http://sourceware.org/ml/gdb-patches/2009-07/msg00015.html>:

So, if you want to use the qxfer interface, please
add a new target object.  One note: I think target object's spirit is
to transfer  the whole data block, which is what would make
sense to me when requesting a TLB _object_.   The reason that
makes me consider transfering the whole blob instead of an address
and then relying on plain memory reads issued from GDB,
is that on other targets that may want to reuse the
interface, the TLB-like object may not be mapped or
accessible on the address space accessible with plain memory
reads.  This is exactly the rationale behind objects like
TARGET_OBJECT_AUXV, TARGET_OBJECT_WCOOKIE or
TARGET_OBJECT_SIGNAL_INFO: each of these objects can
be seen as a blob of data in its own address space.

If just transfering the address of the data is the way
to go, as you're doing presently, then I'm not certain
the xfer_partial interface is a good fit for this --- for
example, a simple packet like we use to fetch the tls data
pointer seems like a better fit.  For example, a new
target_get_thread_local_block target method, and a
new "qGetTLBAddr:XXX" packet: see the "qGetTLSAddr:" packet
for inspiration.

I don't have a strong preference which of the directions
above should be followed, but, mind you, but, as I said
before, TARGET_OBJECT_OSDATA isn't the right interface for
this.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING] [RFC-v3] Add windows Thread Information Block
  2010-03-10 23:30                   ` Daniel Jacobowitz
@ 2010-03-11  0:11                     ` Pedro Alves
  0 siblings, 0 replies; 34+ messages in thread
From: Pedro Alves @ 2010-03-11  0:11 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: Pierre Muller, gdb-patches

On Wednesday 10 March 2010 23:30:40, Daniel Jacobowitz wrote:
> On Wed, Mar 10, 2010 at 11:22:51PM +0100, Pierre Muller wrote:
> >   OK, I start to remember now,
> > you said that TARGET_OBJECT_DATA should use xml syntax for 
> > all data transmission, what that it?
> 
> My two cents... the issue isn't that you aren't using XML, but that
> you're using TARGET_OBJECT_OSDATA.  That's for information about the
> operating system, like the list of all running processes, not about
> the current process.
> 
> Pedro, this raises an interesting question.  Suppose Pierre added a
> new qXfer object.  How would he indicate to a remote target which
> process's object was requested?  This may be something already
> handled, but I don't know the answer.

The "general thread" is reused for target objects.  There's
no way in the protocol to select a process as context, other than
selecting a thread of it.  Example, TARGET_OBJECT_SIGNAL_INFO
(for $_siginfo) transfers from the remote protocol
current|general thread.  I think we'd do the same for this?  A
non-thread specific xfer example: TARGET_OBJECT_AUXV transfers
from the process of the currently selected thread.

Some packets specify the thread/process explicitly. For example,
the `qGetTLBAddr' packet alternative would do like
`qGetTLSAddr' does: `qGetTLBAddr:TID...' if multiprocess
is off, or `qGetTLBAddr:pPID.TID...' if multiprocess is
on.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING] [RFC-v3] Add windows Thread Information Block
  2010-03-10 17:14             ` [PING] [RFC-v3] Add windows Thread Information Block Pierre Muller
  2010-03-10 17:26               ` Pedro Alves
  2010-03-10 18:48               ` [PING] [RFC-v3] Add windows " Mark Kettenis
@ 2010-03-11  0:24               ` Pedro Alves
  2010-03-11  8:01                 ` Pierre Muller
  2 siblings, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2010-03-11  0:24 UTC (permalink / raw)
  To: gdb-patches; +Cc: Pierre Muller

On Wednesday 10 March 2010 17:14:19, Pierre Muller wrote:
> +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;

Where did you get these offsets from?
According to <http://en.wikipedia.org/wiki/Win32_Thread_Information_Block>,
thread_local_storage should be 0x2c, and active_rpc_handle 0x28, as in,
someone has it swapped.  I think I actually tested that wikipedia had it
right last time I asked you this, but in any case, can you confirm?

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* RE: [PING] [RFC-v3] Add windows Thread Information Block
  2010-03-11  0:24               ` Pedro Alves
@ 2010-03-11  8:01                 ` Pierre Muller
  0 siblings, 0 replies; 34+ messages in thread
From: Pierre Muller @ 2010-03-11  8:01 UTC (permalink / raw)
  To: 'Pedro Alves', gdb-patches

Hi Pedro,

> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Pedro Alves
> Envoyé : Thursday, March 11, 2010 1:24 AM
> À : gdb-patches@sourceware.org
> Cc : Pierre Muller
> Objet : Re: [PING] [RFC-v3] Add windows Thread Information Block
> 
> On Wednesday 10 March 2010 17:14:19, Pierre Muller wrote:
> > +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;
> 
> Where did you get these offsets from?
> According to
> <http://en.wikipedia.org/wiki/Win32_Thread_Information_Block>,
> thread_local_storage should be 0x2c, and active_rpc_handle 0x28, as in,
> someone has it swapped.

  Strange because, IIRC, this is the source where I got the offsets too...

>  I think I actually tested that wikipedia had
> it
> right last time I asked you this, but in any case, can you confirm?

  I checked it on gdb itself, but both fields are zeroed.
Now I remember having read somewhere that 
for newer Windows OS, the Thread Local Storage block is inside the 
Thread Information block itself:
see same Wikipedia page:
address : FS[0xE10]  length : 256 description : TLS slots, 4 bytes per slot
so I will need to check on an older Win9X virtual machine
before I can answer this question.

Pierre

^ permalink raw reply	[flat|nested] 34+ messages in thread

* RE: [PING] [RFC-v3] Add windows Thread Information Block
  2010-03-11  0:00                   ` Pedro Alves
@ 2010-03-11  8:13                     ` Pierre Muller
  2010-03-15 21:40                       ` [RFC-v4] Add windows OS " Pierre Muller
       [not found]                     ` <002101cac0f2$a2298890$e67c99b0$%muller@ics-cnrs.unistra.fr>
  1 sibling, 1 reply; 34+ messages in thread
From: Pierre Muller @ 2010-03-11  8:13 UTC (permalink / raw)
  To: 'Pedro Alves', gdb-patches

Hi Pedro,

> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Pedro Alves
> Envoyé : Thursday, March 11, 2010 1:01 AM
> À : gdb-patches@sourceware.org
> Cc : Pierre Muller
> Objet : Re: [PING] [RFC-v3] Add windows Thread Information Block
> 
> On Wednesday 10 March 2010 22:22:51, Pierre Muller wrote:
> 
> > > Sorry, I already explained long ago that TARGET_OBJECT_OSDATA
> > > is being misused here.
> >   OK, I start to remember now,
> > you said that TARGET_OBJECT_DATA should use xml syntax for
> > all data transmission, what that it?
> 
> Basically repeating from
> <http://sourceware.org/ml/gdb-patches/2009-07/msg00011.html>:

  Sorry to bother you and bug you with all that.
I really completely forgot these last emails, I should have
reread them before sending this PING.

> TARGET_OBJECT_OSDATA is meant be used through the
> get_osdata interface, which assumes the target returns
> xml encoded tabular form data.  See gdb/osdata.c, and
> the "info os" command (use and implementation).  You
> can try "info os processes" against linux native or
> gdbserver to see it in action.  The basic idea of this
> object, is to be able to fetch tables of operating system
> related data, like the list of running processes, or the
> list of running threads, which are the present uses.
OK, so let's use another scheme.
 
> > > Why the resistence to change that?
> > It's not resistance, its just that I have no xml knowledge,
> > and I still don't really understand why
> > xml should be required for all TARGET_OBJECT_DATA.
> 
> See above.
> 
> > > There's another bit you haven't addressed yet:
> > >
> > > > +     if (len == 8)
> > > > +       {
> > > > +         uint64_t tlb = th->thread_local_base;
> > > > +         memcpy ((void *)readbuf, (void *) &tlb, len);
> > > > +         return len;
> > > > +       }
> > > > +          else if (len == 4)
> > >
> > > As I explained before, for partial xfers you should not
> > > design the protocol relying on `len' being exactly 4 or 8.
> > > Also, this is just transfering a number, why make that
> > > target-endian dependant (see memcpy above) ?
> >
> >   My code does assume that there is a unique call that
> > will fetch either 4 bytes (for windows 32 bit inferior)
> > or 8 bytes for (windows 64 bit inferior) in a unique call,
> > which avoids the static struct used in the linux counter part...
> > (I could have added a check that offset is zero).
> >
> >   Anyhow, if you insist on using xml, you will need to
> > help me on how to handle and extract the relevant data from
> > the generated xml.
> 
> I never insisted you used xml...  I do insist however,
> that everything that goes through TARGET_OBJECT_OSDATA
> respects the get_osdata interface, and that, is
> tabular/xml based transfer of data.
> 
> Basically repeating from:
> <http://sourceware.org/ml/gdb-patches/2009-07/msg00015.html>:
> 
> So, if you want to use the qxfer interface, please
> add a new target object.  One note: I think target object's spirit is
> to transfer  the whole data block, which is what would make
> sense to me when requesting a TLB _object_.   The reason that
> makes me consider transfering the whole blob instead of an address
> and then relying on plain memory reads issued from GDB,
> is that on other targets that may want to reuse the
> interface, the TLB-like object may not be mapped or
> accessible on the address space accessible with plain memory
> reads.  This is exactly the rationale behind objects like
> TARGET_OBJECT_AUXV, TARGET_OBJECT_WCOOKIE or
> TARGET_OBJECT_SIGNAL_INFO: each of these objects can
> be seen as a blob of data in its own address space.

  
 
> If just transfering the address of the data is the way
> to go, as you're doing presently, then I'm not certain
> the xfer_partial interface is a good fit for this --- for
> example, a simple packet like we use to fetch the tls data
> pointer seems like a better fit.  For example, a new
> target_get_thread_local_block target method, and a
> new "qGetTLBAddr:XXX" packet: see the "qGetTLSAddr:" packet
> for inspiration.
 So I will try this out, but adding new target methods
is something I am afraid of not being capable...
  I will probably need so time to get that working...

  Pedro, 
  I would like to apologize here, because my first email
sounded like an attack on you, but it was just that I I
still had not understood your reasons for the opposition 
against another use of TARGET_OBJECT_OSDATA.
  I was thinking that the Thread Information Block was an
OS specific feature, and as such would clearly be eligible 
for the use of TARGET_OBJECT_OSDATA.
  Your answer that it should all be processed through the
get_osdata function has finally convinced me.
It should already have last year, but I must have been 
in a 'worse' mind and didn't understand your reasons then.


Thanks for all,

Pierre

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [RFC-v4] Add windows OS Thread Information Block
  2010-03-11  8:13                     ` Pierre Muller
@ 2010-03-15 21:40                       ` Pierre Muller
  2010-03-16  0:10                         ` Christopher Faylor
  2010-04-01  9:41                         ` [PING][RFC-v4] " Pierre Muller
  0 siblings, 2 replies; 34+ messages in thread
From: Pierre Muller @ 2010-03-15 21:40 UTC (permalink / raw)
  To: gdb-patches

  This is a new version of my patch to add support for
displaying thread-information-block for Windows OS
inferior programs.

  I tried to follow several advices I got earlier and made several 
changes.
  The most important one concerns the remote/gdbserver communication:
instead of using TARGET_OBJECT_DATA, I defined a new target_ops method
called to_get_tib_address and defined a new query packet
PACKET_qGetTIBAddr adapted from the existing PACKET_qGetTLSAddr.

  I also tried to write a first draft of the documentation
patch and hope for some input from Eli on this matter...

  There are only minor changes in the windows-nat and windows-tdep files,
the main one being the adaptation to the new to_get_tib_addr
field of the target_ops struct.

  I hope this new version will be closer to the expectation
of most of you and look forward to hearing your comments.


Pierre

PS: After checking, I indeed change the order of 
active_rpc_handle and thead_local_storage fields in 
windows-tdep.c as mentioned by Pedro. 
There are a few other minor changes, some due to the fact that
I got access to a windows-64 bit machine, which allowed me to
correct some field widths for some internally defined structures
in windows-tdep.c file.



2010-03-15  Pierre Muller  <muller@ics.u-strasbg.fr>

	* remote.c (PACKET_qGetTIBAddr): New enum element.
	(remote_get_tib_address): New function.
	(init_remote_ops): Set TO_GET_TIB_ADDRESS field
	to remote_get_tib_address.
	(_initialize_remote): Add add_packet_config_cmd
	for PACKET_qGetTIBAddr.
	* target.c (update_current_target): Set default value for
	new TO_GET_TIB_ADDRESS field.
	* target.h (target_ops): New field TO_GET_TIB_ADDRESS.
	(target_get_tib_address): New macro.
	
	* windows-nat.c (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_get_tib_address): New function.
	(init_windows_ops): Set TO_GET_TIB_ADDRESS field
	to remote_get_tib_address.
	(_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:

	* server.c (handle_query): Acknowledge support
	for 'qGetTIBAddr' if GET_TIB_ADDR field of THE_TARGET
	is set.
	Handle 'qGetTIBAddr' query.
	* target.h (target_ops): New GET_TIB_ADDRESS field.
	* win32-low.h (win32_thread_info): Add THREAD_LOCAL_BASE field.
	* win32-low.c (child_add_thread): Add TLB argument.
	Set THREAD_LOCAL_BASE field to TLB argument.
	(get_child_debug_event): Adapt to child_add_thread change.
	(win32_get_tib_address): New function.
	(win32_target_ops): Set GET_TIB_ADDRESS field to
	win32_get_tib_address
	

doc/ChangeLog entry:

	gdb.texinfo ($__tlb): Document new automatic convience variable.
	(info w32 thread-information-block): Docmuent new command.
	(qGetTIBAddress): Document new gdbserver query.
	(maint set/show show-all-tib): Document new command.



Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.389
diff -u -p -r1.389 remote.c
--- remote.c	7 Mar 2010 14:36:44 -0000	1.389
+++ remote.c	15 Mar 2010 21:12:43 -0000
@@ -1141,6 +1141,7 @@ enum {
   PACKET_qXfer_spu_write,
   PACKET_qXfer_osdata,
   PACKET_qXfer_threads,
+  PACKET_qGetTIBAddr,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
   PACKET_QPassSignals,
@@ -8380,6 +8381,48 @@ remote_get_thread_local_address (struct 
   return 0;
 }
 
+/* Provide thead local base, i.e. Thread Information Block address.  */
+/* Returns 1 if ptid is found and thread_local_base is non zero.  */
+int
+remote_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  if (remote_protocol_packets[PACKET_qGetTIBAddr].support !=
PACKET_DISABLE)
+    {
+      struct remote_state *rs = get_remote_state ();
+      char *p = rs->buf;
+      char *endp = rs->buf + get_remote_packet_size ();
+      enum packet_result result;
+
+      strcpy (p, "qGetTIBAddr:");
+      p += strlen (p);
+      p = write_ptid (p, endp, ptid);
+      *p++ = '\0';
+
+      putpkt (rs->buf);
+      getpkt (&rs->buf, &rs->buf_size, 0);
+      result = packet_ok (rs->buf,
+			  &remote_protocol_packets[PACKET_qGetTIBAddr]);
+      if (result == PACKET_OK)
+	{
+	  ULONGEST result;
+
+	  unpack_varlen_hex (rs->buf, &result);
+	  if (addr)
+	    *addr = (CORE_ADDR) result;
+	  return 1;
+	}
+      else if (result == PACKET_UNKNOWN)
+	error (_("Remote target doesn't support qGetTIBAddr packet"));
+      else
+	error (_("Remote target failed to process qGetTIBAddr request"));
+    }
+  else
+    error (_("qGetTIBAddr not supported or disabled on this target"));
+  /* Not reached.  */
+  return 0;
+}
+
+
 /* Support for inferring a target description based on the current
    architecture and the size of a 'g' packet.  While the 'g' packet
    can have any size (since optional registers can be left off the
@@ -9737,6 +9780,7 @@ Specify the serial device it is connecte
   remote_ops.to_get_raw_trace_data = remote_get_raw_trace_data;
   remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing;
   remote_ops.to_core_of_thread = remote_core_of_thread;
+  remote_ops.to_get_tib_address = remote_get_tib_address;
 }
 
 /* Set up the extended remote vector by making a copy of the standard
@@ -10156,6 +10200,10 @@ Show the maximum size of the address (in
 			 "qGetTLSAddr", "get-thread-local-storage-address",
 			 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTIBAddr],
+			 "qGetTIBAddr",
"get-thread-information-block-address",
+			 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_bc],
 			 "bc", "reverse-continue", 0);
 
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.242
diff -u -p -r1.242 target.c
--- target.c	12 Mar 2010 03:54:45 -0000	1.242
+++ target.c	15 Mar 2010 21:12:45 -0000
@@ -659,6 +659,7 @@ update_current_target (void)
       INHERIT (to_upload_trace_state_variables, t);
       INHERIT (to_get_raw_trace_data, t);
       INHERIT (to_set_disconnected_tracing, t);
+      INHERIT (to_get_tib_address, t);
       INHERIT (to_magic, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
@@ -849,6 +850,9 @@ update_current_target (void)
   de_fault (to_set_disconnected_tracing,
 	    (void (*) (int))
 	    tcomplain);
+  de_fault (to_get_tib_address,
+	    (int (*) (ptid_t, CORE_ADDR *))
+	    tcomplain);
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.173
diff -u -p -r1.173 target.h
--- target.h	22 Feb 2010 23:35:16 -0000	1.173
+++ target.h	15 Mar 2010 21:12:45 -0000
@@ -673,6 +673,10 @@ struct target_ops
        right now, or in this debug session, or for this target -- return
-1.  */
     int (*to_core_of_thread) (struct target_ops *, ptid_t ptid);
 
+    /* Return the address of the start of the Thread Information Block
+       a windows OS specific feature.  */
+    int (*to_get_tib_address) (ptid_t ptid, CORE_ADDR *addr);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm
related?
      */
@@ -1359,6 +1363,9 @@ extern int target_search_memory (CORE_AD
 #define target_set_disconnected_tracing(val) \
   (*current_target.to_set_disconnected_tracing) (val)
 
+#define target_get_tib_address(ptid, addr) \
+  (*current_target.to_get_tib_address) ((ptid), (addr))
+
 /* Command logging facility.  */
 
 #define target_log_command(p)						\
Index: windows-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/windows-nat.c,v
retrieving revision 1.207
diff -u -p -r1.207 windows-nat.c
--- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
+++ windows-nat.c	15 Mar 2010 21:12:46 -0000
@@ -191,6 +191,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;
@@ -320,7 +321,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;
@@ -335,6 +336,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);
@@ -1074,15 +1076,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 (\
@@ -1271,9 +1264,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;
 }
 
@@ -1447,7 +1442,9 @@ 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:
@@ -1481,7 +1478,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;
 
@@ -2266,6 +2264,26 @@ windows_xfer_partial (struct target_ops 
     }
 }
 
+/* Provide thead local base, i.e. Thread Information Block address.  */
+/* Returns 1 if ptid is found and thread_local_base is non zero.  */
+int
+windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  thread_info *th;
+
+  th = thread_rec (ptid_get_tid (ptid), 0);
+  if (th == NULL)
+    return 0;
+
+  if (addr)
+    {
+      *addr = (CORE_ADDR) th->thread_local_base;
+    }
+  if (th->thread_local_base)
+    return 1;
+  return 0;
+}
+
 static ptid_t
 windows_get_ada_task_ptid (long lwp, long thread)
 {
@@ -2314,6 +2332,7 @@ init_windows_ops (void)
   windows_ops.to_has_execution = default_child_has_execution;
   windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
   windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
+  windows_ops.to_get_tib_address = windows_get_tib_address;
 
   i386_use_watchpoints (&windows_ops);
 
@@ -2415,9 +2434,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.5
diff -u -p -r1.5 windows-tdep.c
--- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
+++ windows-tdep.c	15 Mar 2010 21:12:46 -0000
@@ -19,6 +19,361 @@
 #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 active_rpc_handle;			/* %fs:0x0028 */
+    uint32_t thread_local_storage;		/* %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 */
+    uint64_t environment_pointer;		/* %gs:0x0038 */
+    uint64_t process_id;			/* %gs:0x0040 */
+    uint64_t current_thread_id;			/* %gs:0x0048 */
+    uint64_t active_rpc_handle;			/* %gs:0x0050 */
+    uint64_t thread_local_storage;		/* %gs:0x0058 */
+    uint64_t process_environment_block;		/* %gs:0x0060 */
+    uint64_t last_error_number;			/* %gs:0x0068 */
+  }
+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 */
+    " active_rpc_handle           ",	/* %fs:0x0028 */
+    " thread_local_storage        ",	/* %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, *dword32_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");
+  dword32_type = arch_integer_type (gdbarch, 32,
+				 1, "DWORD32");
+  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", dword32_type);
+  append_composite_type_field (peb_ldr_type, "initialized", dword32_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 active_rpc_handle;		%fs:0x0028 */
+  append_composite_type_field (tib_type, "active_rpc_handle",
dword_ptr_type);
+  /* uint32_t thread_local_storage;		%fs:0x002c */
+  append_composite_type_field (tib_type, "thread_local_storage",
void_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 *val)
+{
+  CORE_ADDR tlb;
+  ULONGEST num;
+  struct type *type = check_typedef (value_type (val));
+  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+  struct value *parent = value_parent (val);
+  LONGEST offset = value_offset (val);
+  int length = TYPE_LENGTH (type);
+
+  /* This needs to be changed if multi-process support is added.  */
+
+  if (!target_get_tib_address (inferior_ptid, &tlb))
+    error (_("Unable to read tlb"));
+  num = (ULONGEST) tlb;
+  store_unsigned_integer (value_contents_raw (val), length, byte_order,
num);
+}
+
+/* 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 (ptid_t ptid)
+{
+#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.  */
+
+  if (target_get_tib_address (ptid, &thread_local_base) == 0)
+    {
+      printf_filtered ("Unable to get thread local base for ThreadId %s\n",
+	pulongest (ptid_get_tid(ptid)));
+      return -1;
+    }
+
+  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 (ptid_get_tid (ptid)), 
+	paddress (target_gdbarch, thread_local_base));
+      return -1;
+    }
+
+  printf_filtered ("Thread Information Block %s at %s\n",
+		   pulongest (ptid_get_tid (ptid)),
+		   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 (ptid_build (ptid_get_pid (inferior_ptid), 0, id));
+    }
+  else if (!ptid_equal (inferior_ptid, null_ptid))
+    display_one_tib (inferior_ptid);
+}
 
 void
 windows_xfer_shared_library (const char* so_name, CORE_ADDR load_addr,
@@ -36,3 +391,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.4
diff -u -p -r1.4 windows-tdep.h
--- windows-tdep.h	1 Jan 2010 07:31:46 -0000	1.4
+++ windows-tdep.h	15 Mar 2010 21:12:46 -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: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.680
diff -u -p -r1.680 gdb.texinfo
--- doc/gdb.texinfo	12 Mar 2010 19:15:52 -0000	1.680
+++ doc/gdb.texinfo	15 Mar 2010 21:13:00 -0000
@@ -8050,6 +8050,14 @@ The variable @code{$_siginfo} contains e
 (@pxref{extra signal information}).  Note that @code{$_siginfo}
 could be empty, if the application has not yet received any signals.
 For example, it will be empty before you execute the @code{run} command.
+
+@item $_tlb
+@vindex $_tlb@r{, convenience variable}
+The variable @code{$_tlb} is automatically set for Windows OS running
+applications in native mode or connected to a gdbserver that supports
+@code{qGetTIBAddr} requests. This variable contains the address of the
thread
+information block.
+
 @end table
 
 On HP-UX systems, if you refer to a function or variable name that
@@ -15692,6 +15700,10 @@ are:
 @tab @code{qGetTLSAddr}
 @tab Displaying @code{__thread} variables
 
+@item @code{w32 thread-information-block}
+@tab @code{qGetTIBAddr}
+@tab Display Windows OS Thread Information Block.
+
 @item @code{search-memory}
 @tab @code{qSearch:memory}
 @tab @code{find}
@@ -16471,6 +16483,11 @@ a long value to give the information abo
 Without argument, this command displays information
 about the six segment registers.
 
+@item info w32 thread-information-block
+This command displays thread specific information stored in the
+Thread Information Block (readable using @code{$fs} selector for 32-bit
+programs and @code{$gs} for 64-bit programs).
+
 @kindex info dll
 @item info dll
 This is a Cygwin-specific alias of @code{info shared}.
@@ -28875,6 +28892,14 @@ enabled, the debug registers values are 
 removes a hardware breakpoint or watchpoint, and when the inferior
 triggers a hardware-assisted breakpoint or watchpoint.
 
+@kindex maint set show-all-tib
+@kindex maint show show-all-tib
+@item maint set show-all-tib
+@itemx maint show show-all-tib
+Control whether to show all non zero areas within a 1k block starting
+at thread local base, when using @samp{info w32 thread-information-block}
+command.
+
 @kindex maint space
 @cindex memory used by commands
 @item maint space
@@ -30088,6 +30113,28 @@ An error occurred.  @var{nn} are hex dig
 An empty reply indicates that @samp{qGetTLSAddr} is not supported by the
stub.
 @end table
 
+@item qGetTIBAddr:@var{thread-id}:
+@cindex get thread information block address
+@cindex @samp{qGetTIBAddr} packet
+Fetch address of the Windows OS specific Thread Information Block.
+
+@var{thread-id} is the thread ID associated with the thread.
+
+Reply:
+@table @samp
+@item @var{XX}@dots{}
+Hex encoded (big endian) bytes representing the linear address of the
+thread information block.
+
+@item E @var{nn}
+An error occured. This means that either the thread was not found, or the
+address could not be retrieved.
+
+@item
+An empty reply indicates that @samp{qGetTIBAddr} is not supported by the
stub.
+@end table
+
+
 @item qL @var{startflag} @var{threadcount} @var{nextthread}
 Obtain thread information from RTOS.  Where: @var{startflag} (one hex
 digit) is one to indicate the first query and zero to indicate a
Index: gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.108
diff -u -p -r1.108 server.c
--- gdbserver/server.c	20 Jan 2010 22:55:38 -0000	1.108
+++ gdbserver/server.c	15 Mar 2010 21:13:01 -0000
@@ -1280,6 +1280,9 @@ handle_query (char *own_buf, int packet_
       if (the_target->qxfer_osdata != NULL)
 	strcat (own_buf, ";qXfer:osdata:read+");
 
+      if (the_target->get_tib_address != NULL)
+	strcat (own_buf, ";qGetTIBAddr+");
+
       if (target_supports_multi_process ())
 	strcat (own_buf, ";multiprocess+");
 
@@ -1356,6 +1359,31 @@ handle_query (char *own_buf, int packet_
       /* Otherwise, pretend we do not understand this packet.  */
     }
 
+  /* Windows OS Thread Information Block address support.  */
+  if (the_target->get_tib_address != NULL
+      && strncmp ("qGetTIBAddr:", own_buf, 12) == 0)
+    {
+      char *annex;
+      int n;
+      CORE_ADDR tlb;
+      ptid_t ptid = read_ptid (own_buf + 12, &annex);
+
+      n = (*the_target->get_tib_address) (ptid, &tlb);
+      if (n == 1)
+	{
+	  sprintf (own_buf, "%llx", tlb);
+	  return;
+	}
+      else if (n == 0)
+	{
+	  write_enn (own_buf);
+	  return;
+	}
+      return;
+    }
+
+
+
   /* Handle "monitor" commands.  */
   if (strncmp ("qRcmd,", own_buf, 6) == 0)
     {
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.43
diff -u -p -r1.43 target.h
--- gdbserver/target.h	20 Jan 2010 22:55:38 -0000	1.43
+++ gdbserver/target.h	15 Mar 2010 21:13:01 -0000
@@ -267,6 +267,9 @@ struct target_ops
 			unsigned const char *writebuf,
 			CORE_ADDR offset, int len);
 
+  /* Read Thread Information Block address.  */
+  int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address);
+
   int (*supports_non_stop) (void);
 
   /* Enables async target events.  Returns the previous enable
Index: gdbserver/win32-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v
retrieving revision 1.43
diff -u -p -r1.43 win32-low.c
--- gdbserver/win32-low.c	20 Jan 2010 22:55:38 -0000	1.43
+++ gdbserver/win32-low.c	15 Mar 2010 21:13:01 -0000
@@ -178,7 +178,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);
@@ -189,6 +189,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 *)
@@ -1449,7 +1450,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:
@@ -1479,7 +1481,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
@@ -1750,6 +1753,22 @@ wince_hostio_last_error (char *buf)
 }
 #endif
 
+/* Write Windows OS Thread Information Block address.  */
+static int
+win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  win32_thread_info *th;
+  th = thread_rec (ptid, 0);
+  if (th == NULL)
+    return 0;
+  if (addr)
+    *addr = (CORE_ADDR) th->thread_local_base;
+  if (th->thread_local_base)
+    return 1;
+  return 0;
+}
+
+
 static struct target_ops win32_target_ops = {
   win32_create_inferior,
   win32_attach,
@@ -1778,6 +1797,9 @@ static struct target_ops win32_target_op
 #else
   hostio_last_error_from_errno,
 #endif
+  NULL,
+  NULL,
+  win32_get_tib_address,
 };
 
 /* Initialize the Win32 backend.  */
Index: gdbserver/win32-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v
retrieving revision 1.12
diff -u -p -r1.12 win32-low.h
--- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
+++ gdbserver/win32-low.h	15 Mar 2010 21:13:01 -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;
 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC-v4] Add windows OS Thread Information Block
  2010-03-15 21:40                       ` [RFC-v4] Add windows OS " Pierre Muller
@ 2010-03-16  0:10                         ` Christopher Faylor
  2010-04-01  9:41                         ` [PING][RFC-v4] " Pierre Muller
  1 sibling, 0 replies; 34+ messages in thread
From: Christopher Faylor @ 2010-03-16  0:10 UTC (permalink / raw)
  To: gdb-patches, Pierre Muller

On Mon, Mar 15, 2010 at 10:40:38PM +0100, Pierre Muller wrote:
>  This is a new version of my patch to add support for
>displaying thread-information-block for Windows OS
>inferior programs.
>
>  I tried to follow several advices I got earlier and made several 
>changes.
>  The most important one concerns the remote/gdbserver communication:
>instead of using TARGET_OBJECT_DATA, I defined a new target_ops method
>called to_get_tib_address and defined a new query packet
>PACKET_qGetTIBAddr adapted from the existing PACKET_qGetTLSAddr.
>
>  I also tried to write a first draft of the documentation
>patch and hope for some input from Eli on this matter...
>
>  There are only minor changes in the windows-nat and windows-tdep files,
>the main one being the adaptation to the new to_get_tib_addr
>field of the target_ops struct.
>
>  I hope this new version will be closer to the expectation
>of most of you and look forward to hearing your comments.
>
>
>Pierre
>
>PS: After checking, I indeed change the order of 
>active_rpc_handle and thead_local_storage fields in 

You call this "thead" rather than "thread" in a couple of places.

Other than that it looks ok, assuming that others concerns have
been addressed.

Thanks.

cgf

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PING][RFC-v4] Add windows OS Thread Information Block
  2010-03-15 21:40                       ` [RFC-v4] Add windows OS " Pierre Muller
  2010-03-16  0:10                         ` Christopher Faylor
@ 2010-04-01  9:41                         ` Pierre Muller
  2010-04-01 11:21                           ` Pedro Alves
  1 sibling, 1 reply; 34+ messages in thread
From: Pierre Muller @ 2010-04-01  9:41 UTC (permalink / raw)
  To: gdb-patches

  I am still waiting for a comment from any global
maintainer concerning the non-(windows specific) parts
of that patch. Christopher approved the windows part.

Pierre Muller

> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Pierre Muller
> Envoyé : Monday, March 15, 2010 10:41 PM
> À : gdb-patches@sourceware.org
> Objet : [RFC-v4] Add windows OS Thread Information Block
> 
>   This is a new version of my patch to add support for
> displaying thread-information-block for Windows OS
> inferior programs.
> 
>   I tried to follow several advices I got earlier and made several
> changes.
>   The most important one concerns the remote/gdbserver communication:
> instead of using TARGET_OBJECT_DATA, I defined a new target_ops method
> called to_get_tib_address and defined a new query packet
> PACKET_qGetTIBAddr adapted from the existing PACKET_qGetTLSAddr.
> 
>   I also tried to write a first draft of the documentation
> patch and hope for some input from Eli on this matter...
> 
>   There are only minor changes in the windows-nat and windows-tdep
> files,
> the main one being the adaptation to the new to_get_tib_addr
> field of the target_ops struct.
> 
>   I hope this new version will be closer to the expectation
> of most of you and look forward to hearing your comments.
> 
> 
> Pierre
> 
> PS: After checking, I indeed change the order of
> active_rpc_handle and thead_local_storage fields in
> windows-tdep.c as mentioned by Pedro.
> There are a few other minor changes, some due to the fact that
> I got access to a windows-64 bit machine, which allowed me to
> correct some field widths for some internally defined structures
> in windows-tdep.c file.
> 
> 
> 
> 2010-03-15  Pierre Muller  <muller@ics.u-strasbg.fr>
> 
> 	* remote.c (PACKET_qGetTIBAddr): New enum element.
> 	(remote_get_tib_address): New function.
> 	(init_remote_ops): Set TO_GET_TIB_ADDRESS field
> 	to remote_get_tib_address.
> 	(_initialize_remote): Add add_packet_config_cmd
> 	for PACKET_qGetTIBAddr.
> 	* target.c (update_current_target): Set default value for
> 	new TO_GET_TIB_ADDRESS field.
> 	* target.h (target_ops): New field TO_GET_TIB_ADDRESS.
> 	(target_get_tib_address): New macro.
> 
> 	* windows-nat.c (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_get_tib_address): New function.
> 	(init_windows_ops): Set TO_GET_TIB_ADDRESS field
> 	to remote_get_tib_address.
> 	(_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:
> 
> 	* server.c (handle_query): Acknowledge support
> 	for 'qGetTIBAddr' if GET_TIB_ADDR field of THE_TARGET
> 	is set.
> 	Handle 'qGetTIBAddr' query.
> 	* target.h (target_ops): New GET_TIB_ADDRESS field.
> 	* win32-low.h (win32_thread_info): Add THREAD_LOCAL_BASE field.
> 	* win32-low.c (child_add_thread): Add TLB argument.
> 	Set THREAD_LOCAL_BASE field to TLB argument.
> 	(get_child_debug_event): Adapt to child_add_thread change.
> 	(win32_get_tib_address): New function.
> 	(win32_target_ops): Set GET_TIB_ADDRESS field to
> 	win32_get_tib_address
> 
> 
> doc/ChangeLog entry:
> 
> 	gdb.texinfo ($__tlb): Document new automatic convience variable.
> 	(info w32 thread-information-block): Docmuent new command.
> 	(qGetTIBAddress): Document new gdbserver query.
> 	(maint set/show show-all-tib): Document new command.
> 
> 
> 
> Index: remote.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/remote.c,v
> retrieving revision 1.389
> diff -u -p -r1.389 remote.c
> --- remote.c	7 Mar 2010 14:36:44 -0000	1.389
> +++ remote.c	15 Mar 2010 21:12:43 -0000
> @@ -1141,6 +1141,7 @@ enum {
>    PACKET_qXfer_spu_write,
>    PACKET_qXfer_osdata,
>    PACKET_qXfer_threads,
> +  PACKET_qGetTIBAddr,
>    PACKET_qGetTLSAddr,
>    PACKET_qSupported,
>    PACKET_QPassSignals,
> @@ -8380,6 +8381,48 @@ remote_get_thread_local_address (struct
>    return 0;
>  }
> 
> +/* Provide thead local base, i.e. Thread Information Block address.
> */
> +/* Returns 1 if ptid is found and thread_local_base is non zero.  */
> +int
> +remote_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
> +{
> +  if (remote_protocol_packets[PACKET_qGetTIBAddr].support !=
> PACKET_DISABLE)
> +    {
> +      struct remote_state *rs = get_remote_state ();
> +      char *p = rs->buf;
> +      char *endp = rs->buf + get_remote_packet_size ();
> +      enum packet_result result;
> +
> +      strcpy (p, "qGetTIBAddr:");
> +      p += strlen (p);
> +      p = write_ptid (p, endp, ptid);
> +      *p++ = '\0';
> +
> +      putpkt (rs->buf);
> +      getpkt (&rs->buf, &rs->buf_size, 0);
> +      result = packet_ok (rs->buf,
> +			  &remote_protocol_packets[PACKET_qGetTIBAddr]);
> +      if (result == PACKET_OK)
> +	{
> +	  ULONGEST result;
> +
> +	  unpack_varlen_hex (rs->buf, &result);
> +	  if (addr)
> +	    *addr = (CORE_ADDR) result;
> +	  return 1;
> +	}
> +      else if (result == PACKET_UNKNOWN)
> +	error (_("Remote target doesn't support qGetTIBAddr packet"));
> +      else
> +	error (_("Remote target failed to process qGetTIBAddr request"));
> +    }
> +  else
> +    error (_("qGetTIBAddr not supported or disabled on this target"));
> +  /* Not reached.  */
> +  return 0;
> +}
> +
> +
>  /* Support for inferring a target description based on the current
>     architecture and the size of a 'g' packet.  While the 'g' packet
>     can have any size (since optional registers can be left off the
> @@ -9737,6 +9780,7 @@ Specify the serial device it is connecte
>    remote_ops.to_get_raw_trace_data = remote_get_raw_trace_data;
>    remote_ops.to_set_disconnected_tracing =
> remote_set_disconnected_tracing;
>    remote_ops.to_core_of_thread = remote_core_of_thread;
> +  remote_ops.to_get_tib_address = remote_get_tib_address;
>  }
> 
>  /* Set up the extended remote vector by making a copy of the standard
> @@ -10156,6 +10200,10 @@ Show the maximum size of the address (in
>  			 "qGetTLSAddr", "get-thread-local-storage-address",
>  			 0);
> 
> +  add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTIBAddr],
> +			 "qGetTIBAddr",
> "get-thread-information-block-address",
> +			 0);
> +
>    add_packet_config_cmd (&remote_protocol_packets[PACKET_bc],
>  			 "bc", "reverse-continue", 0);
> 
> Index: target.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/target.c,v
> retrieving revision 1.242
> diff -u -p -r1.242 target.c
> --- target.c	12 Mar 2010 03:54:45 -0000	1.242
> +++ target.c	15 Mar 2010 21:12:45 -0000
> @@ -659,6 +659,7 @@ update_current_target (void)
>        INHERIT (to_upload_trace_state_variables, t);
>        INHERIT (to_get_raw_trace_data, t);
>        INHERIT (to_set_disconnected_tracing, t);
> +      INHERIT (to_get_tib_address, t);
>        INHERIT (to_magic, t);
>        /* Do not inherit to_memory_map.  */
>        /* Do not inherit to_flash_erase.  */
> @@ -849,6 +850,9 @@ update_current_target (void)
>    de_fault (to_set_disconnected_tracing,
>  	    (void (*) (int))
>  	    tcomplain);
> +  de_fault (to_get_tib_address,
> +	    (int (*) (ptid_t, CORE_ADDR *))
> +	    tcomplain);
>  #undef de_fault
> 
>    /* Finally, position the target-stack beneath the squashed
> Index: target.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/target.h,v
> retrieving revision 1.173
> diff -u -p -r1.173 target.h
> --- target.h	22 Feb 2010 23:35:16 -0000	1.173
> +++ target.h	15 Mar 2010 21:12:45 -0000
> @@ -673,6 +673,10 @@ struct target_ops
>         right now, or in this debug session, or for this target --
> return
> -1.  */
>      int (*to_core_of_thread) (struct target_ops *, ptid_t ptid);
> 
> +    /* Return the address of the start of the Thread Information Block
> +       a windows OS specific feature.  */
> +    int (*to_get_tib_address) (ptid_t ptid, CORE_ADDR *addr);
> +
>      int to_magic;
>      /* Need sub-structure for target machine related rather than comm
> related?
>       */
> @@ -1359,6 +1363,9 @@ extern int target_search_memory (CORE_AD
>  #define target_set_disconnected_tracing(val) \
>    (*current_target.to_set_disconnected_tracing) (val)
> 
> +#define target_get_tib_address(ptid, addr) \
> +  (*current_target.to_get_tib_address) ((ptid), (addr))
> +
>  /* Command logging facility.  */
> 
>  #define target_log_command(p)
\
> Index: windows-nat.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/windows-nat.c,v
> retrieving revision 1.207
> diff -u -p -r1.207 windows-nat.c
> --- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
> +++ windows-nat.c	15 Mar 2010 21:12:46 -0000
> @@ -191,6 +191,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;
> @@ -320,7 +321,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;
> @@ -335,6 +336,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);
> @@ -1074,15 +1076,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 (\
> @@ -1271,9 +1264,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;
>  }
> 
> @@ -1447,7 +1442,9 @@ 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:
> @@ -1481,7 +1478,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;
> 
> @@ -2266,6 +2264,26 @@ windows_xfer_partial (struct target_ops
>      }
>  }
> 
> +/* Provide thead local base, i.e. Thread Information Block address.
> */
> +/* Returns 1 if ptid is found and thread_local_base is non zero.  */
> +int
> +windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
> +{
> +  thread_info *th;
> +
> +  th = thread_rec (ptid_get_tid (ptid), 0);
> +  if (th == NULL)
> +    return 0;
> +
> +  if (addr)
> +    {
> +      *addr = (CORE_ADDR) th->thread_local_base;
> +    }
> +  if (th->thread_local_base)
> +    return 1;
> +  return 0;
> +}
> +
>  static ptid_t
>  windows_get_ada_task_ptid (long lwp, long thread)
>  {
> @@ -2314,6 +2332,7 @@ init_windows_ops (void)
>    windows_ops.to_has_execution = default_child_has_execution;
>    windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
>    windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
> +  windows_ops.to_get_tib_address = windows_get_tib_address;
> 
>    i386_use_watchpoints (&windows_ops);
> 
> @@ -2415,9 +2434,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.5
> diff -u -p -r1.5 windows-tdep.c
> --- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
> +++ windows-tdep.c	15 Mar 2010 21:12:46 -0000
> @@ -19,6 +19,361 @@
>  #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 active_rpc_handle;			/* %fs:0x0028 */
> +    uint32_t thread_local_storage;		/* %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 */
> +    uint64_t environment_pointer;		/* %gs:0x0038 */
> +    uint64_t process_id;			/* %gs:0x0040 */
> +    uint64_t current_thread_id;			/* %gs:0x0048 */
> +    uint64_t active_rpc_handle;			/* %gs:0x0050 */
> +    uint64_t thread_local_storage;		/* %gs:0x0058 */
> +    uint64_t process_environment_block;		/* %gs:0x0060 */
> +    uint64_t last_error_number;			/* %gs:0x0068 */
> +  }
> +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 */
> +    " active_rpc_handle           ",	/* %fs:0x0028 */
> +    " thread_local_storage        ",	/* %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, *dword32_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");
> +  dword32_type = arch_integer_type (gdbarch, 32,
> +				 1, "DWORD32");
> +  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", dword32_type);
> +  append_composite_type_field (peb_ldr_type, "initialized",
> dword32_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 active_rpc_handle;		%fs:0x0028 */
> +  append_composite_type_field (tib_type, "active_rpc_handle",
> dword_ptr_type);
> +  /* uint32_t thread_local_storage;		%fs:0x002c */
> +  append_composite_type_field (tib_type, "thread_local_storage",
> void_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 *val)
> +{
> +  CORE_ADDR tlb;
> +  ULONGEST num;
> +  struct type *type = check_typedef (value_type (val));
> +  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch
> (type));
> +  struct value *parent = value_parent (val);
> +  LONGEST offset = value_offset (val);
> +  int length = TYPE_LENGTH (type);
> +
> +  /* This needs to be changed if multi-process support is added.  */
> +
> +  if (!target_get_tib_address (inferior_ptid, &tlb))
> +    error (_("Unable to read tlb"));
> +  num = (ULONGEST) tlb;
> +  store_unsigned_integer (value_contents_raw (val), length,
> byte_order,
> num);
> +}
> +
> +/* 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 (ptid_t ptid)
> +{
> +#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.  */
> +
> +  if (target_get_tib_address (ptid, &thread_local_base) == 0)
> +    {
> +      printf_filtered ("Unable to get thread local base for ThreadId
> %s\n",
> +	pulongest (ptid_get_tid(ptid)));
> +      return -1;
> +    }
> +
> +  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 (ptid_get_tid (ptid)),
> +	paddress (target_gdbarch, thread_local_base));
> +      return -1;
> +    }
> +
> +  printf_filtered ("Thread Information Block %s at %s\n",
> +		   pulongest (ptid_get_tid (ptid)),
> +		   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 (ptid_build (ptid_get_pid (inferior_ptid), 0,
> id));
> +    }
> +  else if (!ptid_equal (inferior_ptid, null_ptid))
> +    display_one_tib (inferior_ptid);
> +}
> 
>  void
>  windows_xfer_shared_library (const char* so_name, CORE_ADDR load_addr,
> @@ -36,3 +391,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.4
> diff -u -p -r1.4 windows-tdep.h
> --- windows-tdep.h	1 Jan 2010 07:31:46 -0000	1.4
> +++ windows-tdep.h	15 Mar 2010 21:12:46 -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: doc/gdb.texinfo
> ===================================================================
> RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
> retrieving revision 1.680
> diff -u -p -r1.680 gdb.texinfo
> --- doc/gdb.texinfo	12 Mar 2010 19:15:52 -0000	1.680
> +++ doc/gdb.texinfo	15 Mar 2010 21:13:00 -0000
> @@ -8050,6 +8050,14 @@ The variable @code{$_siginfo} contains e
>  (@pxref{extra signal information}).  Note that @code{$_siginfo}
>  could be empty, if the application has not yet received any signals.
>  For example, it will be empty before you execute the @code{run}
> command.
> +
> +@item $_tlb
> +@vindex $_tlb@r{, convenience variable}
> +The variable @code{$_tlb} is automatically set for Windows OS running
> +applications in native mode or connected to a gdbserver that supports
> +@code{qGetTIBAddr} requests. This variable contains the address of the
> thread
> +information block.
> +
>  @end table
> 
>  On HP-UX systems, if you refer to a function or variable name that
> @@ -15692,6 +15700,10 @@ are:
>  @tab @code{qGetTLSAddr}
>  @tab Displaying @code{__thread} variables
> 
> +@item @code{w32 thread-information-block}
> +@tab @code{qGetTIBAddr}
> +@tab Display Windows OS Thread Information Block.
> +
>  @item @code{search-memory}
>  @tab @code{qSearch:memory}
>  @tab @code{find}
> @@ -16471,6 +16483,11 @@ a long value to give the information abo
>  Without argument, this command displays information
>  about the six segment registers.
> 
> +@item info w32 thread-information-block
> +This command displays thread specific information stored in the
> +Thread Information Block (readable using @code{$fs} selector for 32-
> bit
> +programs and @code{$gs} for 64-bit programs).
> +
>  @kindex info dll
>  @item info dll
>  This is a Cygwin-specific alias of @code{info shared}.
> @@ -28875,6 +28892,14 @@ enabled, the debug registers values are
>  removes a hardware breakpoint or watchpoint, and when the inferior
>  triggers a hardware-assisted breakpoint or watchpoint.
> 
> +@kindex maint set show-all-tib
> +@kindex maint show show-all-tib
> +@item maint set show-all-tib
> +@itemx maint show show-all-tib
> +Control whether to show all non zero areas within a 1k block starting
> +at thread local base, when using @samp{info w32 thread-information-
> block}
> +command.
> +
>  @kindex maint space
>  @cindex memory used by commands
>  @item maint space
> @@ -30088,6 +30113,28 @@ An error occurred.  @var{nn} are hex dig
>  An empty reply indicates that @samp{qGetTLSAddr} is not supported by
> the
> stub.
>  @end table
> 
> +@item qGetTIBAddr:@var{thread-id}:
> +@cindex get thread information block address
> +@cindex @samp{qGetTIBAddr} packet
> +Fetch address of the Windows OS specific Thread Information Block.
> +
> +@var{thread-id} is the thread ID associated with the thread.
> +
> +Reply:
> +@table @samp
> +@item @var{XX}@dots{}
> +Hex encoded (big endian) bytes representing the linear address of the
> +thread information block.
> +
> +@item E @var{nn}
> +An error occured. This means that either the thread was not found, or
> the
> +address could not be retrieved.
> +
> +@item
> +An empty reply indicates that @samp{qGetTIBAddr} is not supported by
> the
> stub.
> +@end table
> +
> +
>  @item qL @var{startflag} @var{threadcount} @var{nextthread}
>  Obtain thread information from RTOS.  Where: @var{startflag} (one hex
>  digit) is one to indicate the first query and zero to indicate a
> Index: gdbserver/server.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
> retrieving revision 1.108
> diff -u -p -r1.108 server.c
> --- gdbserver/server.c	20 Jan 2010 22:55:38 -0000	1.108
> +++ gdbserver/server.c	15 Mar 2010 21:13:01 -0000
> @@ -1280,6 +1280,9 @@ handle_query (char *own_buf, int packet_
>        if (the_target->qxfer_osdata != NULL)
>  	strcat (own_buf, ";qXfer:osdata:read+");
> 
> +      if (the_target->get_tib_address != NULL)
> +	strcat (own_buf, ";qGetTIBAddr+");
> +
>        if (target_supports_multi_process ())
>  	strcat (own_buf, ";multiprocess+");
> 
> @@ -1356,6 +1359,31 @@ handle_query (char *own_buf, int packet_
>        /* Otherwise, pretend we do not understand this packet.  */
>      }
> 
> +  /* Windows OS Thread Information Block address support.  */
> +  if (the_target->get_tib_address != NULL
> +      && strncmp ("qGetTIBAddr:", own_buf, 12) == 0)
> +    {
> +      char *annex;
> +      int n;
> +      CORE_ADDR tlb;
> +      ptid_t ptid = read_ptid (own_buf + 12, &annex);
> +
> +      n = (*the_target->get_tib_address) (ptid, &tlb);
> +      if (n == 1)
> +	{
> +	  sprintf (own_buf, "%llx", tlb);
> +	  return;
> +	}
> +      else if (n == 0)
> +	{
> +	  write_enn (own_buf);
> +	  return;
> +	}
> +      return;
> +    }
> +
> +
> +
>    /* Handle "monitor" commands.  */
>    if (strncmp ("qRcmd,", own_buf, 6) == 0)
>      {
> Index: gdbserver/target.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
> retrieving revision 1.43
> diff -u -p -r1.43 target.h
> --- gdbserver/target.h	20 Jan 2010 22:55:38 -0000	1.43
> +++ gdbserver/target.h	15 Mar 2010 21:13:01 -0000
> @@ -267,6 +267,9 @@ struct target_ops
>  			unsigned const char *writebuf,
>  			CORE_ADDR offset, int len);
> 
> +  /* Read Thread Information Block address.  */
> +  int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address);
> +
>    int (*supports_non_stop) (void);
> 
>    /* Enables async target events.  Returns the previous enable
> Index: gdbserver/win32-low.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v
> retrieving revision 1.43
> diff -u -p -r1.43 win32-low.c
> --- gdbserver/win32-low.c	20 Jan 2010 22:55:38 -0000	1.43
> +++ gdbserver/win32-low.c	15 Mar 2010 21:13:01 -0000
> @@ -178,7 +178,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);
> @@ -189,6 +189,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 *)
> @@ -1449,7 +1450,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:
> @@ -1479,7 +1481,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
> @@ -1750,6 +1753,22 @@ wince_hostio_last_error (char *buf)
>  }
>  #endif
> 
> +/* Write Windows OS Thread Information Block address.  */
> +static int
> +win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
> +{
> +  win32_thread_info *th;
> +  th = thread_rec (ptid, 0);
> +  if (th == NULL)
> +    return 0;
> +  if (addr)
> +    *addr = (CORE_ADDR) th->thread_local_base;
> +  if (th->thread_local_base)
> +    return 1;
> +  return 0;
> +}
> +
> +
>  static struct target_ops win32_target_ops = {
>    win32_create_inferior,
>    win32_attach,
> @@ -1778,6 +1797,9 @@ static struct target_ops win32_target_op
>  #else
>    hostio_last_error_from_errno,
>  #endif
> +  NULL,
> +  NULL,
> +  win32_get_tib_address,
>  };
> 
>  /* Initialize the Win32 backend.  */
> Index: gdbserver/win32-low.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v
> retrieving revision 1.12
> diff -u -p -r1.12 win32-low.h
> --- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
> +++ gdbserver/win32-low.h	15 Mar 2010 21:13:01 -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;
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING][RFC-v4] Add windows OS Thread Information Block
  2010-04-01  9:41                         ` [PING][RFC-v4] " Pierre Muller
@ 2010-04-01 11:21                           ` Pedro Alves
  2010-04-01 12:57                             ` [RFC-v5] " Pierre Muller
  0 siblings, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2010-04-01 11:21 UTC (permalink / raw)
  To: gdb-patches; +Cc: Pierre Muller

On Thursday 01 April 2010 10:40:50, Pierre Muller wrote:
>   I am still waiting for a comment from any global
> maintainer concerning the non-(windows specific) parts
> of that patch. Christopher approved the windows part.

It is my intention to look at it.  It's taking me a
bit because it's biggish.  On a quick look (not a formal
review) I saw:

 - what looked like some mixed over returning the TIB
   or the TLB.  E.g.:

> +/* Write Windows OS Thread Information Block address.  */
> +static int
> +win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
             ^^^
> +{
> +  win32_thread_info *th;
> +  th = thread_rec (ptid, 0);
> +  if (th == NULL)
> +    return 0;
> +  if (addr)
> +    *addr = (CORE_ADDR) th->thread_local_base;
> +  if (th->thread_local_base)
         ^^^^^^^^^^^^^^^^^^^^^
> +    return 1;

  Does the new packet return the TIB, or the TLB?
  The object is $_tlb now, isn't it?

> > +tlb_value_read (struct value *val)
> > +{
...
> > +  if (!target_get_tib_address (inferior_ptid, &tlb))
> > +    error (_("Unable to read tlb"));

  Either this is quite confused, or I am.



 - Assumptions that GDB thread ids are always the
   same as Win32 threads ids.

> > +/* 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 (ptid_build (ptid_get_pid (inferior_ptid), 0,
> > id));


> > +  if (target_get_tib_address (ptid, &thread_local_base) == 0)
> > +    {
> > +      printf_filtered ("Unable to get thread local base for ThreadId
> > %s\n",
> > +     pulongest (ptid_get_tid(ptid)));
> > +      return -1;

There's no garantee the TID field of ptid matches a windows
thread id , particularly when remote debugging (read: that
it will always be that way).  Do you really need to make this
bypass the internal GDB thread id?  It would avoid pain if
this always worked with the GDB thread id instead.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [RFC-v5] Add windows OS Thread Information Block
  2010-04-01 11:21                           ` Pedro Alves
@ 2010-04-01 12:57                             ` Pierre Muller
  2010-04-01 13:21                               ` Pedro Alves
  2010-04-11 15:10                               ` Pedro Alves
  0 siblings, 2 replies; 34+ messages in thread
From: Pierre Muller @ 2010-04-01 12:57 UTC (permalink / raw)
  To: 'Pedro Alves', gdb-patches



> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Pedro Alves
> Envoyé : Thursday, April 01, 2010 1:22 PM
> À : gdb-patches@sourceware.org
> Cc : Pierre Muller
> Objet : Re: [PING][RFC-v4] Add windows OS Thread Information Block
> 
> On Thursday 01 April 2010 10:40:50, Pierre Muller wrote:
> >   I am still waiting for a comment from any global
> > maintainer concerning the non-(windows specific) parts
> > of that patch. Christopher approved the windows part.
> 
> It is my intention to look at it.  It's taking me a
> bit because it's biggish.  

  I know, but it is difficult to subdivise it.

> On a quick look (not a formal
> review) I saw:
> 
>  - what looked like some mixed over returning the TIB
>    or the TLB.  E.g.:
> 
> > +/* Write Windows OS Thread Information Block address.  */
> > +static int
> > +win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
              ^^^
  which could also be called
    win32_get_tlb (see below).

> > +{
> > +  win32_thread_info *th;
> > +  th = thread_rec (ptid, 0);
> > +  if (th == NULL)
> > +    return 0;
> > +  if (addr)
> > +    *addr = (CORE_ADDR) th->thread_local_base;
> > +  if (th->thread_local_base)
>          ^^^^^^^^^^^^^^^^^^^^^
> > +    return 1;
> 
>   Does the new packet return the TIB, or the TLB?
  The thread local base is the address of
the Thread Information Block which itself 
is a block of memory (usually of size 0x1000)
containing thread specific information.

>   The object is $_tlb now, isn't it?
  This object is a pointer in debuggee memory
to the Thread Information Block. 


 
> > > +tlb_value_read (struct value *val)
> > > +{
> ...
> > > +  if (!target_get_tib_address (inferior_ptid, &tlb))
> > > +    error (_("Unable to read tlb"));
> 
>   Either this is quite confused, or I am.

  Should I remove convert all tib_address into tlb,
would that make things less confusing?
  tlb and tib are still two different things,
tlb is a pointer to tib, but this pointer is the only thing 
that needs to be fetch by special means,
the Thread Information Block is in the usual debuggee memory,
and can be read using usual ???_xfer_memory type functions.
 
>  - Assumptions that GDB thread ids are always the
>    same as Win32 threads ids.

  No, version 4 patch does really required the
windows OS thread Id to work not the GDB thread Id.
  The new version below, is changed to 
use internal GDB thread Ids.

> > > +/* 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 (ptid_build (ptid_get_pid (inferior_ptid),
> 0,
> > > id));
> 
> 
> > > +  if (target_get_tib_address (ptid, &thread_local_base) == 0)
> > > +    {
> > > +      printf_filtered ("Unable to get thread local base for
> ThreadId
> > > %s\n",
> > > +     pulongest (ptid_get_tid(ptid)));
> > > +      return -1;
> 
> There's no garantee the TID field of ptid matches a windows
> thread id , particularly when remote debugging (read: that
> it will always be that way).  
  Older gdbservers that don't support the new query packet 'qGetTIBAddr' 
would fail anyhow, and current gdbserver implementation does have this issue

anymore, or do I miss something?

> Do you really need to make this
> bypass the internal GDB thread id?  It would avoid pain if
> this always worked with the GDB thread id instead.

  I did modify the user interface to use GDB internal thread Ids.

  I wonder if I also need to change the first parameter of 
get_tib_address function to just accept the gdb thread id 
number. But I do not see any benefit from it.

Here is an updated patch (I got some conflicts when
I tried to reapply of today's CVS version 4 I submitted).
Other than line changes, the only modification 
is for 
'info w32 thread-information-block XX'
will now interpret XX as an internal GDB thread Id.

Pierre


2010-03-15  Pierre Muller  <muller@ics.u-strasbg.fr>

	* remote.c (PACKET_qGetTIBAddr): New enum element.
	(remote_get_tib_address): New function.
	(init_remote_ops): Set TO_GET_TIB_ADDRESS field
	to remote_get_tib_address.
	(_initialize_remote): Add add_packet_config_cmd
	for PACKET_qGetTIBAddr.
	* target.c (update_current_target): Set default value for
	new TO_GET_TIB_ADDRESS field.
	* target.h (target_ops): New field TO_GET_TIB_ADDRESS.
	(target_get_tib_address): New macro.
	
	* windows-nat.c (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_get_tib_address): New function.
	(init_windows_ops): Set TO_GET_TIB_ADDRESS field
	to remote_get_tib_address.
	(_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:

	* server.c (handle_query): Acknowledge support
	for 'qGetTIBAddr' if GET_TIB_ADDR field of THE_TARGET
	is set.
	Handle 'qGetTIBAddr' query.
	* target.h (target_ops): New GET_TIB_ADDRESS field.
	* win32-low.h (win32_thread_info): Add THREAD_LOCAL_BASE field.
	* win32-low.c (child_add_thread): Add TLB argument.
	Set THREAD_LOCAL_BASE field to TLB argument.
	(get_child_debug_event): Adapt to child_add_thread change.
	(win32_get_tib_address): New function.
	(win32_target_ops): Set GET_TIB_ADDRESS field to
	win32_get_tib_address
	

doc/ChangeLog entry:

	gdb.texinfo ($__tlb): Document new automatic convience variable.
	(info w32 thread-information-block): Docmuent new command.
	(qGetTIBAddress): Document new gdbserver query.
	(maint set/show show-all-tib): Document new command.

Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.397
diff -u -p -r1.397 remote.c
--- remote.c	31 Mar 2010 14:36:41 -0000	1.397
+++ remote.c	1 Apr 2010 12:46:43 -0000
@@ -1139,6 +1139,7 @@ enum {
   PACKET_qXfer_spu_write,
   PACKET_qXfer_osdata,
   PACKET_qXfer_threads,
+  PACKET_qGetTIBAddr,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
   PACKET_QPassSignals,
@@ -8441,6 +8442,48 @@ remote_get_thread_local_address (struct 
   return 0;
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.  */
+/* Returns 1 if ptid is found and thread_local_base is non zero.  */
+int
+remote_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  if (remote_protocol_packets[PACKET_qGetTIBAddr].support !=
PACKET_DISABLE)
+    {
+      struct remote_state *rs = get_remote_state ();
+      char *p = rs->buf;
+      char *endp = rs->buf + get_remote_packet_size ();
+      enum packet_result result;
+
+      strcpy (p, "qGetTIBAddr:");
+      p += strlen (p);
+      p = write_ptid (p, endp, ptid);
+      *p++ = '\0';
+
+      putpkt (rs->buf);
+      getpkt (&rs->buf, &rs->buf_size, 0);
+      result = packet_ok (rs->buf,
+			  &remote_protocol_packets[PACKET_qGetTIBAddr]);
+      if (result == PACKET_OK)
+	{
+	  ULONGEST result;
+
+	  unpack_varlen_hex (rs->buf, &result);
+	  if (addr)
+	    *addr = (CORE_ADDR) result;
+	  return 1;
+	}
+      else if (result == PACKET_UNKNOWN)
+	error (_("Remote target doesn't support qGetTIBAddr packet"));
+      else
+	error (_("Remote target failed to process qGetTIBAddr request"));
+    }
+  else
+    error (_("qGetTIBAddr not supported or disabled on this target"));
+  /* Not reached.  */
+  return 0;
+}
+
+
 /* Support for inferring a target description based on the current
    architecture and the size of a 'g' packet.  While the 'g' packet
    can have any size (since optional registers can be left off the
@@ -9885,6 +9928,8 @@ Specify the serial device it is connecte
   remote_ops.to_set_circular_trace_buffer =
remote_set_circular_trace_buffer;
   remote_ops.to_core_of_thread = remote_core_of_thread;
   remote_ops.to_verify_memory = remote_verify_memory;
+  remote_ops.to_get_tib_address = remote_get_tib_address;
+ 
 }
 
 /* Set up the extended remote vector by making a copy of the standard
@@ -10304,6 +10349,10 @@ Show the maximum size of the address (in
 			 "qGetTLSAddr", "get-thread-local-storage-address",
 			 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTIBAddr],
+			 "qGetTIBAddr",
"get-thread-information-block-address",
+			 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_bc],
 			 "bc", "reverse-continue", 0);
 
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.245
diff -u -p -r1.245 target.c
--- target.c	24 Mar 2010 01:12:13 -0000	1.245
+++ target.c	1 Apr 2010 12:46:44 -0000
@@ -660,6 +660,7 @@ update_current_target (void)
       INHERIT (to_get_raw_trace_data, t);
       INHERIT (to_set_disconnected_tracing, t);
       INHERIT (to_set_circular_trace_buffer, t);
+      INHERIT (to_get_tib_address, t);
       INHERIT (to_magic, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
@@ -853,6 +854,9 @@ update_current_target (void)
   de_fault (to_set_circular_trace_buffer,
 	    (void (*) (int))
 	    target_ignore);
+  de_fault (to_get_tib_address,
+	    (int (*) (ptid_t, CORE_ADDR *))
+	    tcomplain);
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.177
diff -u -p -r1.177 target.h
--- target.h	24 Mar 2010 01:12:13 -0000	1.177
+++ target.h	1 Apr 2010 12:46:45 -0000
@@ -682,6 +682,10 @@ struct target_ops
     int (*to_verify_memory) (struct target_ops *, const gdb_byte *data,
 			     CORE_ADDR memaddr, ULONGEST size);
 
+    /* Return the address of the start of the Thread Information Block
+       a windows OS specific feature.  */
+    int (*to_get_tib_address) (ptid_t ptid, CORE_ADDR *addr);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm
related?
      */
@@ -1371,6 +1375,9 @@ extern int target_search_memory (CORE_AD
 #define	target_set_circular_trace_buffer(val)	\
   (*current_target.to_set_circular_trace_buffer) (val)
 
+#define target_get_tib_address(ptid, addr) \
+  (*current_target.to_get_tib_address) ((ptid), (addr))
+
 /* Command logging facility.  */
 
 #define target_log_command(p)						\
Index: windows-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/windows-nat.c,v
retrieving revision 1.207
diff -u -p -r1.207 windows-nat.c
--- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
+++ windows-nat.c	1 Apr 2010 12:46:45 -0000
@@ -191,6 +191,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;
@@ -320,7 +321,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;
@@ -335,6 +336,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);
@@ -1074,15 +1076,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 (\
@@ -1271,9 +1264,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;
 }
 
@@ -1447,7 +1442,9 @@ 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:
@@ -1481,7 +1478,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;
 
@@ -2266,6 +2264,26 @@ windows_xfer_partial (struct target_ops 
     }
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.  */
+/* Returns 1 if ptid is found and thread_local_base is non zero.  */
+int
+windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  thread_info *th;
+
+  th = thread_rec (ptid_get_tid (ptid), 0);
+  if (th == NULL)
+    return 0;
+
+  if (addr)
+    {
+      *addr = (CORE_ADDR) th->thread_local_base;
+    }
+  if (th->thread_local_base)
+    return 1;
+  return 0;
+}
+
 static ptid_t
 windows_get_ada_task_ptid (long lwp, long thread)
 {
@@ -2314,6 +2332,7 @@ init_windows_ops (void)
   windows_ops.to_has_execution = default_child_has_execution;
   windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
   windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
+  windows_ops.to_get_tib_address = windows_get_tib_address;
 
   i386_use_watchpoints (&windows_ops);
 
@@ -2415,9 +2434,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.5
diff -u -p -r1.5 windows-tdep.c
--- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
+++ windows-tdep.c	1 Apr 2010 12:46:45 -0000
@@ -19,6 +19,372 @@
 #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"
+#include "gdbthread.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 active_rpc_handle;			/* %fs:0x0028 */
+    uint32_t thread_local_storage;		/* %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 */
+    uint64_t environment_pointer;		/* %gs:0x0038 */
+    uint64_t process_id;			/* %gs:0x0040 */
+    uint64_t current_thread_id;			/* %gs:0x0048 */
+    uint64_t active_rpc_handle;			/* %gs:0x0050 */
+    uint64_t thread_local_storage;		/* %gs:0x0058 */
+    uint64_t process_environment_block;		/* %gs:0x0060 */
+    uint64_t last_error_number;			/* %gs:0x0068 */
+  }
+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 */
+    " active_rpc_handle           ",	/* %fs:0x0028 */
+    " thread_local_storage        ",	/* %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, *dword32_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");
+  dword32_type = arch_integer_type (gdbarch, 32,
+				 1, "DWORD32");
+  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", dword32_type);
+  append_composite_type_field (peb_ldr_type, "initialized", dword32_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 active_rpc_handle;		%fs:0x0028 */
+  append_composite_type_field (tib_type, "active_rpc_handle",
dword_ptr_type);
+  /* uint32_t thread_local_storage;		%fs:0x002c */
+  append_composite_type_field (tib_type, "thread_local_storage",
void_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 *val)
+{
+  CORE_ADDR tlb;
+  ULONGEST num;
+  struct type *type = check_typedef (value_type (val));
+  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+  struct value *parent = value_parent (val);
+  LONGEST offset = value_offset (val);
+  int length = TYPE_LENGTH (type);
+
+  /* This needs to be changed if multi-process support is added.  */
+
+  if (!target_get_tib_address (inferior_ptid, &tlb))
+    error (_("Unable to read tlb"));
+  num = (ULONGEST) tlb;
+  store_unsigned_integer (value_contents_raw (val), length, byte_order,
num);
+}
+
+/* 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 (ptid_t ptid)
+{
+#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.  */
+
+  if (target_get_tib_address (ptid, &thread_local_base) == 0)
+    {
+      printf_filtered ("Unable to get thread local base for ThreadId %s\n",
+	pulongest (ptid_get_tid(ptid)));
+      return -1;
+    }
+
+  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 (ptid_get_tid (ptid)), 
+	paddress (target_gdbarch, thread_local_base));
+      return -1;
+    }
+
+  printf_filtered ("Thread Information Block %s at %s\n",
+		   pulongest (ptid_get_tid (ptid)),
+		   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)
+    {
+      struct thread_info *tp;
+      int gdb_id = value_as_long (parse_and_eval (args));
+
+      tp = find_thread_id (gdb_id);
+
+      if (!tp)
+	error (_("Thread ID %d not known."), gdb_id);
+
+      if (!target_thread_alive (tp->ptid))
+	error (_("Thread ID %d has terminated."), gdb_id);
+
+      display_one_tib (tp->ptid);
+    }
+  else if (!ptid_equal (inferior_ptid, null_ptid))
+    display_one_tib (inferior_ptid);
+}
 
 void
 windows_xfer_shared_library (const char* so_name, CORE_ADDR load_addr,
@@ -36,3 +402,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.4
diff -u -p -r1.4 windows-tdep.h
--- windows-tdep.h	1 Jan 2010 07:31:46 -0000	1.4
+++ windows-tdep.h	1 Apr 2010 12:46:45 -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: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.692
diff -u -p -r1.692 gdb.texinfo
--- doc/gdb.texinfo	31 Mar 2010 12:19:52 -0000	1.692
+++ doc/gdb.texinfo	1 Apr 2010 12:46:53 -0000
@@ -8054,6 +8054,14 @@ The variable @code{$_siginfo} contains e
 (@pxref{extra signal information}).  Note that @code{$_siginfo}
 could be empty, if the application has not yet received any signals.
 For example, it will be empty before you execute the @code{run} command.
+
+@item $_tlb
+@vindex $_tlb@r{, convenience variable}
+The variable @code{$_tlb} is automatically set for Windows OS running
+applications in native mode or connected to a gdbserver that supports
+@code{qGetTIBAddr} requests. This variable contains the address of the
thread
+information block.
+
 @end table
 
 On HP-UX systems, if you refer to a function or variable name that
@@ -15729,6 +15737,10 @@ are:
 @tab @code{qGetTLSAddr}
 @tab Displaying @code{__thread} variables
 
+@item @code{w32 thread-information-block}
+@tab @code{qGetTIBAddr}
+@tab Display Windows OS Thread Information Block.
+
 @item @code{search-memory}
 @tab @code{qSearch:memory}
 @tab @code{find}
@@ -16508,6 +16520,11 @@ a long value to give the information abo
 Without argument, this command displays information
 about the six segment registers.
 
+@item info w32 thread-information-block
+This command displays thread specific information stored in the
+Thread Information Block (readable using @code{$fs} selector for 32-bit
+programs and @code{$gs} for 64-bit programs).
+
 @kindex info dll
 @item info dll
 This is a Cygwin-specific alias of @code{info shared}.
@@ -29173,6 +29190,14 @@ enabled, the debug registers values are 
 removes a hardware breakpoint or watchpoint, and when the inferior
 triggers a hardware-assisted breakpoint or watchpoint.
 
+@kindex maint set show-all-tib
+@kindex maint show show-all-tib
+@item maint set show-all-tib
+@itemx maint show show-all-tib
+Control whether to show all non zero areas within a 1k block starting
+at thread local base, when using @samp{info w32 thread-information-block}
+command.
+
 @kindex maint space
 @cindex memory used by commands
 @item maint space
@@ -30386,6 +30411,28 @@ An error occurred.  @var{nn} are hex dig
 An empty reply indicates that @samp{qGetTLSAddr} is not supported by the
stub.
 @end table
 
+@item qGetTIBAddr:@var{thread-id}:
+@cindex get thread information block address
+@cindex @samp{qGetTIBAddr} packet
+Fetch address of the Windows OS specific Thread Information Block.
+
+@var{thread-id} is the thread ID associated with the thread.
+
+Reply:
+@table @samp
+@item @var{XX}@dots{}
+Hex encoded (big endian) bytes representing the linear address of the
+thread information block.
+
+@item E @var{nn}
+An error occured. This means that either the thread was not found, or the
+address could not be retrieved.
+
+@item
+An empty reply indicates that @samp{qGetTIBAddr} is not supported by the
stub.
+@end table
+
+
 @item qL @var{startflag} @var{threadcount} @var{nextthread}
 Obtain thread information from RTOS.  Where: @var{startflag} (one hex
 digit) is one to indicate the first query and zero to indicate a
Index: gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.110
diff -u -p -r1.110 server.c
--- gdbserver/server.c	24 Mar 2010 00:14:54 -0000	1.110
+++ gdbserver/server.c	1 Apr 2010 12:46:54 -0000
@@ -1321,6 +1321,9 @@ handle_query (char *own_buf, int packet_
       if (the_target->qxfer_osdata != NULL)
 	strcat (own_buf, ";qXfer:osdata:read+");
 
+      if (the_target->get_tib_address != NULL)
+	strcat (own_buf, ";qGetTIBAddr+");
+
       if (target_supports_multi_process ())
 	strcat (own_buf, ";multiprocess+");
 
@@ -1397,6 +1400,31 @@ handle_query (char *own_buf, int packet_
       /* Otherwise, pretend we do not understand this packet.  */
     }
 
+  /* Windows OS Thread Information Block address support.  */
+  if (the_target->get_tib_address != NULL
+      && strncmp ("qGetTIBAddr:", own_buf, 12) == 0)
+    {
+      char *annex;
+      int n;
+      CORE_ADDR tlb;
+      ptid_t ptid = read_ptid (own_buf + 12, &annex);
+
+      n = (*the_target->get_tib_address) (ptid, &tlb);
+      if (n == 1)
+	{
+	  sprintf (own_buf, "%llx", tlb);
+	  return;
+	}
+      else if (n == 0)
+	{
+	  write_enn (own_buf);
+	  return;
+	}
+      return;
+    }
+
+
+
   /* Handle "monitor" commands.  */
   if (strncmp ("qRcmd,", own_buf, 6) == 0)
     {
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.43
diff -u -p -r1.43 target.h
--- gdbserver/target.h	20 Jan 2010 22:55:38 -0000	1.43
+++ gdbserver/target.h	1 Apr 2010 12:46:54 -0000
@@ -267,6 +267,9 @@ struct target_ops
 			unsigned const char *writebuf,
 			CORE_ADDR offset, int len);
 
+  /* Read Thread Information Block address.  */
+  int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address);
+
   int (*supports_non_stop) (void);
 
   /* Enables async target events.  Returns the previous enable
Index: gdbserver/win32-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v
retrieving revision 1.43
diff -u -p -r1.43 win32-low.c
--- gdbserver/win32-low.c	20 Jan 2010 22:55:38 -0000	1.43
+++ gdbserver/win32-low.c	1 Apr 2010 12:46:54 -0000
@@ -178,7 +178,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);
@@ -189,6 +189,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 *)
@@ -1449,7 +1450,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:
@@ -1479,7 +1481,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
@@ -1750,6 +1753,22 @@ wince_hostio_last_error (char *buf)
 }
 #endif
 
+/* Write Windows OS Thread Information Block address.  */
+static int
+win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  win32_thread_info *th;
+  th = thread_rec (ptid, 0);
+  if (th == NULL)
+    return 0;
+  if (addr)
+    *addr = (CORE_ADDR) th->thread_local_base;
+  if (th->thread_local_base)
+    return 1;
+  return 0;
+}
+
+
 static struct target_ops win32_target_ops = {
   win32_create_inferior,
   win32_attach,
@@ -1778,6 +1797,9 @@ static struct target_ops win32_target_op
 #else
   hostio_last_error_from_errno,
 #endif
+  NULL,
+  NULL,
+  win32_get_tib_address,
 };
 
 /* Initialize the Win32 backend.  */
Index: gdbserver/win32-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v
retrieving revision 1.12
diff -u -p -r1.12 win32-low.h
--- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
+++ gdbserver/win32-low.h	1 Apr 2010 12:46:54 -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;
 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC-v5] Add windows OS Thread Information Block
  2010-04-01 12:57                             ` [RFC-v5] " Pierre Muller
@ 2010-04-01 13:21                               ` Pedro Alves
  2010-04-01 13:31                                 ` Pierre Muller
  2010-04-11 15:10                               ` Pedro Alves
  1 sibling, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2010-04-01 13:21 UTC (permalink / raw)
  To: Pierre Muller; +Cc: gdb-patches

On Thursday 01 April 2010 13:56:50, Pierre Muller wrote:
> >   Does the new packet return the TIB, or the TLB?
>   The thread local base is the address of
> the Thread Information Block which itself 
> is a block of memory (usually of size 0x1000)
> containing thread specific information.

Okay, thanks, that makes the terminology clearer.

> >   The object is $_tlb now, isn't it?
>   This object is a pointer in debuggee memory
> to the Thread Information Block. 

If the TLB is a pointer to the TIB, then if "ptype $_tlb" shows
something not a pointer, something isn't right, wouldn't
you say?  Isn't "ptype $_tlb"/"p $_tib" printing the _TIB_
instead?  This is where things are still confusing.

> +@item $_tlb
> +@vindex $_tlb@r{, convenience variable}
> +The variable @code{$_tlb} is automatically set for Windows OS running
> +applications in native mode or connected to a gdbserver that supports
> +@code{qGetTIBAddr} requests. This variable contains the address of the
> thread
> +information block.

Does the variable really contain an address?

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING][RFC-v4] Add windows OS Thread Information Block
       [not found]                         ` <001201cad17f$6a058980$3e109c80$%muller@ics-cnrs.unistra.fr>
@ 2010-04-01 13:30                           ` Eli Zaretskii
  2010-04-01 16:17                             ` Pierre Muller
       [not found]                             ` <003c01cad1b6$d69e44b0$83dace10$%muller@ics-cnrs.unistra.fr>
  0 siblings, 2 replies; 34+ messages in thread
From: Eli Zaretskii @ 2010-04-01 13:30 UTC (permalink / raw)
  To: Pierre Muller; +Cc: gdb-patches

> From: "Pierre Muller" <pierre.muller@ics-cnrs.unistra.fr>
> Date: Thu, 1 Apr 2010 11:40:50 +0200
> 
>   I am still waiting for a comment from any global
> maintainer concerning the non-(windows specific) parts
> of that patch. Christopher approved the windows part.

Sorry I missed that.

> > +  if (target_get_tib_address (ptid, &thread_local_base) == 0)
> > +    {
> > +      printf_filtered ("Unable to get thread local base for ThreadId
> > %s\n",
> > +	pulongest (ptid_get_tid(ptid)));

Please add _() around the user messages.

> > +      printf_filtered ("Unable to read thread information block for
> > ThreadId %s at address %s\n",
> > +	pulongest (ptid_get_tid (ptid)),
> > +	paddress (target_gdbarch, thread_local_base));

Ditto.

> > +  printf_filtered ("Thread Information Block %s at %s\n",
> > +		   pulongest (ptid_get_tid (ptid)),
> > +		   paddress (target_gdbarch, thread_local_base));

Ditto.

> > +	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));

Ditto.

> > +      add_prefix_cmd ("w32", class_info, info_w32_command,
> > +		      _("Print information specific to Win32 debugging."),

RMS would say "don't call Windows ``a win''".

> > +If enabled, all non-zero fields of thread information block are displayed,\n\
> > +even if its meaning is unknown."),

"its" is inappropriate here, as "fields" are in plural.  I suggest
"their" instead.

> > +@item $_tlb
> > +@vindex $_tlb@r{, convenience variable}
> > +The variable @code{$_tlb} is automatically set for Windows OS running
> > +applications in native mode or connected to a gdbserver that supports

This is backwards: it makes it sound like we set the variable for
Windows, not for the application.  I suggest the following alternative
wording:

  The variable @code{$_tlb} is automatically set when debugging
  applications running on MS-Windows in native mode or connected to
  gdbserver that supports the @code{qGetTIBAddr} request.

Please also add an @xref to where the qGetTIBAddr packet is
described.

> > +@code{qGetTIBAddr} requests. This variable contains the address of the
                                ^^
Two spaces between sentences, please.

> > +@tab Display Windows OS Thread Information Block.

"Display MS-Windows Thread Information Block."

> > +An error occured. This means that either the thread was not found, or
                     ^^
Two spaces.

The patch for the manual is okay with the above changes.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* RE: [RFC-v5] Add windows OS Thread Information Block
  2010-04-01 13:21                               ` Pedro Alves
@ 2010-04-01 13:31                                 ` Pierre Muller
  2010-04-01 13:43                                   ` Pedro Alves
  0 siblings, 1 reply; 34+ messages in thread
From: Pierre Muller @ 2010-04-01 13:31 UTC (permalink / raw)
  To: 'Pedro Alves'; +Cc: gdb-patches



> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Pedro Alves
> Envoyé : Thursday, April 01, 2010 3:21 PM
> À : Pierre Muller
> Cc : gdb-patches@sourceware.org
> Objet : Re: [RFC-v5] Add windows OS Thread Information Block
> 
> On Thursday 01 April 2010 13:56:50, Pierre Muller wrote:
> > >   Does the new packet return the TIB, or the TLB?
> >   The thread local base is the address of
> > the Thread Information Block which itself
> > is a block of memory (usually of size 0x1000)
> > containing thread specific information.
> 
> Okay, thanks, that makes the terminology clearer.
> 
> > >   The object is $_tlb now, isn't it?
> >   This object is a pointer in debuggee memory
> > to the Thread Information Block.
> 
> If the TLB is a pointer to the TIB, then if "ptype $_tlb" shows
> something not a pointer, something isn't right, wouldn't
> you say?  Isn't "ptype $_tlb"/"p $_tib" printing the _TIB_
> instead?  This is where things are still confusing.

(top-gdb) start
Temporary breakpoint 3 at 0x40107a: file ../../src/gdb/gdb.c, line 28.
Starting program: /usr/local/src/gdbcvs/build-norm/gdb/gdb.exe
[New Thread 5136.0x16b4]
[New Thread 5136.0x2b4]

Temporary breakpoint 3, main (argc=1, argv=0x1d82428)
    at ../../src/gdb/gdb.c:28
28        memset (&args, 0, sizeof args);
(top-gdb) p $_tlb
$3 = (tib *) 0x7ffdf000
(top-gdb) ptyp  $_tlb
type = struct {
    seh *current_seh;
    void *current_top_of_stack;
    void *current_bottom_of_stack;
    void *sub_system_tib;
    void *fiber_data;
    void *arbitrary_data_slot;
    void *linear_address_tib;
    void *environment_pointer;
    DWORD_PTR process_id;
    DWORD_PTR thread_id;
    DWORD_PTR active_rpc_handle;
    void *thread_local_storage;
    peb *process_environment_block;
    DWORD_PTR last_error_number;
} *

  This seems correct to me.
 
> > +@item $_tlb
> > +@vindex $_tlb@r{, convenience variable}
> > +The variable @code{$_tlb} is automatically set for Windows OS
> running
> > +applications in native mode or connected to a gdbserver that
> supports
> > +@code{qGetTIBAddr} requests. This variable contains the address of
> the
> > thread
> > +information block.
> 
> Does the variable really contain an address?

  I hope the output above is enough to convince you,
to get the display of the Thread information Block you need to use
p *$_tlb

Pierre


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC-v5] Add windows OS Thread Information Block
  2010-04-01 13:31                                 ` Pierre Muller
@ 2010-04-01 13:43                                   ` Pedro Alves
  0 siblings, 0 replies; 34+ messages in thread
From: Pedro Alves @ 2010-04-01 13:43 UTC (permalink / raw)
  To: Pierre Muller; +Cc: gdb-patches

On Thursday 01 April 2010 14:31:12, Pierre Muller wrote:
>   I hope the output above is enough to convince you,
> to get the display of the Thread information Block you need to use
> p *$_tlb
> 

Urgh, I'm convinced, though surprised.  A picture is really
worth a thousand words.  :-)  I really was assuming users
wouldn't care about the address, and you'd just do "p $_tib"
to inspect the object.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* RE: [PING][RFC-v4] Add windows OS Thread Information Block
  2010-04-01 13:30                           ` [PING][RFC-v4] Add windows " Eli Zaretskii
@ 2010-04-01 16:17                             ` Pierre Muller
       [not found]                             ` <003c01cad1b6$d69e44b0$83dace10$%muller@ics-cnrs.unistra.fr>
  1 sibling, 0 replies; 34+ messages in thread
From: Pierre Muller @ 2010-04-01 16:17 UTC (permalink / raw)
  To: 'Eli Zaretskii'; +Cc: gdb-patches



> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Eli Zaretskii
> Envoyé : Thursday, April 01, 2010 3:30 PM
> À : Pierre Muller
> Cc : gdb-patches@sourceware.org
> Objet : Re: [PING][RFC-v4] Add windows OS Thread Information Block
> 
> > From: "Pierre Muller" <pierre.muller@ics-cnrs.unistra.fr>
> > Date: Thu, 1 Apr 2010 11:40:50 +0200
> >
> >   I am still waiting for a comment from any global
> > maintainer concerning the non-(windows specific) parts
> > of that patch. Christopher approved the windows part.
> 
> Sorry I missed that.
> 
> > > +  if (target_get_tib_address (ptid, &thread_local_base) == 0)
> > > +    {
> > > +      printf_filtered ("Unable to get thread local base for
> ThreadId
> > > %s\n",
> > > +	pulongest (ptid_get_tid(ptid)));
> 
> Please add _() around the user messages.
 OK. 
> > > +      add_prefix_cmd ("w32", class_info, info_w32_command,
> > > +		      _("Print information specific to Win32 debugging."),
> 
> RMS would say "don't call Windows ``a win''".

  This is just displaced code from windows-nat.c to windows-tdep.c,
so I am not sure I should touch this.
 
> > > +If enabled, all non-zero fields of thread information block are
> displayed,\n\
> > > +even if its meaning is unknown."),
> 
> "its" is inappropriate here, as "fields" are in plural.  I suggest
> "their" instead.

  I completely agree with you!

> > > +@item $_tlb
> > > +@vindex $_tlb@r{, convenience variable}
> > > +The variable @code{$_tlb} is automatically set for Windows OS
> running
> > > +applications in native mode or connected to a gdbserver that
> supports
> 
> This is backwards: it makes it sound like we set the variable for
> Windows, not for the application.  I suggest the following alternative
> wording:
> 
>   The variable @code{$_tlb} is automatically set when debugging
>   applications running on MS-Windows in native mode or connected to
>   gdbserver that supports the @code{qGetTIBAddr} request.
> 
> Please also add an @xref to where the qGetTIBAddr packet is
> described.

  The node I found is called "General Query Packets", should I refer
to this general section, or add a new node just for qGetTIBAddr?

 
> > > +@code{qGetTIBAddr} requests. This variable contains the address of
> the
>                                 ^^
> Two spaces between sentences, please.
 Disappeared with my @xref addition. 
> > > +@tab Display Windows OS Thread Information Block.
> 
> "Display MS-Windows Thread Information Block."
 OK. 
> > > +An error occured. This means that either the thread was not found,
> or
>                      ^^
> Two spaces.
  Done. 
> The patch for the manual is okay with the above changes.

  
 Thanks, I attach the modified doc/gdb.texinfo diff

Pierre



$ cvs diff -u doc/gdb.texinfo
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.693
diff -u -r1.693 gdb.texinfo
--- doc/gdb.texinfo     1 Apr 2010 14:11:23 -0000       1.693
+++ doc/gdb.texinfo     1 Apr 2010 16:07:57 -0000
@@ -8055,6 +8055,15 @@
 (@pxref{extra signal information}).  Note that @code{$_siginfo}
 could be empty, if the application has not yet received any signals.
 For example, it will be empty before you execute the @code{run} command.
+
+@item $_tlb
+@vindex $_tlb@r{, convenience variable}
+The variable @code{$_tlb} is automatically set when debugging
+applications running on MS-Windows in native mode or connected to
+gdbserver that supports the @code{qGetTIBAddr} request.
+@xref{General Query Packets}.
+This variable contains the address of the thread information block.
+
 @end table

 On HP-UX systems, if you refer to a function or variable name that
@@ -15730,6 +15739,10 @@
 @tab @code{qGetTLSAddr}
 @tab Displaying @code{__thread} variables

+@item @code{w32 thread-information-block}
+@tab @code{qGetTIBAddr}
+@tab Display MS-Windows Thread Information Block.
+
 @item @code{search-memory}
 @tab @code{qSearch:memory}
 @tab @code{find}
@@ -16509,6 +16522,11 @@
 Without argument, this command displays information
 about the six segment registers.

+@item info w32 thread-information-block
+This command displays thread specific information stored in the
+Thread Information Block (readable using @code{$fs} selector for 32-bit
+programs and @code{$gs} for 64-bit programs).
+
 @kindex info dll
 @item info dll
 This is a Cygwin-specific alias of @code{info shared}.
@@ -29174,6 +29192,14 @@
 removes a hardware breakpoint or watchpoint, and when the inferior
 triggers a hardware-assisted breakpoint or watchpoint.

+@kindex maint set show-all-tib
+@kindex maint show show-all-tib
+@item maint set show-all-tib
+@itemx maint show show-all-tib
+Control whether to show all non zero areas within a 1k block starting
+at thread local base, when using @samp{info w32 thread-information-block}
+command.
+
 @kindex maint space
 @cindex memory used by commands
 @item maint space
@@ -30387,6 +30413,28 @@
 An empty reply indicates that @samp{qGetTLSAddr} is not supported by the
stub.
 @end table

+@item qGetTIBAddr:@var{thread-id}:
+@cindex get thread information block address
+@cindex @samp{qGetTIBAddr} packet
+Fetch address of the Windows OS specific Thread Information Block.
+
+@var{thread-id} is the thread ID associated with the thread.
+
+Reply:
+@table @samp
+@item @var{XX}@dots{}
+Hex encoded (big endian) bytes representing the linear address of the
+thread information block.
+
+@item E @var{nn}
+An error occured.  This means that either the thread was not found, or the
+address could not be retrieved.
+
+@item
+An empty reply indicates that @samp{qGetTIBAddr} is not supported by the
stub.
+@end table
+
+
 @item qL @var{startflag} @var{threadcount} @var{nextthread}
 Obtain thread information from RTOS.  Where: @var{startflag} (one hex
 digit) is one to indicate the first query and zero to indicate a

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING][RFC-v4] Add windows OS Thread Information Block
       [not found]                             ` <003c01cad1b6$d69e44b0$83dace10$%muller@ics-cnrs.unistra.fr>
@ 2010-04-01 16:58                               ` Eli Zaretskii
  0 siblings, 0 replies; 34+ messages in thread
From: Eli Zaretskii @ 2010-04-01 16:58 UTC (permalink / raw)
  To: Pierre Muller; +Cc: gdb-patches

> From: "Pierre Muller" <pierre.muller@ics-cnrs.unistra.fr>
> Cc: <gdb-patches@sourceware.org>
> Date: Thu, 1 Apr 2010 18:17:34 +0200
> 
> >   The variable @code{$_tlb} is automatically set when debugging
> >   applications running on MS-Windows in native mode or connected to
> >   gdbserver that supports the @code{qGetTIBAddr} request.
> > 
> > Please also add an @xref to where the qGetTIBAddr packet is
> > described.
> 
>   The node I found is called "General Query Packets", should I refer
> to this general section, or add a new node just for qGetTIBAddr?

No need for a new node, you can use @anchor instead, to point an @xref
to any arbitrary place.  We already do that in other places in the
manual.

Okay with that change.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC-v5] Add windows OS Thread Information Block
  2010-04-01 12:57                             ` [RFC-v5] " Pierre Muller
  2010-04-01 13:21                               ` Pedro Alves
@ 2010-04-11 15:10                               ` Pedro Alves
  2010-04-12 13:52                                 ` [RFC-v6] " Pierre Muller
  1 sibling, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2010-04-11 15:10 UTC (permalink / raw)
  To: Pierre Muller; +Cc: gdb-patches

On Thursday 01 April 2010 13:56:50, Pierre Muller wrote:

> 2010-03-15  Pierre Muller  <muller@ics.u-strasbg.fr>
> 
> 	* remote.c (PACKET_qGetTIBAddr): New enum element.
> 	(remote_get_tib_address): New function.
> 	(init_remote_ops): Set TO_GET_TIB_ADDRESS field
> 	to remote_get_tib_address.
> 	(_initialize_remote): Add add_packet_config_cmd
> 	for PACKET_qGetTIBAddr.
> 	* target.c (update_current_target): Set default value for
> 	new TO_GET_TIB_ADDRESS field.
> 	* target.h (target_ops): New field TO_GET_TIB_ADDRESS.
> 	(target_get_tib_address): New macro.
> 	
> 	* windows-nat.c (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_get_tib_address): New function.
> 	(init_windows_ops): Set TO_GET_TIB_ADDRESS field
> 	to remote_get_tib_address.
> 	(_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:
> 
> 	* server.c (handle_query): Acknowledge support
> 	for 'qGetTIBAddr' if GET_TIB_ADDR field of THE_TARGET
> 	is set.
> 	Handle 'qGetTIBAddr' query.
> 	* target.h (target_ops): New GET_TIB_ADDRESS field.
> 	* win32-low.h (win32_thread_info): Add THREAD_LOCAL_BASE field.
> 	* win32-low.c (child_add_thread): Add TLB argument.
> 	Set THREAD_LOCAL_BASE field to TLB argument.
> 	(get_child_debug_event): Adapt to child_add_thread change.
> 	(win32_get_tib_address): New function.
> 	(win32_target_ops): Set GET_TIB_ADDRESS field to
> 	win32_get_tib_address

Uppercasing variables names is for talking about a
variable's _value_, not name:

http://www.gnu.org/prep/standards/standards.html#Comments:

 "The variable name itself should be lower case, but write it in upper case
 when you are speaking about the value rather than the variable itself. Thus,
 “the inode number NODE_NUM” rather than “an inode”."


> 	
> 
> doc/ChangeLog entry:
> 
> 	gdb.texinfo ($__tlb): Document new automatic convience variable.
> 	(info w32 thread-information-block): Docmuent new command.
> 	(qGetTIBAddress): Document new gdbserver query.
> 	(maint set/show show-all-tib): Document new command.

Typos: convience, Docmuent

> 
> Index: remote.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/remote.c,v
> retrieving revision 1.397
> diff -u -p -r1.397 remote.c
> --- remote.c	31 Mar 2010 14:36:41 -0000	1.397
> +++ remote.c	1 Apr 2010 12:46:43 -0000
> @@ -1139,6 +1139,7 @@ enum {
>    PACKET_qXfer_spu_write,
>    PACKET_qXfer_osdata,
>    PACKET_qXfer_threads,
> +  PACKET_qGetTIBAddr,
>    PACKET_qGetTLSAddr,
>    PACKET_qSupported,
>    PACKET_QPassSignals,
> @@ -8441,6 +8442,48 @@ remote_get_thread_local_address (struct 
>    return 0;
>  }
>  
> +/* Provide thread local base, i.e. Thread Information Block address.  */
> +/* Returns 1 if ptid is found and thread_local_base is non zero.  */
> +int

Merge both comments in a single /**/ block.  Please add an empty
line between comment and function (everywhere).

> +remote_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
> +{
> +  if (remote_protocol_packets[PACKET_qGetTIBAddr].support !=
> PACKET_DISABLE)
> +    {
> +      struct remote_state *rs = get_remote_state ();
> +      char *p = rs->buf;
> +      char *endp = rs->buf + get_remote_packet_size ();
> +      enum packet_result result;
> +
> +      strcpy (p, "qGetTIBAddr:");
> +      p += strlen (p);
> +      p = write_ptid (p, endp, ptid);
> +      *p++ = '\0';
> +
> +      putpkt (rs->buf);
> +      getpkt (&rs->buf, &rs->buf_size, 0);
> +      result = packet_ok (rs->buf,
> +			  &remote_protocol_packets[PACKET_qGetTIBAddr]);
> +      if (result == PACKET_OK)
> +	{
> +	  ULONGEST result;
> +
> +	  unpack_varlen_hex (rs->buf, &result);
> +	  if (addr)
> +	    *addr = (CORE_ADDR) result;
> +	  return 1;
> +	}
> +      else if (result == PACKET_UNKNOWN)
> +	error (_("Remote target doesn't support qGetTIBAddr packet"));
> +      else
> +	error (_("Remote target failed to process qGetTIBAddr request"));
> +    }
> +  else
> +    error (_("qGetTIBAddr not supported or disabled on this target"));
> +  /* Not reached.  */
> +  return 0;
> +}
> +
> +
>  /* Support for inferring a target description based on the current
>     architecture and the size of a 'g' packet.  While the 'g' packet
>     can have any size (since optional registers can be left off the
> @@ -9885,6 +9928,8 @@ Specify the serial device it is connecte
>    remote_ops.to_set_circular_trace_buffer =
> remote_set_circular_trace_buffer;
>    remote_ops.to_core_of_thread = remote_core_of_thread;
>    remote_ops.to_verify_memory = remote_verify_memory;
> +  remote_ops.to_get_tib_address = remote_get_tib_address;
> + 
>  }
>  
>  /* Set up the extended remote vector by making a copy of the standard
> @@ -10304,6 +10349,10 @@ Show the maximum size of the address (in
>  			 "qGetTLSAddr", "get-thread-local-storage-address",
>  			 0);
>  
> +  add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTIBAddr],
> +			 "qGetTIBAddr",
> "get-thread-information-block-address",
> +			 0);
> +

It looks like the patch got line-wrap mangled here, and
in several other places.  Could you make sure line-wrapping
is disabled when you paste patches in the email?  Thanks.


>    add_packet_config_cmd (&remote_protocol_packets[PACKET_bc],
>  			 "bc", "reverse-continue", 0);
>  
> Index: target.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/target.c,v
> retrieving revision 1.245
> diff -u -p -r1.245 target.c
> --- target.c	24 Mar 2010 01:12:13 -0000	1.245
> +++ target.c	1 Apr 2010 12:46:44 -0000
> @@ -660,6 +660,7 @@ update_current_target (void)
>        INHERIT (to_get_raw_trace_data, t);
>        INHERIT (to_set_disconnected_tracing, t);
>        INHERIT (to_set_circular_trace_buffer, t);
> +      INHERIT (to_get_tib_address, t);
>        INHERIT (to_magic, t);
>        /* Do not inherit to_memory_map.  */
>        /* Do not inherit to_flash_erase.  */
> @@ -853,6 +854,9 @@ update_current_target (void)
>    de_fault (to_set_circular_trace_buffer,
>  	    (void (*) (int))
>  	    target_ignore);
> +  de_fault (to_get_tib_address,
> +	    (int (*) (ptid_t, CORE_ADDR *))
> +	    tcomplain);
>  #undef de_fault
>  
>    /* Finally, position the target-stack beneath the squashed
> Index: target.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/target.h,v
> retrieving revision 1.177
> diff -u -p -r1.177 target.h
> --- target.h	24 Mar 2010 01:12:13 -0000	1.177
> +++ target.h	1 Apr 2010 12:46:45 -0000
> @@ -682,6 +682,10 @@ struct target_ops
>      int (*to_verify_memory) (struct target_ops *, const gdb_byte *data,
>  			     CORE_ADDR memaddr, ULONGEST size);
>  
> +    /* Return the address of the start of the Thread Information Block
> +       a windows OS specific feature.  */

Windows.

> +    int (*to_get_tib_address) (ptid_t ptid, CORE_ADDR *addr);
> +
>      int to_magic;
>      /* Need sub-structure for target machine related rather than comm
> related?
>       */
> @@ -1371,6 +1375,9 @@ extern int target_search_memory (CORE_AD
>  #define	target_set_circular_trace_buffer(val)	\
>    (*current_target.to_set_circular_trace_buffer) (val)
>  
> +#define target_get_tib_address(ptid, addr) \
> +  (*current_target.to_get_tib_address) ((ptid), (addr))
> +
>  /* Command logging facility.  */
>  
>  #define target_log_command(p)						\
> Index: windows-nat.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/windows-nat.c,v
> retrieving revision 1.207
> diff -u -p -r1.207 windows-nat.c
> --- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
> +++ windows-nat.c	1 Apr 2010 12:46:45 -0000
> @@ -191,6 +191,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;
> @@ -320,7 +321,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;
> @@ -335,6 +336,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);
> @@ -1074,15 +1076,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 (\
> @@ -1271,9 +1264,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;
>  }
>  
> @@ -1447,7 +1442,9 @@ 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:
> @@ -1481,7 +1478,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;
>  
> @@ -2266,6 +2264,26 @@ windows_xfer_partial (struct target_ops 
>      }
>  }
>  
> +/* Provide thread local base, i.e. Thread Information Block address.  */
> +/* Returns 1 if ptid is found and thread_local_base is non zero.  */
> +int

Same here regarding the /**/ merging, and empty line missing.

> +windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
> +{
> +  thread_info *th;
> +
> +  th = thread_rec (ptid_get_tid (ptid), 0);
> +  if (th == NULL)
> +    return 0;
> +
> +  if (addr)
> +    {
> +      *addr = (CORE_ADDR) th->thread_local_base;
> +    }

One line statements don't get a wrapped in {}, just
like you have correctly done above.  Drop the
cast, as the new thread_local_base field is already
a CORE_ADDR.  In one case, you've checked a pointer
against NULL, and in the other you haven't.  Please
make this all consistent:

  if (addr != NULL)
    *addr = th->thread_local_base;

> +  if (th->thread_local_base)
> +    return 1;

Style wise, it looks strange to fill *addr even when
th->thread_local_base would be 0, and hence you'd return
0 below.

> +  return 0;
> +}

Here's what I'd suggest:

  th = thread_rec (ptid_get_tid (ptid), 0);
  if (th == NULL || th->thread_local_base == 0)
    return 0;

  if (addr != NULL)
    *addr = th->thread_local_base;

  return 1;



> +
>  static ptid_t
>  windows_get_ada_task_ptid (long lwp, long thread)
>  {
> @@ -2314,6 +2332,7 @@ init_windows_ops (void)
>    windows_ops.to_has_execution = default_child_has_execution;
>    windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
>    windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
> +  windows_ops.to_get_tib_address = windows_get_tib_address;
>  
>    i386_use_watchpoints (&windows_ops);
>  
> @@ -2415,9 +2434,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.5
> diff -u -p -r1.5 windows-tdep.c
> --- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
> +++ windows-tdep.c	1 Apr 2010 12:46:45 -0000
> @@ -19,6 +19,372 @@
>  #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"
> +#include "gdbthread.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 active_rpc_handle;			/* %fs:0x0028 */
> +    uint32_t thread_local_storage;		/* %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 */
> +    uint64_t environment_pointer;		/* %gs:0x0038 */
> +    uint64_t process_id;			/* %gs:0x0040 */
> +    uint64_t current_thread_id;			/* %gs:0x0048 */
> +    uint64_t active_rpc_handle;			/* %gs:0x0050 */
> +    uint64_t thread_local_storage;		/* %gs:0x0058 */
> +    uint64_t process_environment_block;		/* %gs:0x0060 */
> +    uint64_t last_error_number;			/* %gs:0x0068 */
> +  }
> +thread_information_64;
> +
> +
> +static const
> +char* TIB_NAME[] =

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 */
> +    " active_rpc_handle           ",	/* %fs:0x0028 */
> +    " thread_local_storage        ",	/* %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;

Only functions need a line break before the function name.

> +
> +static int maint_display_all_tib = 0;
> +
> +/* Define ThreadLocalBase pointer type */

Missing period.  Two spaces after period.  Empty line between comment
and function.

> +struct type *
> +windows_get_tlb_type (struct gdbarch *gdbarch)
> +{
> +  struct type *dword_ptr_type, *dword32_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");
> +  dword32_type = arch_integer_type (gdbarch, 32,
> +				 1, "DWORD32");
> +  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.  */

Is this still 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", dword32_type);
> +  append_composite_type_field (peb_ldr_type, "initialized", dword32_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 active_rpc_handle;		%fs:0x0028 */
> +  append_composite_type_field (tib_type, "active_rpc_handle",
> dword_ptr_type);
> +  /* uint32_t thread_local_storage;		%fs:0x002c */
> +  append_composite_type_field (tib_type, "thread_local_storage",
> void_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 *val)
> +{
> +  CORE_ADDR tlb;
> +  ULONGEST num;
> +  struct type *type = check_typedef (value_type (val));
> +  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
> +  struct value *parent = value_parent (val);
> +  LONGEST offset = value_offset (val);

What are these two for?

> +  int length = TYPE_LENGTH (type);
> +
> +  /* This needs to be changed if multi-process support is added.  */
> +
> +  if (!target_get_tib_address (inferior_ptid, &tlb))
> +    error (_("Unable to read tlb"));
> +  num = (ULONGEST) tlb;
> +  store_unsigned_integer (value_contents_raw (val), length, byte_order,
> num);

This assumes `tlb' is an address, and VAL is a pointer, so, take a look
at value_from_pointer, and try doing something similar instead:
 
  store_typed_address (value_contents_raw (val), type, addr);

> +}
> +
> +/* This function implements the lval_computed support for writing a
> +   $_siginfo value.  */

Copy/paste error:  s/_siginfo/_tlb/

> +
> +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 (ptid_t ptid)
> +{
> +#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.  */

What needs changing?

> +
> +  if (target_get_tib_address (ptid, &thread_local_base) == 0)
> +    {
> +      printf_filtered ("Unable to get thread local base for ThreadId %s\n",
> +	pulongest (ptid_get_tid(ptid)));

Incomplete transition: please avoid the ptid_get_tid in common code.

> +      return -1;
> +    }
> +
> +  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 (ptid_get_tid (ptid)), 
> +	paddress (target_gdbarch, thread_local_base));

Same.  Missing i18n.

> +      return -1;
> +    }
> +
> +  printf_filtered ("Thread Information Block %s at %s\n",
> +		   pulongest (ptid_get_tid (ptid)),
> +		   paddress (target_gdbarch, thread_local_base));

Same.

> +
> +  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));

No space in array subscripting:

 TIB_NAME[i]

> +      else if (val != 0)
> +	printf_filtered ("TIB[0x%s] is 0x%s\n", phex (i*size, 2),
> +			 phex (val, size));

i18n.  Spaces missing around '*'.

> +      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)
> +    {
> +      struct thread_info *tp;
> +      int gdb_id = value_as_long (parse_and_eval (args));
> +
> +      tp = find_thread_id (gdb_id);
> +
> +      if (!tp)
> +	error (_("Thread ID %d not known."), gdb_id);
> +
> +      if (!target_thread_alive (tp->ptid))
> +	error (_("Thread ID %d has terminated."), gdb_id);
> +
> +      display_one_tib (tp->ptid);
> +    }
> +  else if (!ptid_equal (inferior_ptid, null_ptid))
> +    display_one_tib (inferior_ptid);
> +}
>  
>  void
>  windows_xfer_shared_library (const char* so_name, CORE_ADDR load_addr,
> @@ -36,3 +402,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.4
> diff -u -p -r1.4 windows-tdep.h
> --- windows-tdep.h	1 Jan 2010 07:31:46 -0000	1.4
> +++ windows-tdep.h	1 Apr 2010 12:46:45 -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: doc/gdb.texinfo
> ===================================================================
> RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
> retrieving revision 1.692
> diff -u -p -r1.692 gdb.texinfo
> --- doc/gdb.texinfo	31 Mar 2010 12:19:52 -0000	1.692
> +++ doc/gdb.texinfo	1 Apr 2010 12:46:53 -0000
> @@ -8054,6 +8054,14 @@ The variable @code{$_siginfo} contains e
>  (@pxref{extra signal information}).  Note that @code{$_siginfo}
>  could be empty, if the application has not yet received any signals.
>  For example, it will be empty before you execute the @code{run} command.
> +
> +@item $_tlb
> +@vindex $_tlb@r{, convenience variable}
> +The variable @code{$_tlb} is automatically set for Windows OS running
> +applications in native mode or connected to a gdbserver that supports
> +@code{qGetTIBAddr} requests. This variable contains the address of the
> thread
> +information block.

I don't think users would (or should) know what a qGetTIBAddr request
is, or how to check if their gdbserver supports it.

> +
>  @end table
>  
>  On HP-UX systems, if you refer to a function or variable name that
> @@ -15729,6 +15737,10 @@ are:
>  @tab @code{qGetTLSAddr}
>  @tab Displaying @code{__thread} variables
>  
> +@item @code{w32 thread-information-block}
> +@tab @code{qGetTIBAddr}
> +@tab Display Windows OS Thread Information Block.
> +
>  @item @code{search-memory}
>  @tab @code{qSearch:memory}
>  @tab @code{find}
> @@ -16508,6 +16520,11 @@ a long value to give the information abo
>  Without argument, this command displays information
>  about the six segment registers.
>  
> +@item info w32 thread-information-block
> +This command displays thread specific information stored in the
> +Thread Information Block (readable using @code{$fs} selector for 32-bit
> +programs and @code{$gs} for 64-bit programs).

This implies x86; ARM Windows CE programs are also 32-bit, but that
comment would apply.

> +
>  @kindex info dll
>  @item info dll
>  This is a Cygwin-specific alias of @code{info shared}.
> @@ -29173,6 +29190,14 @@ enabled, the debug registers values are 
>  removes a hardware breakpoint or watchpoint, and when the inferior
>  triggers a hardware-assisted breakpoint or watchpoint.
>  
> +@kindex maint set show-all-tib
> +@kindex maint show show-all-tib
> +@item maint set show-all-tib
> +@itemx maint show show-all-tib
> +Control whether to show all non zero areas within a 1k block starting
> +at thread local base, when using @samp{info w32 thread-information-block}
> +command.
> +
>  @kindex maint space
>  @cindex memory used by commands
>  @item maint space
> @@ -30386,6 +30411,28 @@ An error occurred.  @var{nn} are hex dig
>  An empty reply indicates that @samp{qGetTLSAddr} is not supported by the
> stub.
>  @end table
>  
> +@item qGetTIBAddr:@var{thread-id}:
> +@cindex get thread information block address
> +@cindex @samp{qGetTIBAddr} packet
> +Fetch address of the Windows OS specific Thread Information Block.
> +
> +@var{thread-id} is the thread ID associated with the thread.
> +
> +Reply:
> +@table @samp
> +@item @var{XX}@dots{}
> +Hex encoded (big endian) bytes representing the linear address of the
> +thread information block.
> +
> +@item E @var{nn}
> +An error occured. This means that either the thread was not found, or the
> +address could not be retrieved.
> +
> +@item
> +An empty reply indicates that @samp{qGetTIBAddr} is not supported by the
> stub.
> +@end table
> +
> +
>  @item qL @var{startflag} @var{threadcount} @var{nextthread}
>  Obtain thread information from RTOS.  Where: @var{startflag} (one hex
>  digit) is one to indicate the first query and zero to indicate a
> Index: gdbserver/server.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
> retrieving revision 1.110
> diff -u -p -r1.110 server.c
> --- gdbserver/server.c	24 Mar 2010 00:14:54 -0000	1.110
> +++ gdbserver/server.c	1 Apr 2010 12:46:54 -0000
> @@ -1321,6 +1321,9 @@ handle_query (char *own_buf, int packet_
>        if (the_target->qxfer_osdata != NULL)
>  	strcat (own_buf, ";qXfer:osdata:read+");
>  
> +      if (the_target->get_tib_address != NULL)
> +	strcat (own_buf, ";qGetTIBAddr+");

Was this documented?  Is this needed at all?

> +
>        if (target_supports_multi_process ())
>  	strcat (own_buf, ";multiprocess+");
>  
> @@ -1397,6 +1400,31 @@ handle_query (char *own_buf, int packet_
>        /* Otherwise, pretend we do not understand this packet.  */
>      }
>  
> +  /* Windows OS Thread Information Block address support.  */
> +  if (the_target->get_tib_address != NULL
> +      && strncmp ("qGetTIBAddr:", own_buf, 12) == 0)
> +    {
> +      char *annex;
> +      int n;
> +      CORE_ADDR tlb;
> +      ptid_t ptid = read_ptid (own_buf + 12, &annex);
> +
> +      n = (*the_target->get_tib_address) (ptid, &tlb);
> +      if (n == 1)
> +	{
> +	  sprintf (own_buf, "%llx", tlb);
> +	  return;
> +	}
> +      else if (n == 0)
> +	{
> +	  write_enn (own_buf);
> +	  return;
> +	}
> +      return;
> +    }
> +
> +
> +
>    /* Handle "monitor" commands.  */
>    if (strncmp ("qRcmd,", own_buf, 6) == 0)
>      {
> Index: gdbserver/target.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
> retrieving revision 1.43
> diff -u -p -r1.43 target.h
> --- gdbserver/target.h	20 Jan 2010 22:55:38 -0000	1.43
> +++ gdbserver/target.h	1 Apr 2010 12:46:54 -0000
> @@ -267,6 +267,9 @@ struct target_ops
>  			unsigned const char *writebuf,
>  			CORE_ADDR offset, int len);
>  
> +  /* Read Thread Information Block address.  */
> +  int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address);
> +
>    int (*supports_non_stop) (void);
>  
>    /* Enables async target events.  Returns the previous enable
> Index: gdbserver/win32-low.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v
> retrieving revision 1.43
> diff -u -p -r1.43 win32-low.c
> --- gdbserver/win32-low.c	20 Jan 2010 22:55:38 -0000	1.43
> +++ gdbserver/win32-low.c	1 Apr 2010 12:46:54 -0000
> @@ -178,7 +178,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);
> @@ -189,6 +189,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 *)
> @@ -1449,7 +1450,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:
> @@ -1479,7 +1481,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
> @@ -1750,6 +1753,22 @@ wince_hostio_last_error (char *buf)
>  }
>  #endif
>  
> +/* Write Windows OS Thread Information Block address.  */
> +static int
> +win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
> +{
> +  win32_thread_info *th;
> +  th = thread_rec (ptid, 0);
> +  if (th == NULL)
> +    return 0;
> +  if (addr)
> +    *addr = (CORE_ADDR) th->thread_local_base;
> +  if (th->thread_local_base)
> +    return 1;
> +  return 0;

Same comments as for the same windows-nat.c changes.

> +}
> +
> +
>  static struct target_ops win32_target_ops = {
>    win32_create_inferior,
>    win32_attach,
> @@ -1778,6 +1797,9 @@ static struct target_ops win32_target_op
>  #else
>    hostio_last_error_from_errno,
>  #endif
> +  NULL,
> +  NULL,
> +  win32_get_tib_address,
>  };
>  
>  /* Initialize the Win32 backend.  */
> Index: gdbserver/win32-low.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v
> retrieving revision 1.12
> diff -u -p -r1.12 win32-low.h
> --- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
> +++ gdbserver/win32-low.h	1 Apr 2010 12:46:54 -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;
>  

Otherwise, it's looking good.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [RFC-v6] Add windows OS Thread Information Block
  2010-04-11 15:10                               ` Pedro Alves
@ 2010-04-12 13:52                                 ` Pierre Muller
  2010-04-12 16:43                                   ` Pedro Alves
  0 siblings, 1 reply; 34+ messages in thread
From: Pierre Muller @ 2010-04-12 13:52 UTC (permalink / raw)
  To: 'Pedro Alves'; +Cc: gdb-patches

  I will try to answer all points that you raised:
> Uppercasing variables names is for talking about a
> variable's _value_, not name:
> 
> http://www.gnu.org/prep/standards/standards.html#Comments:
> 
>  "The variable name itself should be lower case, but write it in upper
> case
>  when you are speaking about the value rather than the variable itself.
> Thus,
>  “the inode number NODE_NUM” rather than “an inode”."

  Thanks for this information.
> >
> >
> > doc/ChangeLog entry:
> >
> > 	gdb.texinfo ($__tlb): Document new automatic convience variable.
> > 	(info w32 thread-information-block): Docmuent new command.
> > 	(qGetTIBAddress): Document new gdbserver query.
> > 	(maint set/show show-all-tib): Document new command.
> 
> Typos: convience, Docmuent

 Fixed.
> >
> > Index: remote.c
> > +/* Provide thread local base, i.e. Thread Information Block address.
> */
> > +/* Returns 1 if ptid is found and thread_local_base is non zero.  */
> > +int
> 
> Merge both comments in a single /**/ block.  Please add an empty
> line between comment and function (everywhere).
  Done. 
> (&remote_protocol_packets[PACKET_qGetTIBAddr],
> > +			 "qGetTIBAddr",
> > "get-thread-information-block-address",
> > +			 0);
> > +
> 
> It looks like the patch got line-wrap mangled here, and
> in several other places.  Could you make sure line-wrapping
> is disabled when you paste patches in the email?  Thanks.

  I will try to be more careful.
 
> > Index: target.h
> > ===================================================================
> > RCS file: /cvs/src/src/gdb/target.h,v
> > retrieving revision 1.177
> > diff -u -p -r1.177 target.h
> > --- target.h	24 Mar 2010 01:12:13 -0000	1.177
> > +++ target.h	1 Apr 2010 12:46:45 -0000
> > @@ -682,6 +682,10 @@ struct target_ops
> >      int (*to_verify_memory) (struct target_ops *, const gdb_byte
> *data,
> >  			     CORE_ADDR memaddr, ULONGEST size);
> >
> > +    /* Return the address of the start of the Thread Information
> Block
> > +       a windows OS specific feature.  */
> 
> Windows.

 Corrected.
> > Index: windows-nat.c
> > ===================================================================
> > RCS file: /cvs/src/src/gdb/windows-nat.c,v
> > retrieving revision 1.207
> > diff -u -p -r1.207 windows-nat.c
> > --- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
> > +++ windows-nat.c	1 Apr 2010 12:46:45 -0000
> > +/* Returns 1 if ptid is found and thread_local_base is non zero.  */
> > +int
> 
> Same here regarding the /**/ merging, and empty line missing.


 
> > +windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
> > +{
> > +  thread_info *th;
> > +
> > +  th = thread_rec (ptid_get_tid (ptid), 0);
> > +  if (th == NULL)
> > +    return 0;
> > +
> > +  if (addr)
> > +    {
> > +      *addr = (CORE_ADDR) th->thread_local_base;
> > +    }
> 
> One line statements don't get a wrapped in {}, just
> like you have correctly done above.
  Corrected.
> Drop the cast, as the new thread_local_base field is already
> a CORE_ADDR.  
  This was probably a left over from earlier versions
for which thread_local_base was of ULONGEST type, suppressed.
> In one case, you've checked a pointer
> against NULL, and in the other you haven't.  Please
> make this all consistent:
> 
>   if (addr != NULL)
>     *addr = th->thread_local_base;
> 
> > +  if (th->thread_local_base)
> > +    return 1;
> 
> Style wise, it looks strange to fill *addr even when
> th->thread_local_base would be 0, and hence you'd return
> 0 below.
> 
> > +  return 0;
> > +}
> 
> Here's what I'd suggest:
> 
>   th = thread_rec (ptid_get_tid (ptid), 0);
>   if (th == NULL || th->thread_local_base == 0)
>     return 0;
> 
>   if (addr != NULL)
>     *addr = th->thread_local_base;
> 
>   return 1;

  Seems good to me, as I anyhow don't think that
Windows OS will ever use '0' as a Thread Information Block address.
Note that this is only a guess, but it might be required 
if Windows OS guarantees that the null address is not accessible,
but I don't know if this is indeed written somewhere in the specs. 
 
  I was just wondering why I made this function global,
and as I saw no reason, I made it static.
 
> > Index: windows-tdep.c
> > ===================================================================
> > RCS file: /cvs/src/src/gdb/windows-tdep.c,v
> > retrieving revision 1.5
> > diff -u -p -r1.5 windows-tdep.c
> > --- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
> > +++ windows-tdep.c	1 Apr 2010 12:46:45 -0000
> > @@ -19,6 +19,372 @@
> >  #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"
> > +#include "gdbthread.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 active_rpc_handle;			/* %fs:0x0028 */
> > +    uint32_t thread_local_storage;		/* %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 */
> > +    uint64_t environment_pointer;		/* %gs:0x0038 */
> > +    uint64_t process_id;			/* %gs:0x0040 */
> > +    uint64_t current_thread_id;			/* %gs:0x0048 */
> > +    uint64_t active_rpc_handle;			/* %gs:0x0050 */
> > +    uint64_t thread_local_storage;		/* %gs:0x0058 */
> > +    uint64_t process_environment_block;		/* %gs:0x0060 */
> > +    uint64_t last_error_number;			/* %gs:0x0068 */
> > +  }
> > +thread_information_64;
> > +
> > +
> > +static const
> > +char* TIB_NAME[] =
> 
> 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 */
> > +    " active_rpc_handle           ",	/* %fs:0x0028 */
> > +    " thread_local_storage        ",	/* %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;
> 
> Only functions need a line break before the function name.

  Again, I show my lack of knowledge about C formatting :(
 
> > +
> > +static int maint_display_all_tib = 0;
> > +
> > +/* Define ThreadLocalBase pointer type */
> 
> Missing period.  Two spaces after period.  Empty line between comment
> and function.
 Corrected.
> > +struct type *
> > +windows_get_tlb_type (struct gdbarch *gdbarch)
> > +
> > +  /* struct _PEB_LDR_DATA */
> > +  /* FIXME: 64bit layout is unknown.  */
> 
> Is this still unknown?
  I tested it on one particular 64-bit Windows OS, 
for which it seemed to give reasonable values...
I removed the FIXME.
 
> > +  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",
> dword32_type);
> > +  append_composite_type_field (peb_ldr_type, "initialized",
> dword32_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 active_rpc_handle;		%fs:0x0028 */
> > +  append_composite_type_field (tib_type, "active_rpc_handle",
> > dword_ptr_type);
> > +  /* uint32_t thread_local_storage;		%fs:0x002c */
> > +  append_composite_type_field (tib_type, "thread_local_storage",
> > void_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 *val)
> > +{
> > +  CORE_ADDR tlb;
> > +  ULONGEST num;
> > +  struct type *type = check_typedef (value_type (val));
> > +  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch
> (type));
> > +  struct value *parent = value_parent (val);
> > +  LONGEST offset = value_offset (val);
> 
> What are these two for?
  I don't know, probably some copy/paste without 
re-inspection afterwards. Removed.

> > +  int length = TYPE_LENGTH (type);
> > +
> > +  /* This needs to be changed if multi-process support is added.  */
> > +
> > +  if (!target_get_tib_address (inferior_ptid, &tlb))
> > +    error (_("Unable to read tlb"));
> > +  num = (ULONGEST) tlb;
> > +  store_unsigned_integer (value_contents_raw (val), length,
> byte_order,
> > num);
> 
> This assumes `tlb' is an address, and VAL is a pointer, so, take a look
> at value_from_pointer, and try doing something similar instead:
> 
>   store_typed_address (value_contents_raw (val), type, addr);
 Changed to your proposal.
 
> > +}
> > +
> > +/* This function implements the lval_computed support for writing a
> > +   $_siginfo value.  */
> 
> Copy/paste error:  s/_siginfo/_tlb/

  Corrected.
> > +
> > +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 (ptid_t ptid)
> > +{
> > +#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.  */
> 
> What needs changing?
  I think that this is also a leftover from a previous version
in which only the Thread Id was given as parameter.
> > +
> > +  if (target_get_tib_address (ptid, &thread_local_base) == 0)
> > +    {
> > +      printf_filtered ("Unable to get thread local base for ThreadId
> %s\n",
> > +	pulongest (ptid_get_tid(ptid)));
> 
> Incomplete transition: please avoid the ptid_get_tid in common code.
  I changed it to use target_pid_to_str everywhere.
 
> > +      return -1;
> > +    }
> > +
> > +  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 (ptid_get_tid (ptid)),
> > +	paddress (target_gdbarch, thread_local_base));
> 
> Same.  Missing i18n.
Fixed.
> > +      return -1;
> > +    }
> > +
> > +  printf_filtered ("Thread Information Block %s at %s\n",
> > +		   pulongest (ptid_get_tid (ptid)),
> > +		   paddress (target_gdbarch, thread_local_base));
> 
> Same.
Fixed.
> > +
> > +  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));
> 
> No space in array subscripting:
> 
>  TIB_NAME[i]
 Corrected 
> > +      else if (val != 0)
> > +	printf_filtered ("TIB[0x%s] is 0x%s\n", phex (i*size, 2),
> > +			 phex (val, size));
> 
> i18n.  Spaces missing around '*'.
Corrected. 
> > Index: doc/gdb.texinfo
> > ===================================================================
> > RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
> > retrieving revision 1.692
> > diff -u -p -r1.692 gdb.texinfo
> > --- doc/gdb.texinfo	31 Mar 2010 12:19:52 -0000	1.692
> > +++ doc/gdb.texinfo	1 Apr 2010 12:46:53 -0000
> > @@ -8054,6 +8054,14 @@ The variable @code{$_siginfo} contains e
> >  (@pxref{extra signal information}).  Note that @code{$_siginfo}
> >  could be empty, if the application has not yet received any signals.
> >  For example, it will be empty before you execute the @code{run}
> command.
> > +
> > +@item $_tlb
> > +@vindex $_tlb@r{, convenience variable}
> > +The variable @code{$_tlb} is automatically set for Windows OS
> running
> > +applications in native mode or connected to a gdbserver that
> supports
> > +@code{qGetTIBAddr} requests. This variable contains the address of
> the
> > thread
> > +information block.
> 
> I don't think users would (or should) know what a qGetTIBAddr request
> is, or how to check if their gdbserver supports it.
Eli was OK for this with a reference to 'General query packets'
which I added.
 
> > +
> >  @end table
> >
> >  On HP-UX systems, if you refer to a function or variable name that
> > @@ -15729,6 +15737,10 @@ are:
> >  @tab @code{qGetTLSAddr}
> >  @tab Displaying @code{__thread} variables
> >
> > +@item @code{w32 thread-information-block}
> > +@tab @code{qGetTIBAddr}
> > +@tab Display Windows OS Thread Information Block.
> > +
> >  @item @code{search-memory}
> >  @tab @code{qSearch:memory}
> >  @tab @code{find}
> > @@ -16508,6 +16520,11 @@ a long value to give the information abo
> >  Without argument, this command displays information
> >  about the six segment registers.
> >
> > +@item info w32 thread-information-block
> > +This command displays thread specific information stored in the
> > +Thread Information Block (readable using @code{$fs} selector for 32-
> bit
> > +programs and @code{$gs} for 64-bit programs).
> 
> This implies x86; ARM Windows CE programs are also 32-bit, but that
> comment would apply.

You are right, this only applies to x86 CPU family.
Another question is if this is supported by Windows-CE running on i386.
Apparently, The Windows CE API also has this
lpThreadLocalBase field in the CREATE_PROCESS_DEBUG_INFO
structure, but I have no idea about the layout of
the Thread Information Block for Windows CE.

> > Index: gdbserver/win32-low.c
> > ===================================================================
> > RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v
> > retrieving revision 1.43
> > diff -u -p -r1.43 win32-low.c
> > --- gdbserver/win32-low.c	20 Jan 2010 22:55:38 -0000	1.43
> > +++ gdbserver/win32-low.c	1 Apr 2010 12:46:54 -0000
> > @@ -178,7 +178,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);
> > @@ -189,6 +189,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 *)
> > @@ -1449,7 +1450,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:
> > @@ -1479,7 +1481,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
> > @@ -1750,6 +1753,22 @@ wince_hostio_last_error (char *buf)
> >  }
> >  #endif
> >
> > +/* Write Windows OS Thread Information Block address.  */
> > +static int
> > +win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
> > +{
> > +  win32_thread_info *th;
> > +  th = thread_rec (ptid, 0);
> > +  if (th == NULL)
> > +    return 0;
> > +  if (addr)
> > +    *addr = (CORE_ADDR) th->thread_local_base;
> > +  if (th->thread_local_base)
> > +    return 1;
> > +  return 0;
> 
> Same comments as for the same windows-nat.c changes.
  Corrected. 
> > +}
> > +
> > +
> >  static struct target_ops win32_target_ops = {
> >    win32_create_inferior,
> >    win32_attach,
> > @@ -1778,6 +1797,9 @@ static struct target_ops win32_target_op
> >  #else
> >    hostio_last_error_from_errno,
> >  #endif
> > +  NULL,
> > +  NULL,
> > +  win32_get_tib_address,
> >  };
> >
> >  /* Initialize the Win32 backend.  */
> > Index: gdbserver/win32-low.h
> > ===================================================================
> > RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v
> > retrieving revision 1.12
> > diff -u -p -r1.12 win32-low.h
> > --- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
> > +++ gdbserver/win32-low.h	1 Apr 2010 12:46:54 -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;
> >
> 
> Otherwise, it's looking good.
Thanks for the review.

 Here is a new version of the patch,

Pierre Muller

2010-04-12  Pierre Muller  <muller@ics.u-strasbg.fr>

	* remote.c (PACKET_qGetTIBAddr): New enum element.
	(remote_get_tib_address): New function.
	(init_remote_ops): Set to_get_tib_address field
	to remote_get_tib_address.
	(_initialize_remote): Add add_packet_config_cmd
	for PACKET_qGetTIBAddr.
	* target.c (update_current_target): Set default value for
	new to_get_tib_address field.
	* target.h (target_ops): New field to_get_tib_address.
	(target_get_tib_address): New macro.
	* windows-nat.c (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_get_tib_address): New function.
	(init_windows_ops): Set to_get_tib_address field
	to remote_get_tib_address.
	(_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:

	* server.c (handle_query): Acknowledge support
	for 'qGetTIBAddr' if get_tib_addr field of the_target
	is set.
	Handle 'qGetTIBAddr' query.
	* target.h (target_ops): New get_tib_address field.
	* win32-low.h (win32_thread_info): Add thread_local_base field.
	* win32-low.c (child_add_thread): Add tlb argument.
	Set thread_local_base field to TLB.
	(get_child_debug_event): Adapt to child_add_thread change.
	(win32_get_tib_address): New function.
	(win32_target_ops): Set get_tib_address field to
	win32_get_tib_address
	

doc/ChangeLog entry:

	gdb.texinfo ($__tlb): Document new automatic convinience variable.
	(info w32 thread-information-block): Document new command.
	(qGetTIBAddress): Document new gdbserver query.
	(maint set/show show-all-tib): Document new command.

Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.400
diff -u -p -r1.400 remote.c
--- remote.c	9 Apr 2010 03:00:57 -0000	1.400
+++ remote.c	12 Apr 2010 11:53:12 -0000
@@ -1139,6 +1139,7 @@ enum {
   PACKET_qXfer_spu_write,
   PACKET_qXfer_osdata,
   PACKET_qXfer_threads,
+  PACKET_qGetTIBAddr,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
   PACKET_QPassSignals,
@@ -8441,6 +8442,49 @@ remote_get_thread_local_address (struct 
   return 0;
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.
+   Returns 1 if ptid is found and thread_local_base is non zero.  */
+
+int
+remote_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  if (remote_protocol_packets[PACKET_qGetTIBAddr].support != PACKET_DISABLE)
+    {
+      struct remote_state *rs = get_remote_state ();
+      char *p = rs->buf;
+      char *endp = rs->buf + get_remote_packet_size ();
+      enum packet_result result;
+
+      strcpy (p, "qGetTIBAddr:");
+      p += strlen (p);
+      p = write_ptid (p, endp, ptid);
+      *p++ = '\0';
+
+      putpkt (rs->buf);
+      getpkt (&rs->buf, &rs->buf_size, 0);
+      result = packet_ok (rs->buf,
+			  &remote_protocol_packets[PACKET_qGetTIBAddr]);
+      if (result == PACKET_OK)
+	{
+	  ULONGEST result;
+
+	  unpack_varlen_hex (rs->buf, &result);
+	  if (addr)
+	    *addr = (CORE_ADDR) result;
+	  return 1;
+	}
+      else if (result == PACKET_UNKNOWN)
+	error (_("Remote target doesn't support qGetTIBAddr packet"));
+      else
+	error (_("Remote target failed to process qGetTIBAddr request"));
+    }
+  else
+    error (_("qGetTIBAddr not supported or disabled on this target"));
+  /* Not reached.  */
+  return 0;
+}
+
+
 /* Support for inferring a target description based on the current
    architecture and the size of a 'g' packet.  While the 'g' packet
    can have any size (since optional registers can be left off the
@@ -9890,6 +9934,8 @@ Specify the serial device it is connecte
   remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer;
   remote_ops.to_core_of_thread = remote_core_of_thread;
   remote_ops.to_verify_memory = remote_verify_memory;
+  remote_ops.to_get_tib_address = remote_get_tib_address;
+ 
 }
 
 /* Set up the extended remote vector by making a copy of the standard
@@ -10309,6 +10355,10 @@ Show the maximum size of the address (in
 			 "qGetTLSAddr", "get-thread-local-storage-address",
 			 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTIBAddr],
+			 "qGetTIBAddr", "get-thread-information-block-address",
+			 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_bc],
 			 "bc", "reverse-continue", 0);
 
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.245
diff -u -p -r1.245 target.c
--- target.c	24 Mar 2010 01:12:13 -0000	1.245
+++ target.c	12 Apr 2010 11:53:13 -0000
@@ -660,6 +660,7 @@ update_current_target (void)
       INHERIT (to_get_raw_trace_data, t);
       INHERIT (to_set_disconnected_tracing, t);
       INHERIT (to_set_circular_trace_buffer, t);
+      INHERIT (to_get_tib_address, t);
       INHERIT (to_magic, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
@@ -853,6 +854,9 @@ update_current_target (void)
   de_fault (to_set_circular_trace_buffer,
 	    (void (*) (int))
 	    target_ignore);
+  de_fault (to_get_tib_address,
+	    (int (*) (ptid_t, CORE_ADDR *))
+	    tcomplain);
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.177
diff -u -p -r1.177 target.h
--- target.h	24 Mar 2010 01:12:13 -0000	1.177
+++ target.h	12 Apr 2010 11:53:13 -0000
@@ -682,6 +682,10 @@ struct target_ops
     int (*to_verify_memory) (struct target_ops *, const gdb_byte *data,
 			     CORE_ADDR memaddr, ULONGEST size);
 
+    /* Return the address of the start of the Thread Information Block
+       a Windows OS specific feature.  */
+    int (*to_get_tib_address) (ptid_t ptid, CORE_ADDR *addr);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -1371,6 +1375,9 @@ extern int target_search_memory (CORE_AD
 #define	target_set_circular_trace_buffer(val)	\
   (*current_target.to_set_circular_trace_buffer) (val)
 
+#define target_get_tib_address(ptid, addr) \
+  (*current_target.to_get_tib_address) ((ptid), (addr))
+
 /* Command logging facility.  */
 
 #define target_log_command(p)						\
Index: windows-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/windows-nat.c,v
retrieving revision 1.207
diff -u -p -r1.207 windows-nat.c
--- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
+++ windows-nat.c	12 Apr 2010 11:53:14 -0000
@@ -191,6 +191,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;
@@ -320,7 +321,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;
@@ -335,6 +336,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);
@@ -1074,15 +1076,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 (\
@@ -1271,9 +1264,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;
 }
 
@@ -1447,7 +1442,9 @@ 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:
@@ -1481,7 +1478,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;
 
@@ -2266,6 +2264,24 @@ windows_xfer_partial (struct target_ops 
     }
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.
+   Returns 1 if ptid is found and thread_local_base is non zero.  */
+
+static int
+windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  thread_info *th;
+
+  th = thread_rec (ptid_get_tid (ptid), 0);
+  if (th == NULL || th->thread_local_base == 0)
+    return 0;
+
+  if (addr != NULL)
+    *addr = th->thread_local_base;
+
+  return 1;
+}
+
 static ptid_t
 windows_get_ada_task_ptid (long lwp, long thread)
 {
@@ -2314,6 +2330,7 @@ init_windows_ops (void)
   windows_ops.to_has_execution = default_child_has_execution;
   windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
   windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
+  windows_ops.to_get_tib_address = windows_get_tib_address;
 
   i386_use_watchpoints (&windows_ops);
 
@@ -2415,9 +2432,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.5
diff -u -p -r1.5 windows-tdep.c
--- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
+++ windows-tdep.c	12 Apr 2010 11:53:14 -0000
@@ -19,6 +19,360 @@
 #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"
+#include "gdbthread.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 active_rpc_handle;			/* %fs:0x0028 */
+    uint32_t thread_local_storage;		/* %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 */
+    uint64_t environment_pointer;		/* %gs:0x0038 */
+    uint64_t process_id;			/* %gs:0x0040 */
+    uint64_t current_thread_id;			/* %gs:0x0048 */
+    uint64_t active_rpc_handle;			/* %gs:0x0050 */
+    uint64_t thread_local_storage;		/* %gs:0x0058 */
+    uint64_t process_environment_block;		/* %gs:0x0060 */
+    uint64_t last_error_number;			/* %gs:0x0068 */
+  }
+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 */
+    " active_rpc_handle           ",	/* %fs:0x0028 */
+    " thread_local_storage        ",	/* %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 Thread Local Base pointer type.  */
+
+static struct type *
+windows_get_tlb_type (struct gdbarch *gdbarch)
+{
+  struct type *dword_ptr_type, *dword32_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");
+  dword32_type = arch_integer_type (gdbarch, 32,
+				 1, "DWORD32");
+  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 */
+  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", dword32_type);
+  append_composite_type_field (peb_ldr_type, "initialized", dword32_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");
+
+  /* First bytes contain several flags.  */
+  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 active_rpc_handle;		%fs:0x0028 */
+  append_composite_type_field (tib_type, "active_rpc_handle", dword_ptr_type);
+  /* uint32_t thread_local_storage;		%fs:0x002c */
+  append_composite_type_field (tib_type, "thread_local_storage", void_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 *val)
+{
+  CORE_ADDR tlb;
+  struct type *type = check_typedef (value_type (val));
+
+  if (!target_get_tib_address (inferior_ptid, &tlb))
+    error (_("Unable to read tlb"));
+  store_typed_address (value_contents_raw (val), type, tlb);
+}
+
+/* This function implements the lval_computed support for writing a
+   $_tlb 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 (ptid_t ptid)
+{
+#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.  */
+
+  if (target_get_tib_address (ptid, &thread_local_base) == 0)
+    {
+      printf_filtered (_("Unable to get thread local base for %s\n"),
+	target_pid_to_str (ptid));
+      return -1;
+    }
+
+  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 %s at \
+address %s\n"),
+	target_pid_to_str (ptid), 
+	paddress (target_gdbarch, thread_local_base));
+      return -1;
+    }
+
+  printf_filtered (_("Thread Information Block %s at %s\n"),
+		   target_pid_to_str (ptid),
+		   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)
+    {
+      struct thread_info *tp;
+      int gdb_id = value_as_long (parse_and_eval (args));
+
+      tp = find_thread_id (gdb_id);
+
+      if (!tp)
+	error (_("Thread ID %d not known."), gdb_id);
+
+      if (!target_thread_alive (tp->ptid))
+	error (_("Thread ID %d has terminated."), gdb_id);
+
+      display_one_tib (tp->ptid);
+    }
+  else if (!ptid_equal (inferior_ptid, null_ptid))
+    display_one_tib (inferior_ptid);
+}
 
 void
 windows_xfer_shared_library (const char* so_name, CORE_ADDR load_addr,
@@ -36,3 +390,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 their 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.4
diff -u -p -r1.4 windows-tdep.h
--- windows-tdep.h	1 Jan 2010 07:31:46 -0000	1.4
+++ windows-tdep.h	12 Apr 2010 11:53:14 -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: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.703
diff -u -p -r1.703 gdb.texinfo
--- doc/gdb.texinfo	9 Apr 2010 20:46:40 -0000	1.703
+++ doc/gdb.texinfo	12 Apr 2010 11:53:22 -0000
@@ -8054,6 +8054,15 @@ The variable @code{$_siginfo} contains e
 (@pxref{extra signal information}).  Note that @code{$_siginfo}
 could be empty, if the application has not yet received any signals.
 For example, it will be empty before you execute the @code{run} command.
+
+@item $_tlb
+@vindex $_tlb@r{, convenience variable}
+The variable @code{$_tlb} is automatically set when debugging
+applications running on MS-Windows in native mode or connected to
+gdbserver that supports the @code{qGetTIBAddr} request. 
+@xref{General Query Packets}.
+This variable contains the address of the thread information block.
+
 @end table
 
 On HP-UX systems, if you refer to a function or variable name that
@@ -15755,6 +15764,10 @@ are:
 @tab @code{qGetTLSAddr}
 @tab Displaying @code{__thread} variables
 
+@item @code{w32 thread-information-block}
+@tab @code{qGetTIBAddr}
+@tab Display MS-Windows Thread Information Block.
+
 @item @code{search-memory}
 @tab @code{qSearch:memory}
 @tab @code{find}
@@ -16534,6 +16547,11 @@ a long value to give the information abo
 Without argument, this command displays information
 about the six segment registers.
 
+@item info w32 thread-information-block
+This command displays thread specific information stored in the
+Thread Information Block for x86 CPU family (readable using @code{$fs}
+selector for 32-bit programs and @code{$gs} for 64-bit programs).
+
 @kindex info dll
 @item info dll
 This is a Cygwin-specific alias of @code{info shared}.
@@ -29382,6 +29400,14 @@ enabled, the debug registers values are 
 removes a hardware breakpoint or watchpoint, and when the inferior
 triggers a hardware-assisted breakpoint or watchpoint.
 
+@kindex maint set show-all-tib
+@kindex maint show show-all-tib
+@item maint set show-all-tib
+@itemx maint show show-all-tib
+Control whether to show all non zero areas within a 1k block starting
+at thread local base, when using @samp{info w32 thread-information-block}
+command.
+
 @kindex maint space
 @cindex memory used by commands
 @item maint space
@@ -30595,6 +30621,28 @@ An error occurred.  @var{nn} are hex dig
 An empty reply indicates that @samp{qGetTLSAddr} is not supported by the stub.
 @end table
 
+@item qGetTIBAddr:@var{thread-id}:
+@cindex get thread information block address
+@cindex @samp{qGetTIBAddr} packet
+Fetch address of the Windows OS specific Thread Information Block.
+
+@var{thread-id} is the thread ID associated with the thread.
+
+Reply:
+@table @samp
+@item @var{XX}@dots{}
+Hex encoded (big endian) bytes representing the linear address of the
+thread information block.
+
+@item E @var{nn}
+An error occured.  This means that either the thread was not found, or the
+address could not be retrieved.
+
+@item
+An empty reply indicates that @samp{qGetTIBAddr} is not supported by the stub.
+@end table
+
+
 @item qL @var{startflag} @var{threadcount} @var{nextthread}
 Obtain thread information from RTOS.  Where: @var{startflag} (one hex
 digit) is one to indicate the first query and zero to indicate a
Index: gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.114
diff -u -p -r1.114 server.c
--- gdbserver/server.c	11 Apr 2010 16:33:56 -0000	1.114
+++ gdbserver/server.c	12 Apr 2010 11:53:23 -0000
@@ -1379,6 +1379,9 @@ handle_query (char *own_buf, int packet_
       if (the_target->qxfer_osdata != NULL)
 	strcat (own_buf, ";qXfer:osdata:read+");
 
+      if (the_target->get_tib_address != NULL)
+	strcat (own_buf, ";qGetTIBAddr+");
+
       if (target_supports_multi_process ())
 	strcat (own_buf, ";multiprocess+");
 
@@ -1463,6 +1466,31 @@ handle_query (char *own_buf, int packet_
       /* Otherwise, pretend we do not understand this packet.  */
     }
 
+  /* Windows OS Thread Information Block address support.  */
+  if (the_target->get_tib_address != NULL
+      && strncmp ("qGetTIBAddr:", own_buf, 12) == 0)
+    {
+      char *annex;
+      int n;
+      CORE_ADDR tlb;
+      ptid_t ptid = read_ptid (own_buf + 12, &annex);
+
+      n = (*the_target->get_tib_address) (ptid, &tlb);
+      if (n == 1)
+	{
+	  sprintf (own_buf, "%llx", tlb);
+	  return;
+	}
+      else if (n == 0)
+	{
+	  write_enn (own_buf);
+	  return;
+	}
+      return;
+    }
+
+
+
   /* Handle "monitor" commands.  */
   if (strncmp ("qRcmd,", own_buf, 6) == 0)
     {
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.46
diff -u -p -r1.46 target.h
--- gdbserver/target.h	11 Apr 2010 16:33:56 -0000	1.46
+++ gdbserver/target.h	12 Apr 2010 11:53:23 -0000
@@ -271,6 +271,9 @@ struct target_ops
 			unsigned const char *writebuf,
 			CORE_ADDR offset, int len);
 
+  /* Read Thread Information Block address.  */
+  int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address);
+
   int (*supports_non_stop) (void);
 
   /* Enables async target events.  Returns the previous enable
Index: gdbserver/win32-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v
retrieving revision 1.44
diff -u -p -r1.44 win32-low.c
--- gdbserver/win32-low.c	11 Apr 2010 16:33:56 -0000	1.44
+++ gdbserver/win32-low.c	12 Apr 2010 11:53:23 -0000
@@ -178,7 +178,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);
@@ -189,6 +189,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 *)
@@ -1449,7 +1450,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:
@@ -1479,7 +1481,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
@@ -1747,6 +1750,21 @@ wince_hostio_last_error (char *buf)
 }
 #endif
 
+/* Write Windows OS Thread Information Block address.  */
+
+static int
+win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  win32_thread_info *th;
+  th = thread_rec (ptid, 0);
+  if (th == NULL || th->thread_local_base == 0)
+    return 0;
+  if (addr)
+    *addr = th->thread_local_base;
+  return 1;
+}
+
+
 static struct target_ops win32_target_ops = {
   win32_create_inferior,
   win32_attach,
@@ -1776,6 +1794,9 @@ static struct target_ops win32_target_op
 #else
   hostio_last_error_from_errno,
 #endif
+  NULL,
+  NULL,
+  win32_get_tib_address,
 };
 
 /* Initialize the Win32 backend.  */
Index: gdbserver/win32-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v
retrieving revision 1.12
diff -u -p -r1.12 win32-low.h
--- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
+++ gdbserver/win32-low.h	12 Apr 2010 11: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;
 
Index: tui/tui-regs.c
===================================================================
RCS file: /cvs/src/src/gdb/tui/tui-regs.c,v
retrieving revision 1.36
diff -u -p -r1.36 tui-regs.c
--- tui/tui-regs.c	1 Jan 2010 07:32:07 -0000	1.36
+++ tui/tui-regs.c	12 Apr 2010 11:53:24 -0000
@@ -541,7 +541,7 @@ tui_display_register (struct tui_data_el
       int i;
 
       if (data->highlight)
-	wstandout (win_info->handle);
+	(void) wstandout (win_info->handle);
       
       wmove (win_info->handle, 0, 0);
       for (i = 1; i < win_info->width; i++)
@@ -551,7 +551,7 @@ tui_display_register (struct tui_data_el
         waddstr (win_info->handle, data->content);
 
       if (data->highlight)
-	wstandend (win_info->handle);
+	(void) wstandend (win_info->handle);
       tui_refresh_win (win_info);
     }
 }
Index: tui/tui-stack.c
===================================================================
RCS file: /cvs/src/src/gdb/tui/tui-stack.c,v
retrieving revision 1.34
diff -u -p -r1.34 tui-stack.c
--- tui/tui-stack.c	1 Jan 2010 07:32:07 -0000	1.34
+++ tui/tui-stack.c	12 Apr 2010 11:53:24 -0000
@@ -256,10 +256,10 @@ tui_show_locator_content (void)
 
       string = tui_make_status_line (&element->which_element.locator);
       wmove (locator->handle, 0, 0);
-      wstandout (locator->handle);
+      (void) wstandout (locator->handle);
       waddstr (locator->handle, string);
       wclrtoeol (locator->handle);
-      wstandend (locator->handle);
+      (void) wstandend (locator->handle);
       tui_refresh_win (locator);
       wmove (locator->handle, 0, 0);
       xfree (string);

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC-v6] Add windows OS Thread Information Block
  2010-04-12 13:52                                 ` [RFC-v6] " Pierre Muller
@ 2010-04-12 16:43                                   ` Pedro Alves
  2010-04-13  8:38                                     ` [RFA-v7] " Pierre Muller
  0 siblings, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2010-04-12 16:43 UTC (permalink / raw)
  To: Pierre Muller; +Cc: gdb-patches

On Monday 12 April 2010 14:51:27, Pierre Muller wrote:
>         gdb.texinfo ($__tlb): Document new automatic convinience variable.

One _ too much?

>   Seems good to me, as I anyhow don't think that
> Windows OS will ever use '0' as a Thread Information Block address.
> Note that this is only a guess, but it might be required 
> if Windows OS guarantees that the null address is not accessible,
> but I don't know if this is indeed written somewhere in the specs. 

Then don't guess, just remove the check, and we'll add
it later if found necessary.  Otherwise, it's just bloat and
adds to confusion (it makes one stop and wonder when
reading that code; I know I have).


On Monday 12 April 2010 14:51:27, Pierre Muller wrote:
> +  return tib_ptr_type;
> +}
> +/* The $_tlb convenience variable is a bit special.  We don't know

Missing newline between previous function and following function's comment.


Something else I just noticed now:

> +/* Display thread information block of a given thread.  */
> +
> +static int
> +display_one_tib (ptid_t ptid)
> +{
> +#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;
...
> +  if (target_read (&current_target, TARGET_OBJECT_MEMORY,
> +                  annex, tib, thread_local_base, tib_size) != tib_size)

This annex handling also seems something used in a previous
patch revision.  I think you meant to drop it.

Also:

> +  add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTIBAddr],
> +                        "qGetTIBAddr", "get-thread-information-block-address",
> +                        0);

this new command should be documented.  In addition, all new packets
and commands should be mentioned in NEWS.



> +      if (the_target->get_tib_address != NULL)
> +       strcat (own_buf, ";qGetTIBAddr+");

You missed addressing a comment I made to this:

I can't seem to find where this new qsupported feature
was documented in the manual changes?  (and is this needed
at all?  I guess it doesn't hurt.)


Also, you have unrelated hunks touching these files:

 > RCS file: /cvs/src/src/gdb/tui/tui-regs.c,v
 > RCS file: /cvs/src/src/gdb/tui/tui-stack.c,v

please make sure these are not included in the patch.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [RFA-v7] Add windows OS Thread Information Block
  2010-04-12 16:43                                   ` Pedro Alves
@ 2010-04-13  8:38                                     ` Pierre Muller
  2010-04-13 11:14                                       ` Pedro Alves
  0 siblings, 1 reply; 34+ messages in thread
From: Pierre Muller @ 2010-04-13  8:38 UTC (permalink / raw)
  To: 'Pedro Alves', 'Eli Zaretskii'; +Cc: gdb-patches



> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Pedro Alves
> Envoyé : Monday, April 12, 2010 6:44 PM
> À : Pierre Muller
> Cc : gdb-patches@sourceware.org
> Objet : Re: [RFC-v6] Add windows OS Thread Information Block
> 
> On Monday 12 April 2010 14:51:27, Pierre Muller wrote:
> >         gdb.texinfo ($__tlb): Document new automatic convinience
> variable.
> 
> One _ too much?

  Yes indeed.
 
> >   Seems good to me, as I anyhow don't think that
> > Windows OS will ever use '0' as a Thread Information Block address.
> > Note that this is only a guess, but it might be required
> > if Windows OS guarantees that the null address is not accessible,
> > but I don't know if this is indeed written somewhere in the specs.
> 
> Then don't guess, just remove the check, and we'll add
> it later if found necessary.  Otherwise, it's just bloat and
> adds to confusion (it makes one stop and wonder when
> reading that code; I know I have).

OK, modified as you propose.
 
> On Monday 12 April 2010 14:51:27, Pierre Muller wrote:
> > +  return tib_ptr_type;
> > +}
> > +/* The $_tlb convenience variable is a bit special.  We don't know
> 
> Missing newline between previous function and following function's
> comment.

  Missing newline added.
 
> 
> Something else I just noticed now:
> 
> > +/* Display thread information block of a given thread.  */
> > +
> > +static int
> > +display_one_tib (ptid_t ptid)
> > +{
> > +#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;
> ...
> > +  if (target_read (&current_target, TARGET_OBJECT_MEMORY,
> > +                  annex, tib, thread_local_base, tib_size) !=
> tib_size)
> 
> This annex handling also seems something used in a previous
> patch revision.  I think you meant to drop it.

  Yes, I forgot to remove that part, done now.
 
> Also:
> 
> > +  add_packet_config_cmd
> (&remote_protocol_packets[PACKET_qGetTIBAddr],
> > +                        "qGetTIBAddr", "get-thread-information-
> block-address",
> > +                        0);
> 
> this new command should be documented.  In addition, all new packets
> and commands should be mentioned in NEWS.

  It was in the documentation but under a wrong name,
I corrected this.
 
> 
> 
> > +      if (the_target->get_tib_address != NULL)
> > +       strcat (own_buf, ";qGetTIBAddr+");
> 
> You missed addressing a comment I made to this:

  I guessed that this is the needed counterpart of the fact
that qGetTIBAddr is in the list of features that can be disabled.
 
> I can't seem to find where this new qsupported feature
> was documented in the manual changes?  (and is this needed
> at all?  I guess it doesn't hurt.)

  At least, I tested disabling it with 'set remote get-thread-information-block-address off'
and that worked OK.
 
> 
> Also, you have unrelated hunks touching these files:
> 
>  > RCS file: /cvs/src/src/gdb/tui/tui-regs.c,v
>  > RCS file: /cvs/src/src/gdb/tui/tui-stack.c,v 
> please make sure these are not included in the patch.

  Let's make sure I remove them from this version already.
It should not be in that patch.

  Here is one more version.
  The main change (apart from the suggestions made by Pedro)
is the addition of a NEWS entry.

Pierre



2010-04-13  Pierre Muller  <muller@ics.u-strasbg.fr>

	Support for Windows OS Thread Information Block.
	* NEWS: Document new feature.
	* remote.c (PACKET_qGetTIBAddr): New enum element.
	(remote_get_tib_address): New function.
	(init_remote_ops): Set to_get_tib_address field
	to remote_get_tib_address.
	(_initialize_remote): Add add_packet_config_cmd
	for PACKET_qGetTIBAddr.
	* target.c (update_current_target): Set default value for
	new to_get_tib_address field.
	* target.h (target_ops): New field to_get_tib_address.
	(target_get_tib_address): New macro.
	* windows-nat.c (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_get_tib_address): New function.
	(init_windows_ops): Set to_get_tib_address field
	to remote_get_tib_address.
	(_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:

	* server.c (handle_query): Acknowledge support
	for 'qGetTIBAddr' if get_tib_addr field of the_target
	is set.
	Handle 'qGetTIBAddr' query.
	* target.h (target_ops): New get_tib_address field.
	* win32-low.h (win32_thread_info): Add thread_local_base field.
	* win32-low.c (child_add_thread): Add tlb argument.
	Set thread_local_base field to TLB.
	(get_child_debug_event): Adapt to child_add_thread change.
	(win32_get_tib_address): New function.
	(win32_target_ops): Set get_tib_address field to
	win32_get_tib_address.
	

doc/ChangeLog entry:

	gdb.texinfo ($_tlb): Document new automatic convinience variable.
	(info w32 thread-information-block): Document new command.
	(qGetTIBAddress): Document new gdbserver query.
	(maint set/show show-all-tib): Document new command.


Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.369
diff -u -p -r1.369 NEWS
--- NEWS	9 Apr 2010 15:26:54 -0000	1.369
+++ NEWS	13 Apr 2010 07:34:59 -0000
@@ -3,6 +3,14 @@
 
 *** Changes since GDB 7.1
 
+* New Windows OS feature: Thread Information Block.
+
+  - GDB now supports disaplying of thread specific information for
+  Windows OS executables. This feature is accessible either as a new command
+  'info w32 thread-information-block' or as a new computed internal variable
+  named '$_tlb' a thread-specific pointer to the Thread Information Block.
+  'qGetTIBAddr' is a new remote packet associated with this feature.
+
 * New features in the GDB remote stub, GDBserver
 
   - GDBserver now support tracepoints.  The feature is currently
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.400
diff -u -p -r1.400 remote.c
--- remote.c	9 Apr 2010 03:00:57 -0000	1.400
+++ remote.c	13 Apr 2010 07:35:11 -0000
@@ -1139,6 +1139,7 @@ enum {
   PACKET_qXfer_spu_write,
   PACKET_qXfer_osdata,
   PACKET_qXfer_threads,
+  PACKET_qGetTIBAddr,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
   PACKET_QPassSignals,
@@ -8441,6 +8442,49 @@ remote_get_thread_local_address (struct 
   return 0;
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.
+   Returns 1 if ptid is found and thread_local_base is non zero.  */
+
+int
+remote_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  if (remote_protocol_packets[PACKET_qGetTIBAddr].support != PACKET_DISABLE)
+    {
+      struct remote_state *rs = get_remote_state ();
+      char *p = rs->buf;
+      char *endp = rs->buf + get_remote_packet_size ();
+      enum packet_result result;
+
+      strcpy (p, "qGetTIBAddr:");
+      p += strlen (p);
+      p = write_ptid (p, endp, ptid);
+      *p++ = '\0';
+
+      putpkt (rs->buf);
+      getpkt (&rs->buf, &rs->buf_size, 0);
+      result = packet_ok (rs->buf,
+			  &remote_protocol_packets[PACKET_qGetTIBAddr]);
+      if (result == PACKET_OK)
+	{
+	  ULONGEST result;
+
+	  unpack_varlen_hex (rs->buf, &result);
+	  if (addr)
+	    *addr = (CORE_ADDR) result;
+	  return 1;
+	}
+      else if (result == PACKET_UNKNOWN)
+	error (_("Remote target doesn't support qGetTIBAddr packet"));
+      else
+	error (_("Remote target failed to process qGetTIBAddr request"));
+    }
+  else
+    error (_("qGetTIBAddr not supported or disabled on this target"));
+  /* Not reached.  */
+  return 0;
+}
+
+
 /* Support for inferring a target description based on the current
    architecture and the size of a 'g' packet.  While the 'g' packet
    can have any size (since optional registers can be left off the
@@ -9890,6 +9934,8 @@ Specify the serial device it is connecte
   remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer;
   remote_ops.to_core_of_thread = remote_core_of_thread;
   remote_ops.to_verify_memory = remote_verify_memory;
+  remote_ops.to_get_tib_address = remote_get_tib_address;
+ 
 }
 
 /* Set up the extended remote vector by making a copy of the standard
@@ -10309,6 +10355,10 @@ Show the maximum size of the address (in
 			 "qGetTLSAddr", "get-thread-local-storage-address",
 			 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTIBAddr],
+			 "qGetTIBAddr", "get-thread-information-block-address",
+			 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_bc],
 			 "bc", "reverse-continue", 0);
 
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.245
diff -u -p -r1.245 target.c
--- target.c	24 Mar 2010 01:12:13 -0000	1.245
+++ target.c	13 Apr 2010 07:35:20 -0000
@@ -660,6 +660,7 @@ update_current_target (void)
       INHERIT (to_get_raw_trace_data, t);
       INHERIT (to_set_disconnected_tracing, t);
       INHERIT (to_set_circular_trace_buffer, t);
+      INHERIT (to_get_tib_address, t);
       INHERIT (to_magic, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
@@ -853,6 +854,9 @@ update_current_target (void)
   de_fault (to_set_circular_trace_buffer,
 	    (void (*) (int))
 	    target_ignore);
+  de_fault (to_get_tib_address,
+	    (int (*) (ptid_t, CORE_ADDR *))
+	    tcomplain);
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.177
diff -u -p -r1.177 target.h
--- target.h	24 Mar 2010 01:12:13 -0000	1.177
+++ target.h	13 Apr 2010 07:35:21 -0000
@@ -682,6 +682,10 @@ struct target_ops
     int (*to_verify_memory) (struct target_ops *, const gdb_byte *data,
 			     CORE_ADDR memaddr, ULONGEST size);
 
+    /* Return the address of the start of the Thread Information Block
+       a Windows OS specific feature.  */
+    int (*to_get_tib_address) (ptid_t ptid, CORE_ADDR *addr);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -1371,6 +1375,9 @@ extern int target_search_memory (CORE_AD
 #define	target_set_circular_trace_buffer(val)	\
   (*current_target.to_set_circular_trace_buffer) (val)
 
+#define target_get_tib_address(ptid, addr) \
+  (*current_target.to_get_tib_address) ((ptid), (addr))
+
 /* Command logging facility.  */
 
 #define target_log_command(p)						\
Index: windows-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/windows-nat.c,v
retrieving revision 1.207
diff -u -p -r1.207 windows-nat.c
--- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
+++ windows-nat.c	13 Apr 2010 07:35:24 -0000
@@ -191,6 +191,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;
@@ -320,7 +321,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;
@@ -335,6 +336,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);
@@ -1074,15 +1076,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 (\
@@ -1271,9 +1264,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;
 }
 
@@ -1447,7 +1442,9 @@ 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:
@@ -1481,7 +1478,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;
 
@@ -2266,6 +2264,24 @@ windows_xfer_partial (struct target_ops 
     }
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.
+   Returns 1 if ptid is found and thread_local_base is non zero.  */
+
+static int
+windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  thread_info *th;
+
+  th = thread_rec (ptid_get_tid (ptid), 0);
+  if (th == NULL)
+    return 0;
+
+  if (addr != NULL)
+    *addr = th->thread_local_base;
+
+  return 1;
+}
+
 static ptid_t
 windows_get_ada_task_ptid (long lwp, long thread)
 {
@@ -2314,6 +2330,7 @@ init_windows_ops (void)
   windows_ops.to_has_execution = default_child_has_execution;
   windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
   windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
+  windows_ops.to_get_tib_address = windows_get_tib_address;
 
   i386_use_watchpoints (&windows_ops);
 
@@ -2415,9 +2432,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.5
diff -u -p -r1.5 windows-tdep.c
--- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
+++ windows-tdep.c	13 Apr 2010 07:35:25 -0000
@@ -19,6 +19,353 @@
 #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"
+#include "gdbthread.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 active_rpc_handle;			/* %fs:0x0028 */
+    uint32_t thread_local_storage;		/* %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 */
+    uint64_t environment_pointer;		/* %gs:0x0038 */
+    uint64_t process_id;			/* %gs:0x0040 */
+    uint64_t current_thread_id;			/* %gs:0x0048 */
+    uint64_t active_rpc_handle;			/* %gs:0x0050 */
+    uint64_t thread_local_storage;		/* %gs:0x0058 */
+    uint64_t process_environment_block;		/* %gs:0x0060 */
+    uint64_t last_error_number;			/* %gs:0x0068 */
+  }
+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 */
+    " active_rpc_handle           ",	/* %fs:0x0028 */
+    " thread_local_storage        ",	/* %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 Thread Local Base pointer type.  */
+
+static struct type *
+windows_get_tlb_type (struct gdbarch *gdbarch)
+{
+  struct type *dword_ptr_type, *dword32_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");
+  dword32_type = arch_integer_type (gdbarch, 32,
+				 1, "DWORD32");
+  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 */
+  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", dword32_type);
+  append_composite_type_field (peb_ldr_type, "initialized", dword32_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");
+
+  /* First bytes contain several flags.  */
+  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 active_rpc_handle;		%fs:0x0028 */
+  append_composite_type_field (tib_type, "active_rpc_handle", dword_ptr_type);
+  /* uint32_t thread_local_storage;		%fs:0x002c */
+  append_composite_type_field (tib_type, "thread_local_storage", void_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 is
+   also dependent on which thread you have selected.  */
+
+/* This function implements the lval_computed support for reading a
+   $_tlb value.  */
+
+static void
+tlb_value_read (struct value *val)
+{
+  CORE_ADDR tlb;
+  struct type *type = check_typedef (value_type (val));
+
+  if (!target_get_tib_address (inferior_ptid, &tlb))
+    error (_("Unable to read tlb"));
+  store_typed_address (value_contents_raw (val), type, tlb);
+}
+
+/* This function implements the lval_computed support for writing a
+   $_tlb 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 (ptid_t ptid)
+{
+  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.  */
+
+  if (target_get_tib_address (ptid, &thread_local_base) == 0)
+    {
+      printf_filtered (_("Unable to get thread local base for %s\n"),
+	target_pid_to_str (ptid));
+      return -1;
+    }
+
+  if (target_read (&current_target, TARGET_OBJECT_MEMORY,
+		   NULL, tib, thread_local_base, tib_size) != tib_size)
+    {
+      printf_filtered (_("Unable to read thread information block for %s at \
+address %s\n"),
+	target_pid_to_str (ptid), 
+	paddress (target_gdbarch, thread_local_base));
+      return -1;
+    }
+
+  printf_filtered (_("Thread Information Block %s at %s\n"),
+		   target_pid_to_str (ptid),
+		   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)
+    {
+      struct thread_info *tp;
+      int gdb_id = value_as_long (parse_and_eval (args));
+
+      tp = find_thread_id (gdb_id);
+
+      if (!tp)
+	error (_("Thread ID %d not known."), gdb_id);
+
+      if (!target_thread_alive (tp->ptid))
+	error (_("Thread ID %d has terminated."), gdb_id);
+
+      display_one_tib (tp->ptid);
+    }
+  else if (!ptid_equal (inferior_ptid, null_ptid))
+    display_one_tib (inferior_ptid);
+}
 
 void
 windows_xfer_shared_library (const char* so_name, CORE_ADDR load_addr,
@@ -36,3 +383,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 their 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.4
diff -u -p -r1.4 windows-tdep.h
--- windows-tdep.h	1 Jan 2010 07:31:46 -0000	1.4
+++ windows-tdep.h	13 Apr 2010 07:35:25 -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: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.703
diff -u -p -r1.703 gdb.texinfo
--- doc/gdb.texinfo	9 Apr 2010 20:46:40 -0000	1.703
+++ doc/gdb.texinfo	13 Apr 2010 07:35:40 -0000
@@ -8054,6 +8054,15 @@ The variable @code{$_siginfo} contains e
 (@pxref{extra signal information}).  Note that @code{$_siginfo}
 could be empty, if the application has not yet received any signals.
 For example, it will be empty before you execute the @code{run} command.
+
+@item $_tlb
+@vindex $_tlb@r{, convenience variable}
+The variable @code{$_tlb} is automatically set when debugging
+applications running on MS-Windows in native mode or connected to
+gdbserver that supports the @code{qGetTIBAddr} request. 
+@xref{General Query Packets}.
+This variable contains the address of the thread information block.
+
 @end table
 
 On HP-UX systems, if you refer to a function or variable name that
@@ -15755,6 +15764,10 @@ are:
 @tab @code{qGetTLSAddr}
 @tab Displaying @code{__thread} variables
 
+@item @code{get-thread-information-block-address}
+@tab @code{qGetTIBAddr}
+@tab Display MS-Windows Thread Information Block.
+
 @item @code{search-memory}
 @tab @code{qSearch:memory}
 @tab @code{find}
@@ -16534,6 +16547,11 @@ a long value to give the information abo
 Without argument, this command displays information
 about the six segment registers.
 
+@item info w32 thread-information-block
+This command displays thread specific information stored in the
+Thread Information Block for x86 CPU family (readable using @code{$fs}
+selector for 32-bit programs and @code{$gs} for 64-bit programs).
+
 @kindex info dll
 @item info dll
 This is a Cygwin-specific alias of @code{info shared}.
@@ -29382,6 +29400,14 @@ enabled, the debug registers values are 
 removes a hardware breakpoint or watchpoint, and when the inferior
 triggers a hardware-assisted breakpoint or watchpoint.
 
+@kindex maint set show-all-tib
+@kindex maint show show-all-tib
+@item maint set show-all-tib
+@itemx maint show show-all-tib
+Control whether to show all non zero areas within a 1k block starting
+at thread local base, when using @samp{info w32 thread-information-block}
+command.
+
 @kindex maint space
 @cindex memory used by commands
 @item maint space
@@ -30595,6 +30621,28 @@ An error occurred.  @var{nn} are hex dig
 An empty reply indicates that @samp{qGetTLSAddr} is not supported by the stub.
 @end table
 
+@item qGetTIBAddr:@var{thread-id}:
+@cindex get thread information block address
+@cindex @samp{qGetTIBAddr} packet
+Fetch address of the Windows OS specific Thread Information Block.
+
+@var{thread-id} is the thread ID associated with the thread.
+
+Reply:
+@table @samp
+@item @var{XX}@dots{}
+Hex encoded (big endian) bytes representing the linear address of the
+thread information block.
+
+@item E @var{nn}
+An error occured.  This means that either the thread was not found, or the
+address could not be retrieved.
+
+@item
+An empty reply indicates that @samp{qGetTIBAddr} is not supported by the stub.
+@end table
+
+
 @item qL @var{startflag} @var{threadcount} @var{nextthread}
 Obtain thread information from RTOS.  Where: @var{startflag} (one hex
 digit) is one to indicate the first query and zero to indicate a
Index: gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.115
diff -u -p -r1.115 server.c
--- gdbserver/server.c	12 Apr 2010 17:39:42 -0000	1.115
+++ gdbserver/server.c	13 Apr 2010 07:35:41 -0000
@@ -1379,6 +1379,9 @@ handle_query (char *own_buf, int packet_
       if (the_target->qxfer_osdata != NULL)
 	strcat (own_buf, ";qXfer:osdata:read+");
 
+      if (the_target->get_tib_address != NULL)
+	strcat (own_buf, ";qGetTIBAddr+");
+
       if (target_supports_multi_process ())
 	strcat (own_buf, ";multiprocess+");
 
@@ -1463,6 +1466,31 @@ handle_query (char *own_buf, int packet_
       /* Otherwise, pretend we do not understand this packet.  */
     }
 
+  /* Windows OS Thread Information Block address support.  */
+  if (the_target->get_tib_address != NULL
+      && strncmp ("qGetTIBAddr:", own_buf, 12) == 0)
+    {
+      char *annex;
+      int n;
+      CORE_ADDR tlb;
+      ptid_t ptid = read_ptid (own_buf + 12, &annex);
+
+      n = (*the_target->get_tib_address) (ptid, &tlb);
+      if (n == 1)
+	{
+	  sprintf (own_buf, "%llx", tlb);
+	  return;
+	}
+      else if (n == 0)
+	{
+	  write_enn (own_buf);
+	  return;
+	}
+      return;
+    }
+
+
+
   /* Handle "monitor" commands.  */
   if (strncmp ("qRcmd,", own_buf, 6) == 0)
     {
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.46
diff -u -p -r1.46 target.h
--- gdbserver/target.h	11 Apr 2010 16:33:56 -0000	1.46
+++ gdbserver/target.h	13 Apr 2010 07:35:41 -0000
@@ -271,6 +271,9 @@ struct target_ops
 			unsigned const char *writebuf,
 			CORE_ADDR offset, int len);
 
+  /* Read Thread Information Block address.  */
+  int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address);
+
   int (*supports_non_stop) (void);
 
   /* Enables async target events.  Returns the previous enable
Index: gdbserver/win32-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v
retrieving revision 1.45
diff -u -p -r1.45 win32-low.c
--- gdbserver/win32-low.c	12 Apr 2010 17:39:42 -0000	1.45
+++ gdbserver/win32-low.c	13 Apr 2010 07:35:42 -0000
@@ -178,7 +178,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);
@@ -189,6 +189,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 *)
@@ -1455,7 +1456,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:
@@ -1485,7 +1487,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
@@ -1753,6 +1756,21 @@ wince_hostio_last_error (char *buf)
 }
 #endif
 
+/* Write Windows OS Thread Information Block address.  */
+
+static int
+win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  win32_thread_info *th;
+  th = thread_rec (ptid, 0);
+  if (th == NULL)
+    return 0;
+  if (addr != NULL)
+    *addr = th->thread_local_base;
+  return 1;
+}
+
+
 static struct target_ops win32_target_ops = {
   win32_create_inferior,
   win32_attach,
@@ -1782,6 +1800,9 @@ static struct target_ops win32_target_op
 #else
   hostio_last_error_from_errno,
 #endif
+  NULL,
+  NULL,
+  win32_get_tib_address,
 };
 
 /* Initialize the Win32 backend.  */
Index: gdbserver/win32-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v
retrieving revision 1.12
diff -u -p -r1.12 win32-low.h
--- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
+++ gdbserver/win32-low.h	13 Apr 2010 07:35:42 -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;
 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFA-v7] Add windows OS Thread Information Block
  2010-04-13  8:38                                     ` [RFA-v7] " Pierre Muller
@ 2010-04-13 11:14                                       ` Pedro Alves
  2010-04-13 13:21                                         ` [RFA-v8] " Pierre Muller
  0 siblings, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2010-04-13 11:14 UTC (permalink / raw)
  To: Pierre Muller; +Cc: 'Eli Zaretskii', gdb-patches

On Tuesday 13 April 2010 09:38:23, Pierre Muller wrote:

> > > +      if (the_target->get_tib_address != NULL)
> > > +       strcat (own_buf, ";qGetTIBAddr+");
> > 
> > You missed addressing a comment I made to this:
> 
>   I guessed that this is the needed counterpart of the fact
> that qGetTIBAddr is in the list of features that can be disabled.

Not really.  Notice how The `qGetTLSAddr' packet, which you're
basing your new packet on, doesn't have this equivalent qSupported
feature, and you can still disable it with the
`set remote get-thread-local-storage-address' command.

> > I can't seem to find where this new qsupported feature
> > was documented in the manual changes?  (and is this needed
> > at all?  I guess it doesn't hurt.)
> 
>   At least, I tested disabling it with 'set remote get-thread-information-block-address off'
> and that worked OK.

See above.  The way it is in your patch currently, this
isn't doing what you think it is.  It's actually doing nothing.
For it to work, you'd need to add a new entry in the `remote_protocol_features'
array, with PACKED_DISABLE as default, so that only when the feature
is reported would this test:

+  if (remote_protocol_packets[PACKET_qGetTIBAddr].support != PACKET_DISABLE)
+    {

fail.

As is, remote_protocol_packets[PACKET_qGetTIBAddr].support starts as
PACKET_SUPPORT_UNKNOWN, and on first use, the packet_ok call below
updates it depending on the remote stub reply:

+      getpkt (&rs->buf, &rs->buf_size, 0);
+      result = packet_ok (rs->buf,
+                         &remote_protocol_packets[PACKET_qGetTIBAddr]);


Again, what I'm saying is: _new qSupported features need to be
documented in the manual_.  If this stays, it needs to be
documented.  But if it stays, it needs to be made to work correctly.
And hence my earlier question: (is this needed at all?).
Please, do try to fully understand all code you write and propose.
I think these hints should get you a good start.

>   Here is one more version.
>   The main change (apart from the suggestions made by Pedro)
> is the addition of a NEWS entry.
> 

> 	*  windows-tdep.h (info_w32_cmdlist): Declare.

             ^  spurious double space.

> Index: NEWS
> ===================================================================
> RCS file: /cvs/src/src/gdb/NEWS,v
> retrieving revision 1.369
> diff -u -p -r1.369 NEWS
> --- NEWS	9 Apr 2010 15:26:54 -0000	1.369
> +++ NEWS	13 Apr 2010 07:34:59 -0000
> @@ -3,6 +3,14 @@
>  
>  *** Changes since GDB 7.1
>  
> +* New Windows OS feature: Thread Information Block.
> +
> +  - GDB now supports disaplying of thread specific information for
> +  Windows OS executables. This feature is accessible either as a new command
> +  'info w32 thread-information-block' or as a new computed internal variable
> +  named '$_tlb' a thread-specific pointer to the Thread Information Block.
> +  'qGetTIBAddr' is a new remote packet associated with this feature.
> +

Typo "disaplying".  Double space after period.  Note that the GNU
single-quote style is to open a quote with a back-quote (`).  Also, you're
not adding a new feature to the OS.  :-)  May I suggest this instead ? :

Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS   2010-04-13 11:34:17.000000000 +0100
+++ src/gdb/NEWS        2010-04-13 11:37:54.000000000 +0100
@@ -3,6 +3,22 @@

 *** Changes since GDB 7.1

+* Windows Thread Information Block access.
+
+  On Windows targets, GDB now supports displaying the Windows Thread
+  Information Block (TIB) structure.  This structure is visible either
+  by using the new command `info w32 thread-information-block' or, by
+  dereferencing the new convenience variable named `$_tlb', a
+  thread-specific pointer to the TIB.  This feature is also supported
+  when remote debugging using GDBserver.
+
+* New remote packets
+
+qGetTIBAddr
+
+  Return the address of the Windows Thread Information Block of the
+  current thread.
+
 * New features in the GDB remote stub, GDBserver

   - GDBserver now support tracepoints.  The feature is currently


>  /* Support for inferring a target description based on the current
>     architecture and the size of a 'g' packet.  While the 'g' packet
>     can have any size (since optional registers can be left off the
> @@ -9890,6 +9934,8 @@ Specify the serial device it is connecte
>    remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer;
>    remote_ops.to_core_of_thread = remote_core_of_thread;
>    remote_ops.to_verify_memory = remote_verify_memory;
> +  remote_ops.to_get_tib_address = remote_get_tib_address;
> + 

Spurious new line.

>  }


> +/* Provide thread local base, i.e. Thread Information Block address.
> +   Returns 1 if ptid is found and thread_local_base is non zero.  */

You also need to update the comment...

> +
> +static int
> +windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
> +{
> +  thread_info *th;
> +
> +  th = thread_rec (ptid_get_tid (ptid), 0);
> +  if (th == NULL)
> +    return 0;
> +
> +  if (addr != NULL)
> +    *addr = th->thread_local_base;
> +
> +  return 1;
> +}


> +static void
> +tlb_value_write (struct value *v, struct value *fromval)
> +{
> +  error (_("Impossible to change tlb"));

This is really a nit, but I suggest

  error (_("Impossible to change the Thread Local Base."));

Or,

  error (_("Impossible to change the TLB."));


> +  tib = alloca (tib_size);
> +
> +  /* This needs to be changed if multi-process support is added.  */

This comment is still here.  I thought you were going to remove it?


> +/* 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

While we're at it, add a new line here too, please.

> +display_tib (char * args, int from_tty)


> +  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 their meaning is unknown."),
> +			   NULL,
> +			   NULL,

If you would please install a real `show' callback instead of this
second NULL, I'd appreciate it.  The reason is that the default callback
when this is left as NULL can't work correctly in non-English.  A goal
is to have no command left with this callback left as NULL.
But if you don't want to do it now (too many iterations already!), it's
quite fine.

> +@item info w32 thread-information-block
> +This command displays thread specific information stored in the
> +Thread Information Block for x86 CPU family (readable using @code{$fs}
> +selector for 32-bit programs and @code{$gs} for 64-bit programs).

Could you instead say:

+Thread Information Block (readable on the X86 CPU family using @code{$fs}
+selector for 32-bit programs and @code{$gs} for 64-bit programs).


> +@kindex maint set show-all-tib
> +@kindex maint show show-all-tib
> +@item maint set show-all-tib
> +@itemx maint show show-all-tib
> +Control whether to show all non zero areas within a 1k block starting
> +at thread local base, when using @samp{info w32 thread-information-block}
> +command.

when using _the_ ... command.


> +@item qGetTIBAddr:@var{thread-id}:

                                    ^

This `:' is spurious; it isn't a part of the packet.  Please remove it.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [RFA-v8] Add windows OS Thread Information Block
  2010-04-13 11:14                                       ` Pedro Alves
@ 2010-04-13 13:21                                         ` Pierre Muller
  2010-04-13 15:06                                           ` Pedro Alves
  0 siblings, 1 reply; 34+ messages in thread
From: Pierre Muller @ 2010-04-13 13:21 UTC (permalink / raw)
  To: 'Pedro Alves'; +Cc: 'Eli Zaretskii', gdb-patches

> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Pedro Alves
> Envoyé : Tuesday, April 13, 2010 1:14 PM
> À : Pierre Muller
> Cc : 'Eli Zaretskii'; gdb-patches@sourceware.org
> Objet : Re: [RFA-v7] Add windows OS Thread Information Block
> 
> On Tuesday 13 April 2010 09:38:23, Pierre Muller wrote:
> 
> > > > +      if (the_target->get_tib_address != NULL)
> > > > +       strcat (own_buf, ";qGetTIBAddr+");
> > >
> > > You missed addressing a comment I made to this:
> >
> >   I guessed that this is the needed counterpart of the fact
> > that qGetTIBAddr is in the list of features that can be disabled.
> 
> Not really.  Notice how The `qGetTLSAddr' packet, which you're
> basing your new packet on, doesn't have this equivalent qSupported
> feature, and you can still disable it with the
> `set remote get-thread-local-storage-address' command.

  OK, I think I now understand that I was mixing the 'set remote XXX off'
and this qSupported packet.
  I thus agree that it is probably not useful and I thus removed it 
from gdbserver/server.c code.
 
> >   Here is one more version.
> >   The main change (apart from the suggestions made by Pedro)
> > is the addition of a NEWS entry.
> >
> 
> > 	*  windows-tdep.h (info_w32_cmdlist): Declare.
> 
>              ^  spurious double space.
Fixed.
 

> Typo "disaplying".  Double space after period.  Note that the GNU
> single-quote style is to open a quote with a back-quote (`).  Also,
> you're
> not adding a new feature to the OS.  :-)  May I suggest this instead ?
> :
> 
> Index: src/gdb/NEWS
> ===================================================================
> --- src.orig/gdb/NEWS   2010-04-13 11:34:17.000000000 +0100
> +++ src/gdb/NEWS        2010-04-13 11:37:54.000000000 +0100
> @@ -3,6 +3,22 @@
> 
>  *** Changes since GDB 7.1
> 
> +* Windows Thread Information Block access.
> +
> +  On Windows targets, GDB now supports displaying the Windows Thread
> +  Information Block (TIB) structure.  This structure is visible either
> +  by using the new command `info w32 thread-information-block' or, by
> +  dereferencing the new convenience variable named `$_tlb', a
> +  thread-specific pointer to the TIB.  This feature is also supported
> +  when remote debugging using GDBserver.
> +
> +* New remote packets
> +
> +qGetTIBAddr
> +
> +  Return the address of the Windows Thread Information Block of the
> +  current thread.
> +
>  * New features in the GDB remote stub, GDBserver
> 
>    - GDBserver now support tracepoints.  The feature is currently
> 

  This is perfect for me, inserted as is.
 
> >  /* Support for inferring a target description based on the current
> >     architecture and the size of a 'g' packet.  While the 'g' packet
> >     can have any size (since optional registers can be left off the
> > @@ -9890,6 +9934,8 @@ Specify the serial device it is connecte
> >    remote_ops.to_set_circular_trace_buffer =
> remote_set_circular_trace_buffer;
> >    remote_ops.to_core_of_thread = remote_core_of_thread;
> >    remote_ops.to_verify_memory = remote_verify_memory;
> > +  remote_ops.to_get_tib_address = remote_get_tib_address;
> > +
> 
> Spurious new line.

  Removed.
> >  }
> 
> 
> > +/* Provide thread local base, i.e. Thread Information Block address.
> > +   Returns 1 if ptid is found and thread_local_base is non zero.  */
> 
> You also need to update the comment...

Done.
> > +
> > +static int
> > +windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
> > +{
> > +  thread_info *th;
> > +
> > +  th = thread_rec (ptid_get_tid (ptid), 0);
> > +  if (th == NULL)
> > +    return 0;
> > +
> > +  if (addr != NULL)
> > +    *addr = th->thread_local_base;
> > +
> > +  return 1;
> > +}
> 
> 
> > +static void
> > +tlb_value_write (struct value *v, struct value *fromval)
> > +{
> > +  error (_("Impossible to change tlb"));
> 
> This is really a nit, but I suggest
> 
>   error (_("Impossible to change the Thread Local Base."));

  I will go for this one.
 
> > +  tib = alloca (tib_size);
> > +
> > +  /* This needs to be changed if multi-process support is added.  */
> 
> This comment is still here.  I thought you were going to remove it?
 
  One more that I missed, sorry.
 
> > +/* 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
> 
> While we're at it, add a new line here too, please.
Empty line added.
 
> > +display_tib (char * args, int from_tty)
> 
> 
> > +  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 their meaning is unknown."),
> > +			   NULL,
> > +			   NULL,
> 
> If you would please install a real `show' callback instead of this
> second NULL, I'd appreciate it.  The reason is that the default
> callback
> when this is left as NULL can't work correctly in non-English.  A goal
> is to have no command left with this callback left as NULL.
> But if you don't want to do it now (too many iterations already!), it's
> quite fine.

  I wrote something, but I didn't really understand why 
the string that is the fifth argument doesn't allow proper
internalization...
 
> > +@item info w32 thread-information-block
> > +This command displays thread specific information stored in the
> > +Thread Information Block for x86 CPU family (readable using
> @code{$fs}
> > +selector for 32-bit programs and @code{$gs} for 64-bit programs).
> 
> Could you instead say:
> 
> +Thread Information Block (readable on the X86 CPU family using
> @code{$fs}
> +selector for 32-bit programs and @code{$gs} for 64-bit programs).

  Seems good to me, changed.
 
> > +@kindex maint set show-all-tib
> > +@kindex maint show show-all-tib
> > +@item maint set show-all-tib
> > +@itemx maint show show-all-tib
> > +Control whether to show all non zero areas within a 1k block
> starting
> > +at thread local base, when using @samp{info w32 thread-information-
> block}
> > +command.
> 
> when using _the_ ... command.
> 
`the ' added.
 
> > +@item qGetTIBAddr:@var{thread-id}:
> 
>                                     ^
> 
> This `:' is spurious; it isn't a part of the packet.  Please remove it.

  spurious `:' removed.

Here is version 8:

Let's hope the final version is near...

2010-04-13  Pierre Muller  <muller@ics.u-strasbg.fr>

	Support for Windows OS Thread Information Block.
	* NEWS: Document new feature.
	* remote.c (PACKET_qGetTIBAddr): New enum element.
	(remote_get_tib_address): New function.
	(init_remote_ops): Set to_get_tib_address field
	to remote_get_tib_address.
	(_initialize_remote): Add add_packet_config_cmd
	for PACKET_qGetTIBAddr.
	* target.c (update_current_target): Set default value for
	new to_get_tib_address field.
	* target.h (target_ops): New field to_get_tib_address.
	(target_get_tib_address): New macro.
	* windows-nat.c (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_get_tib_address): New function.
	(init_windows_ops): Set to_get_tib_address field
	to remote_get_tib_address.
	(_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:

	* server.c (handle_query): Acknowledge support
	for 'qGetTIBAddr' if get_tib_addr field of the_target
	is set.
	Handle 'qGetTIBAddr' query.
	* target.h (target_ops): New get_tib_address field.
	* win32-low.h (win32_thread_info): Add thread_local_base field.
	* win32-low.c (child_add_thread): Add tlb argument.
	Set thread_local_base field to TLB.
	(get_child_debug_event): Adapt to child_add_thread change.
	(win32_get_tib_address): New function.
	(win32_target_ops): Set get_tib_address field to
	win32_get_tib_address.

doc/ChangeLog entry:

	gdb.texinfo ($_tlb): Document new automatic convinience variable.
	(info w32 thread-information-block): Document new command.
	(qGetTIBAddress): Document new gdbserver query.
	(maint set/show show-all-tib): Document new command.

Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.369
diff -u -p -r1.369 NEWS
--- NEWS	9 Apr 2010 15:26:54 -0000	1.369
+++ NEWS	13 Apr 2010 13:18:37 -0000
@@ -3,6 +3,22 @@
 
 *** Changes since GDB 7.1
 
+* Windows Thread Information Block access.
+
+  On Windows targets, GDB now supports displaying the Windows Thread
+  Information Block (TIB) structure.  This structure is visible either
+  by using the new command `info w32 thread-information-block' or, by
+  dereferencing the new convenience variable named `$_tlb', a
+  thread-specific pointer to the TIB.  This feature is also supported
+  when remote debugging using GDBserver.
+
+* New remote packets
+
+qGetTIBAddr
+
+  Return the address of the Windows Thread Information Block of the
+  current thread.
+
 * New features in the GDB remote stub, GDBserver
 
   - GDBserver now support tracepoints.  The feature is currently
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.400
diff -u -p -r1.400 remote.c
--- remote.c	9 Apr 2010 03:00:57 -0000	1.400
+++ remote.c	13 Apr 2010 13:18:40 -0000
@@ -1139,6 +1139,7 @@ enum {
   PACKET_qXfer_spu_write,
   PACKET_qXfer_osdata,
   PACKET_qXfer_threads,
+  PACKET_qGetTIBAddr,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
   PACKET_QPassSignals,
@@ -8441,6 +8442,48 @@ remote_get_thread_local_address (struct 
   return 0;
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.
+   Returns 1 if ptid is found and thread_local_base is non zero.  */
+
+int
+remote_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  if (remote_protocol_packets[PACKET_qGetTIBAddr].support != PACKET_DISABLE)
+    {
+      struct remote_state *rs = get_remote_state ();
+      char *p = rs->buf;
+      char *endp = rs->buf + get_remote_packet_size ();
+      enum packet_result result;
+
+      strcpy (p, "qGetTIBAddr:");
+      p += strlen (p);
+      p = write_ptid (p, endp, ptid);
+      *p++ = '\0';
+
+      putpkt (rs->buf);
+      getpkt (&rs->buf, &rs->buf_size, 0);
+      result = packet_ok (rs->buf,
+			  &remote_protocol_packets[PACKET_qGetTIBAddr]);
+      if (result == PACKET_OK)
+	{
+	  ULONGEST result;
+
+	  unpack_varlen_hex (rs->buf, &result);
+	  if (addr)
+	    *addr = (CORE_ADDR) result;
+	  return 1;
+	}
+      else if (result == PACKET_UNKNOWN)
+	error (_("Remote target doesn't support qGetTIBAddr packet"));
+      else
+	error (_("Remote target failed to process qGetTIBAddr request"));
+    }
+  else
+    error (_("qGetTIBAddr not supported or disabled on this target"));
+  /* Not reached.  */
+  return 0;
+}
+
 /* Support for inferring a target description based on the current
    architecture and the size of a 'g' packet.  While the 'g' packet
    can have any size (since optional registers can be left off the
@@ -9890,6 +9933,7 @@ Specify the serial device it is connecte
   remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer;
   remote_ops.to_core_of_thread = remote_core_of_thread;
   remote_ops.to_verify_memory = remote_verify_memory;
+  remote_ops.to_get_tib_address = remote_get_tib_address;
 }
 
 /* Set up the extended remote vector by making a copy of the standard
@@ -10309,6 +10353,10 @@ Show the maximum size of the address (in
 			 "qGetTLSAddr", "get-thread-local-storage-address",
 			 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTIBAddr],
+			 "qGetTIBAddr", "get-thread-information-block-address",
+			 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_bc],
 			 "bc", "reverse-continue", 0);
 
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.245
diff -u -p -r1.245 target.c
--- target.c	24 Mar 2010 01:12:13 -0000	1.245
+++ target.c	13 Apr 2010 13:18:42 -0000
@@ -660,6 +660,7 @@ update_current_target (void)
       INHERIT (to_get_raw_trace_data, t);
       INHERIT (to_set_disconnected_tracing, t);
       INHERIT (to_set_circular_trace_buffer, t);
+      INHERIT (to_get_tib_address, t);
       INHERIT (to_magic, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
@@ -853,6 +854,9 @@ update_current_target (void)
   de_fault (to_set_circular_trace_buffer,
 	    (void (*) (int))
 	    target_ignore);
+  de_fault (to_get_tib_address,
+	    (int (*) (ptid_t, CORE_ADDR *))
+	    tcomplain);
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.177
diff -u -p -r1.177 target.h
--- target.h	24 Mar 2010 01:12:13 -0000	1.177
+++ target.h	13 Apr 2010 13:18:42 -0000
@@ -682,6 +682,10 @@ struct target_ops
     int (*to_verify_memory) (struct target_ops *, const gdb_byte *data,
 			     CORE_ADDR memaddr, ULONGEST size);
 
+    /* Return the address of the start of the Thread Information Block
+       a Windows OS specific feature.  */
+    int (*to_get_tib_address) (ptid_t ptid, CORE_ADDR *addr);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -1371,6 +1375,9 @@ extern int target_search_memory (CORE_AD
 #define	target_set_circular_trace_buffer(val)	\
   (*current_target.to_set_circular_trace_buffer) (val)
 
+#define target_get_tib_address(ptid, addr) \
+  (*current_target.to_get_tib_address) ((ptid), (addr))
+
 /* Command logging facility.  */
 
 #define target_log_command(p)						\
Index: windows-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/windows-nat.c,v
retrieving revision 1.207
diff -u -p -r1.207 windows-nat.c
--- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
+++ windows-nat.c	13 Apr 2010 13:18:43 -0000
@@ -191,6 +191,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;
@@ -320,7 +321,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;
@@ -335,6 +336,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);
@@ -1074,15 +1076,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 (\
@@ -1271,9 +1264,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;
 }
 
@@ -1447,7 +1442,9 @@ 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:
@@ -1481,7 +1478,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;
 
@@ -2266,6 +2264,24 @@ windows_xfer_partial (struct target_ops 
     }
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.
+   Returns 1 if ptid is found and sets *ADDR to thread_local_base.  */
+
+static int
+windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  thread_info *th;
+
+  th = thread_rec (ptid_get_tid (ptid), 0);
+  if (th == NULL)
+    return 0;
+
+  if (addr != NULL)
+    *addr = th->thread_local_base;
+
+  return 1;
+}
+
 static ptid_t
 windows_get_ada_task_ptid (long lwp, long thread)
 {
@@ -2314,6 +2330,7 @@ init_windows_ops (void)
   windows_ops.to_has_execution = default_child_has_execution;
   windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
   windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
+  windows_ops.to_get_tib_address = windows_get_tib_address;
 
   i386_use_watchpoints (&windows_ops);
 
@@ -2415,9 +2432,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.5
diff -u -p -r1.5 windows-tdep.c
--- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
+++ windows-tdep.c	13 Apr 2010 13:18:43 -0000
@@ -19,6 +19,352 @@
 #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"
+#include "gdbthread.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 active_rpc_handle;			/* %fs:0x0028 */
+    uint32_t thread_local_storage;		/* %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 */
+    uint64_t environment_pointer;		/* %gs:0x0038 */
+    uint64_t process_id;			/* %gs:0x0040 */
+    uint64_t current_thread_id;			/* %gs:0x0048 */
+    uint64_t active_rpc_handle;			/* %gs:0x0050 */
+    uint64_t thread_local_storage;		/* %gs:0x0058 */
+    uint64_t process_environment_block;		/* %gs:0x0060 */
+    uint64_t last_error_number;			/* %gs:0x0068 */
+  }
+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 */
+    " active_rpc_handle           ",	/* %fs:0x0028 */
+    " thread_local_storage        ",	/* %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 Thread Local Base pointer type.  */
+
+static struct type *
+windows_get_tlb_type (struct gdbarch *gdbarch)
+{
+  struct type *dword_ptr_type, *dword32_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");
+  dword32_type = arch_integer_type (gdbarch, 32,
+				 1, "DWORD32");
+  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 */
+  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", dword32_type);
+  append_composite_type_field (peb_ldr_type, "initialized", dword32_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");
+
+  /* First bytes contain several flags.  */
+  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 active_rpc_handle;		%fs:0x0028 */
+  append_composite_type_field (tib_type, "active_rpc_handle", dword_ptr_type);
+  /* uint32_t thread_local_storage;		%fs:0x002c */
+  append_composite_type_field (tib_type, "thread_local_storage", void_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 is
+   also dependent on which thread you have selected.  */
+
+/* This function implements the lval_computed support for reading a
+   $_tlb value.  */
+
+static void
+tlb_value_read (struct value *val)
+{
+  CORE_ADDR tlb;
+  struct type *type = check_typedef (value_type (val));
+
+  if (!target_get_tib_address (inferior_ptid, &tlb))
+    error (_("Unable to read tlb"));
+  store_typed_address (value_contents_raw (val), type, tlb);
+}
+
+/* This function implements the lval_computed support for writing a
+   $_tlb value.  */
+
+static void
+tlb_value_write (struct value *v, struct value *fromval)
+{
+  error (_("Impossible to change the Thread Local Base"));
+}
+
+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 (ptid_t ptid)
+{
+  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);
+
+  if (target_get_tib_address (ptid, &thread_local_base) == 0)
+    {
+      printf_filtered (_("Unable to get thread local base for %s\n"),
+	target_pid_to_str (ptid));
+      return -1;
+    }
+
+  if (target_read (&current_target, TARGET_OBJECT_MEMORY,
+		   NULL, tib, thread_local_base, tib_size) != tib_size)
+    {
+      printf_filtered (_("Unable to read thread information block for %s at \
+address %s\n"),
+	target_pid_to_str (ptid), 
+	paddress (target_gdbarch, thread_local_base));
+      return -1;
+    }
+
+  printf_filtered (_("Thread Information Block %s at %s\n"),
+		   target_pid_to_str (ptid),
+		   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)
+    {
+      struct thread_info *tp;
+      int gdb_id = value_as_long (parse_and_eval (args));
+
+      tp = find_thread_id (gdb_id);
+
+      if (!tp)
+	error (_("Thread ID %d not known."), gdb_id);
+
+      if (!target_thread_alive (tp->ptid))
+	error (_("Thread ID %d has terminated."), gdb_id);
+
+      display_one_tib (tp->ptid);
+    }
+  else if (!ptid_equal (inferior_ptid, null_ptid))
+    display_one_tib (inferior_ptid);
+}
 
 void
 windows_xfer_shared_library (const char* so_name, CORE_ADDR load_addr,
@@ -36,3 +382,59 @@ windows_xfer_shared_library (const char*
   obstack_grow_str (obstack, paddress (gdbarch, load_addr + 0x1000));
   obstack_grow_str (obstack, "\"/></library>");
 }
+
+static void
+show_maint_show_all_tib (struct ui_file *file, int from_tty,
+		struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Show all non-zero elements of Thread Information \
+Block is %s.\n"), value);
+}
+
+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 their meaning is unknown."),
+			   NULL,
+			   show_maint_show_all_tib,
+			   &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.4
diff -u -p -r1.4 windows-tdep.h
--- windows-tdep.h	1 Jan 2010 07:31:46 -0000	1.4
+++ windows-tdep.h	13 Apr 2010 13:18:43 -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: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.703
diff -u -p -r1.703 gdb.texinfo
--- doc/gdb.texinfo	9 Apr 2010 20:46:40 -0000	1.703
+++ doc/gdb.texinfo	13 Apr 2010 13:18:57 -0000
@@ -8054,6 +8054,15 @@ The variable @code{$_siginfo} contains e
 (@pxref{extra signal information}).  Note that @code{$_siginfo}
 could be empty, if the application has not yet received any signals.
 For example, it will be empty before you execute the @code{run} command.
+
+@item $_tlb
+@vindex $_tlb@r{, convenience variable}
+The variable @code{$_tlb} is automatically set when debugging
+applications running on MS-Windows in native mode or connected to
+gdbserver that supports the @code{qGetTIBAddr} request. 
+@xref{General Query Packets}.
+This variable contains the address of the thread information block.
+
 @end table
 
 On HP-UX systems, if you refer to a function or variable name that
@@ -15755,6 +15764,10 @@ are:
 @tab @code{qGetTLSAddr}
 @tab Displaying @code{__thread} variables
 
+@item @code{get-thread-information-block-address}
+@tab @code{qGetTIBAddr}
+@tab Display MS-Windows Thread Information Block.
+
 @item @code{search-memory}
 @tab @code{qSearch:memory}
 @tab @code{find}
@@ -16534,6 +16547,11 @@ a long value to give the information abo
 Without argument, this command displays information
 about the six segment registers.
 
+@item info w32 thread-information-block
+This command displays thread specific information stored in the
+Thread Information Block (readable on the X86 CPU family using @code{$fs}
+selector for 32-bit programs and @code{$gs} for 64-bit programs).
+
 @kindex info dll
 @item info dll
 This is a Cygwin-specific alias of @code{info shared}.
@@ -29382,6 +29400,14 @@ enabled, the debug registers values are 
 removes a hardware breakpoint or watchpoint, and when the inferior
 triggers a hardware-assisted breakpoint or watchpoint.
 
+@kindex maint set show-all-tib
+@kindex maint show show-all-tib
+@item maint set show-all-tib
+@itemx maint show show-all-tib
+Control whether to show all non zero areas within a 1k block starting
+at thread local base, when using the @samp{info w32 thread-information-block}
+command.
+
 @kindex maint space
 @cindex memory used by commands
 @item maint space
@@ -30595,6 +30621,27 @@ An error occurred.  @var{nn} are hex dig
 An empty reply indicates that @samp{qGetTLSAddr} is not supported by the stub.
 @end table
 
+@item qGetTIBAddr:@var{thread-id}
+@cindex get thread information block address
+@cindex @samp{qGetTIBAddr} packet
+Fetch address of the Windows OS specific Thread Information Block.
+
+@var{thread-id} is the thread ID associated with the thread.
+
+Reply:
+@table @samp
+@item @var{XX}@dots{}
+Hex encoded (big endian) bytes representing the linear address of the
+thread information block.
+
+@item E @var{nn}
+An error occured.  This means that either the thread was not found, or the
+address could not be retrieved.
+
+@item
+An empty reply indicates that @samp{qGetTIBAddr} is not supported by the stub.
+@end table
+
 @item qL @var{startflag} @var{threadcount} @var{nextthread}
 Obtain thread information from RTOS.  Where: @var{startflag} (one hex
 digit) is one to indicate the first query and zero to indicate a
Index: gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.115
diff -u -p -r1.115 server.c
--- gdbserver/server.c	12 Apr 2010 17:39:42 -0000	1.115
+++ gdbserver/server.c	13 Apr 2010 13:18:58 -0000
@@ -1463,6 +1463,29 @@ handle_query (char *own_buf, int packet_
       /* Otherwise, pretend we do not understand this packet.  */
     }
 
+  /* Windows OS Thread Information Block address support.  */
+  if (the_target->get_tib_address != NULL
+      && strncmp ("qGetTIBAddr:", own_buf, 12) == 0)
+    {
+      char *annex;
+      int n;
+      CORE_ADDR tlb;
+      ptid_t ptid = read_ptid (own_buf + 12, &annex);
+
+      n = (*the_target->get_tib_address) (ptid, &tlb);
+      if (n == 1)
+	{
+	  sprintf (own_buf, "%llx", tlb);
+	  return;
+	}
+      else if (n == 0)
+	{
+	  write_enn (own_buf);
+	  return;
+	}
+      return;
+    }
+
   /* Handle "monitor" commands.  */
   if (strncmp ("qRcmd,", own_buf, 6) == 0)
     {
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.46
diff -u -p -r1.46 target.h
--- gdbserver/target.h	11 Apr 2010 16:33:56 -0000	1.46
+++ gdbserver/target.h	13 Apr 2010 13:18:59 -0000
@@ -271,6 +271,9 @@ struct target_ops
 			unsigned const char *writebuf,
 			CORE_ADDR offset, int len);
 
+  /* Read Thread Information Block address.  */
+  int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address);
+
   int (*supports_non_stop) (void);
 
   /* Enables async target events.  Returns the previous enable
Index: gdbserver/win32-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v
retrieving revision 1.45
diff -u -p -r1.45 win32-low.c
--- gdbserver/win32-low.c	12 Apr 2010 17:39:42 -0000	1.45
+++ gdbserver/win32-low.c	13 Apr 2010 13:18:59 -0000
@@ -178,7 +178,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);
@@ -189,6 +189,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 *)
@@ -1455,7 +1456,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:
@@ -1485,7 +1487,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
@@ -1753,6 +1756,20 @@ wince_hostio_last_error (char *buf)
 }
 #endif
 
+/* Write Windows OS Thread Information Block address.  */
+
+static int
+win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  win32_thread_info *th;
+  th = thread_rec (ptid, 0);
+  if (th == NULL)
+    return 0;
+  if (addr != NULL)
+    *addr = th->thread_local_base;
+  return 1;
+}
+
 static struct target_ops win32_target_ops = {
   win32_create_inferior,
   win32_attach,
@@ -1782,6 +1799,9 @@ static struct target_ops win32_target_op
 #else
   hostio_last_error_from_errno,
 #endif
+  NULL,
+  NULL,
+  win32_get_tib_address,
 };
 
 /* Initialize the Win32 backend.  */
Index: gdbserver/win32-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v
retrieving revision 1.12
diff -u -p -r1.12 win32-low.h
--- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
+++ gdbserver/win32-low.h	13 Apr 2010 13:18:59 -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;
 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFA-v8] Add windows OS Thread Information Block
  2010-04-13 13:21                                         ` [RFA-v8] " Pierre Muller
@ 2010-04-13 15:06                                           ` Pedro Alves
  2010-04-13 17:42                                             ` Eli Zaretskii
                                                               ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Pedro Alves @ 2010-04-13 15:06 UTC (permalink / raw)
  To: Pierre Muller; +Cc: 'Eli Zaretskii', gdb-patches

On Tuesday 13 April 2010 14:21:09, Pierre Muller wrote:

> > +  Return the address of the Windows Thread Information Block of the
> > +  current thread.

This one's my fault: s/of the current/of a given/ please.  The thread
is explicitly specified in the packet.  No need to repost for this.

>   This is perfect for me, inserted as is.

> > If you would please install a real `show' callback instead of this
> > second NULL, I'd appreciate it.  The reason is that the default
> > callback
> > when this is left as NULL can't work correctly in non-English.  A goal
> > is to have no command left with this callback left as NULL.
> > But if you don't want to do it now (too many iterations already!), it's
> > quite fine.
> 
>   I wrote something, but I didn't really understand why 
> the string that is the fifth argument doesn't allow proper
> internalization...

Thanks.  The default callback (deprecated_show_value_hack) literally
skips 5 characters, strips the whitespace, and then uppercases the
following letter.  Then it appends "is <value>".  So, in your example:

  "Show whether to display all non-zero fields of thread information block"

is auto-transformed to:

  "Whether to display all non-zero fields of thread information block is <value>"

If the string is translated to non-English, this isn't going to work correctly.

> gdbserver/ChangeLog entry:
> 
> 	* server.c (handle_query): Acknowledge support
> 	for 'qGetTIBAddr' if get_tib_addr field of the_target
> 	is set.

This first sentence is no longer true.  May be good to go through
the whole changelog before committing.  Some more bits may be
out of date; I'm not going to check that myself.


One final thing you need to address when committing.  In gdbserver:

> +  /* Read Thread Information Block address.  */
> +  int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address);
> +
>    int (*supports_non_stop) (void);

and:

>  static struct target_ops win32_target_ops = {
>    win32_create_inferior,
>    win32_attach,
> @@ -1782,6 +1799,9 @@ static struct target_ops win32_target_op
>  #else
>    hostio_last_error_from_errno,
>  #endif
> +  NULL,
> +  NULL,
> +  win32_get_tib_address,
>  };

Please remember to update this correctly, by putting your
new callback as _last_ callback in the structure.  Otherwise,
you'd have to update all other target_ops (linux-low.c, nto-low.c,
spu.low.c).

Otherwise, this version looks good to me.  Please check it in if
Eli is okay with it as well.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFA-v8] Add windows OS Thread Information Block
  2010-04-13 15:06                                           ` Pedro Alves
@ 2010-04-13 17:42                                             ` Eli Zaretskii
  2010-04-15 22:54                                             ` [RFA-v9] Add Windows " Pierre Muller
       [not found]                                             ` <000c01cadcee$7ffcedd0$7ff6c970$%muller@ics-cnrs.unistra.fr>
  2 siblings, 0 replies; 34+ messages in thread
From: Eli Zaretskii @ 2010-04-13 17:42 UTC (permalink / raw)
  To: Pedro Alves; +Cc: pierre.muller, gdb-patches

> From: Pedro Alves <pedro@codesourcery.com>
> Date: Tue, 13 Apr 2010 16:06:35 +0100
> Cc: "'Eli Zaretskii'" <eliz@gnu.org>,
>  gdb-patches@sourceware.org
> 
> Otherwise, this version looks good to me.  Please check it in if
> Eli is okay with it as well.

I am.

Thanks.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [RFA-v9] Add Windows OS Thread Information Block
  2010-04-13 15:06                                           ` Pedro Alves
  2010-04-13 17:42                                             ` Eli Zaretskii
@ 2010-04-15 22:54                                             ` Pierre Muller
       [not found]                                             ` <000c01cadcee$7ffcedd0$7ff6c970$%muller@ics-cnrs.unistra.fr>
  2 siblings, 0 replies; 34+ messages in thread
From: Pierre Muller @ 2010-04-15 22:54 UTC (permalink / raw)
  To: 'Eli Zaretskii'; +Cc: 'Pedro Alves', gdb-patches

  Here is a (hopefully final) version of this patch to
support Thread Information Block for Windows OS executable in GDB.
I updated the NEWS and moved the get_tib_address field in gdbserver directory
to the last field as Pedro suggested about version 8.

  I got approval from Christopher for the windows files a while ago, and
from Pedro for general files.
  I still need the approval from Eli for the documentation part.
 
Pierre Muller


gdb/ChangeLog entry

2010-04-16  Pierre Muller  <muller@ics.u-strasbg.fr>

	Support for Windows OS Thread Information Block.
	* NEWS: Document new feature.
	* remote.c (PACKET_qGetTIBAddr): New enum element.
	(remote_get_tib_address): New function.
	(init_remote_ops): Set to_get_tib_address field
	to remote_get_tib_address.
	(_initialize_remote): Add add_packet_config_cmd
	for PACKET_qGetTIBAddr.
	* target.c (update_current_target): Set default value for
	new to_get_tib_address field.
	* target.h (target_ops): New field to_get_tib_address.
	(target_get_tib_address): New macro.
	* windows-nat.c (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_get_tib_address): New function.
	(init_windows_ops): Set to_get_tib_address field
	to remote_get_tib_address.
	(_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.

gdb/gdbserver/ChangeLog entry:
2010-04-16  Pierre Muller  <muller@ics.u-strasbg.fr>

	* server.c (handle_query): Handle 'qGetTIBAddr' query.
	* target.h (target_ops): New get_tib_address field.
	* win32-low.h (win32_thread_info): Add thread_local_base field.
	* win32-low.c (child_add_thread): Add tlb argument.
	Set thread_local_base field to TLB.
	(get_child_debug_event): Adapt to child_add_thread change.
	(win32_get_tib_address): New function.
	(win32_target_ops): Set get_tib_address field to
	win32_get_tib_address.

gdb/doc/ChangeLog entry:
2010-04-16  Pierre Muller  <muller@ics.u-strasbg.fr>

	gdb.texinfo ($_tlb): Document new automatic convinience variable.
	(info w32 thread-information-block): Document new command.
	(qGetTIBAddress): Document new gdbserver query.
	(maint set/show show-all-tib): Document new command.

Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.371
diff -u -p -r1.371 NEWS
--- NEWS	15 Apr 2010 19:54:12 -0000	1.371
+++ NEWS	15 Apr 2010 22:41:20 -0000
@@ -3,6 +3,21 @@
 
 *** Changes since GDB 7.1
 
+* Windows Thread Information Block access.
+
+  On Windows targets, GDB now supports displaying the Windows Thread
+  Information Block (TIB) structure.  This structure is visible either
+  by using the new command `info w32 thread-information-block' or, by
+  dereferencing the new convenience variable named `$_tlb', a
+  thread-specific pointer to the TIB.  This feature is also supported
+  when remote debugging using GDBserver.
+
+* New remote packets
+
+qGetTIBAddr
+
+  Return the address of the Windows Thread Information Block of a given thread.
+
 * The source command now accepts a -s option to force searching for the
   script in the source search path even if the script name specifies
   a directory.
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.401
diff -u -p -r1.401 remote.c
--- remote.c	13 Apr 2010 16:08:28 -0000	1.401
+++ remote.c	15 Apr 2010 22:41:23 -0000
@@ -1136,6 +1136,7 @@ enum {
   PACKET_qXfer_spu_write,
   PACKET_qXfer_osdata,
   PACKET_qXfer_threads,
+  PACKET_qGetTIBAddr,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
   PACKET_QPassSignals,
@@ -8437,6 +8438,48 @@ remote_get_thread_local_address (struct 
   return 0;
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.
+   Returns 1 if ptid is found and thread_local_base is non zero.  */
+
+int
+remote_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  if (remote_protocol_packets[PACKET_qGetTIBAddr].support != PACKET_DISABLE)
+    {
+      struct remote_state *rs = get_remote_state ();
+      char *p = rs->buf;
+      char *endp = rs->buf + get_remote_packet_size ();
+      enum packet_result result;
+
+      strcpy (p, "qGetTIBAddr:");
+      p += strlen (p);
+      p = write_ptid (p, endp, ptid);
+      *p++ = '\0';
+
+      putpkt (rs->buf);
+      getpkt (&rs->buf, &rs->buf_size, 0);
+      result = packet_ok (rs->buf,
+			  &remote_protocol_packets[PACKET_qGetTIBAddr]);
+      if (result == PACKET_OK)
+	{
+	  ULONGEST result;
+
+	  unpack_varlen_hex (rs->buf, &result);
+	  if (addr)
+	    *addr = (CORE_ADDR) result;
+	  return 1;
+	}
+      else if (result == PACKET_UNKNOWN)
+	error (_("Remote target doesn't support qGetTIBAddr packet"));
+      else
+	error (_("Remote target failed to process qGetTIBAddr request"));
+    }
+  else
+    error (_("qGetTIBAddr not supported or disabled on this target"));
+  /* Not reached.  */
+  return 0;
+}
+
 /* Support for inferring a target description based on the current
    architecture and the size of a 'g' packet.  While the 'g' packet
    can have any size (since optional registers can be left off the
@@ -9904,6 +9947,7 @@ Specify the serial device it is connecte
   remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer;
   remote_ops.to_core_of_thread = remote_core_of_thread;
   remote_ops.to_verify_memory = remote_verify_memory;
+  remote_ops.to_get_tib_address = remote_get_tib_address;
 }
 
 /* Set up the extended remote vector by making a copy of the standard
@@ -10323,6 +10367,10 @@ Show the maximum size of the address (in
 			 "qGetTLSAddr", "get-thread-local-storage-address",
 			 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTIBAddr],
+			 "qGetTIBAddr", "get-thread-information-block-address",
+			 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_bc],
 			 "bc", "reverse-continue", 0);
 
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.245
diff -u -p -r1.245 target.c
--- target.c	24 Mar 2010 01:12:13 -0000	1.245
+++ target.c	15 Apr 2010 22:41:25 -0000
@@ -660,6 +660,7 @@ update_current_target (void)
       INHERIT (to_get_raw_trace_data, t);
       INHERIT (to_set_disconnected_tracing, t);
       INHERIT (to_set_circular_trace_buffer, t);
+      INHERIT (to_get_tib_address, t);
       INHERIT (to_magic, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
@@ -853,6 +854,9 @@ update_current_target (void)
   de_fault (to_set_circular_trace_buffer,
 	    (void (*) (int))
 	    target_ignore);
+  de_fault (to_get_tib_address,
+	    (int (*) (ptid_t, CORE_ADDR *))
+	    tcomplain);
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.177
diff -u -p -r1.177 target.h
--- target.h	24 Mar 2010 01:12:13 -0000	1.177
+++ target.h	15 Apr 2010 22:41:25 -0000
@@ -682,6 +682,10 @@ struct target_ops
     int (*to_verify_memory) (struct target_ops *, const gdb_byte *data,
 			     CORE_ADDR memaddr, ULONGEST size);
 
+    /* Return the address of the start of the Thread Information Block
+       a Windows OS specific feature.  */
+    int (*to_get_tib_address) (ptid_t ptid, CORE_ADDR *addr);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -1371,6 +1375,9 @@ extern int target_search_memory (CORE_AD
 #define	target_set_circular_trace_buffer(val)	\
   (*current_target.to_set_circular_trace_buffer) (val)
 
+#define target_get_tib_address(ptid, addr) \
+  (*current_target.to_get_tib_address) ((ptid), (addr))
+
 /* Command logging facility.  */
 
 #define target_log_command(p)						\
Index: windows-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/windows-nat.c,v
retrieving revision 1.207
diff -u -p -r1.207 windows-nat.c
--- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
+++ windows-nat.c	15 Apr 2010 22:41:26 -0000
@@ -191,6 +191,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;
@@ -320,7 +321,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;
@@ -335,6 +336,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);
@@ -1074,15 +1076,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 (\
@@ -1271,9 +1264,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;
 }
 
@@ -1447,7 +1442,9 @@ 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:
@@ -1481,7 +1478,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;
 
@@ -2266,6 +2264,24 @@ windows_xfer_partial (struct target_ops 
     }
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.
+   Returns 1 if ptid is found and sets *ADDR to thread_local_base.  */
+
+static int
+windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  thread_info *th;
+
+  th = thread_rec (ptid_get_tid (ptid), 0);
+  if (th == NULL)
+    return 0;
+
+  if (addr != NULL)
+    *addr = th->thread_local_base;
+
+  return 1;
+}
+
 static ptid_t
 windows_get_ada_task_ptid (long lwp, long thread)
 {
@@ -2314,6 +2330,7 @@ init_windows_ops (void)
   windows_ops.to_has_execution = default_child_has_execution;
   windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
   windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
+  windows_ops.to_get_tib_address = windows_get_tib_address;
 
   i386_use_watchpoints (&windows_ops);
 
@@ -2415,9 +2432,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.5
diff -u -p -r1.5 windows-tdep.c
--- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
+++ windows-tdep.c	15 Apr 2010 22:41:26 -0000
@@ -19,6 +19,352 @@
 #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"
+#include "gdbthread.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 active_rpc_handle;			/* %fs:0x0028 */
+    uint32_t thread_local_storage;		/* %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 */
+    uint64_t environment_pointer;		/* %gs:0x0038 */
+    uint64_t process_id;			/* %gs:0x0040 */
+    uint64_t current_thread_id;			/* %gs:0x0048 */
+    uint64_t active_rpc_handle;			/* %gs:0x0050 */
+    uint64_t thread_local_storage;		/* %gs:0x0058 */
+    uint64_t process_environment_block;		/* %gs:0x0060 */
+    uint64_t last_error_number;			/* %gs:0x0068 */
+  }
+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 */
+    " active_rpc_handle           ",	/* %fs:0x0028 */
+    " thread_local_storage        ",	/* %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 Thread Local Base pointer type.  */
+
+static struct type *
+windows_get_tlb_type (struct gdbarch *gdbarch)
+{
+  struct type *dword_ptr_type, *dword32_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");
+  dword32_type = arch_integer_type (gdbarch, 32,
+				 1, "DWORD32");
+  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 */
+  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", dword32_type);
+  append_composite_type_field (peb_ldr_type, "initialized", dword32_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");
+
+  /* First bytes contain several flags.  */
+  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 active_rpc_handle;		%fs:0x0028 */
+  append_composite_type_field (tib_type, "active_rpc_handle", dword_ptr_type);
+  /* uint32_t thread_local_storage;		%fs:0x002c */
+  append_composite_type_field (tib_type, "thread_local_storage", void_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 is
+   also dependent on which thread you have selected.  */
+
+/* This function implements the lval_computed support for reading a
+   $_tlb value.  */
+
+static void
+tlb_value_read (struct value *val)
+{
+  CORE_ADDR tlb;
+  struct type *type = check_typedef (value_type (val));
+
+  if (!target_get_tib_address (inferior_ptid, &tlb))
+    error (_("Unable to read tlb"));
+  store_typed_address (value_contents_raw (val), type, tlb);
+}
+
+/* This function implements the lval_computed support for writing a
+   $_tlb value.  */
+
+static void
+tlb_value_write (struct value *v, struct value *fromval)
+{
+  error (_("Impossible to change the Thread Local Base"));
+}
+
+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 (ptid_t ptid)
+{
+  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);
+
+  if (target_get_tib_address (ptid, &thread_local_base) == 0)
+    {
+      printf_filtered (_("Unable to get thread local base for %s\n"),
+	target_pid_to_str (ptid));
+      return -1;
+    }
+
+  if (target_read (&current_target, TARGET_OBJECT_MEMORY,
+		   NULL, tib, thread_local_base, tib_size) != tib_size)
+    {
+      printf_filtered (_("Unable to read thread information block for %s at \
+address %s\n"),
+	target_pid_to_str (ptid), 
+	paddress (target_gdbarch, thread_local_base));
+      return -1;
+    }
+
+  printf_filtered (_("Thread Information Block %s at %s\n"),
+		   target_pid_to_str (ptid),
+		   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)
+    {
+      struct thread_info *tp;
+      int gdb_id = value_as_long (parse_and_eval (args));
+
+      tp = find_thread_id (gdb_id);
+
+      if (!tp)
+	error (_("Thread ID %d not known."), gdb_id);
+
+      if (!target_thread_alive (tp->ptid))
+	error (_("Thread ID %d has terminated."), gdb_id);
+
+      display_one_tib (tp->ptid);
+    }
+  else if (!ptid_equal (inferior_ptid, null_ptid))
+    display_one_tib (inferior_ptid);
+}
 
 void
 windows_xfer_shared_library (const char* so_name, CORE_ADDR load_addr,
@@ -36,3 +382,59 @@ windows_xfer_shared_library (const char*
   obstack_grow_str (obstack, paddress (gdbarch, load_addr + 0x1000));
   obstack_grow_str (obstack, "\"/></library>");
 }
+
+static void
+show_maint_show_all_tib (struct ui_file *file, int from_tty,
+		struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Show all non-zero elements of Thread Information \
+Block is %s.\n"), value);
+}
+
+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 their meaning is unknown."),
+			   NULL,
+			   show_maint_show_all_tib,
+			   &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.4
diff -u -p -r1.4 windows-tdep.h
--- windows-tdep.h	1 Jan 2010 07:31:46 -0000	1.4
+++ windows-tdep.h	15 Apr 2010 22:41:26 -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: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.706
diff -u -p -r1.706 gdb.texinfo
--- doc/gdb.texinfo	15 Apr 2010 19:54:13 -0000	1.706
+++ doc/gdb.texinfo	15 Apr 2010 22:41:39 -0000
@@ -8054,6 +8054,15 @@ The variable @code{$_siginfo} contains e
 (@pxref{extra signal information}).  Note that @code{$_siginfo}
 could be empty, if the application has not yet received any signals.
 For example, it will be empty before you execute the @code{run} command.
+
+@item $_tlb
+@vindex $_tlb@r{, convenience variable}
+The variable @code{$_tlb} is automatically set when debugging
+applications running on MS-Windows in native mode or connected to
+gdbserver that supports the @code{qGetTIBAddr} request. 
+@xref{General Query Packets}.
+This variable contains the address of the thread information block.
+
 @end table
 
 On HP-UX systems, if you refer to a function or variable name that
@@ -15755,6 +15764,10 @@ are:
 @tab @code{qGetTLSAddr}
 @tab Displaying @code{__thread} variables
 
+@item @code{get-thread-information-block-address}
+@tab @code{qGetTIBAddr}
+@tab Display MS-Windows Thread Information Block.
+
 @item @code{search-memory}
 @tab @code{qSearch:memory}
 @tab @code{find}
@@ -16534,6 +16547,11 @@ a long value to give the information abo
 Without argument, this command displays information
 about the six segment registers.
 
+@item info w32 thread-information-block
+This command displays thread specific information stored in the
+Thread Information Block (readable on the X86 CPU family using @code{$fs}
+selector for 32-bit programs and @code{$gs} for 64-bit programs).
+
 @kindex info dll
 @item info dll
 This is a Cygwin-specific alias of @code{info shared}.
@@ -29449,6 +29467,14 @@ enabled, the debug registers values are 
 removes a hardware breakpoint or watchpoint, and when the inferior
 triggers a hardware-assisted breakpoint or watchpoint.
 
+@kindex maint set show-all-tib
+@kindex maint show show-all-tib
+@item maint set show-all-tib
+@itemx maint show show-all-tib
+Control whether to show all non zero areas within a 1k block starting
+at thread local base, when using the @samp{info w32 thread-information-block}
+command.
+
 @kindex maint space
 @cindex memory used by commands
 @item maint space
@@ -30662,6 +30688,27 @@ An error occurred.  @var{nn} are hex dig
 An empty reply indicates that @samp{qGetTLSAddr} is not supported by the stub.
 @end table
 
+@item qGetTIBAddr:@var{thread-id}
+@cindex get thread information block address
+@cindex @samp{qGetTIBAddr} packet
+Fetch address of the Windows OS specific Thread Information Block.
+
+@var{thread-id} is the thread ID associated with the thread.
+
+Reply:
+@table @samp
+@item @var{XX}@dots{}
+Hex encoded (big endian) bytes representing the linear address of the
+thread information block.
+
+@item E @var{nn}
+An error occured.  This means that either the thread was not found, or the
+address could not be retrieved.
+
+@item
+An empty reply indicates that @samp{qGetTIBAddr} is not supported by the stub.
+@end table
+
 @item qL @var{startflag} @var{threadcount} @var{nextthread}
 Obtain thread information from RTOS.  Where: @var{startflag} (one hex
 digit) is one to indicate the first query and zero to indicate a
Index: gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.142
diff -u -p -r1.142 linux-low.c
--- gdbserver/linux-low.c	12 Apr 2010 17:39:42 -0000	1.142
+++ gdbserver/linux-low.c	15 Apr 2010 22:41:41 -0000
@@ -4334,7 +4334,8 @@ static struct target_ops linux_target_op
   linux_read_pc,
   linux_write_pc,
   linux_thread_stopped,
-  linux_pause_all
+  linux_pause_all,
+  NULL,	      /* get_tib_address (Windows OS specific).  */
 };
 
 static void
Index: gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.115
diff -u -p -r1.115 server.c
--- gdbserver/server.c	12 Apr 2010 17:39:42 -0000	1.115
+++ gdbserver/server.c	15 Apr 2010 22:41:42 -0000
@@ -1463,6 +1463,29 @@ handle_query (char *own_buf, int packet_
       /* Otherwise, pretend we do not understand this packet.  */
     }
 
+  /* Windows OS Thread Information Block address support.  */
+  if (the_target->get_tib_address != NULL
+      && strncmp ("qGetTIBAddr:", own_buf, 12) == 0)
+    {
+      char *annex;
+      int n;
+      CORE_ADDR tlb;
+      ptid_t ptid = read_ptid (own_buf + 12, &annex);
+
+      n = (*the_target->get_tib_address) (ptid, &tlb);
+      if (n == 1)
+	{
+	  sprintf (own_buf, "%llx", tlb);
+	  return;
+	}
+      else if (n == 0)
+	{
+	  write_enn (own_buf);
+	  return;
+	}
+      return;
+    }
+
   /* Handle "monitor" commands.  */
   if (strncmp ("qRcmd,", own_buf, 6) == 0)
     {
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.46
diff -u -p -r1.46 target.h
--- gdbserver/target.h	11 Apr 2010 16:33:56 -0000	1.46
+++ gdbserver/target.h	15 Apr 2010 22:41:42 -0000
@@ -309,6 +309,9 @@ struct target_ops
 
   /* Pause all threads.  */
   void (*pause_all) (void);
+
+  /* Read Thread Information Block address.  */
+  int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address);
 };
 
 extern struct target_ops *the_target;
Index: gdbserver/win32-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v
retrieving revision 1.45
diff -u -p -r1.45 win32-low.c
--- gdbserver/win32-low.c	12 Apr 2010 17:39:42 -0000	1.45
+++ gdbserver/win32-low.c	15 Apr 2010 22:41:42 -0000
@@ -178,7 +178,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);
@@ -189,6 +189,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 *)
@@ -1455,7 +1456,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:
@@ -1485,7 +1487,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
@@ -1753,6 +1756,20 @@ wince_hostio_last_error (char *buf)
 }
 #endif
 
+/* Write Windows OS Thread Information Block address.  */
+
+static int
+win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  win32_thread_info *th;
+  th = thread_rec (ptid, 0);
+  if (th == NULL)
+    return 0;
+  if (addr != NULL)
+    *addr = th->thread_local_base;
+  return 1;
+}
+
 static struct target_ops win32_target_ops = {
   win32_create_inferior,
   win32_attach,
@@ -1767,21 +1784,36 @@ static struct target_ops win32_target_op
   win32_store_inferior_registers,
   win32_read_inferior_memory,
   win32_write_inferior_memory,
-  NULL,
+  NULL, /* lookup_symbols */
   win32_request_interrupt,
-  NULL,
+  NULL, /* read_auxv */
   win32_insert_point,
   win32_remove_point,
   win32_stopped_by_watchpoint,
   win32_stopped_data_address,
-  NULL,
-  NULL,
-  NULL,
+  NULL, /* read_offsets */
+  NULL, /* get_tls_address */
+  NULL, /* qxfer_spu */
 #ifdef _WIN32_WCE
   wince_hostio_last_error,
 #else
   hostio_last_error_from_errno,
 #endif
+  NULL, /* qxfer_osdata */
+  NULL, /* qxfer_siginfo */
+  NULL, /* supports_non_stop */
+  NULL, /* async */
+  NULL, /* start_non_stop */
+  NULL, /* supports_multi_process */
+  NULL, /* handle_monitor_command */
+  NULL, /* core_of_thread */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* read_pc */
+  NULL, /* write_pc */
+  NULL, /* thread_stopped */
+  NULL, /* pause_all */
+  win32_get_tib_address,
 };
 
 /* Initialize the Win32 backend.  */
Index: gdbserver/win32-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v
retrieving revision 1.12
diff -u -p -r1.12 win32-low.h
--- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
+++ gdbserver/win32-low.h	15 Apr 2010 22:41:42 -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;
 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFA-v9] Add Windows OS Thread Information Block
       [not found]                                             ` <000c01cadcee$7ffcedd0$7ff6c970$%muller@ics-cnrs.unistra.fr>
@ 2010-04-16  6:29                                               ` Eli Zaretskii
  2010-04-16  7:53                                                 ` Pierre Muller
  2010-04-16 20:30                                                 ` Christopher Faylor
  0 siblings, 2 replies; 34+ messages in thread
From: Eli Zaretskii @ 2010-04-16  6:29 UTC (permalink / raw)
  To: Pierre Muller; +Cc: pedro, gdb-patches

> From: "Pierre Muller" <pierre.muller@ics-cnrs.unistra.fr>
> Cc: "'Pedro Alves'" <pedro@codesourcery.com>, <gdb-patches@sourceware.org>
> Date: Fri, 16 Apr 2010 00:53:42 +0200
> 
>   I still need the approval from Eli for the documentation part.

You've got it.  Pedro did such an excellent job reviewing the
documentation part that I simply had no reasons to chime in.

Thanks.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* RE: [RFA-v9] Add Windows OS Thread Information Block
  2010-04-16  6:29                                               ` Eli Zaretskii
@ 2010-04-16  7:53                                                 ` Pierre Muller
  2010-04-16 20:30                                                 ` Christopher Faylor
  1 sibling, 0 replies; 34+ messages in thread
From: Pierre Muller @ 2010-04-16  7:53 UTC (permalink / raw)
  To: 'Eli Zaretskii'; +Cc: pedro, gdb-patches

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

 Thanks to Pedro, Christopher and Eli for the patience and advices.

  I committed the patch.

For the record I attached what I committed.
(I added two lines to the ChangeLogs that were missing).

Pierre Muller

> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Eli Zaretskii
> Envoyé : Friday, April 16, 2010 8:28 AM
> À : Pierre Muller
> Cc : pedro@codesourcery.com; gdb-patches@sourceware.org
> Objet : Re: [RFA-v9] Add Windows OS Thread Information Block
> 
> > From: "Pierre Muller" <pierre.muller@ics-cnrs.unistra.fr>
> > Cc: "'Pedro Alves'" <pedro@codesourcery.com>, <gdb-
> patches@sourceware.org>
> > Date: Fri, 16 Apr 2010 00:53:42 +0200
> >
> >   I still need the approval from Eli for the documentation part.
> 
> You've got it.  Pedro did such an excellent job reviewing the
> documentation part that I simply had no reasons to chime in.
> 
> Thanks.

[-- Attachment #2: windows-tlb-final.patch --]
[-- Type: application/octet-stream, Size: 40487 bytes --]

? .swp
? ChangeLog.mmx
? added.lst
? mydiffs
? mydiffs2
? mydiffs3
? p-exp.y.new
? p-lang.c.new
? p-typeprint.c.new
? remove.lst
? features/i386/i386-go32v2-hidden.c
? gdbtk/commit.txt
? testsuite/gdb.pascal/gdb11492.pas
Index: ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.11627
diff -u -p -r1.11627 ChangeLog
--- ChangeLog	16 Apr 2010 04:34:30 -0000	1.11627
+++ ChangeLog	16 Apr 2010 07:47:04 -0000
@@ -1,3 +1,51 @@
+2010-04-16  Pierre Muller  <muller@ics.u-strasbg.fr>
+
+	Support for Windows OS Thread Information Block.
+	* NEWS: Document new feature.
+	* remote.c (PACKET_qGetTIBAddr): New enum element.
+	(remote_get_tib_address): New function.
+	(init_remote_ops): Set to_get_tib_address field
+	to remote_get_tib_address.
+	(_initialize_remote): Add add_packet_config_cmd
+	for PACKET_qGetTIBAddr.
+	* target.c (update_current_target): Set default value for
+	new to_get_tib_address field.
+	* target.h (target_ops): New field to_get_tib_address.
+	(target_get_tib_address): New macro.
+	* windows-nat.c (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_get_tib_address): New function.
+	(init_windows_ops): Set to_get_tib_address field
+	to remote_get_tib_address.
+	(_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.
+	(show_maint_show_all_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.
+
 2010-04-16  Joel Brobecker  <brobecker@adacore.com>
 
 	* tui/tui-regs.c (tui_display_register): Add comment about
Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.371
diff -u -p -r1.371 NEWS
--- NEWS	15 Apr 2010 19:54:12 -0000	1.371
+++ NEWS	16 Apr 2010 07:47:04 -0000
@@ -3,6 +3,21 @@
 
 *** Changes since GDB 7.1
 
+* Windows Thread Information Block access.
+
+  On Windows targets, GDB now supports displaying the Windows Thread
+  Information Block (TIB) structure.  This structure is visible either
+  by using the new command `info w32 thread-information-block' or, by
+  dereferencing the new convenience variable named `$_tlb', a
+  thread-specific pointer to the TIB.  This feature is also supported
+  when remote debugging using GDBserver.
+
+* New remote packets
+
+qGetTIBAddr
+
+  Return the address of the Windows Thread Information Block of a given thread.
+
 * The source command now accepts a -s option to force searching for the
   script in the source search path even if the script name specifies
   a directory.
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.401
diff -u -p -r1.401 remote.c
--- remote.c	13 Apr 2010 16:08:28 -0000	1.401
+++ remote.c	16 Apr 2010 07:47:06 -0000
@@ -1136,6 +1136,7 @@ enum {
   PACKET_qXfer_spu_write,
   PACKET_qXfer_osdata,
   PACKET_qXfer_threads,
+  PACKET_qGetTIBAddr,
   PACKET_qGetTLSAddr,
   PACKET_qSupported,
   PACKET_QPassSignals,
@@ -8437,6 +8438,48 @@ remote_get_thread_local_address (struct 
   return 0;
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.
+   Returns 1 if ptid is found and thread_local_base is non zero.  */
+
+int
+remote_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  if (remote_protocol_packets[PACKET_qGetTIBAddr].support != PACKET_DISABLE)
+    {
+      struct remote_state *rs = get_remote_state ();
+      char *p = rs->buf;
+      char *endp = rs->buf + get_remote_packet_size ();
+      enum packet_result result;
+
+      strcpy (p, "qGetTIBAddr:");
+      p += strlen (p);
+      p = write_ptid (p, endp, ptid);
+      *p++ = '\0';
+
+      putpkt (rs->buf);
+      getpkt (&rs->buf, &rs->buf_size, 0);
+      result = packet_ok (rs->buf,
+			  &remote_protocol_packets[PACKET_qGetTIBAddr]);
+      if (result == PACKET_OK)
+	{
+	  ULONGEST result;
+
+	  unpack_varlen_hex (rs->buf, &result);
+	  if (addr)
+	    *addr = (CORE_ADDR) result;
+	  return 1;
+	}
+      else if (result == PACKET_UNKNOWN)
+	error (_("Remote target doesn't support qGetTIBAddr packet"));
+      else
+	error (_("Remote target failed to process qGetTIBAddr request"));
+    }
+  else
+    error (_("qGetTIBAddr not supported or disabled on this target"));
+  /* Not reached.  */
+  return 0;
+}
+
 /* Support for inferring a target description based on the current
    architecture and the size of a 'g' packet.  While the 'g' packet
    can have any size (since optional registers can be left off the
@@ -9904,6 +9947,7 @@ Specify the serial device it is connecte
   remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer;
   remote_ops.to_core_of_thread = remote_core_of_thread;
   remote_ops.to_verify_memory = remote_verify_memory;
+  remote_ops.to_get_tib_address = remote_get_tib_address;
 }
 
 /* Set up the extended remote vector by making a copy of the standard
@@ -10323,6 +10367,10 @@ Show the maximum size of the address (in
 			 "qGetTLSAddr", "get-thread-local-storage-address",
 			 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTIBAddr],
+			 "qGetTIBAddr", "get-thread-information-block-address",
+			 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_bc],
 			 "bc", "reverse-continue", 0);
 
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.245
diff -u -p -r1.245 target.c
--- target.c	24 Mar 2010 01:12:13 -0000	1.245
+++ target.c	16 Apr 2010 07:47:07 -0000
@@ -660,6 +660,7 @@ update_current_target (void)
       INHERIT (to_get_raw_trace_data, t);
       INHERIT (to_set_disconnected_tracing, t);
       INHERIT (to_set_circular_trace_buffer, t);
+      INHERIT (to_get_tib_address, t);
       INHERIT (to_magic, t);
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
@@ -853,6 +854,9 @@ update_current_target (void)
   de_fault (to_set_circular_trace_buffer,
 	    (void (*) (int))
 	    target_ignore);
+  de_fault (to_get_tib_address,
+	    (int (*) (ptid_t, CORE_ADDR *))
+	    tcomplain);
 #undef de_fault
 
   /* Finally, position the target-stack beneath the squashed
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.177
diff -u -p -r1.177 target.h
--- target.h	24 Mar 2010 01:12:13 -0000	1.177
+++ target.h	16 Apr 2010 07:47:08 -0000
@@ -682,6 +682,10 @@ struct target_ops
     int (*to_verify_memory) (struct target_ops *, const gdb_byte *data,
 			     CORE_ADDR memaddr, ULONGEST size);
 
+    /* Return the address of the start of the Thread Information Block
+       a Windows OS specific feature.  */
+    int (*to_get_tib_address) (ptid_t ptid, CORE_ADDR *addr);
+
     int to_magic;
     /* Need sub-structure for target machine related rather than comm related?
      */
@@ -1371,6 +1375,9 @@ extern int target_search_memory (CORE_AD
 #define	target_set_circular_trace_buffer(val)	\
   (*current_target.to_set_circular_trace_buffer) (val)
 
+#define target_get_tib_address(ptid, addr) \
+  (*current_target.to_get_tib_address) ((ptid), (addr))
+
 /* Command logging facility.  */
 
 #define target_log_command(p)						\
Index: windows-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/windows-nat.c,v
retrieving revision 1.207
diff -u -p -r1.207 windows-nat.c
--- windows-nat.c	10 Mar 2010 15:57:07 -0000	1.207
+++ windows-nat.c	16 Apr 2010 07:47:08 -0000
@@ -191,6 +191,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;
@@ -320,7 +321,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;
@@ -335,6 +336,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);
@@ -1074,15 +1076,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 (\
@@ -1271,9 +1264,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;
 }
 
@@ -1447,7 +1442,9 @@ 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:
@@ -1481,7 +1478,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;
 
@@ -2266,6 +2264,24 @@ windows_xfer_partial (struct target_ops 
     }
 }
 
+/* Provide thread local base, i.e. Thread Information Block address.
+   Returns 1 if ptid is found and sets *ADDR to thread_local_base.  */
+
+static int
+windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  thread_info *th;
+
+  th = thread_rec (ptid_get_tid (ptid), 0);
+  if (th == NULL)
+    return 0;
+
+  if (addr != NULL)
+    *addr = th->thread_local_base;
+
+  return 1;
+}
+
 static ptid_t
 windows_get_ada_task_ptid (long lwp, long thread)
 {
@@ -2314,6 +2330,7 @@ init_windows_ops (void)
   windows_ops.to_has_execution = default_child_has_execution;
   windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file;
   windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid;
+  windows_ops.to_get_tib_address = windows_get_tib_address;
 
   i386_use_watchpoints (&windows_ops);
 
@@ -2415,9 +2432,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.5
diff -u -p -r1.5 windows-tdep.c
--- windows-tdep.c	1 Jan 2010 07:31:46 -0000	1.5
+++ windows-tdep.c	16 Apr 2010 07:47:08 -0000
@@ -19,6 +19,352 @@
 #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"
+#include "gdbthread.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 active_rpc_handle;			/* %fs:0x0028 */
+    uint32_t thread_local_storage;		/* %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 */
+    uint64_t environment_pointer;		/* %gs:0x0038 */
+    uint64_t process_id;			/* %gs:0x0040 */
+    uint64_t current_thread_id;			/* %gs:0x0048 */
+    uint64_t active_rpc_handle;			/* %gs:0x0050 */
+    uint64_t thread_local_storage;		/* %gs:0x0058 */
+    uint64_t process_environment_block;		/* %gs:0x0060 */
+    uint64_t last_error_number;			/* %gs:0x0068 */
+  }
+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 */
+    " active_rpc_handle           ",	/* %fs:0x0028 */
+    " thread_local_storage        ",	/* %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 Thread Local Base pointer type.  */
+
+static struct type *
+windows_get_tlb_type (struct gdbarch *gdbarch)
+{
+  struct type *dword_ptr_type, *dword32_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");
+  dword32_type = arch_integer_type (gdbarch, 32,
+				 1, "DWORD32");
+  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 */
+  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", dword32_type);
+  append_composite_type_field (peb_ldr_type, "initialized", dword32_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");
+
+  /* First bytes contain several flags.  */
+  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 active_rpc_handle;		%fs:0x0028 */
+  append_composite_type_field (tib_type, "active_rpc_handle", dword_ptr_type);
+  /* uint32_t thread_local_storage;		%fs:0x002c */
+  append_composite_type_field (tib_type, "thread_local_storage", void_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 is
+   also dependent on which thread you have selected.  */
+
+/* This function implements the lval_computed support for reading a
+   $_tlb value.  */
+
+static void
+tlb_value_read (struct value *val)
+{
+  CORE_ADDR tlb;
+  struct type *type = check_typedef (value_type (val));
+
+  if (!target_get_tib_address (inferior_ptid, &tlb))
+    error (_("Unable to read tlb"));
+  store_typed_address (value_contents_raw (val), type, tlb);
+}
+
+/* This function implements the lval_computed support for writing a
+   $_tlb value.  */
+
+static void
+tlb_value_write (struct value *v, struct value *fromval)
+{
+  error (_("Impossible to change the Thread Local Base"));
+}
+
+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 (ptid_t ptid)
+{
+  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);
+
+  if (target_get_tib_address (ptid, &thread_local_base) == 0)
+    {
+      printf_filtered (_("Unable to get thread local base for %s\n"),
+	target_pid_to_str (ptid));
+      return -1;
+    }
+
+  if (target_read (&current_target, TARGET_OBJECT_MEMORY,
+		   NULL, tib, thread_local_base, tib_size) != tib_size)
+    {
+      printf_filtered (_("Unable to read thread information block for %s at \
+address %s\n"),
+	target_pid_to_str (ptid), 
+	paddress (target_gdbarch, thread_local_base));
+      return -1;
+    }
+
+  printf_filtered (_("Thread Information Block %s at %s\n"),
+		   target_pid_to_str (ptid),
+		   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)
+    {
+      struct thread_info *tp;
+      int gdb_id = value_as_long (parse_and_eval (args));
+
+      tp = find_thread_id (gdb_id);
+
+      if (!tp)
+	error (_("Thread ID %d not known."), gdb_id);
+
+      if (!target_thread_alive (tp->ptid))
+	error (_("Thread ID %d has terminated."), gdb_id);
+
+      display_one_tib (tp->ptid);
+    }
+  else if (!ptid_equal (inferior_ptid, null_ptid))
+    display_one_tib (inferior_ptid);
+}
 
 void
 windows_xfer_shared_library (const char* so_name, CORE_ADDR load_addr,
@@ -36,3 +382,59 @@ windows_xfer_shared_library (const char*
   obstack_grow_str (obstack, paddress (gdbarch, load_addr + 0x1000));
   obstack_grow_str (obstack, "\"/></library>");
 }
+
+static void
+show_maint_show_all_tib (struct ui_file *file, int from_tty,
+		struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Show all non-zero elements of Thread Information \
+Block is %s.\n"), value);
+}
+
+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 their meaning is unknown."),
+			   NULL,
+			   show_maint_show_all_tib,
+			   &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.4
diff -u -p -r1.4 windows-tdep.h
--- windows-tdep.h	1 Jan 2010 07:31:46 -0000	1.4
+++ windows-tdep.h	16 Apr 2010 07:47:08 -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: doc/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/doc/ChangeLog,v
retrieving revision 1.1048
diff -u -p -r1.1048 ChangeLog
--- doc/ChangeLog	15 Apr 2010 19:54:13 -0000	1.1048
+++ doc/ChangeLog	16 Apr 2010 07:47:10 -0000
@@ -1,3 +1,10 @@
+2010-04-16  Pierre Muller  <muller@ics.u-strasbg.fr>
+
+	gdb.texinfo ($_tlb): Document new automatic convinience variable.
+	(info w32 thread-information-block): Document new command.
+	(qGetTIBAddress): Document new gdbserver query.
+	(maint set/show show-all-tib): Document new command.
+
 2010-04-15  Doug Evans  <dje@google.com>
 
 	* gdb.texinfo (Python API): Add progspaces section.
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.706
diff -u -p -r1.706 gdb.texinfo
--- doc/gdb.texinfo	15 Apr 2010 19:54:13 -0000	1.706
+++ doc/gdb.texinfo	16 Apr 2010 07:47:18 -0000
@@ -8054,6 +8054,15 @@ The variable @code{$_siginfo} contains e
 (@pxref{extra signal information}).  Note that @code{$_siginfo}
 could be empty, if the application has not yet received any signals.
 For example, it will be empty before you execute the @code{run} command.
+
+@item $_tlb
+@vindex $_tlb@r{, convenience variable}
+The variable @code{$_tlb} is automatically set when debugging
+applications running on MS-Windows in native mode or connected to
+gdbserver that supports the @code{qGetTIBAddr} request. 
+@xref{General Query Packets}.
+This variable contains the address of the thread information block.
+
 @end table
 
 On HP-UX systems, if you refer to a function or variable name that
@@ -15755,6 +15764,10 @@ are:
 @tab @code{qGetTLSAddr}
 @tab Displaying @code{__thread} variables
 
+@item @code{get-thread-information-block-address}
+@tab @code{qGetTIBAddr}
+@tab Display MS-Windows Thread Information Block.
+
 @item @code{search-memory}
 @tab @code{qSearch:memory}
 @tab @code{find}
@@ -16534,6 +16547,11 @@ a long value to give the information abo
 Without argument, this command displays information
 about the six segment registers.
 
+@item info w32 thread-information-block
+This command displays thread specific information stored in the
+Thread Information Block (readable on the X86 CPU family using @code{$fs}
+selector for 32-bit programs and @code{$gs} for 64-bit programs).
+
 @kindex info dll
 @item info dll
 This is a Cygwin-specific alias of @code{info shared}.
@@ -29449,6 +29467,14 @@ enabled, the debug registers values are 
 removes a hardware breakpoint or watchpoint, and when the inferior
 triggers a hardware-assisted breakpoint or watchpoint.
 
+@kindex maint set show-all-tib
+@kindex maint show show-all-tib
+@item maint set show-all-tib
+@itemx maint show show-all-tib
+Control whether to show all non zero areas within a 1k block starting
+at thread local base, when using the @samp{info w32 thread-information-block}
+command.
+
 @kindex maint space
 @cindex memory used by commands
 @item maint space
@@ -30662,6 +30688,27 @@ An error occurred.  @var{nn} are hex dig
 An empty reply indicates that @samp{qGetTLSAddr} is not supported by the stub.
 @end table
 
+@item qGetTIBAddr:@var{thread-id}
+@cindex get thread information block address
+@cindex @samp{qGetTIBAddr} packet
+Fetch address of the Windows OS specific Thread Information Block.
+
+@var{thread-id} is the thread ID associated with the thread.
+
+Reply:
+@table @samp
+@item @var{XX}@dots{}
+Hex encoded (big endian) bytes representing the linear address of the
+thread information block.
+
+@item E @var{nn}
+An error occured.  This means that either the thread was not found, or the
+address could not be retrieved.
+
+@item
+An empty reply indicates that @samp{qGetTIBAddr} is not supported by the stub.
+@end table
+
 @item qL @var{startflag} @var{threadcount} @var{nextthread}
 Obtain thread information from RTOS.  Where: @var{startflag} (one hex
 digit) is one to indicate the first query and zero to indicate a
Index: gdbserver/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/ChangeLog,v
retrieving revision 1.361
diff -u -p -r1.361 ChangeLog
--- gdbserver/ChangeLog	12 Apr 2010 17:46:05 -0000	1.361
+++ gdbserver/ChangeLog	16 Apr 2010 07:47:19 -0000
@@ -1,3 +1,16 @@
+2010-04-16  Pierre Muller  <muller@ics.u-strasbg.fr>
+
+	* server.c (handle_query): Handle 'qGetTIBAddr' query.
+	* target.h (target_ops): New get_tib_address field.
+	* win32-low.h (win32_thread_info): Add thread_local_base field.
+	* win32-low.c (child_add_thread): Add tlb argument.
+	Set thread_local_base field to TLB.
+	(get_child_debug_event): Adapt to child_add_thread change.
+	(win32_get_tib_address): New function.
+	(win32_target_ops): Set get_tib_address field to
+	win32_get_tib_address.
+	* linux-low.c (linux_target_ops): Set get_tib_address field to NULL.
+
 2010-04-12  Pedro Alves  <pedro@codesourcery.com>
 
 	* linux-low.c (linux_mourn): Also remove the process.
Index: gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.142
diff -u -p -r1.142 linux-low.c
--- gdbserver/linux-low.c	12 Apr 2010 17:39:42 -0000	1.142
+++ gdbserver/linux-low.c	16 Apr 2010 07:47:20 -0000
@@ -4334,7 +4334,8 @@ static struct target_ops linux_target_op
   linux_read_pc,
   linux_write_pc,
   linux_thread_stopped,
-  linux_pause_all
+  linux_pause_all,
+  NULL,	      /* get_tib_address (Windows OS specific).  */
 };
 
 static void
Index: gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.115
diff -u -p -r1.115 server.c
--- gdbserver/server.c	12 Apr 2010 17:39:42 -0000	1.115
+++ gdbserver/server.c	16 Apr 2010 07:47:20 -0000
@@ -1463,6 +1463,29 @@ handle_query (char *own_buf, int packet_
       /* Otherwise, pretend we do not understand this packet.  */
     }
 
+  /* Windows OS Thread Information Block address support.  */
+  if (the_target->get_tib_address != NULL
+      && strncmp ("qGetTIBAddr:", own_buf, 12) == 0)
+    {
+      char *annex;
+      int n;
+      CORE_ADDR tlb;
+      ptid_t ptid = read_ptid (own_buf + 12, &annex);
+
+      n = (*the_target->get_tib_address) (ptid, &tlb);
+      if (n == 1)
+	{
+	  sprintf (own_buf, "%llx", tlb);
+	  return;
+	}
+      else if (n == 0)
+	{
+	  write_enn (own_buf);
+	  return;
+	}
+      return;
+    }
+
   /* Handle "monitor" commands.  */
   if (strncmp ("qRcmd,", own_buf, 6) == 0)
     {
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.46
diff -u -p -r1.46 target.h
--- gdbserver/target.h	11 Apr 2010 16:33:56 -0000	1.46
+++ gdbserver/target.h	16 Apr 2010 07:47:21 -0000
@@ -309,6 +309,9 @@ struct target_ops
 
   /* Pause all threads.  */
   void (*pause_all) (void);
+
+  /* Read Thread Information Block address.  */
+  int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address);
 };
 
 extern struct target_ops *the_target;
Index: gdbserver/win32-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v
retrieving revision 1.45
diff -u -p -r1.45 win32-low.c
--- gdbserver/win32-low.c	12 Apr 2010 17:39:42 -0000	1.45
+++ gdbserver/win32-low.c	16 Apr 2010 07:47:21 -0000
@@ -178,7 +178,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);
@@ -189,6 +189,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 *)
@@ -1455,7 +1456,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:
@@ -1485,7 +1487,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
@@ -1753,6 +1756,20 @@ wince_hostio_last_error (char *buf)
 }
 #endif
 
+/* Write Windows OS Thread Information Block address.  */
+
+static int
+win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+  win32_thread_info *th;
+  th = thread_rec (ptid, 0);
+  if (th == NULL)
+    return 0;
+  if (addr != NULL)
+    *addr = th->thread_local_base;
+  return 1;
+}
+
 static struct target_ops win32_target_ops = {
   win32_create_inferior,
   win32_attach,
@@ -1767,21 +1784,36 @@ static struct target_ops win32_target_op
   win32_store_inferior_registers,
   win32_read_inferior_memory,
   win32_write_inferior_memory,
-  NULL,
+  NULL, /* lookup_symbols */
   win32_request_interrupt,
-  NULL,
+  NULL, /* read_auxv */
   win32_insert_point,
   win32_remove_point,
   win32_stopped_by_watchpoint,
   win32_stopped_data_address,
-  NULL,
-  NULL,
-  NULL,
+  NULL, /* read_offsets */
+  NULL, /* get_tls_address */
+  NULL, /* qxfer_spu */
 #ifdef _WIN32_WCE
   wince_hostio_last_error,
 #else
   hostio_last_error_from_errno,
 #endif
+  NULL, /* qxfer_osdata */
+  NULL, /* qxfer_siginfo */
+  NULL, /* supports_non_stop */
+  NULL, /* async */
+  NULL, /* start_non_stop */
+  NULL, /* supports_multi_process */
+  NULL, /* handle_monitor_command */
+  NULL, /* core_of_thread */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* read_pc */
+  NULL, /* write_pc */
+  NULL, /* thread_stopped */
+  NULL, /* pause_all */
+  win32_get_tib_address,
 };
 
 /* Initialize the Win32 backend.  */
Index: gdbserver/win32-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v
retrieving revision 1.12
diff -u -p -r1.12 win32-low.h
--- gdbserver/win32-low.h	20 Jan 2010 22:55:38 -0000	1.12
+++ gdbserver/win32-low.h	16 Apr 2010 07:47:21 -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;
 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFA-v9] Add Windows OS Thread Information Block
  2010-04-16  6:29                                               ` Eli Zaretskii
  2010-04-16  7:53                                                 ` Pierre Muller
@ 2010-04-16 20:30                                                 ` Christopher Faylor
  1 sibling, 0 replies; 34+ messages in thread
From: Christopher Faylor @ 2010-04-16 20:30 UTC (permalink / raw)
  To: gdb-patches, pedro, Pierre Muller, Eli Zaretskii

On Fri, Apr 16, 2010 at 09:27:53AM +0300, Eli Zaretskii wrote:
>> From: "Pierre Muller" <pierre.muller@ics-cnrs.unistra.fr>
>> Cc: "'Pedro Alves'" <pedro@codesourcery.com>, <gdb-patches@sourceware.org>
>> Date: Fri, 16 Apr 2010 00:53:42 +0200
>> 
>>   I still need the approval from Eli for the documentation part.
>
>You've got it.  Pedro did such an excellent job reviewing the
>documentation part that I simply had no reasons to chime in.

Yes, big thanks to Pedro for being so meticulous.

cgf

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2010-04-16 20:30 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <000901c9f5ef$4ee06f10$eca14d30$@u-strasbg.fr>
     [not found] ` <20090626155254.GA15627@caradoc.them.org>
     [not found]   ` <001f01c9fa5a$0e1297f0$2a37c7d0$@u-strasbg.fr>
     [not found]     ` <831vp047u8.fsf@gnu.org>
     [not found]       ` <20090701180419.GA8152@ednor.casa.cgf.cx>
     [not found]         ` <003a01c9fbf8$f3e91610$dbbb4230$@u-strasbg.fr>
     [not found]           ` <20090703194220.GA30668@ednor.casa.cgf.cx>
2010-03-10 17:14             ` [PING] [RFC-v3] Add windows Thread Information Block Pierre Muller
2010-03-10 17:26               ` Pedro Alves
2010-03-10 22:23                 ` Pierre Muller
2010-03-10 23:30                   ` Daniel Jacobowitz
2010-03-11  0:11                     ` Pedro Alves
2010-03-11  0:00                   ` Pedro Alves
2010-03-11  8:13                     ` Pierre Muller
2010-03-15 21:40                       ` [RFC-v4] Add windows OS " Pierre Muller
2010-03-16  0:10                         ` Christopher Faylor
2010-04-01  9:41                         ` [PING][RFC-v4] " Pierre Muller
2010-04-01 11:21                           ` Pedro Alves
2010-04-01 12:57                             ` [RFC-v5] " Pierre Muller
2010-04-01 13:21                               ` Pedro Alves
2010-04-01 13:31                                 ` Pierre Muller
2010-04-01 13:43                                   ` Pedro Alves
2010-04-11 15:10                               ` Pedro Alves
2010-04-12 13:52                                 ` [RFC-v6] " Pierre Muller
2010-04-12 16:43                                   ` Pedro Alves
2010-04-13  8:38                                     ` [RFA-v7] " Pierre Muller
2010-04-13 11:14                                       ` Pedro Alves
2010-04-13 13:21                                         ` [RFA-v8] " Pierre Muller
2010-04-13 15:06                                           ` Pedro Alves
2010-04-13 17:42                                             ` Eli Zaretskii
2010-04-15 22:54                                             ` [RFA-v9] Add Windows " Pierre Muller
     [not found]                                             ` <000c01cadcee$7ffcedd0$7ff6c970$%muller@ics-cnrs.unistra.fr>
2010-04-16  6:29                                               ` Eli Zaretskii
2010-04-16  7:53                                                 ` Pierre Muller
2010-04-16 20:30                                                 ` Christopher Faylor
     [not found]                     ` <002101cac0f2$a2298890$e67c99b0$%muller@ics-cnrs.unistra.fr>
     [not found]                       ` <000e01cac488$27dcf970$7796ec50$%muller@ics-cnrs.unistra.fr>
     [not found]                         ` <001201cad17f$6a058980$3e109c80$%muller@ics-cnrs.unistra.fr>
2010-04-01 13:30                           ` [PING][RFC-v4] Add windows " Eli Zaretskii
2010-04-01 16:17                             ` Pierre Muller
     [not found]                             ` <003c01cad1b6$d69e44b0$83dace10$%muller@ics-cnrs.unistra.fr>
2010-04-01 16:58                               ` Eli Zaretskii
2010-03-10 18:48               ` [PING] [RFC-v3] Add windows " Mark Kettenis
2010-03-10 22:25                 ` Pierre Muller
2010-03-11  0:24               ` Pedro Alves
2010-03-11  8:01                 ` Pierre Muller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).