[RFC] Add windows Thread Information Block

Pierre Muller
2009-06-25T23:47:41Z

On windows operating system
each thread gets a Thread Information Block
which contains several interesting informations:
- Current top of Structured Exception Handlers
- Thread Variable allocations
- Process information
- Current limits of stack
The last could be particularly interesting when we try to
to figure out an optimized stack frame.

When we hit a frameless function without debug information,
we could try to find up the stack a valid pair of stored (EBP,EIP)
of the outer frame having a frame pointer.
Testing for EBP to bee within the limits given by
current_top_of_stack andcurrent_bottom_of_stack
would help to find correct pairs.

I only tried to implement the 32bit version of
this until now, the 64bit version has a different layout...
More fields are available, some being version (or simulation layer)
dependent...
The current patch adds the code to windows-nat.c
despite the fact that I added the thread_local_base field
to both windows-nat.c and gdbserver/win32-low.c.
To be also usable for a remote gdbserver,
I would need to move that to windows-tdep.c

But here I need advice on how to move the display_tib function
to windows-tdep.c file, as it is currently using internal information
of windows-nat.c thread_info struct.
Also how should I handle the remote case?
Should I add a new query, something like 'qTlb'?
How should I call this from windows-tdep code?

All comments welcomed!

Pierre Muller
Pascal language support maintainer for GDB

2009-06-26 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 *'.
Assign TLB to new field THREAD_LOCAL_BASE of thread_info struct.
(fake_create_process): Adapt windows_add_thread call.
(get_windows_debug_event): Idem.
(display_tib): New function.
(display_current_tib): New function.
(_initialize_windows_nat): Add 'information w32 tib' command.

* gdbserver/win32-low.c (thread_info): Add THREAD_LOCAL_BASE field.
(child_add_thread): Add TLB argument of type 'void *'.
(get_child_debug_event): Adapt call to child_add_thread.

Index: windows-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/windows-nat.c,v
retrieving revision 1.195
diff -u -p -r1.195 windows-nat.c
--- windows-nat.c 17 Jun 2009 18:44:23 -0000 1.195
+++ windows-nat.c 25 Jun 2009 23:27:34 -0000
@@ -140,6 +140,9 @@ static int debug_registers_used;
static void windows_stop (ptid_t);
static int windows_thread_alive (struct target_ops *, ptid_t);
static void windows_kill_inferior (struct target_ops *);
+static int windows_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len,
+ int write, struct mem_attrib *mem,
+ struct target_ops *target);

static void cygwin_set_dr (int i, CORE_ADDR addr);
static void cygwin_set_dr7 (unsigned long val);
@@ -155,6 +158,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;
@@ -165,6 +169,50 @@ thread_info;

static thread_info thread_head;

+
+typedef struct thread_information_block
+ {
+ 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;
+
+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_TIB = sizeof (TIB_NAME) / sizeof (char*);
+
+
+
/* The process and thread handles for the above context. */

static DEBUG_EVENT current_event; /* The current debug event from
@@ -284,7 +332,7 @@ thread_rec (DWORD id, int get_context)

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

+/* Display thread information block of a given thread. */
+static int
+display_tib (thread_info* th)
+{
+ thread_info tib;
+
+ if (!th)
+ return 0;
+ if (th->thread_local_base)
+ {
+ if (windows_xfer_memory (th->thread_local_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,
+ th->thread_local_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;
+}
+
+/* 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_current_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_tib (th);
+ else
+ printf_filtered ("%ld is not a valid ThreadId\n", id);
+ }
+ else if (current_thread)
+ display_tib (current_thread);
+}
+
static struct cmd_list_element *info_w32_cmdlist = NULL;

static void
@@ -1181,9 +1281,11 @@ fake_create_process (void)
/* We can not debug anything in that case. */
}
main_thread_id = current_event.dwThreadId;
- current_thread = windows_add_thread (ptid_build
(current_event.dwProcessId, 0,
-
current_event.dwThreadId),
-
current_event.u.CreateThread.hThread);
+ current_thread = windows_add_thread (
+ ptid_build (current_event.dwProcessId, 0,
+ current_event.dwThreadId),
+ current_event.u.CreateThread.hThread,
+ current_event.u.CreateThread.lpThreadLocalBase);
return main_thread_id;
}

@@ -1357,7 +1459,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:
@@ -1390,7 +1494,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;

@@ -2278,6 +2383,10 @@ Show whether to display kernel exception
add_cmd ("selector", class_info, display_selectors,
_("Display selectors infos."),
&info_w32_cmdlist);
+ add_cmd ("tib", class_info, display_current_tib,
+ _("Display thread information block."),
+ &info_w32_cmdlist);
+
add_target (&windows_ops);
deprecated_init_ui_hook = set_windows_aliases;
}