From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15156 invoked by alias); 1 Apr 2010 12:57:14 -0000 Received: (qmail 15087 invoked by uid 22791); 1 Apr 2010 12:57:08 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=BAYES_00,MSGID_MULTIPLE_AT,TW_CP X-Spam-Check-By: sourceware.org Received: from mailhost.u-strasbg.fr (HELO mailhost.u-strasbg.fr) (130.79.200.151) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 01 Apr 2010 12:56:57 +0000 Received: from baal.u-strasbg.fr (baal.u-strasbg.fr [IPv6:2001:660:2402::41]) by mailhost.u-strasbg.fr (8.14.3/jtpda-5.5pre1) with ESMTP id o31CukVj027840 ; Thu, 1 Apr 2010 14:56:46 +0200 (CEST) (envelope-from pierre.muller@ics-cnrs.unistra.fr) Received: from mailserver.u-strasbg.fr (ms2.u-strasbg.fr [IPv6:2001:660:2402:d::11]) by baal.u-strasbg.fr (8.14.0/jtpda-5.5pre1) with ESMTP id o31Cukmp031058 ; Thu, 1 Apr 2010 14:56:46 +0200 (CEST) (envelope-from pierre.muller@ics-cnrs.unistra.fr) Received: from d620muller (gw-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 o31Cujk5084590 (version=TLSv1/SSLv3 cipher=RC4-MD5 bits=128 verify=NO) ; Thu, 1 Apr 2010 14:56:45 +0200 (CEST) (envelope-from pierre.muller@ics-cnrs.unistra.fr) From: "Pierre Muller" To: "'Pedro Alves'" , References: <000901c9f5ef$4ee06f10$eca14d30$@u-strasbg.fr> <000e01cac488$27dcf970$7796ec50$@muller@ics-cnrs.unistra.fr> <001201cad17f$6a058980$3e109c80$@muller@ics-cnrs.unistra.fr> <201004011221.36972.pedro@codesourcery.com> In-Reply-To: <201004011221.36972.pedro@codesourcery.com> Subject: [RFC-v5] Add windows OS Thread Information Block Date: Thu, 01 Apr 2010 12:57:00 -0000 Message-ID: <001801cad19a$cbcc40d0$6364c270$@muller@ics-cnrs.unistra.fr> MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable 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: 2010-04/txt/msg00008.txt.bz2 > -----Message d'origine----- > De=A0: gdb-patches-owner@sourceware.org [mailto:gdb-patches- > owner@sourceware.org] De la part de Pedro Alves > Envoy=E9=A0: Thursday, April 01, 2010 1:22 PM > =C0=A0: gdb-patches@sourceware.org > Cc=A0: Pierre Muller > Objet=A0: Re: [PING][RFC-v4] Add windows OS Thread Information Block >=20 > 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. >=20 > It is my intention to look at it. It's taking me a > bit because it's biggish.=20=20 I know, but it is difficult to subdivise it. > On a quick look (not a formal > review) I saw: >=20 > - what looked like some mixed over returning the TIB > or the TLB. E.g.: >=20 > > +/* 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 =3D thread_rec (ptid, 0); > > + if (th =3D=3D NULL) > > + return 0; > > + if (addr) > > + *addr =3D (CORE_ADDR) th->thread_local_base; > > + if (th->thread_local_base) > ^^^^^^^^^^^^^^^^^^^^^ > > + return 1; >=20 > Does the new packet return the TIB, or the TLB? The thread local base is the address of the Thread Information Block which itself=20 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.=20 =20 > > > +tlb_value_read (struct value *val) > > > +{ > ... > > > + if (!target_get_tib_address (inferior_ptid, &tlb)) > > > + error (_("Unable to read tlb")); >=20 > 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=20 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. =20 > - 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=20 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 =3D (ULONGEST) parse_and_eval_long (args); > > > + display_one_tib (ptid_build (ptid_get_pid (inferior_ptid), > 0, > > > id)); >=20 >=20 > > > + if (target_get_tib_address (ptid, &thread_local_base) =3D=3D 0) > > > + { > > > + printf_filtered ("Unable to get thread local base for > ThreadId > > > %s\n", > > > + pulongest (ptid_get_tid(ptid))); > > > + return -1; >=20 > 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).=20=20 Older gdbservers that don't support the new query packet 'qGetTIBAddr'=20 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=20 get_tib_address function to just accept the gdb thread id=20 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=20 is for=20 'info w32 thread-information-block XX' will now interpret XX as an internal GDB thread Id. Pierre 2010-03-15 Pierre Muller * 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. =09 * 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=20 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 =09 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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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=20 return 0; } =20 +/* 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 !=3D PACKET_DISABLE) + { + struct remote_state *rs =3D get_remote_state (); + char *p =3D rs->buf; + char *endp =3D rs->buf + get_remote_packet_size (); + enum packet_result result; + + strcpy (p, "qGetTIBAddr:"); + p +=3D strlen (p); + p =3D write_ptid (p, endp, ptid); + *p++ =3D '\0'; + + putpkt (rs->buf); + getpkt (&rs->buf, &rs->buf_size, 0); + result =3D packet_ok (rs->buf, + &remote_protocol_packets[PACKET_qGetTIBAddr]); + if (result =3D=3D PACKET_OK) + { + ULONGEST result; + + unpack_varlen_hex (rs->buf, &result); + if (addr) + *addr =3D (CORE_ADDR) result; + return 1; + } + else if (result =3D=3D 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 =3D remote_set_circular_trace_buffer; remote_ops.to_core_of_thread =3D remote_core_of_thread; remote_ops.to_verify_memory =3D remote_verify_memory; + remote_ops.to_get_tib_address =3D remote_get_tib_address; +=20 } =20 /* 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); =20 + 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); =20 Index: target.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 =20 /* Finally, position the target-stack beneath the squashed Index: target.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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); =20 + /* 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) =20 +#define target_get_tib_address(ptid, addr) \ + (*current_target.to_get_tib_address) ((ptid), (addr)) + /* Command logging facility. */ =20 #define target_log_command(p) \ Index: windows-nat.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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) =20 /* 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=20 th =3D XZALLOC (thread_info); th->id =3D id; th->h =3D h; + th->thread_local_base =3D (CORE_ADDR) (uintptr_t) tlb; th->next =3D thread_head.next; thread_head.next =3D th; add_thread (ptid); @@ -1074,15 +1076,6 @@ display_selectors (char * args, int from } } =20 -static struct cmd_list_element *info_w32_cmdlist =3D 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 =3D current_event.dwThreadId; - current_thread =3D windows_add_thread (ptid_build (current_event.dwProcessId, 0, - current_event.dwThreadId), - current_event.u.CreateThread.hThread); + current_thread =3D 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; } =20 @@ -1447,7 +1442,9 @@ get_windows_debug_event (struct target_o retval =3D current_event.dwThreadId; th =3D 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; =20 case EXIT_THREAD_DEBUG_EVENT: @@ -1481,7 +1478,8 @@ get_windows_debug_event (struct target_o /* Add the main thread */ th =3D 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 =3D current_event.dwThreadId; break; =20 @@ -2266,6 +2264,26 @@ windows_xfer_partial (struct target_ops=20 } } =20 +/* 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 =3D thread_rec (ptid_get_tid (ptid), 0); + if (th =3D=3D NULL) + return 0; + + if (addr) + { + *addr =3D (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 =3D default_child_has_execution; windows_ops.to_pid_to_exec_file =3D windows_pid_to_exec_file; windows_ops.to_get_ada_task_ptid =3D windows_get_ada_task_ptid; + windows_ops.to_get_tib_address =3D windows_get_tib_address; =20 i386_use_watchpoints (&windows_ops); =20 @@ -2415,9 +2434,7 @@ Show whether to display kernel exception NULL, /* FIXME: i18n: */ &setlist, &showlist); =20 - 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 (); =20 add_cmd ("selector", class_info, display_selectors, _("Display selectors infos."), Index: windows-tdep.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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[] =3D + { + " 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 =3D sizeof (thread_information_32) / sizeof (uint32_t); +static const int +MAX_TIB64 =3D sizeof (thread_information_64) / sizeof (uint64_t); +static const int +FULL_TIB_SIZE =3D 0x1000; + +static int maint_display_all_tib =3D 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 =3D arch_integer_type (gdbarch, gdbarch_ptr_bit (gdbarch), + 1, "DWORD_PTR"); + dword32_type =3D arch_integer_type (gdbarch, 32, + 1, "DWORD32"); + void_ptr_type =3D lookup_pointer_type (builtin_type (gdbarch)->builtin_void); + + /* list entry */ + + list_type =3D arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + TYPE_NAME (list_type) =3D xstrdup ("list"); + + list_ptr_type =3D arch_type (gdbarch, TYPE_CODE_PTR, + TYPE_LENGTH (void_ptr_type), NULL); + + module_list_ptr_type =3D 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 =3D arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + TYPE_NAME (seh_type) =3D xstrdup ("seh"); + + seh_ptr_type =3D arch_type (gdbarch, TYPE_CODE_PTR, + TYPE_LENGTH (void_ptr_type), NULL); + TYPE_TARGET_TYPE (seh_ptr_type) =3D 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 =3D arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + TYPE_NAME (peb_ldr_type) =3D 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 =3D arch_type (gdbarch, TYPE_CODE_PTR, + TYPE_LENGTH (void_ptr_type), NULL); + TYPE_TARGET_TYPE (peb_ldr_ptr_type) =3D peb_ldr_type; + + + /* struct process environment block */ + peb_type =3D arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + TYPE_NAME (peb_type) =3D 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 =3D arch_type (gdbarch, TYPE_CODE_PTR, + TYPE_LENGTH (void_ptr_type), NULL); + TYPE_TARGET_TYPE (peb_ptr_type) =3D peb_type; + + + /* struct thread information block */ + tib_type =3D arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + TYPE_NAME (tib_type) =3D 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 =3D arch_type (gdbarch, TYPE_CODE_PTR, + TYPE_LENGTH (void_ptr_type), NULL); + TYPE_TARGET_TYPE (tib_ptr_type) =3D 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 =3D check_typedef (value_type (val)); + enum bfd_endian byte_order =3D gdbarch_byte_order (get_type_arch (type)); + struct value *parent =3D value_parent (val); + LONGEST offset =3D value_offset (val); + int length =3D 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 =3D (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 =3D + { + 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 =3D 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 =3D annex + PTID_STRING_SIZE; + gdb_byte *tib =3D NULL; + gdb_byte *index; + CORE_ADDR thread_local_base; + ULONGEST i, val, max, max_name, size, tib_size; + ULONGEST sizeof_ptr =3D gdbarch_ptr_bit (target_gdbarch); + enum bfd_endian byte_order =3D gdbarch_byte_order (target_gdbarch); + + if (sizeof_ptr =3D=3D 64) + { + size =3D sizeof (uint64_t); + tib_size =3D sizeof (thread_information_64); + max =3D MAX_TIB64; + } + else + { + size =3D sizeof (uint32_t); + tib_size =3D sizeof (thread_information_32); + max =3D MAX_TIB32; + } + + max_name =3D max; + + if (maint_display_all_tib) + { + tib_size =3D FULL_TIB_SIZE; + max =3D tib_size / size; + } +=20=20 + tib =3D alloca (tib_size); + + /* This needs to be changed if multi-process support is added. */ + + if (target_get_tib_address (ptid, &thread_local_base) =3D=3D 0) + { + printf_filtered ("Unable to get thread local base for ThreadId %s\n", + pulongest (ptid_get_tid(ptid))); + return -1; + } + + if (target_read (¤t_target, TARGET_OBJECT_MEMORY, + annex, tib, thread_local_base, tib_size) !=3D tib_size) + { + printf_filtered ("Unable to read thread information block for ThreadId %s at address %s\n", + pulongest (ptid_get_tid (ptid)),=20 + 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 =3D (gdb_byte *) tib; + + /* All fields have the size of a pointer, this allows to iterate=20 + using the same for loop for both layouts. */ + for (i =3D 0; i < max; i++) + { + val =3D 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 !=3D 0) + printf_filtered ("TIB[0x%s] is 0x%s\n", phex (i*size, 2), + phex (val, size)); + index +=3D size; + }=20 + return 1;=20=20 +} + +/* 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 =3D value_as_long (parse_and_eval (args)); + + tp =3D 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); +} =20 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, "\"/>"); } + +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 =3D 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 =3D 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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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; =20 +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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 =20 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 =20 +@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. =20 +@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=20 removes a hardware breakpoint or watchpoint, and when the inferior triggers a hardware-assisted breakpoint or watchpoint. =20 +@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 =20 +@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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 !=3D NULL) strcat (own_buf, ";qXfer:osdata:read+"); =20 + if (the_target->get_tib_address !=3D NULL) + strcat (own_buf, ";qGetTIBAddr+"); + if (target_supports_multi_process ()) strcat (own_buf, ";multiprocess+"); =20 @@ -1397,6 +1400,31 @@ handle_query (char *own_buf, int packet_ /* Otherwise, pretend we do not understand this packet. */ } =20 + /* Windows OS Thread Information Block address support. */ + if (the_target->get_tib_address !=3D NULL + && strncmp ("qGetTIBAddr:", own_buf, 12) =3D=3D 0) + { + char *annex; + int n; + CORE_ADDR tlb; + ptid_t ptid =3D read_ptid (own_buf + 12, &annex); + + n =3D (*the_target->get_tib_address) (ptid, &tlb); + if (n =3D=3D 1) + { + sprintf (own_buf, "%llx", tlb); + return; + } + else if (n =3D=3D 0) + { + write_enn (own_buf); + return; + } + return; + } + + + /* Handle "monitor" commands. */ if (strncmp ("qRcmd,", own_buf, 6) =3D=3D 0) { Index: gdbserver/target.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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); =20 + /* Read Thread Information Block address. */ + int (*get_tib_address) (ptid_t ptid, CORE_ADDR *address); + int (*supports_non_stop) (void); =20 /* Enables async target events. Returns the previous enable Index: gdbserver/win32-low.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 =20 /* 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 =3D ptid_build (pid, tid, 0); @@ -189,6 +189,7 @@ child_add_thread (DWORD pid, DWORD tid,=20 th =3D xcalloc (1, sizeof (*th)); th->tid =3D tid; th->h =3D h; + th->thread_local_base =3D (CORE_ADDR) (uintptr_t) tlb; =20 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; =20 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); =20 ourstatus->value.related_pid =3D debug_event_ptid (¤t_event); #ifdef _WIN32_WCE @@ -1750,6 +1753,22 @@ wince_hostio_last_error (char *buf) } #endif =20 +/* Write Windows OS Thread Information Block address. */ +static int +win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr) +{ + win32_thread_info *th; + th =3D thread_rec (ptid, 0); + if (th =3D=3D NULL) + return 0; + if (addr) + *addr =3D (CORE_ADDR) th->thread_local_base; + if (th->thread_local_base) + return 1; + return 0; +} + + static struct target_ops win32_target_ops =3D { 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, }; =20 /* Initialize the Win32 backend. */ Index: gdbserver/win32-low.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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; =20 + /* Thread Information Block address. */ + CORE_ADDR thread_local_base; + /* Non zero if SuspendThread was called on this thread. */ int suspended; =20