From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11140 invoked by alias); 1 Jul 2009 14:41:53 -0000 Received: (qmail 11128 invoked by uid 22791); 1 Jul 2009 14:41:50 -0000 X-SWARE-Spam-Status: No, hits=-0.6 required=5.0 tests=AWL,BAYES_00,RCVD_IN_JMF_BL X-Spam-Check-By: sourceware.org Received: from mailhost.u-strasbg.fr (HELO mailhost.u-strasbg.fr) (130.79.200.158) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 01 Jul 2009 14:41:42 +0000 Received: from baal.u-strasbg.fr (baal.u-strasbg.fr [IPv6:2001:660:2402::41]) by mailhost.u-strasbg.fr (8.14.2/jtpda-5.5pre1) with ESMTP id n61EfY3J052239 ; Wed, 1 Jul 2009 16:41:34 +0200 (CEST) Received: from mailserver.u-strasbg.fr (ms1.u-strasbg.fr [IPv6:2001:660:2402:d::10]) by baal.u-strasbg.fr (8.14.0/jtpda-5.5pre1) with ESMTP id n61EfYTM030387 ; Wed, 1 Jul 2009 16:41:34 +0200 (CEST) (envelope-from muller@ics.u-strasbg.fr) Received: from d620muller (www-ics.u-strasbg.fr [130.79.210.225]) (user=mullerp mech=LOGIN) by mailserver.u-strasbg.fr (8.14.3/jtpda-5.5pre1) with ESMTP id n61EfXIS063744 (version=TLSv1/SSLv3 cipher=RC4-MD5 bits=128 verify=NO) ; Wed, 1 Jul 2009 16:41:33 +0200 (CEST) (envelope-from muller@ics.u-strasbg.fr) From: "Pierre Muller" To: "'Daniel Jacobowitz'" Cc: References: <000901c9f5ef$4ee06f10$eca14d30$@u-strasbg.fr> <20090626155254.GA15627@caradoc.them.org> In-Reply-To: <20090626155254.GA15627@caradoc.them.org> Subject: [RFC-v2] Add windows Thread Information Block Date: Wed, 01 Jul 2009 14:41:00 -0000 Message-ID: <001f01c9fa5a$0e1297f0$2a37c7d0$@u-strasbg.fr> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-07/txt/msg00010.txt.bz2 I tried to look at the siginfo stuff as Daniel suggested, but found out finally that there is already a TARGET_OBJECT_OSDATA type that can be used for this case. Here is a new version of the patch that works for me both native and remote. For the remote it should also work if the host OS has a different endianess and different sizes for standard types as I use explicit types and extract_unsigned_integer functions. For now I left it as a "info w32" sub command. info w32 thread-information-block with info w32 tib as an alias. But the code itself tries to also implement w64 version of the thread information block. Thus, maybe it is better not to change it "info tib"? Once this is accepted, I would like to move "info w32 selector" to windows-tdep.c and implement this in the server. Using the first field of the thread information block, I also would like to add a "info w32 structured-exception-handling" command that would display the chain of thread-specific pushed exception handlers. Like in http://sourceware.org/ml/gdb-patches/2009-01/msg00307.html but using the thread_local_base field. Concerning the suggestion to make a convenience variable, I am a bit unsure: if I define a new convenience variable named $_tib that is a pointer to the current thread information block, the problem is that this would mean the doing something like (gdb) set $_tib.current_seh = my_val would change the value of the first field, which seems nice, but is also dangerous as this $_tib is thread specific. Using such a convenience variable would then require that at each thread switch we reload the variable, or at least that we tag it as 'invalid' (or is 'lazy' OK or this?) I have no idea if/how this is possible? Concerning the documentation, I would also like that we first decide if we want it to become "info thread-information-block" or stay "info w32 thread-information-block". Comments welcome, Pierre Muller Pascal language support maintainer for GDB 2009-07-01 Pierre Muller * 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. * windows-nat.c (info_w32_command): Moved from here... * windows-tdep.c (info_w32_command): to here. * windows-nat.c (info_w32_cmdlist): Deleted, move to... * windows-tdep.c (info_w32_cmdlist): to here, made global. * windows-tdep.h (info_w32_cmdlist): Declare. * windows-tdep.c (thread_information_32): New struct. (thread_information_64): New struct. (TIB_NAME): New char array. (MAX_TIB32, MAX_TIB64): New constants. (display_one_tib): New function. (display_tib): New function. (init_w32_command_list): New function. (_initialize_windows_tdep): New function. * windows-tdep.h (init_w32_command_list): New external function declaration. gdbserver/ChangeLog entry: 2009-07-01 Pierre Muller * 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.195 diff -u -p -r1.195 windows-nat.c --- windows-nat.c 17 Jun 2009 18:44:23 -0000 1.195 +++ windows-nat.c 1 Jul 2009 14:10:39 -0000 @@ -57,6 +57,7 @@ #include "solist.h" #include "solib.h" #include "xml-support.h" +#include "target.h" #include "i386-tdep.h" #include "i387-tdep.h" @@ -155,6 +156,7 @@ typedef struct thread_info_struct struct thread_info_struct *next; DWORD id; HANDLE h; + CORE_ADDR thread_local_base; char *name; int suspended; int reload_context; @@ -284,7 +286,7 @@ thread_rec (DWORD id, int get_context) /* Add a thread to the thread list. */ static thread_info * -windows_add_thread (ptid_t ptid, HANDLE h) +windows_add_thread (ptid_t ptid, HANDLE h, void *tlb) { thread_info *th; DWORD id; @@ -299,6 +301,7 @@ windows_add_thread (ptid_t ptid, HANDLE th = XZALLOC (thread_info); th->id = id; th->h = h; + th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb; th->next = thread_head.next; thread_head.next = th; add_thread (ptid); @@ -984,15 +987,6 @@ display_selectors (char * args, int from } } -static struct cmd_list_element *info_w32_cmdlist = NULL; - -static void -info_w32_command (char *args, int from_tty) -{ - help_list (info_w32_cmdlist, "info w32 ", class_info, gdb_stdout); -} - - #define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \ printf_unfiltered ("gdb: Target exception %s at %s\n", x, \ host_address_to_string (\ @@ -1181,9 +1175,11 @@ fake_create_process (void) /* We can not debug anything in that case. */ } main_thread_id = current_event.dwThreadId; - current_thread = windows_add_thread (ptid_build (current_event.dwProcessId, 0, - current_event.dwThreadId), - current_event.u.CreateThread.hThread); + current_thread = windows_add_thread ( + ptid_build (current_event.dwProcessId, 0, + current_event.dwThreadId), + current_event.u.CreateThread.hThread, + current_event.u.CreateThread.lpThreadLocalBase); return main_thread_id; } @@ -1357,7 +1353,8 @@ get_windows_debug_event (struct target_o retval = current_event.dwThreadId; th = windows_add_thread (ptid_build (current_event.dwProcessId, 0, current_event.dwThreadId), - current_event.u.CreateThread.hThread); + current_event.u.CreateThread.hThread, + current_event.u.CreateThread.lpThreadLocalBase); break; case EXIT_THREAD_DEBUG_EVENT: @@ -1390,7 +1387,8 @@ get_windows_debug_event (struct target_o /* Add the main thread */ th = windows_add_thread (ptid_build (current_event.dwProcessId, 0, current_event.dwThreadId), - current_event.u.CreateProcessInfo.hThread); + current_event.u.CreateProcessInfo.hThread, + current_event.u.CreateProcessInfo.lpThreadLocalBase); retval = current_event.dwThreadId; break; @@ -2103,6 +2101,11 @@ windows_xfer_partial (struct target_ops const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST offset, LONGEST len) { + ULONGEST val; + thread_info *th; + char info_type[20]; + char *type_end; + switch (object) { case TARGET_OBJECT_MEMORY: @@ -2114,6 +2117,31 @@ windows_xfer_partial (struct target_ops len, 1/*write*/, NULL, ops); return -1; + case TARGET_OBJECT_OSDATA: + memset (info_type, 0, sizeof (info_type)); + val = 0; + sscanf (annex, "%s %llu", info_type, &val); + if (strcmp (info_type, "tlb:") == 0 && readbuf) + { + th = thread_rec (val, 0); + if (th == NULL) + return -1; + + if (len == 8) + { + uint64_t tlb = th->thread_local_base; + memcpy ((void *)readbuf, (void *) &tlb, len); + return len; + } + else if (len == 4) + { + uint32_t tlb = th->thread_local_base; + memcpy ((void *)readbuf, (void *) &tlb, len); + return len; + } + } + return -1; + case TARGET_OBJECT_LIBRARIES: return windows_xfer_shared_libraries (ops, object, annex, readbuf, writebuf, offset, len); @@ -2271,9 +2299,7 @@ Show whether to display kernel exception NULL, /* FIXME: i18n: */ &setlist, &showlist); - add_prefix_cmd ("w32", class_info, info_w32_command, - _("Print information specific to Win32 debugging."), - &info_w32_cmdlist, "info w32 ", 0, &infolist); + init_w32_command_list (); add_cmd ("selector", class_info, display_selectors, _("Display selectors infos."), Index: windows-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/windows-tdep.c,v retrieving revision 1.3 diff -u -p -r1.3 windows-tdep.c --- windows-tdep.c 13 Jan 2009 04:14:07 -0000 1.3 +++ windows-tdep.c 1 Jul 2009 14:10:39 -0000 @@ -19,6 +19,160 @@ #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); + +/* 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; + CORE_ADDR thread_local_base; + ULONGEST size, tib_size; + ULONGEST sizeof_ptr = gdbarch_ptr_bit (current_gdbarch); + + if (sizeof_ptr == 32) + { + size = sizeof (uint32_t); + tib_size = sizeof (thread_information_32); + } + else + { + size = sizeof (uint64_t); + tib_size = sizeof (thread_information_64); + } + 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 (¤t_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); + if (target_read (¤t_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), paddr (thread_local_base)); + return -1; + } + + if (sizeof_ptr == 32) + { + uint32_t *index = (uint32_t *) tib; + int i; + uint32_t val; + + printf_filtered ("Thread Information Block %s at %s\n", + pulongest (ThreadId), paddr (thread_local_base)); + for (i = 0; i < MAX_TIB32; i++) + { + val = extract_unsigned_integer ((gdb_byte *) &(index [i]), 4); + printf_filtered ("%s is 0x%s\n", TIB_NAME [i], paddr (val)); + } + } + else + { + uint64_t *index = (uint64_t *) tib; + int i; + uint64_t val; + printf_filtered ("Thread Information Block %s\n", pulongest (ThreadId)); + for (i = 0; i < MAX_TIB64; i++) + { + val = extract_unsigned_integer ((gdb_byte *) &(index [i]), 8); + printf_filtered ("%s is 0x%s\n", TIB_NAME [i], paddr (val)); + } + } + 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, @@ -37,3 +191,29 @@ windows_xfer_shared_library (const char* obstack_grow_str (obstack, p); obstack_grow_str (obstack, "\"/>"); } + +static void +info_w32_command (char *args, int from_tty) +{ + help_list (info_w32_cmdlist, "info w32 ", class_info, gdb_stdout); +} + +void +init_w32_command_list (void) +{ + if (!info_w32_cmdlist) + add_prefix_cmd ("w32", class_info, info_w32_command, + _("Print information specific to Win32 debugging."), + &info_w32_cmdlist, "info w32 ", 0, &infolist); +} + +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 ("thread_information-block", "tib", class_info, 1, + &info_w32_cmdlist); +} Index: windows-tdep.h =================================================================== RCS file: /cvs/src/src/gdb/windows-tdep.h,v retrieving revision 1.2 diff -u -p -r1.2 windows-tdep.h --- windows-tdep.h 13 Jan 2009 04:14:07 -0000 1.2 +++ windows-tdep.h 1 Jul 2009 13:46:35 -0000 @@ -20,6 +20,10 @@ struct obstack; +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 obstack *obstack); Index: gdbserver/win32-low.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v retrieving revision 1.37 diff -u -p -r1.37 win32-low.c --- gdbserver/win32-low.c 30 Jun 2009 16:35:25 -0000 1.37 +++ gdbserver/win32-low.c 1 Jul 2009 13:46:35 -0000 @@ -175,7 +175,7 @@ thread_rec (ptid_t ptid, int get_context /* Add a thread to the thread list. */ static win32_thread_info * -child_add_thread (DWORD pid, DWORD tid, HANDLE h) +child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb) { win32_thread_info *th; ptid_t ptid = ptid_build (pid, tid, 0); @@ -186,6 +186,7 @@ child_add_thread (DWORD pid, DWORD tid, th = xcalloc (1, sizeof (*th)); th->tid = tid; th->h = h; + th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb; add_thread (ptid, th); set_inferior_regcache_data ((struct thread_info *) @@ -1427,7 +1428,8 @@ get_child_debug_event (struct target_wai /* Record the existence of this thread. */ child_add_thread (current_event.dwProcessId, current_event.dwThreadId, - current_event.u.CreateThread.hThread); + current_event.u.CreateThread.hThread, + current_event.u.CreateThread.lpThreadLocalBase); break; case EXIT_THREAD_DEBUG_EVENT: @@ -1455,7 +1457,8 @@ get_child_debug_event (struct target_wai /* Add the main thread. */ child_add_thread (current_event.dwProcessId, main_thread_id, - current_event.u.CreateProcessInfo.hThread); + current_event.u.CreateProcessInfo.hThread, + current_event.u.CreateProcessInfo.lpThreadLocalBase); ourstatus->value.related_pid = debug_event_ptid (¤t_event); #ifdef _WIN32_WCE @@ -1723,6 +1726,42 @@ wince_hostio_last_error (char *buf) } #endif +/* Read/Write Windows OS information. */ +int +win32_qxfer_osdata (const char *info_type, + unsigned char *readbuf, unsigned const char *writebuf, + CORE_ADDR offset, int len) + +{ + if (strncmp (info_type, "tlb: ", 5) == 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_build (current_process_id, 0, tid); + th = thread_rec (ptid, 0); + if (th == NULL) + return 0; + + if (len == 8) + { + uint64_t tlb = th->thread_local_base; + memcpy (readbuf, &tlb, len); + return len; + } + else if (len == 4) + { + uint32_t tlb = th->thread_local_base; + memcpy (readbuf, &tlb, len); + return len; + } + } + return -1; +} + + static struct target_ops win32_target_ops = { win32_create_inferior, win32_attach, @@ -1751,6 +1790,7 @@ static struct target_ops win32_target_op #else hostio_last_error_from_errno, #endif + win32_qxfer_osdata, }; /* Initialize the Win32 backend. */ Index: gdbserver/win32-low.h =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/win32-low.h,v retrieving revision 1.10 diff -u -p -r1.10 win32-low.h --- gdbserver/win32-low.h 30 Jun 2009 16:35:25 -0000 1.10 +++ gdbserver/win32-low.h 1 Jul 2009 13:46:35 -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;