From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3529 invoked by alias); 1 Apr 2010 09:41:11 -0000 Received: (qmail 3385 invoked by uid 22791); 1 Apr 2010 09:41:02 -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.154) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 01 Apr 2010 09:40:53 +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 o319elvt088018 for ; Thu, 1 Apr 2010 11:40:47 +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 o319elxI035889 for ; Thu, 1 Apr 2010 11:40:47 +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 o319ekwE025078 (version=TLSv1/SSLv3 cipher=RC4-MD5 bits=128 verify=NO) for ; Thu, 1 Apr 2010 11:40:46 +0200 (CEST) (envelope-from pierre.muller@ics-cnrs.unistra.fr) From: "Pierre Muller" To: References: <000901c9f5ef$4ee06f10$eca14d30$@u-strasbg.fr> <201003101725.48298.pedro@codesourcery.com> <000c01cac0a0$3935fbe0$aba1f3a0$@muller@ics-cnrs.unistra.fr> <201003110000.31184.pedro@codesourcery.com> <002101cac0f2$a2298890$e67c99b0$@muller@ics-cnrs.unistra.fr> <000e01cac488$27dcf970$7796ec50$@muller@ics-cnrs.unistra.fr> In-Reply-To: <000e01cac488$27dcf970$7796ec50$@muller@ics-cnrs.unistra.fr> Subject: [PING][RFC-v4] Add windows OS Thread Information Block Date: Thu, 01 Apr 2010 09:41:00 -0000 Message-ID: <001201cad17f$6a058980$3e109c80$@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/msg00004.txt.bz2 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=A0: gdb-patches-owner@sourceware.org [mailto:gdb-patches- > owner@sourceware.org] De la part de Pierre Muller > Envoy=E9=A0: Monday, March 15, 2010 10:41 PM > =C0=A0: gdb-patches@sourceware.org > Objet=A0: [RFC-v4] Add windows OS Thread Information Block >=20 > This is a new version of my patch to add support for > displaying thread-information-block for Windows OS > inferior programs. >=20 > 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. >=20 > I also tried to write a first draft of the documentation > patch and hope for some input from Eli on this matter... >=20 > 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. >=20 > I hope this new version will be closer to the expectation > of most of you and look forward to hearing your comments. >=20 >=20 > Pierre >=20 > 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. >=20 >=20 >=20 > 2010-03-15 Pierre Muller >=20 > * 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. >=20 > * 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. >=20 > gdbserver/ChangeLog entry: >=20 > * 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 >=20 >=20 > doc/ChangeLog entry: >=20 > 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. >=20 >=20 >=20 > 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.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; > } >=20 > +/* 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 !=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 > @@ -9737,6 +9780,7 @@ Specify the serial device it is connecte > remote_ops.to_get_raw_trace_data =3D remote_get_raw_trace_data; > remote_ops.to_set_disconnected_tracing =3D > remote_set_disconnected_tracing; > remote_ops.to_core_of_thread =3D remote_core_of_thread; > + remote_ops.to_get_tib_address =3D remote_get_tib_address; > } >=20 > /* 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); >=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.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 >=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.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); >=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? > */ > @@ -1359,6 +1363,9 @@ extern int target_search_memory (CORE_AD > #define target_set_disconnected_tracing(val) \ > (*current_target.to_set_disconnected_tracing) (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 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) >=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 > 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 > +/* 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 =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 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[] =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; > + } > + > + 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)), > + 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 > + 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; > + } > + 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 =3D (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); > +} >=20 > 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, "\"/>"); > } > + > +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 15 Mar 2010 21:12:46 -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.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 >=20 > 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 >=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} > @@ -16471,6 +16483,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}. > @@ -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. >=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 > @@ -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 >=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.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 !=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 > @@ -1356,6 +1359,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 15 Mar 2010 21:13:01 -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 15 Mar 2010 21:13:01 -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, > 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 15 Mar 2010 21:13:01 -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