about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2009-11-22 20:42:53 -0800
committerRoland McGrath <roland@redhat.com>2009-12-09 01:01:28 -0800
commit6f1672172c9c9e5eb5afdcf521e3528b38b2e2dd (patch)
treef1ca70b5d1c32d593b0c2e825f10c56b49d14c06
parentee1a7fabb4e0abd3e73e828ce326dcb5fd38b874 (diff)
downloadglibc-roland/nptl_db.tar.gz
glibc-roland/nptl_db.tar.xz
glibc-roland/nptl_db.zip
Make libthread_db work without libpthread, just enough for TLS decoding. roland/nptl_db
-rw-r--r--nptl/ChangeLog5
-rw-r--r--nptl/sysdeps/pthread/Versions6
-rw-r--r--nptl/sysdeps/pthread/dl-sysdep.c38
-rw-r--r--nptl_db/ChangeLog47
-rw-r--r--nptl_db/Makefile10
-rw-r--r--nptl_db/db-symbols.awk4
-rw-r--r--nptl_db/fetch-value.c6
-rw-r--r--nptl_db/rtld-db-symbols.awk5
-rw-r--r--nptl_db/structs.def10
-rw-r--r--nptl_db/td_symbol_list.c6
-rw-r--r--nptl_db/td_ta_clear_event.c7
-rw-r--r--nptl_db/td_ta_event_addr.c6
-rw-r--r--nptl_db/td_ta_event_getmsg.c6
-rw-r--r--nptl_db/td_ta_get_nthreads.c6
-rw-r--r--nptl_db/td_ta_map_lwp2thr.c29
-rw-r--r--nptl_db/td_ta_new.c58
-rw-r--r--nptl_db/td_ta_set_event.c7
-rw-r--r--nptl_db/td_ta_thr_iter.c31
-rw-r--r--nptl_db/td_ta_tsd_iter.c6
-rw-r--r--nptl_db/td_thr_clear_event.c9
-rw-r--r--nptl_db/td_thr_event_enable.c6
-rw-r--r--nptl_db/td_thr_event_getmsg.c9
-rw-r--r--nptl_db/td_thr_get_info.c10
-rw-r--r--nptl_db/td_thr_set_event.c9
-rw-r--r--nptl_db/td_thr_tsd.c7
-rw-r--r--nptl_db/td_thr_validate.c34
-rw-r--r--nptl_db/thread_dbP.h18
27 files changed, 310 insertions, 85 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 494b5904fb..d8dee1c0e9 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,8 @@
+2009-11-23  Roland McGrath  <roland@redhat.com>
+
+	* sysdeps/pthread/dl-sysdep.c: New file.
+	* sysdeps/pthread/Versions: New file.
+
 2009-11-27  Thomas Schwinge  <thomas@codesourcery.com>
 
 	* sysdeps/unix/sysv/linux/sh/pt-initfini.c (_init): Don't call
diff --git a/nptl/sysdeps/pthread/Versions b/nptl/sysdeps/pthread/Versions
new file mode 100644
index 0000000000..ab6aec0fe0
--- /dev/null
+++ b/nptl/sysdeps/pthread/Versions
@@ -0,0 +1,6 @@
+ld {
+  GLIBC_PRIVATE {
+    # These are used by libthread_db, so must be visible somehow.
+    _thread_db_*;
+  }
+}
diff --git a/nptl/sysdeps/pthread/dl-sysdep.c b/nptl/sysdeps/pthread/dl-sysdep.c
new file mode 100644
index 0000000000..3dbeebc4fa
--- /dev/null
+++ b/nptl/sysdeps/pthread/dl-sysdep.c
@@ -0,0 +1,38 @@
+/* libthread_db hooks in the dynamic linker.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* This cpp magic lets us use #include_next in the #else branch.  */
+#ifndef IS_IN_dl_sysdep
+# define IS_IN_dl_sysdep 1
+# include <dl-sysdep.c>
+#else
+
+# include_next <dl-sysdep.c>
+
+/* A dynamic linker with TLS support needs to make some information
+   available to libthread_db so debuggers can figure out TLS lookups
+   even when libpthread is not loaded.  */
+
+# include <version.h>
+
+const char _thread_db_dl_nptl_version[] __attribute_used__ = VERSION;
+
+# include <../nptl_db/db_info.c>
+
+#endif
diff --git a/nptl_db/ChangeLog b/nptl_db/ChangeLog
index f79fc18e4b..55948b5d94 100644
--- a/nptl_db/ChangeLog
+++ b/nptl_db/ChangeLog
@@ -1,3 +1,50 @@
+2009-11-23  Roland McGrath  <roland@redhat.com>
+
+	* rtld-db-symbols.awk: New file.
+	* Makefile (distribute): Add it.
+	($(objpfx)rtld-db-symbols.v.i): New target.
+	($(objpfx)rtld-db-symbols.out): New target.
+	(tests): Depend on that.
+
+	* td_ta_map_lwp2thr.c (td_ta_map_lwp2thr): Handle TD_NOLIBTHREAD case
+	like pre-initialization case.
+	* td_thr_validate.c (td_thr_validate): Likewise.
+	* td_ta_thr_iter.c (td_ta_thr_iter): Likewise.
+
+	* td_ta_clear_event.c: Call _td_ta_check_nptl first and punt on failure.
+	* td_ta_event_addr.c: Likewise.
+	* td_ta_event_getmsg.c: Likewise.
+	* td_ta_get_nthreads.c: Likewise.
+	* td_ta_set_event.c: Likewise.
+	* td_ta_tsd_iter.c: Likewise.
+	* td_thr_clear_event.c: Likewise.
+	* td_thr_event_enable.c: Likewise.
+	* td_thr_event_getmsg.c: Likewise.
+	* td_thr_set_event.c: Likewise.
+	* td_thr_tsd.c: Likewise.
+
+	* td_ta_new.c (check_version): New function, broken out of ...
+	(td_ta_new): ... here.  Call it.  Cache version symbol addresses
+	in *TA.  Accept _thread_db_dl_nptl_version from rtld if libpthread
+	lookup fails.
+	(_td_ta_check_nptl): New function.
+	* thread_dbP.h: Declare it.
+
+	* td_symbol_list.c (td_lookup): Renamed to ...
+	(td_lookup_1): ... this.  Take RTLD flag to choose DSO name.
+	* thread_dbP.h (td_lookup_1): Declare it.
+	(td_lookup): Define as macro using that,
+	now take td_thragent pointer as first argument.
+	(DB_GET_SYMBOL, DB_GET_VALUE, DB_PUT_VALUE): Update callers.
+	* fetch-value.c (_td_locate_field, _td_check_sizeof): Likewise.
+	* td_ta_map_lwp2thr.c: Likewise.
+
+	* structs.def [IS_IN_libpthread || defined IS_IN_libthread_db]:
+	Put most fields under this condition, only TLS ones outside it.
+	[! IS_IN_libpthread]: Add _thread_db_dl_nptl_version symbol.
+	* db-symbols.awk [! IS_IN_rtld]: %define IS_IN_libpthread before
+	%include "db-symbols.h".
+
 2009-08-23  Roland McGrath  <roland@redhat.com>
 
 	* td_ta_map_lwp2thr.c (__td_ta_lookup_th_unique): Move ta_ok check
diff --git a/nptl_db/Makefile b/nptl_db/Makefile
index af542dcac9..8d53779246 100644
--- a/nptl_db/Makefile
+++ b/nptl_db/Makefile
@@ -51,7 +51,8 @@ libthread_db-inhibit-o = $(filter-out .os,$(object-suffixes))
 libthread_db.so-no-z-defs = yes
 
 distribute = thread_dbP.h shlib-versions proc_service.h \
-	     db_info.c structs.def db-symbols.h db-symbols.awk
+	     db_info.c structs.def db-symbols.h \
+	     db-symbols.awk rtld-db-symbols.awk
 include ../Rules
 
 # Depend on libc.so so a DT_NEEDED is generated in the shared objects.
@@ -66,3 +67,10 @@ $(objpfx)db-symbols.out: $(objpfx)db-symbols.v.i \
 	readelf -W -s $(filter %.so,$^) | $(AWK) -f $< > $@
 
 $(objpfx)db-symbols.v.i: db-symbols.awk
+
+tests: $(objpfx)rtld-db-symbols.out
+$(objpfx)rtld-db-symbols.out: $(objpfx)rtld-db-symbols.v.i \
+			 $(common-objpfx)elf/ld.so
+	readelf -W -s $(filter %.so,$^) | $(AWK) -f $< > $@
+
+$(objpfx)rtld-db-symbols.v.i: rtld-db-symbols.awk db-symbols.awk
diff --git a/nptl_db/db-symbols.awk b/nptl_db/db-symbols.awk
index f9a91b93bf..ce8701c806 100644
--- a/nptl_db/db-symbols.awk
+++ b/nptl_db/db-symbols.awk
@@ -1,6 +1,10 @@
 # This script processes the output of 'readelf -W -s' on the libpthread.so
 # we've just built.  It checks for all the symbols used in td_symbol_list.
 
+%ifndef IS_IN_rtld
+%define IS_IN_libpthread
+%endif
+
 BEGIN {
 %define DB_LOOKUP_NAME(idx, name)		required[STRINGIFY (name)] = 1;
 %define DB_LOOKUP_NAME_TH_UNIQUE(idx, name)	th_unique[STRINGIFY (name)] = 1;
diff --git a/nptl_db/fetch-value.c b/nptl_db/fetch-value.c
index 0d9bb0eb80..5c97502e20 100644
--- a/nptl_db/fetch-value.c
+++ b/nptl_db/fetch-value.c
@@ -1,5 +1,5 @@
 /* Helper routines for libthread_db.
-   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -27,7 +27,7 @@ _td_check_sizeof (td_thragent_t *ta, uint32_t *sizep, int sizep_name)
   if (*sizep == 0)
     {
       psaddr_t descptr;
-      ps_err_e err = td_lookup (ta->ph, sizep_name, &descptr);
+      ps_err_e err = td_lookup (ta, sizep_name, &descptr);
       if (err == PS_NOSYM)
 	return TD_NOCAPAB;
       if (err == PS_OK)
@@ -51,7 +51,7 @@ _td_locate_field (td_thragent_t *ta,
     {
       /* Read the information about this field from the inferior.  */
       psaddr_t descptr;
-      ps_err_e err = td_lookup (ta->ph, descriptor_name, &descptr);
+      ps_err_e err = td_lookup (ta, descriptor_name, &descptr);
       if (err == PS_NOSYM)
 	return TD_NOCAPAB;
       if (err == PS_OK)
diff --git a/nptl_db/rtld-db-symbols.awk b/nptl_db/rtld-db-symbols.awk
new file mode 100644
index 0000000000..a916eba718
--- /dev/null
+++ b/nptl_db/rtld-db-symbols.awk
@@ -0,0 +1,5 @@
+/* This file precedes db-symbols.awk before preprocessing when making
+   rtld-db-symbols.v.i for the test.  We just set this macro here so
+   that we get the list of ld.so symbols instead of libpthread ones.  */
+
+%define IS_IN_rtld
diff --git a/nptl_db/structs.def b/nptl_db/structs.def
index 75da95a36e..fbb36538fa 100644
--- a/nptl_db/structs.def
+++ b/nptl_db/structs.def
@@ -1,5 +1,5 @@
 /* List of types and symbols in libpthread examined by libthread_db.
-   Copyright (C) 2003, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2003,2006,2007,2008,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -23,6 +23,8 @@
 # define STRUCTS_DEF_DEFAULTS 1
 #endif
 
+#if defined IS_IN_libpthread || defined IS_IN_libthread_db
+
 DB_STRUCT (pthread)
 DB_STRUCT_FIELD (pthread, list)
 DB_STRUCT_FIELD (pthread, report_events)
@@ -70,6 +72,12 @@ DB_STRUCT_FIELD (pthread_key_data, data)
 DB_STRUCT (pthread_key_data_level2)
 DB_STRUCT_ARRAY_FIELD (pthread_key_data_level2, data)
 
+#endif	/* IS_IN_libpthread || IS_IN_libthread_db */
+
+#ifndef IS_IN_libpthread
+DB_SYMBOL (_thread_db_dl_nptl_version)
+#endif
+
 DB_STRUCT_FIELD (link_map, l_tls_modid)
 
 DB_STRUCT_ARRAY_FIELD (dtv, dtv)
diff --git a/nptl_db/td_symbol_list.c b/nptl_db/td_symbol_list.c
index 474251d627..bf2dbc1809 100644
--- a/nptl_db/td_symbol_list.c
+++ b/nptl_db/td_symbol_list.c
@@ -42,12 +42,12 @@ td_symbol_list (void)
 
 
 ps_err_e
-td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr)
+td_lookup_1 (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr, bool rtld)
 {
   ps_err_e result;
   assert (idx >= 0 && idx < SYM_NUM_MESSAGES);
-  result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx],
-			      sym_addr);
+  result = ps_pglobal_lookup (ps, rtld ? LD_SO : LIBPTHREAD_SO,
+			      symbol_list_arr[idx], sym_addr);
 
 #ifdef HAVE_ASM_GLOBAL_DOT_NAME
   /* For PowerPC, 64-bit uses dot symbols but 32-bit does not.
diff --git a/nptl_db/td_ta_clear_event.c b/nptl_db/td_ta_clear_event.c
index 7a2850c4ea..d3ec1b3409 100644
--- a/nptl_db/td_ta_clear_event.c
+++ b/nptl_db/td_ta_clear_event.c
@@ -1,5 +1,5 @@
 /* Globally disable events.
-   Copyright (C) 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003,2004,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -37,8 +37,11 @@ td_ta_clear_event (ta_arg, event)
   if (! ta_ok (ta))
     return TD_BADTA;
 
+  err = _td_ta_check_nptl (ta);
+
   /* Fetch the old event mask from the inferior and modify it in place.  */
-  err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
+  if (err == TD_OK)
+    err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
   if (err == TD_OK)
     err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t);
   if (err == TD_OK)
diff --git a/nptl_db/td_ta_event_addr.c b/nptl_db/td_ta_event_addr.c
index 37196e643f..1484bae3ca 100644
--- a/nptl_db/td_ta_event_addr.c
+++ b/nptl_db/td_ta_event_addr.c
@@ -1,5 +1,5 @@
 /* Get event address.
-   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -35,6 +35,10 @@ td_ta_event_addr (const td_thragent_t *ta_arg,
   if (! ta_ok (ta))
     return TD_BADTA;
 
+  err = _td_ta_check_nptl (ta);
+  if (err != TD_OK)
+    return err;
+
   switch (event)
     {
     case TD_CREATE:
diff --git a/nptl_db/td_ta_event_getmsg.c b/nptl_db/td_ta_event_getmsg.c
index 6e68ff4ff2..258b4fba14 100644
--- a/nptl_db/td_ta_event_getmsg.c
+++ b/nptl_db/td_ta_event_getmsg.c
@@ -1,5 +1,5 @@
 /* Retrieve event.
-   Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -43,6 +43,10 @@ td_ta_event_getmsg (const td_thragent_t *ta_arg, td_event_msg_t *msg)
   if (! ta_ok (ta))
     return TD_BADTA;
 
+  err = _td_ta_check_nptl (ta);
+  if (err != TD_OK)
+    return err;
+
   /* Get the pointer to the thread descriptor with the last event.  */
   err = DB_GET_VALUE (thp, ta, __nptl_last_event, 0);
   if (err != TD_OK)
diff --git a/nptl_db/td_ta_get_nthreads.c b/nptl_db/td_ta_get_nthreads.c
index ffe78bd57e..a0480d1964 100644
--- a/nptl_db/td_ta_get_nthreads.c
+++ b/nptl_db/td_ta_get_nthreads.c
@@ -1,5 +1,5 @@
 /* Get the number of threads in the process.
-   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -33,6 +33,10 @@ td_ta_get_nthreads (const td_thragent_t *ta_arg, int *np)
   if (! ta_ok (ta))
     return TD_BADTA;
 
+  err = _td_ta_check_nptl (ta);
+  if (err != TD_OK)
+    return err;
+
   /* Access the variable in the inferior that tells us.  */
   err = DB_GET_VALUE (n, ta, __nptl_nthreads, 0);
   if (err == TD_OK)
diff --git a/nptl_db/td_ta_map_lwp2thr.c b/nptl_db/td_ta_map_lwp2thr.c
index 4835f31f94..d140358b5e 100644
--- a/nptl_db/td_ta_map_lwp2thr.c
+++ b/nptl_db/td_ta_map_lwp2thr.c
@@ -38,7 +38,7 @@ __td_ta_lookup_th_unique (const td_thragent_t *ta_arg,
       /* We need to read in from the inferior the instructions what to do.  */
       psaddr_t howto;
 
-      err = td_lookup (ta->ph, SYM_TH_UNIQUE_CONST_THREAD_AREA, &howto);
+      err = td_lookup (ta, SYM_TH_UNIQUE_CONST_THREAD_AREA, &howto);
       if (err == PS_OK)
 	{
 	  err = ps_pdread (ta->ph, howto,
@@ -56,13 +56,12 @@ __td_ta_lookup_th_unique (const td_thragent_t *ta_arg,
 	  switch (sizeof (regs[0]))
 	    {
 	    case 8:
-	      err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER64, &howto);
+	      err = td_lookup (ta, SYM_TH_UNIQUE_REGISTER64, &howto);
 	      if (err == PS_OK)
 		ta->ta_howto = ta_howto_reg;
 	      else if (err == PS_NOSYM)
 		{
-		  err = td_lookup (ta->ph,
-				   SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
+		  err = td_lookup (ta, SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
 				   &howto);
 		  if (err == PS_OK)
 		    ta->ta_howto = ta_howto_reg_thread_area;
@@ -70,13 +69,12 @@ __td_ta_lookup_th_unique (const td_thragent_t *ta_arg,
 	      break;
 
 	    case 4:
-	      err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER32, &howto);
+	      err = td_lookup (ta, SYM_TH_UNIQUE_REGISTER32, &howto);
 	      if (err == PS_OK)
 		ta->ta_howto = ta_howto_reg;
 	      else if (err == PS_NOSYM)
 		{
-		  err = td_lookup (ta->ph,
-				   SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
+		  err = td_lookup (ta, SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
 				   &howto);
 		  if (err == PS_OK)
 		    ta->ta_howto = ta_howto_reg_thread_area;
@@ -187,14 +185,19 @@ td_ta_map_lwp2thr (const td_thragent_t *ta_arg,
      at exec.  So if it looks like initialization is incomplete, we only
      fake a special descriptor for the initial thread.  */
 
-  psaddr_t list;
-  td_err_e err = DB_GET_SYMBOL (list, ta, __stack_user);
-  if (err != TD_OK)
-    return err;
+  psaddr_t list = 0;
 
-  err = DB_GET_FIELD (list, ta, list, list_t, next, 0);
-  if (err != TD_OK)
+  td_err_e err = _td_ta_check_nptl (ta);
+  if (err == TD_NOLIBTHREAD)
+    list = 0;
+  else if (err != TD_OK)
     return err;
+  else
+    {
+      err = DB_GET_SYMBOL (list, ta, __stack_user);
+      if (err == TD_OK)
+	err = DB_GET_FIELD (list, ta, list, list_t, next, 0);
+    }
 
   if (list == 0)
     {
diff --git a/nptl_db/td_ta_new.c b/nptl_db/td_ta_new.c
index f84049af34..bbb4234f68 100644
--- a/nptl_db/td_ta_new.c
+++ b/nptl_db/td_ta_new.c
@@ -1,5 +1,5 @@
 /* Attach to target process.
-   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -30,18 +30,14 @@
    be exactly one so we don't spend much though on making it fast.  */
 LIST_HEAD (__td_agent_list);
 
-
-td_err_e
-td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
+static td_err_e
+check_version (struct ps_prochandle *ps, psaddr_t versaddr)
 {
-  psaddr_t versaddr;
   char versbuf[sizeof (VERSION)];
 
-  LOG ("td_ta_new");
-
-  /* Check whether the versions match.  */
-  if (td_lookup (ps, SYM_nptl_version, &versaddr) != PS_OK)
+  if (versaddr == 0)
     return TD_NOLIBTHREAD;
+
   if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK)
     return TD_ERR;
 
@@ -49,11 +45,35 @@ td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
     /* Not the right version.  */
     return TD_VERSION;
 
+  return TD_OK;
+}
+
+td_err_e
+td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
+{
+  psaddr_t versaddr = 0;
+  psaddr_t dl_versaddr = 0;
+
+  LOG ("td_ta_new");
+
+  /* Check whether the versions match.  */
+  if (td_lookup_1 (ps, SYM_nptl_version, &versaddr, false) != PS_OK
+      && td_lookup_1 (ps, SYM__thread_db_dl_nptl_version,
+		      &dl_versaddr, true) != PS_OK)
+    return TD_NOLIBTHREAD;
+
+  td_err_e result = check_version (ps, versaddr ?: dl_versaddr);
+  if (result != TD_OK)
+    return result;
+
   /* Fill in the appropriate information.  */
   *ta = (td_thragent_t *) calloc (1, sizeof (td_thragent_t));
   if (*ta == NULL)
     return TD_MALLOC;
 
+  (*ta)->ta_addr_nptl_version = versaddr;
+  (*ta)->ta_addr__thread_db_dl_nptl_version = dl_versaddr;
+
   /* Store the proc handle which we will pass to the callback functions
      back into the debugger.  */
   (*ta)->ph = ps;
@@ -63,3 +83,23 @@ td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
 
   return TD_OK;
 }
+
+td_err_e
+_td_ta_check_nptl (td_thragent_t *ta)
+{
+  if (ta->ta_addr_nptl_version != 0)
+    return TD_OK;
+
+  if (ta->ta_addr__thread_db_dl_nptl_version == 0)
+    return TD_BADTA;
+
+  psaddr_t versaddr = 0;
+  if (td_lookup_1 (ta->ph, SYM_nptl_version, &versaddr, false) != PS_OK)
+    return TD_NOLIBTHREAD;
+
+  td_err_e result = check_version (ta->ph, versaddr);
+  if (result == TD_OK)
+    ta->ta_addr_nptl_version = versaddr;
+
+  return result;
+}
diff --git a/nptl_db/td_ta_set_event.c b/nptl_db/td_ta_set_event.c
index 29fc14bfb3..438800a626 100644
--- a/nptl_db/td_ta_set_event.c
+++ b/nptl_db/td_ta_set_event.c
@@ -1,5 +1,5 @@
 /* Globally enable events.
-   Copyright (C) 1999,2001,2002,2003,2004 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003,2004,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -37,8 +37,11 @@ td_ta_set_event (ta_arg, event)
   if (! ta_ok (ta))
     return TD_BADTA;
 
+  err = _td_ta_check_nptl (ta);
+
   /* Fetch the old event mask from the inferior and modify it in place.  */
-  err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
+  if (err == TD_OK)
+    err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
   if (err == TD_OK)
     err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t);
   if (err == TD_OK)
diff --git a/nptl_db/td_ta_thr_iter.c b/nptl_db/td_ta_thr_iter.c
index 9a594ed1d8..b5e71433a0 100644
--- a/nptl_db/td_ta_thr_iter.c
+++ b/nptl_db/td_ta_thr_iter.c
@@ -1,5 +1,5 @@
 /* Iterate over a process's threads.
-   Copyright (C) 1999,2000,2001,2002,2003,2004,2007,2008
+   Copyright (C) 1999,2000,2001,2002,2003,2004,2007,2008,2009
 	Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
@@ -23,6 +23,18 @@
 
 
 static td_err_e
+fake_initial_thread (td_thragent_t *ta, td_thr_iter_f *callback, void *cbdata_p)
+{
+  /* __pthread_initialize_minimal has not run.  There is just the main
+     thread to return.  We cannot rely on its thread register.  They
+     sometimes contain garbage that would confuse us, left by the
+     kernel at exec.  So if it looks like initialization is incomplete,
+     we only fake a special descriptor for the initial thread.  */
+  td_thrhandle_t th = { ta, 0 };
+  return (*callback) (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK;
+}
+
+static td_err_e
 iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback,
 		     void *cbdata_p, td_thr_state_e state, int ti_pri,
 		     psaddr_t head, bool fake_empty, pid_t match_pid)
@@ -41,15 +53,7 @@ iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback,
     return err;
 
   if (next == 0 && fake_empty)
-    {
-      /* __pthread_initialize_minimal has not run.  There is just the main
-	 thread to return.  We cannot rely on its thread register.  They
-	 sometimes contain garbage that would confuse us, left by the
-	 kernel at exec.  So if it looks like initialization is incomplete,
-	 we only fake a special descriptor for the initial thread.  */
-      td_thrhandle_t th = { ta, 0 };
-      return callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK;
-    }
+    return fake_initial_thread (ta, callback, cbdata_p);
 
   /* Cache the offset from struct pthread to its list_t member.  */
   err = DB_GET_FIELD_ADDRESS (ofs, ta, 0, pthread, list, 0);
@@ -148,6 +152,10 @@ td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback,
   if (! ta_ok (ta))
     return TD_BADTA;
 
+  err = _td_ta_check_nptl (ta);
+  if (err == TD_NOLIBTHREAD)
+    return fake_initial_thread (ta, callback, cbdata_p);
+
   /* The thread library keeps two lists for the running threads.  One
      list contains the thread which are using user-provided stacks
      (this includes the main thread) and the other includes the
@@ -156,7 +164,8 @@ td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback,
      list of threads with user-defined stacks.  */
 
   pid_t pid = ps_getpid (ta->ph);
-  err = DB_GET_SYMBOL (list, ta, __stack_user);
+  if (err == TD_OK)
+    err = DB_GET_SYMBOL (list, ta, __stack_user);
   if (err == TD_OK)
     err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
 			       list, true, pid);
diff --git a/nptl_db/td_ta_tsd_iter.c b/nptl_db/td_ta_tsd_iter.c
index 9cfb1e8de0..cf5d919f86 100644
--- a/nptl_db/td_ta_tsd_iter.c
+++ b/nptl_db/td_ta_tsd_iter.c
@@ -1,5 +1,5 @@
 /* Iterate over a process's thread-specific data.
-   Copyright (C) 1999,2000,2001,2002,2003 Free Software Foundation, Inc.
+   Copyright (C) 1999,2000,2001,2002,2003,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -38,6 +38,10 @@ td_ta_tsd_iter (const td_thragent_t *ta_arg, td_key_iter_f *callback,
   if (! ta_ok (ta))
     return TD_BADTA;
 
+  err = _td_ta_check_nptl (ta);
+  if (err != TD_OK)
+    return err;
+
   /* This makes sure we have the size information on hand.  */
   addr = 0;
   err = _td_locate_field (ta,
diff --git a/nptl_db/td_thr_clear_event.c b/nptl_db/td_thr_clear_event.c
index fc999df9c2..6e7b33481e 100644
--- a/nptl_db/td_thr_clear_event.c
+++ b/nptl_db/td_thr_clear_event.c
@@ -1,5 +1,5 @@
 /* Disable specific event for thread.
-   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -34,9 +34,12 @@ td_thr_clear_event (th, event)
 
   LOG ("td_thr_clear_event");
 
+  err = _td_ta_check_nptl (th->th_ta_p);
+
   /* Fetch the old event mask from the inferior and modify it in place.  */
-  err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
-			      th->th_unique, pthread, eventbuf_eventmask, 0);
+  if (err == TD_OK)
+    err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
+				th->th_unique, pthread, eventbuf_eventmask, 0);
   if (err == TD_OK)
     err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t);
   if (err == TD_OK)
diff --git a/nptl_db/td_thr_event_enable.c b/nptl_db/td_thr_event_enable.c
index c8b2cd463d..c6b1e794b7 100644
--- a/nptl_db/td_thr_event_enable.c
+++ b/nptl_db/td_thr_event_enable.c
@@ -1,5 +1,5 @@
 /* Enable event process-wide.
-   Copyright (C) 1999, 2001, 2002, 2003, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003,2007,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -28,6 +28,10 @@ td_thr_event_enable (th, onoff)
 {
   LOG ("td_thr_event_enable");
 
+  td_err_e err = _td_ta_check_nptl (th->th_ta_p);
+  if (err != TD_OK)
+    return err;
+
   if (th->th_unique != 0)
     {
       /* Write the new value into the thread data structure.  */
diff --git a/nptl_db/td_thr_event_getmsg.c b/nptl_db/td_thr_event_getmsg.c
index 70ea6953ed..f10bb5ff01 100644
--- a/nptl_db/td_thr_event_getmsg.c
+++ b/nptl_db/td_thr_event_getmsg.c
@@ -1,5 +1,5 @@
 /* Retrieve event.
-   Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -32,9 +32,12 @@ td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg)
 
   LOG ("td_thr_event_getmsg");
 
+  err = _td_ta_check_nptl (th->th_ta_p);
+
   /* Copy the event message buffer in from the inferior.  */
-  err = DB_GET_FIELD_ADDRESS (eventbuf, th->th_ta_p, th->th_unique, pthread,
-			      eventbuf, 0);
+  if (err == TD_OK)
+    err = DB_GET_FIELD_ADDRESS (eventbuf, th->th_ta_p, th->th_unique, pthread,
+				eventbuf, 0);
   if (err == TD_OK)
     err = DB_GET_STRUCT (copy, th->th_ta_p, eventbuf, td_eventbuf_t);
   if (err != TD_OK)
diff --git a/nptl_db/td_thr_get_info.c b/nptl_db/td_thr_get_info.c
index 52985603bf..80513ea767 100644
--- a/nptl_db/td_thr_get_info.c
+++ b/nptl_db/td_thr_get_info.c
@@ -41,8 +41,14 @@ td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop)
       schedpolicy = SCHED_OTHER;
       schedprio = 0;
       tid = 0;
-      err = DB_GET_VALUE (report_events, th->th_ta_p,
-			  __nptl_initial_report_events, 0);
+      if (th->th_ta_p->ta_addr_nptl_version == 0)
+	{
+	  report_events = 0;
+	  err = TD_OK;
+	}
+      else
+	err = DB_GET_VALUE (report_events, th->th_ta_p,
+			    __nptl_initial_report_events, 0);
     }
   else
     {
diff --git a/nptl_db/td_thr_set_event.c b/nptl_db/td_thr_set_event.c
index 2bb0b9d1f8..772a25fd5e 100644
--- a/nptl_db/td_thr_set_event.c
+++ b/nptl_db/td_thr_set_event.c
@@ -1,5 +1,5 @@
 /* Enable specific event for thread.
-   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -34,9 +34,12 @@ td_thr_set_event (th, event)
 
   LOG ("td_thr_set_event");
 
+  err = _td_ta_check_nptl (th->th_ta_p);
+
   /* Fetch the old event mask from the inferior and modify it in place.  */
-  err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
-			      th->th_unique, pthread, eventbuf_eventmask, 0);
+  if (err == TD_OK)
+    err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
+				th->th_unique, pthread, eventbuf_eventmask, 0);
   if (err == TD_OK)
     err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t);
   if (err == TD_OK)
diff --git a/nptl_db/td_thr_tsd.c b/nptl_db/td_thr_tsd.c
index 08f617b7d2..9082ce3101 100644
--- a/nptl_db/td_thr_tsd.c
+++ b/nptl_db/td_thr_tsd.c
@@ -1,5 +1,5 @@
 /* Get a thread-specific data pointer for a thread.
-   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -31,8 +31,11 @@ td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data)
 
   LOG ("td_thr_tsd");
 
+  err = _td_ta_check_nptl (th->th_ta_p);
+
   /* Get the key entry.  */
-  err = DB_GET_VALUE (tk_seq, th->th_ta_p, __pthread_keys, tk);
+  if (err == TD_OK)
+    err = DB_GET_VALUE (tk_seq, th->th_ta_p, __pthread_keys, tk);
   if (err == TD_NOAPLIC)
     return TD_BADKEY;
   if (err != TD_OK)
diff --git a/nptl_db/td_thr_validate.c b/nptl_db/td_thr_validate.c
index adcde3c87e..45d8546dd8 100644
--- a/nptl_db/td_thr_validate.c
+++ b/nptl_db/td_thr_validate.c
@@ -62,24 +62,30 @@ td_thr_validate (const td_thrhandle_t *th)
 
   LOG ("td_thr_validate");
 
-  /* First check the list with threads using user allocated stacks.  */
-  bool uninit = false;
-  err = DB_GET_SYMBOL (list, th->th_ta_p, __stack_user);
-  if (err == TD_OK)
-    err = check_thread_list (th, list, &uninit);
-
-  /* If our thread is not on this list search the list with stack
-     using implementation allocated stacks.  */
-  if (err == TD_NOTHR)
+  err = _td_ta_check_nptl (th->th_ta_p);
+  if (err == TD_NOLIBTHREAD && th->th_unique == 0)
+    err = TD_OK;
+  else if (err == TD_OK)
     {
-      err = DB_GET_SYMBOL (list, th->th_ta_p, stack_used);
+      /* First check the list with threads using user allocated stacks.  */
+      bool uninit = false;
+      err = DB_GET_SYMBOL (list, th->th_ta_p, __stack_user);
       if (err == TD_OK)
 	err = check_thread_list (th, list, &uninit);
 
-      if (err == TD_NOTHR && uninit && th->th_unique == 0)
-	/* __pthread_initialize_minimal has not run yet.
-	   There is only the special case thread handle.  */
-	err = TD_OK;
+      /* If our thread is not on this list search the list with stack
+	 using implementation allocated stacks.  */
+      if (err == TD_NOTHR)
+	{
+	  err = DB_GET_SYMBOL (list, th->th_ta_p, stack_used);
+	  if (err == TD_OK)
+	    err = check_thread_list (th, list, &uninit);
+
+	  if (err == TD_NOTHR && uninit && th->th_unique == 0)
+	    /* __pthread_initialize_minimal has not run yet.
+	       There is only the special case thread handle.  */
+	    err = TD_OK;
+	}
     }
 
   if (err == TD_OK)
diff --git a/nptl_db/thread_dbP.h b/nptl_db/thread_dbP.h
index e5db9bf94b..6d0e91dea3 100644
--- a/nptl_db/thread_dbP.h
+++ b/nptl_db/thread_dbP.h
@@ -1,5 +1,5 @@
 /* Private header for thread debug library
-   Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2003,2004,2007,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -140,16 +140,16 @@ ta_ok (const td_thragent_t *ta)
 
 
 /* Internal wrapper around ps_pglobal_lookup.  */
-extern ps_err_e td_lookup (struct ps_prochandle *ps,
-			   int idx, psaddr_t *sym_addr) attribute_hidden;
-
-
+extern ps_err_e td_lookup_1 (struct ps_prochandle *ps, int idx,
+			     psaddr_t *sym_addr, bool rtld) attribute_hidden;
+#define td_lookup(ta, idx, sym_addr) \
+  td_lookup_1 ((ta)->ph, idx, sym_addr, (ta)->ta_addr_nptl_version == 0)
 
 
 /* Store in psaddr_t VAR the address of inferior's symbol NAME.  */
 #define DB_GET_SYMBOL(var, ta, name)					      \
   (((ta)->ta_addr_##name == 0						      \
-    && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK)      \
+    && td_lookup ((ta), SYM_##name, &(ta)->ta_addr_##name) != PS_OK)	      \
    ? TD_ERR : ((var) = (ta)->ta_addr_##name, TD_OK))
 
 /* Store in psaddr_t VAR the value of ((TYPE) PTR)->FIELD[IDX] in the inferior.
@@ -181,7 +181,7 @@ extern td_err_e _td_locate_field (td_thragent_t *ta,
    A target value smaller than psaddr_t is zero-extended.  */
 #define DB_GET_VALUE(var, ta, name, idx)				      \
   (((ta)->ta_addr_##name == 0						      \
-    && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK)      \
+    && td_lookup ((ta), SYM_##name, &(ta)->ta_addr_##name) != PS_OK)	      \
    ? TD_ERR								      \
    : _td_fetch_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name, 	      \
 		      (psaddr_t) 0 + (idx), (ta)->ta_addr_##name, &(var)))
@@ -213,7 +213,7 @@ extern td_err_e _td_fetch_value_local (td_thragent_t *ta,
    A target field smaller than psaddr_t is zero-extended.  */
 #define DB_PUT_VALUE(ta, name, idx, value)				      \
   (((ta)->ta_addr_##name == 0						      \
-    && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK)      \
+    && td_lookup ((ta), SYM_##name, &(ta)->ta_addr_##name) != PS_OK)	      \
    ? TD_ERR								      \
    : _td_store_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name, 	      \
 		      (psaddr_t) 0 + (idx), (ta)->ta_addr_##name, (value)))
@@ -254,4 +254,6 @@ extern td_err_e _td_check_sizeof (td_thragent_t *ta, uint32_t *sizep,
 extern td_err_e __td_ta_lookup_th_unique (const td_thragent_t *ta,
 					  lwpid_t lwpid, td_thrhandle_t *th);
 
+extern td_err_e _td_ta_check_nptl (td_thragent_t *ta) attribute_hidden;
+
 #endif /* thread_dbP.h */