This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] 32-bit support for windows thread information block


 I implemented two new command that display
a part of the information of the
thread information block and on
the structured exception handler chain.
 I added these two command to the "info w32" command
prefix, but got into troubles appearing below.

I have several questions regarding the 64-bit support of
windows nat files: 

1) Do hardware watchpoints work?
  the problem is that the dr[8] array is
defined as a unsigned type,
is this enough for win64?
  Is "unsigned" type a 64-bit ?
  
  In the _CONTEXT struct 
  the debug registers are defined as DWORD64...

2) Is GetThreadSelectorEntry function
working in win64 ?
  The reason of the question is that
I have no win64 machine... so that I cannot test directly,
the windows SDK says that it only works on i386 based
machines, but that is sort of vague.
Furthermore, the base address that is computed
with this function is a 32bit address, so I am 
wondering if it is meaningful or not...

The reason of the second question is that I have a
patch that is able to display the thread information block
and the structured exception handler chain on
a win32 program, but I did not find much information on
the the win64 equivalent, apart from the fact
that it is apparently the $gs selector that is 
used on x86_64 in windows64, instead of the $fs for win32.

Thus I wanted to put that new command into i386-windows-nat.c directly,
but I had troubles trying to add the command to "w32" prefix if I
left the prefix in windows-nat.c
(This is probably due to the fact the i386-windows-nat initialization
code is performed before windows-nat code, so that
w32-list was not intitialized yet...)

  My current patch moves "info w32" command prefix to i386-windows-nat,
but I was wondering if this is ok, or if I should
leave "w32" prefix in windows-nat.c file and find another
way to fix the issue above.


Pierre Muller
Pascal language support maintainer for GDB

PS: I am unsure about the ChangeLog syntax,
especially for all the moves.
1) Should I also list the functions in windows-nat.c that change from static
to global because I need them in i386-windows-nat?
2) Should I also list all the new constants that I added 
to i386-windows-hat.c file (TIB_NAME, MAX_TIB, MAX_SEH)

ChangeLog entry


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

	* windows-nat.c (struct thread_info_struct, current_thread): Move to
...
	* windows-nat.h : ... here.
	  (thread_rec, windows_xfer_memory): Declare.
	* windows-nat.c (display_selector, display_selectors)/ Move to ...
	  (info_w32_cmdlist, info_w32_command): Move to ...
	* i386-windows-nat.c : ... here.
	  (struct thread_information_block, struct seh): New structs.
	  (display_this_tib, display_one_tib): New functions.
	  (display_this_seh, display_one_seh): New functions.	  
	  (_initialize_i386_windows_nat): Register new commands.


Index: gdb/i386-windows-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-windows-nat.c,v
retrieving revision 1.3
diff -u -p -r1.3 i386-windows-nat.c
--- gdb/i386-windows-nat.c	13 Jan 2009 04:14:07 -0000	1.3
+++ gdb/i386-windows-nat.c	14 Jan 2009 11:19:27 -0000
@@ -19,6 +19,13 @@
 #include "windows-nat.h"
 
 #include <windows.h>
+#include "value.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+
+static struct cmd_list_element *
+info_w32_cmdlist = NULL;
 
 #define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
 static const int mappings[] =
@@ -69,8 +76,312 @@ static const int mappings[] =
 };
 #undef context_offset
 
+typedef struct seh 
+  {
+    struct seh *next;
+    void *address;
+  }
+structured_exception_handler;
+
+/* This is only the starting of the thread information block
+  More fields are present but some depend on the running OS.  */
+typedef struct thread_information_block
+  {
+    DWORD current_seh;			/* %fs:0x0000 */
+    DWORD current_top_of_stack; 	/* %fs:0x0004 */
+    DWORD current_bottom_of_stack;	/* %fs:0x0008 */
+    DWORD sub_system_tib;		/* %fs:0x000c */
+    DWORD fiber_data;			/* %fs:0x0010 */
+    DWORD arbitrary_data_slot;		/* %fs:0x0014 */
+    DWORD linear_address_tib;		/* %fs:0x0018 */
+    DWORD environment_pointer;		/* %fs:0x001c */
+    DWORD process_id;			/* %fs:0x0020 */
+    DWORD current_thread_id;		/* %fs:0x0024 */
+    DWORD thread_local_storage;		/* %fs:0x0028 */
+    DWORD active_rpc_handle;		/* %fs:0x002c */
+    DWORD process_environment_block;	/* %fs:0x0030 */
+    DWORD last_error_number;		/* %fs:0x0034 */
+  }
+thread_information;
+
+/* Names for the different fields listed in thread_information_block
struct.  */
+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 */
+  };
+
+/* Number of fields in TIB_NAME.  */
+static const int
+MAX_TIB = sizeof (TIB_NAME) / sizeof (char*);
+
+/* Maximum number of iteration to avoid infinite loop.  */
+static const int
+MAX_SEH = 50;
+
+static int
+display_selector (HANDLE thread, DWORD sel)
+{
+  LDT_ENTRY info;
+  if (GetThreadSelectorEntry (thread, sel, &info))
+    {
+      int base, limit;
+      printf_filtered ("0x%03lx: ", sel);
+      if (!info.HighWord.Bits.Pres)
+	{
+	  puts_filtered ("Segment not present\n");
+	  return 0;
+	}
+      base = (info.HighWord.Bits.BaseHi << 24) +
+	     (info.HighWord.Bits.BaseMid << 16)
+	     + info.BaseLow;
+      limit = (info.HighWord.Bits.LimitHi << 16) + info.LimitLow;
+      if (info.HighWord.Bits.Granularity)
+	limit = (limit << 12) | 0xfff;
+      printf_filtered ("base=0x%08x limit=0x%08x", base, limit);
+      if (info.HighWord.Bits.Default_Big)
+	puts_filtered(" 32-bit ");
+      else
+	puts_filtered(" 16-bit ");
+      switch ((info.HighWord.Bits.Type & 0xf) >> 1)
+	{
+	case 0:
+	  puts_filtered ("Data (Read-Only, Exp-up");
+	  break;
+	case 1:
+	  puts_filtered ("Data (Read/Write, Exp-up");
+	  break;
+	case 2:
+	  puts_filtered ("Unused segment (");
+	  break;
+	case 3:
+	  puts_filtered ("Data (Read/Write, Exp-down");
+	  break;
+	case 4:
+	  puts_filtered ("Code (Exec-Only, N.Conf");
+	  break;
+	case 5:
+	  puts_filtered ("Code (Exec/Read, N.Conf");
+	  break;
+	case 6:
+	  puts_filtered ("Code (Exec-Only, Conf");
+	  break;
+	case 7:
+	  puts_filtered ("Code (Exec/Read, Conf");
+	  break;
+	default:
+	  printf_filtered ("Unknown type 0x%x",info.HighWord.Bits.Type);
+	}
+      if ((info.HighWord.Bits.Type & 0x1) == 0)
+	puts_filtered(", N.Acc");
+      puts_filtered (")\n");
+      if ((info.HighWord.Bits.Type & 0x10) == 0)
+	puts_filtered("System selector ");
+      printf_filtered ("Priviledge level = %d. ", info.HighWord.Bits.Dpl);
+      if (info.HighWord.Bits.Granularity)
+	puts_filtered ("Page granular.\n");
+      else
+	puts_filtered ("Byte granular.\n");
+      return 1;
+    }
+  else
+    {
+      printf_filtered ("Invalid selector 0x%lx.\n",sel);
+      return 0;
+    }
+}
+
+static void
+display_selectors (char * args, int from_tty)
+{
+  if (!current_thread)
+    {
+      puts_filtered ("Impossible to display selectors now.\n");
+      return;
+    }
+  if (!args)
+    {
+
+      puts_filtered ("Selector $cs\n");
+      display_selector (current_thread->h,
+	current_thread->context.SegCs);
+      puts_filtered ("Selector $ds\n");
+      display_selector (current_thread->h,
+	current_thread->context.SegDs);
+      puts_filtered ("Selector $es\n");
+      display_selector (current_thread->h,
+	current_thread->context.SegEs);
+      puts_filtered ("Selector $ss\n");
+      display_selector (current_thread->h,
+	current_thread->context.SegSs);
+      puts_filtered ("Selector $fs\n");
+      display_selector (current_thread->h,
+	current_thread->context.SegFs);
+      puts_filtered ("Selector $gs\n");
+      display_selector (current_thread->h,
+	current_thread->context.SegGs);
+    }
+  else
+    {
+      int sel;
+      sel = parse_and_eval_long (args);
+      printf_filtered ("Selector \"%s\"\n",args);
+      display_selector (current_thread->h, sel);
+    }
+}
+
+
+static void
+info_w32_command (char *args, int from_tty)
+{
+  help_list (info_w32_cmdlist, "info w32 ", class_info, gdb_stdout);
+}
+
+
+static int
+display_this_seh (thread_info* th)
+{
+  LDT_ENTRY info;
+  structured_exception_handler seh;
+  DWORD base;
+
+  if (!th)
+    return 0;
+  if (GetThreadSelectorEntry (th->h, th->context.SegFs, &info))
+    {
+      base = (info.HighWord.Bits.BaseHi << 24) +
+	     (info.HighWord.Bits.BaseMid << 16)
+	     + info.BaseLow;
+     if (windows_xfer_memory (base, (gdb_byte *) &seh, sizeof (seh), 
+		     0, NULL, NULL))
+	{
+	  int i;
+	  printf_filtered ("Thread Information Block 0x%lx at 0x%8lx\n",
+			   th->id,
+			   base);
+	  for (i = 0; i < MAX_SEH; i++)
+	    {
+	      base = (DWORD) seh.next;
+	      if (windows_xfer_memory (base, (gdb_byte *) &seh, sizeof
(seh), 
+		     0, NULL, NULL))
+		{
+		  printf_filtered ("(%d) at 0x%08lx ", i, base);
+		  printf_filtered ("handler=0x%08lx next=0x%08lx\n", 
+			(DWORD) seh.address, (DWORD) seh.next);
+		}
+	      else
+		break;
+	      if ((DWORD) seh.next == 0xffffffff)
+		break;
+	    }
+	}
+      else
+	return 0;
+ 
+    } 
+  return 1;  
+}
+
+
+static int
+display_this_tib (thread_info* th)
+{
+  LDT_ENTRY info;
+  thread_information tib;
+  DWORD base;
+
+  if (!th)
+    return 0;
+  if (GetThreadSelectorEntry (th->h, th->context.SegFs, &info))
+    {
+      base = (info.HighWord.Bits.BaseHi << 24) +
+	     (info.HighWord.Bits.BaseMid << 16)
+	     + info.BaseLow;
+     if (windows_xfer_memory (base, (gdb_byte *) &tib, sizeof (tib), 
+		     0, NULL, NULL))
+	{
+	  DWORD* index = (DWORD *) &tib;
+	  int i;
+	  printf_filtered ("Thread Information Block 0x%lx at 0x%8lx\n",
+			   th->id,
+			   base);
+
+	  for (i = 0; i < MAX_TIB; i++)
+	    printf_filtered ("%s is 0x%08lx\n", TIB_NAME [i], index [i]);
+	}
+      else
+	return 0;
+ 
+    } 
+  return 1;  
+}
+
+static void
+display_one_tib (char * args, int from_tty)
+{
+  if (args)
+    {
+      thread_info* th;
+      DWORD id = (DWORD) parse_and_eval_long (args);
+      th = thread_rec (id, 1);
+      if (th)
+	display_this_tib (th);
+      else
+	printf_filtered ("%ld is not a valid ThreadId\n", id);
+    }
+  else if (current_thread)
+    display_this_tib (current_thread);
+}
+ 
+static void
+display_one_seh (char * args, int from_tty)
+{
+  if (args)
+    {
+      thread_info* th;
+      DWORD id = (DWORD) parse_and_eval_long (args);
+      th = thread_rec (id, 1);
+      if (th)
+	display_this_seh (th);
+      else
+	printf_filtered ("%ld is not a valid ThreadId\n", id);
+    }
+  else if (current_thread)
+    display_this_seh (current_thread);
+}
+ 
 void
 _initialize_i386_windows_nat (void)
 {
   windows_set_context_register_offsets (mappings);
+
+  add_prefix_cmd ("w32", class_info, info_w32_command,
+		  _("Print information specific to Win32 debugging."),
+		  &info_w32_cmdlist, "info w32 ", 0, &infolist);
+
+  add_cmd ("selector", class_info, display_selectors,
+	   _("Display selectors infos."),
+	   &info_w32_cmdlist);
+
+  add_cmd ("tib", class_info, display_one_tib,
+	   _("Display thread information block."),
+	   &info_w32_cmdlist);
+
+  add_cmd ("seh", class_info, display_one_seh,
+	   _("Display structured exception handler chain."),
+	   &info_w32_cmdlist);
+
 }
Index: gdb/windows-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/windows-nat.c,v
retrieving revision 1.178
diff -u -p -r1.178 windows-nat.c
--- gdb/windows-nat.c	14 Jan 2009 05:27:48 -0000	1.178
+++ gdb/windows-nat.c	14 Jan 2009 11:19:37 -0000
@@ -119,21 +119,6 @@ static void windows_kill_inferior (void)
 static enum target_signal last_sig = TARGET_SIGNAL_0;
 /* Set if a signal was received from the debugged process */
 
-/* Thread information structure used to track information that is
-   not available in gdb's thread structure.  */
-typedef struct thread_info_struct
-  {
-    struct thread_info_struct *next;
-    DWORD id;
-    HANDLE h;
-    char *name;
-    int suspended;
-    int reload_context;
-    CONTEXT context;
-    STACKFRAME sf;
-  }
-thread_info;
-
 static thread_info thread_head;
 
 /* The process and thread handles for the above context. */
@@ -141,7 +126,6 @@ static thread_info thread_head;
 static DEBUG_EVENT current_event;	/* The current debug event from
 					   WaitForDebugEvent */
 static HANDLE current_process_handle;	/* Currently executing process */
-static thread_info *current_thread;	/* Info on currently selected thread
*/
 static DWORD main_thread_id;		/* Thread ID of the main thread */
 
 /* Counts of things. */
@@ -222,7 +206,7 @@ check (BOOL ok, const char *file, int li
 /* Find a thread record given a thread id.  If GET_CONTEXT is not 0,
    then also retrieve the context for this thread.  If GET_CONTEXT is
    negative, then don't suspend the thread.  */
-static thread_info *
+thread_info *
 thread_rec (DWORD id, int get_context)
 {
   thread_info *th;
@@ -852,125 +836,6 @@ handle_output_debug_string (struct targe
   return retval;
 }
 
-static int
-display_selector (HANDLE thread, DWORD sel)
-{
-  LDT_ENTRY info;
-  if (GetThreadSelectorEntry (thread, sel, &info))
-    {
-      int base, limit;
-      printf_filtered ("0x%03lx: ", sel);
-      if (!info.HighWord.Bits.Pres)
-	{
-	  puts_filtered ("Segment not present\n");
-	  return 0;
-	}
-      base = (info.HighWord.Bits.BaseHi << 24) +
-	     (info.HighWord.Bits.BaseMid << 16)
-	     + info.BaseLow;
-      limit = (info.HighWord.Bits.LimitHi << 16) + info.LimitLow;
-      if (info.HighWord.Bits.Granularity)
-	limit = (limit << 12) | 0xfff;
-      printf_filtered ("base=0x%08x limit=0x%08x", base, limit);
-      if (info.HighWord.Bits.Default_Big)
-	puts_filtered(" 32-bit ");
-      else
-	puts_filtered(" 16-bit ");
-      switch ((info.HighWord.Bits.Type & 0xf) >> 1)
-	{
-	case 0:
-	  puts_filtered ("Data (Read-Only, Exp-up");
-	  break;
-	case 1:
-	  puts_filtered ("Data (Read/Write, Exp-up");
-	  break;
-	case 2:
-	  puts_filtered ("Unused segment (");
-	  break;
-	case 3:
-	  puts_filtered ("Data (Read/Write, Exp-down");
-	  break;
-	case 4:
-	  puts_filtered ("Code (Exec-Only, N.Conf");
-	  break;
-	case 5:
-	  puts_filtered ("Code (Exec/Read, N.Conf");
-	  break;
-	case 6:
-	  puts_filtered ("Code (Exec-Only, Conf");
-	  break;
-	case 7:
-	  puts_filtered ("Code (Exec/Read, Conf");
-	  break;
-	default:
-	  printf_filtered ("Unknown type 0x%x",info.HighWord.Bits.Type);
-	}
-      if ((info.HighWord.Bits.Type & 0x1) == 0)
-	puts_filtered(", N.Acc");
-      puts_filtered (")\n");
-      if ((info.HighWord.Bits.Type & 0x10) == 0)
-	puts_filtered("System selector ");
-      printf_filtered ("Priviledge level = %d. ", info.HighWord.Bits.Dpl);
-      if (info.HighWord.Bits.Granularity)
-	puts_filtered ("Page granular.\n");
-      else
-	puts_filtered ("Byte granular.\n");
-      return 1;
-    }
-  else
-    {
-      printf_filtered ("Invalid selector 0x%lx.\n",sel);
-      return 0;
-    }
-}
-
-static void
-display_selectors (char * args, int from_tty)
-{
-  if (!current_thread)
-    {
-      puts_filtered ("Impossible to display selectors now.\n");
-      return;
-    }
-  if (!args)
-    {
-
-      puts_filtered ("Selector $cs\n");
-      display_selector (current_thread->h,
-	current_thread->context.SegCs);
-      puts_filtered ("Selector $ds\n");
-      display_selector (current_thread->h,
-	current_thread->context.SegDs);
-      puts_filtered ("Selector $es\n");
-      display_selector (current_thread->h,
-	current_thread->context.SegEs);
-      puts_filtered ("Selector $ss\n");
-      display_selector (current_thread->h,
-	current_thread->context.SegSs);
-      puts_filtered ("Selector $fs\n");
-      display_selector (current_thread->h,
-	current_thread->context.SegFs);
-      puts_filtered ("Selector $gs\n");
-      display_selector (current_thread->h,
-	current_thread->context.SegGs);
-    }
-  else
-    {
-      int sel;
-      sel = parse_and_eval_long (args);
-      printf_filtered ("Selector \"%s\"\n",args);
-      display_selector (current_thread->h, sel);
-    }
-}
-
-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 %p\n", x, \
@@ -1949,7 +1814,7 @@ windows_stop (ptid_t ptid)
   registers_changed ();		/* refresh register state */
 }
 
-static int
+int
 windows_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len,
 		   int write, struct mem_attrib *mem,
 		   struct target_ops *target)
@@ -2215,13 +2080,6 @@ 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);
-
-  add_cmd ("selector", class_info, display_selectors,
-	   _("Display selectors infos."),
-	   &info_w32_cmdlist);
   add_target (&windows_ops);
   deprecated_init_ui_hook = set_windows_aliases;
 }
Index: gdb/windows-nat.h
===================================================================
RCS file: /cvs/src/src/gdb/windows-nat.h,v
retrieving revision 1.2
diff -u -p -r1.2 windows-nat.h
--- gdb/windows-nat.h	13 Jan 2009 04:14:07 -0000	1.2
+++ gdb/windows-nat.h	14 Jan 2009 11:19:37 -0000
@@ -18,7 +18,36 @@
 #ifndef WINDOWS_NAT_H
 #define WINDOWS_NAT_H
 
+#include <windows.h>
+#include <imagehlp.h>
+#include "memattr.h"
+#include "command.h"
+
+
+/* Thread information structure used to track information that is
+   not available in gdb's thread structure.  */
+typedef struct thread_info_struct
+  {
+    struct thread_info_struct *next;
+    DWORD id;
+    HANDLE h;
+    char *name;
+    int suspended;
+    int reload_context;
+    CONTEXT context;
+    STACKFRAME sf;
+  }
+thread_info;
+
+thread_info *current_thread;	/* Info on currently selected thread */
+
+extern thread_info * thread_rec (DWORD id, int get_context);
+
 extern void windows_set_context_register_offsets (const int *offsets);
 
+extern int windows_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len,
+		   int write, struct mem_attrib *mem,
+		   struct target_ops *target);
+
 #endif
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]