tcbhead_t gdb access for nonthreaded, gdb for longjmp()

Jan Kratochvil jan.kratochvil@redhat.com
Fri Sep 8 10:23:00 GMT 2006


Hi,

crossposted to gdb+glibc as the patches closely correlate:

currently gdb/glibc cannot access TLS of debugged processes if compiled without
libpthread (nonthreaded).  Command line `print errno' produces one of:
	Cannot find thread-local variables on this target
	Cannot access memory at address 0x8
	[ gdb-20060908-tls-0.patch: gdb.threads/tls-print.exp ]

It also affects stepping over longjmp() as gdb calculates target address which
is PTR_MANGLE()d through TLS-based `pointer_guard' magic, as `next' will now:
	Cannot insert breakpoint -12.
	Error accessing memory address 0xb9227d3b: Input/output error.
	[ gdb-20060908-tls-0.patch: gdb.threads/tls-longjmp.exp ]

I would like to get approval of this design acceptance to finish the details.

glibc part:

 * Provide some access to the `tcbhead_t.pointer_guard' field for gdb.
   Currently implemented by `td_thr_getxregs' providing only `pointer_guard'.
   New non-Solaris `td_thr_*' function could be provided instead.

 * All the `libthread_db' functions accessing inferior's `_thread_db*' symbols
   of `libpthread' fallback to the new `_local_db*' symbols in `libthread_db'
   itself. `libthread_db'<=>`libpthread' versions must match anyway.
   I admit I do not know how may `libthread_db' and `libpthread' as there is
   already required in `td_ta_new' their versions match.  Anyway it should be
   enough for 99% of cases - as the fallback option.

gdb part:

 * `longjmp' decoder attempts to use `td_thr_getxregs', otherwise fallbacks
   to get the TLS base by `ps_get_thread_area' and the offset value
   `offsetof (tcbhead_t, pointer_guard)' from debuginfo, otherwise fallbacks
   to internal constant offset.

 * `SEC_THREAD_LOCAL' symbols are processed as a new expression data type.

 * TLS variables access uses legacy `thread_db_get_thread_local_address'
   as it depends on the `_local_db*' fallback implementation for nonthreaded
   processes missing `libthread_db' with the legacy `_thread_db*' symbols.


`longjmp' decoder can cope without glibc support by using debuginfo instead.
I would rather like to drop this workaround and rely on the glibc support.

TLS access needs the attached glibc patch for the nonthreaded processes.
I could provide gdb decoding without glibc support but I do not like it.

It works now only on i386, x86_64 to be debugged if it is accepted this way.
Patches still contain several FIXMEs; their fixes should not change the design.
glibc part should be arch-dependent, it will now fail to compile on arches
without existing `pointer_guard'.

Behavior changes depending on:
 * Application linked with libpthread or without libpthread.
 * glibc original/patched by this TLS extension.
 * -ggdb3 (overriding the TLS `errno' resolving just by the macro text).
 * Debuginfo availability for libpthread (for `longjmp').
Unfortunately the system changes cannot be tested just by the gdb testsuite.


Thanks,
Jan
-------------- next part --------------
2006-09-08  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* nptl/pthread_create.c: Define `DB_INFO_PREFIX' for `db_info.c'.
	* nptl_db/Makefile (distribute): `db_info' moved from here to...
	(libthread_db-routines): here. 
	* nptl_db/db_info.c (DB_INFO_PREFIX): Provide parameterization.
	(__nptl_last_event): Redefine if missing.
	* nptl_db/fetch-value.c (_td_locate_field): New `desc_default'
	for `desc' if it was not found.
	(_td_fetch_value): Likewise.
	(_td_store_value): Likewise.
	(_td_fetch_value_local): No `desc_default' makes sense locally.
	(_td_store_value_local): Likewise.
	* nptl_db/structs.def: New `pthread.pointer_guard_val' define.
	* nptl_db/td_ta_new.c (td_ta_new): Support `TD_MINIMALONLY'
	to access `tcbhead_t' for nonthreaded processes.
	* nptl_db/td_ta_tsd_iter.c (td_ta_tsd_iter): `desc_default' support.
	* nptl_db/td_thr_event_getmsg.c (td_thr_event_getmsg): Likewise.
	* nptl_db/thread_db.h (td_err_e): New `TD_MINIMALONLY'.
	(prxregset_t): Stucture for accessing `pointer_guard'.
	(td_thr_getgregs): `prxregset_t' prototype update.
	(td_thr_setgregs): Likewise.
	* nptl_db/thread_dbP.h (DB_GET_FIELD): Support new `desc_default'.
	(DB_GET_FIELD_ADDRESS): Likewise.
	(_td_locate_field): Likewise.
	(DB_GET_VALUE): Likewise.
	(_td_fetch_value): Likewise.
	(DB_PUT_FIELD): Likewise.
	(DB_PUT_VALUE): Likewise.
	(_td_store_value): Likewise.


diff -u -rp glibc-20060828T1903-orig/nptl/pthread_create.c glibc-20060828T1903/nptl/pthread_create.c
--- glibc-20060828T1903-orig/nptl/pthread_create.c	2006-08-15 01:06:09.000000000 +0200
+++ glibc-20060828T1903/nptl/pthread_create.c	2006-09-07 13:04:28.000000000 +0200
@@ -579,7 +579,12 @@ compat_symbol (libpthread, __pthread_cre
 
 /* Information for libthread_db.  */
 
+#define DB_INFO_PREFIX _thread_db
+/* We may provide our real `static' definition here.  */
+#define __nptl_last_event __nptl_last_event
 #include "../nptl_db/db_info.c"
+#undef DB_INFO_PREFIX
+#undef __nptl_last_event
 
 /* If pthread_create is present, libgcc_eh.a and libsupc++.a expects some other POSIX thread
    functions to be present as well.  */
diff -u -rp glibc-20060828T1903-orig/nptl_db/Makefile glibc-20060828T1903/nptl_db/Makefile
--- glibc-20060828T1903-orig/nptl_db/Makefile	2003-09-09 08:57:51.000000000 +0200
+++ glibc-20060828T1903/nptl_db/Makefile	2006-09-07 12:51:27.000000000 +0200
@@ -43,14 +43,14 @@ libthread_db-routines = td_init td_log t
 			td_ta_set_event td_ta_event_getmsg \
 			td_ta_clear_event td_symbol_list \
 			td_thr_tlsbase td_thr_tls_get_addr \
-			fetch-value
+			fetch-value db_info
 
 libthread_db-inhibit-o = $(filter-out .os,$(object-suffixes))
 
 # The ps_* callback functions are not defined.
 libthread_db.so-no-z-defs = yes
 
-distribute = thread_dbP.h shlib-versions proc_service.h db_info.c structs.def
+distribute = thread_dbP.h shlib-versions proc_service.h structs.def
 include ../Rules
 
 # Depend on libc.so so a DT_NEEDED is generated in the shared objects.
diff -u -rp glibc-20060828T1903-orig/nptl_db/db_info.c glibc-20060828T1903/nptl_db/db_info.c
--- glibc-20060828T1903-orig/nptl_db/db_info.c	2004-03-14 04:39:57.000000000 +0100
+++ glibc-20060828T1903/nptl_db/db_info.c	2006-09-07 13:29:37.000000000 +0200
@@ -22,6 +22,17 @@
 #include "thread_dbP.h"
 #include <tls.h>
 
+#ifndef DB_INFO_PREFIX
+/* Set to `_thread_db' by `../nptl/pthread_create.c'.  */
+#define DB_INFO_PREFIX _local_db
+#endif
+
+/* `__nptl_last_event' is static in `../nptl/pthread_create.c'.
+   As we are interested only in its type we may redefine it.  */
+#ifndef __nptl_last_event
+#define __nptl_last_event struct pthread *
+#endif
+
 typedef struct pthread pthread;
 typedef struct pthread_key_struct pthread_key_struct;
 typedef struct pthread_key_data pthread_key_data;
@@ -44,12 +55,16 @@ typedef struct link_map link_map;
 #define eventbuf_eventmask eventbuf.eventmask
 #define eventbuf_eventmask_event_bits eventbuf.eventmask.event_bits
 
-#define DESC(name, offset, obj) \
-  DB_DEFINE_DESC (name, 8 * sizeof (obj), 1, offset);
-#define ARRAY_DESC(name, offset, obj) \
-  DB_DEFINE_DESC (name, \
+#define DESC1(nameprefix, name, offset, obj) \
+  DB_DEFINE_DESC (nameprefix##name, 8 * sizeof (obj), 1, offset);
+#define DESC(nameprefix, name, offset, obj) \
+  DESC1 (nameprefix, name, offset, obj)
+#define ARRAY_DESC1(nameprefix, name, offset, obj) \
+  DB_DEFINE_DESC (nameprefix##name, \
 		  8 * sizeof (obj)[0], sizeof (obj) / sizeof (obj)[0], \
 		  offset);
+#define ARRAY_DESC(nameprefix, name, offset, obj) \
+  ARRAY_DESC1 (nameprefix, name, offset, obj)
 
 #if TLS_TCB_AT_TP
 # define dtvp header.dtv
@@ -57,22 +72,26 @@ typedef struct link_map link_map;
 /* Special case hack.  If TLS_TCB_SIZE == 0 (on PowerPC), there is no TCB
    containing the DTV at the TP, but actually the TCB lies behind the TP,
    i.e. at the very end of the area covered by TLS_PRE_TCB_SIZE.  */
-DESC (_thread_db_pthread_dtvp,
+DESC (DB_INFO_PREFIX, _pthread_dtvp,
       TLS_PRE_TCB_SIZE + offsetof (tcbhead_t, dtv)
       - (TLS_TCB_SIZE == 0 ? sizeof (tcbhead_t) : 0), union dtv)
 #endif
 
 
+#define DB_STRUCT2(nameprefix, type) \
+  const uint32_t nameprefix##_sizeof_##type = sizeof (type);
+#define DB_STRUCT1(nameprefix, type) \
+  DB_STRUCT2 (nameprefix, type)
 #define DB_STRUCT(type) \
-  const uint32_t _thread_db_sizeof_##type = sizeof (type);
+  DB_STRUCT1 (DB_INFO_PREFIX, type)
 #define DB_STRUCT_FIELD(type, field) \
-  DESC (_thread_db_##type##_##field, \
+  DESC (DB_INFO_PREFIX, _##type##_##field, \
 	offsetof (type, field), ((type *) 0)->field)
 #define DB_STRUCT_ARRAY_FIELD(type, field) \
-  ARRAY_DESC (_thread_db_##type##_##field, \
+  ARRAY_DESC (DB_INFO_PREFIX, _##type##_##field, \
 	      offsetof (type, field), ((type *) 0)->field)
-#define DB_VARIABLE(name) DESC (_thread_db_##name, 0, name)
-#define DB_ARRAY_VARIABLE(name) ARRAY_DESC (_thread_db_##name, 0, name)
+#define DB_VARIABLE(name) DESC (DB_INFO_PREFIX, _##name, 0, name)
+#define DB_ARRAY_VARIABLE(name) ARRAY_DESC (DB_INFO_PREFIX, _##name, 0, name)
 #define DB_SYMBOL(name)	/* Nothing.  */
 #define DB_FUNCTION(name) /* Nothing.  */
 #include "structs.def"
@@ -91,13 +110,25 @@ DESC (_thread_db_pthread_dtvp,
 # endif
 
 /* This macro is defined in the machine's tls.h using the three below.  */
+# define CONST_THREAD_AREA2(nameprefix, bits, value) \
+  const uint32_t nameprefix##_const_thread_area = (value);
+# define CONST_THREAD_AREA1(nameprefix, bits, value) \
+  CONST_THREAD_AREA2 (nameprefix, bits, value)
 # define CONST_THREAD_AREA(bits, value) \
-  const uint32_t _thread_db_const_thread_area = (value);
-# define REGISTER_THREAD_AREA(bits, regofs, scale) \
-  DB_DEFINE_DESC (_thread_db_register##bits##_thread_area, \
+  CONST_THREAD_AREA1 (DB_INFO_PREFIX, bits, value)
+# define REGISTER_THREAD_AREA2(nameprefix, bits, regofs, scale) \
+  DB_DEFINE_DESC (nameprefix##_register##bits##_thread_area, \
 		  bits, (scale), (regofs));
+# define REGISTER_THREAD_AREA1(nameprefix, bits, regofs, scale) \
+  REGISTER_THREAD_AREA2 (nameprefix, bits, regofs, scale)
+# define REGISTER_THREAD_AREA(bits, regofs, scale) \
+  REGISTER_THREAD_AREA1 (DB_INFO_PREFIX, bits, regofs, scale)
+# define REGISTER2(nameprefix, bits, size, regofs, bias) \
+  DB_DEFINE_DESC (nameprefix##_register##bits, size, (uint32_t)(bias), (regofs));
+# define REGISTER1(nameprefix, bits, size, regofs, bias) \
+  REGISTER2 (nameprefix, size, regofs, bias)
 # define REGISTER(bits, size, regofs, bias) \
-  DB_DEFINE_DESC (_thread_db_register##bits, size, (uint32_t)(bias), (regofs));
+  REGISTER1 (DB_INFO_PREFIX, size, regofs, bias)
 
 DB_THREAD_SELF
 #endif
diff -u -rp glibc-20060828T1903-orig/nptl_db/fetch-value.c glibc-20060828T1903/nptl_db/fetch-value.c
--- glibc-20060828T1903-orig/nptl_db/fetch-value.c	2004-03-25 04:53:30.000000000 +0100
+++ glibc-20060828T1903/nptl_db/fetch-value.c	2006-09-07 00:54:11.000000000 +0200
@@ -42,8 +42,8 @@ _td_check_sizeof (td_thragent_t *ta, uin
 
 td_err_e
 _td_locate_field (td_thragent_t *ta,
-		  db_desc_t desc, int descriptor_name,
-		  psaddr_t idx, psaddr_t *address)
+		  db_desc_t desc, const db_desc_t desc_default,
+		  int descriptor_name, psaddr_t idx, psaddr_t *address)
 {
   uint32_t elemsize;
 
@@ -52,11 +52,13 @@ _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);
-      if (err == PS_NOSYM)
+      if (err == PS_NOSYM && desc_default == NULL)
 	return TD_NOCAPAB;
+      if (err == PS_NOSYM)
+        memcpy (desc, desc_default, DB_SIZEOF_DESC);
       if (err == PS_OK)
 	err = ps_pdread (ta->ph, descptr, desc, DB_SIZEOF_DESC);
-      if (err != PS_OK)
+      if (err != PS_OK && err != PS_NOSYM)
 	return TD_ERR;
       if (DB_DESC_SIZE (desc) == 0)
 	return TD_DBERR;
@@ -85,12 +87,13 @@ _td_locate_field (td_thragent_t *ta,
 
 td_err_e
 _td_fetch_value (td_thragent_t *ta,
-		 db_desc_t desc, int descriptor_name,
-		 psaddr_t idx, psaddr_t address,
+		 db_desc_t desc, const db_desc_t desc_default,
+		 int descriptor_name, psaddr_t idx, psaddr_t address,
 		 psaddr_t *result)
 {
   ps_err_e err;
-  td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
+  td_err_e terr = _td_locate_field (ta, desc, desc_default, descriptor_name,
+				    idx, &address);
   if (terr != TD_OK)
     return terr;
 
@@ -139,11 +142,13 @@ _td_fetch_value (td_thragent_t *ta,
 
 td_err_e
 _td_store_value (td_thragent_t *ta,
-		 uint32_t desc[2], int descriptor_name, psaddr_t idx,
+		 db_desc_t desc, const db_desc_t desc_default,
+		 int descriptor_name, psaddr_t idx,
 		 psaddr_t address, psaddr_t widened_value)
 {
   ps_err_e err;
-  td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
+  td_err_e terr = _td_locate_field (ta, desc, desc_default, descriptor_name,
+				    idx, &address);
   if (terr != TD_OK)
     return terr;
 
@@ -190,7 +195,8 @@ _td_fetch_value_local (td_thragent_t *ta
 		       void *address,
 		       psaddr_t *result)
 {
-  td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
+  td_err_e terr = _td_locate_field (ta, desc, NULL, descriptor_name, idx,
+                                    &address);
   if (terr != TD_OK)
     return terr;
 
@@ -242,7 +248,8 @@ _td_store_value_local (td_thragent_t *ta
 		       uint32_t desc[2], int descriptor_name, psaddr_t idx,
 		       void *address, psaddr_t widened_value)
 {
-  td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
+  td_err_e terr = _td_locate_field (ta, desc, NULL, descriptor_name, idx,
+				    &address);
   if (terr != TD_OK)
     return terr;
 
diff -u -rp glibc-20060828T1903-orig/nptl_db/structs.def glibc-20060828T1903/nptl_db/structs.def
--- glibc-20060828T1903-orig/nptl_db/structs.def	2006-02-04 01:47:58.000000000 +0100
+++ glibc-20060828T1903/nptl_db/structs.def	2006-09-01 00:12:45.000000000 +0200
@@ -80,6 +80,8 @@ DB_STRUCT_FIELD (dtv_t, pointer_val)
 #if !defined IS_IN_libpthread || TLS_TCB_AT_TP
 DB_STRUCT_FIELD (pthread, dtvp)
 #endif
+#define pointer_guard_val header.pointer_guard
+DB_STRUCT_FIELD (pthread, pointer_guard_val)
 
 #ifdef STRUCTS_DEF_DEFAULTS
 # undef DB_STRUCT_ARRAY_FIELD
diff -u -rp glibc-20060828T1903-orig/nptl_db/td_ta_new.c glibc-20060828T1903/nptl_db/td_ta_new.c
--- glibc-20060828T1903-orig/nptl_db/td_ta_new.c	2003-09-09 08:57:51.000000000 +0200
+++ glibc-20060828T1903/nptl_db/td_ta_new.c	2006-09-08 02:37:21.000000000 +0200
@@ -36,18 +36,28 @@ td_ta_new (struct ps_prochandle *ps, td_
 {
   psaddr_t versaddr;
   char versbuf[sizeof (VERSION)];
+  td_err_e retval;
 
   LOG ("td_ta_new");
 
   /* Check whether the versions match.  */
-  if (td_lookup (ps, SYM_nptl_version, &versaddr) != PS_OK)
-    return TD_NOLIBTHREAD;
-  if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK)
-    return TD_ERR;
-
-  if (memcmp (versbuf, VERSION, sizeof VERSION) != 0)
-    /* Not the right version.  */
-    return TD_VERSION;
+  if (td_lookup (ps, SYM_nptl_version, &versaddr) == PS_OK)
+    {
+      if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK)
+	return TD_ERR;
+
+      if (memcmp (versbuf, VERSION, sizeof VERSION) != 0)
+	/* Not the right version.  */
+	return TD_VERSION;
+
+      retval = TD_OK;
+    }
+  else
+    {
+      /* We may leak the `td_thragent_t' memory here if the caller does not
+         expect the `TD_MINIMALONLY' error code.  */
+      retval = TD_MINIMALONLY;
+    }
 
   /* Fill in the appropriate information.  */
   *ta = (td_thragent_t *) calloc (1, sizeof (td_thragent_t));
@@ -61,5 +71,5 @@ td_ta_new (struct ps_prochandle *ps, td_
   /* Now add the new agent descriptor to the list.  */
   list_add (&(*ta)->list, &__td_agent_list);
 
-  return TD_OK;
+  return retval;
 }
diff -u -rp glibc-20060828T1903-orig/nptl_db/td_ta_tsd_iter.c glibc-20060828T1903/nptl_db/td_ta_tsd_iter.c
--- glibc-20060828T1903-orig/nptl_db/td_ta_tsd_iter.c	2003-09-09 08:57:51.000000000 +0200
+++ glibc-20060828T1903/nptl_db/td_ta_tsd_iter.c	2006-09-07 12:57:21.000000000 +0200
@@ -40,9 +40,10 @@ td_ta_tsd_iter (const td_thragent_t *ta_
 
   /* This makes sure we have the size information on hand.  */
   addr = 0;
+  extern const uint32_t _local_db___pthread_keys[3];
   err = _td_locate_field (ta,
-			  ta->ta_var___pthread_keys, SYM_DESC___pthread_keys,
-			  (psaddr_t) 0 + 1, &addr);
+			  ta->ta_var___pthread_keys, _local_db___pthread_keys,
+			  SYM_DESC___pthread_keys, (psaddr_t) 0 + 1, &addr);
   if (err != TD_OK)
     return err;
 
diff -u -rp glibc-20060828T1903-orig/nptl_db/td_thr_event_getmsg.c glibc-20060828T1903/nptl_db/td_thr_event_getmsg.c
--- glibc-20060828T1903-orig/nptl_db/td_thr_event_getmsg.c	2003-09-09 08:57:51.000000000 +0200
+++ glibc-20060828T1903/nptl_db/td_thr_event_getmsg.c	2006-09-07 12:57:40.000000000 +0200
@@ -97,8 +97,10 @@ td_thr_event_getmsg (const td_thrhandle_
 	  if (prevp == next_nextp)
 	    return TD_DBERR;
 
+	  extern const uint32_t _local_db___nptl_last_event[3];
 	  err = _td_store_value (th->th_ta_p,
-				 th->th_ta_p->ta_var___nptl_last_event, -1,
+				 th->th_ta_p->ta_var___nptl_last_event,
+				 _local_db___nptl_last_event, -1,
 				 0, prevp, next);
 	  if (err != TD_OK)
 	    return err;
diff -u -rp glibc-20060828T1903-orig/nptl_db/td_thr_getxregs.c glibc-20060828T1903/nptl_db/td_thr_getxregs.c
--- glibc-20060828T1903-orig/nptl_db/td_thr_getxregs.c	2002-11-26 23:50:50.000000000 +0100
+++ glibc-20060828T1903/nptl_db/td_thr_getxregs.c	2006-09-06 22:01:27.000000000 +0200
@@ -22,9 +22,21 @@
 
 
 td_err_e
-td_thr_getxregs (const td_thrhandle_t *th, void *xregs)
+td_thr_getxregs (const td_thrhandle_t *__th, prxregset_t *__xregs)
 {
-  /* XXX This might be platform specific.  */
+  td_err_e err;
+  psaddr_t pointer_guard;
+
+  /* XXX This needs to be platform specific.  */
   LOG ("td_thr_getxregs");
-  return TD_NOXREGS;
+
+  /* Get the `pointer_guard' pointer from the thread descriptor.  */
+  err = DB_GET_FIELD (pointer_guard, __th->th_ta_p, __th->th_unique, pthread,
+		      pointer_guard_val, 0);
+  if (err != TD_OK)
+    return err;
+
+  __xregs->pointer_guard = pointer_guard;
+
+  return TD_OK;
 }
diff -u -rp glibc-20060828T1903-orig/nptl_db/td_thr_getxregsize.c glibc-20060828T1903/nptl_db/td_thr_getxregsize.c
--- glibc-20060828T1903-orig/nptl_db/td_thr_getxregsize.c	2002-11-26 23:50:52.000000000 +0100
+++ glibc-20060828T1903/nptl_db/td_thr_getxregsize.c	2006-09-01 00:12:45.000000000 +0200
@@ -24,7 +24,10 @@
 td_err_e
 td_thr_getxregsize (const td_thrhandle_t *th, int *sizep)
 {
-  /* XXX This might be platform specific.  */
+  /* Structure size is platform specific.  */
   LOG ("td_thr_getxregsize");
-  return TD_NOXREGS;
+
+  *sizep = sizeof (prxregset_t);
+
+  return TD_OK;
 }
diff -u -rp glibc-20060828T1903-orig/nptl_db/td_thr_setxregs.c glibc-20060828T1903/nptl_db/td_thr_setxregs.c
--- glibc-20060828T1903-orig/nptl_db/td_thr_setxregs.c	2002-11-26 23:50:52.000000000 +0100
+++ glibc-20060828T1903/nptl_db/td_thr_setxregs.c	2006-09-01 00:12:45.000000000 +0200
@@ -22,7 +22,7 @@
 
 
 td_err_e
-td_thr_setxregs (const td_thrhandle_t *ta, const void *addr)
+td_thr_setxregs (const td_thrhandle_t *__th, prxregset_t *__xregs)
 {
   /* XXX This might have to be platform specific.  */
   LOG ("td_thr_setxregs");
diff -u -rp glibc-20060828T1903-orig/nptl_db/thread_db.h glibc-20060828T1903/nptl_db/thread_db.h
--- glibc-20060828T1903-orig/nptl_db/thread_db.h	2003-09-09 08:58:19.000000000 +0200
+++ glibc-20060828T1903/nptl_db/thread_db.h	2006-09-01 00:12:45.000000000 +0200
@@ -56,7 +56,8 @@ typedef enum
   TD_TLSDEFER,	  /* Thread has not yet allocated TLS for given module.  */
   TD_NOTALLOC = TD_TLSDEFER,
   TD_VERSION,	  /* Version if libpthread and libthread_db do not match.  */
-  TD_NOTLS	  /* There is no TLS segment in the given module.  */
+  TD_NOTLS,	  /* There is no TLS segment in the given module.  */
+  TD_MINIMALONLY  /* Single-threaded mode, only some features available.  */
 } td_err_e;
 
 
@@ -289,6 +290,13 @@ typedef struct td_thrinfo
 } td_thrinfo_t;
 
 
+/* Information exchanged by td_thr_getxregs().  */
+typedef struct prxregset
+{
+  psaddr_t pointer_guard;	/* Access tcbhead_t.pointer_guard.  */
+} prxregset_t;
+
+
 
 /* Prototypes for exported library functions.  */
 
@@ -387,7 +395,8 @@ extern td_err_e td_thr_getgregs (const t
 				 prgregset_t __gregs);
 
 /* Retrieve extended register contents of process running thread TH.  */
-extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs);
+extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th,
+				 prxregset_t *__xregs);
 
 /* Get size of extended register set of process running thread TH.  */
 extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep);
@@ -402,7 +411,7 @@ extern td_err_e td_thr_setgregs (const t
 
 /* Set extended register contents of process running thread TH.  */
 extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th,
-				 const void *__addr);
+				 prxregset_t *__xregs);
 
 
 /* Get address of the given module's TLS storage area for the given thread.  */
diff -u -rp glibc-20060828T1903-orig/nptl_db/thread_dbP.h glibc-20060828T1903/nptl_db/thread_dbP.h
--- glibc-20060828T1903-orig/nptl_db/thread_dbP.h	2004-05-03 23:30:30.000000000 +0200
+++ glibc-20060828T1903/nptl_db/thread_dbP.h	2006-09-07 12:56:26.000000000 +0200
@@ -29,6 +29,7 @@
 #include "proc_service.h"
 #include "thread_db.h"
 #include "../nptl/pthreadP.h"  	/* This is for *_BITMASK only.  */
+#include <link.h>
 
 /* Indeces for the symbol names.  */
 enum
@@ -155,18 +156,23 @@ extern ps_err_e td_lookup (struct ps_pro
 /* Store in psaddr_t VAR the value of ((TYPE) PTR)->FIELD[IDX] in the inferior.
    A target field smaller than psaddr_t is zero-extended.  */
 #define DB_GET_FIELD(var, ta, ptr, type, field, idx) \
-  _td_fetch_value ((ta), (ta)->ta_field_##type##_##field, \
-		   SYM_##type##_FIELD_##field, \
-		   (psaddr_t) 0 + (idx), (ptr), &(var))
-
-#define DB_GET_FIELD_ADDRESS(var, ta, ptr, type, field, idx) \
-  ((var) = (ptr), _td_locate_field ((ta), (ta)->ta_field_##type##_##field, \
-				    SYM_##type##_FIELD_##field, \
-				    (psaddr_t) 0 + (idx), &(var)))
+  ({ extern const uint32_t _local_db_##type##_##field[3];		      \
+    _td_fetch_value ((ta), (ta)->ta_field_##type##_##field,		      \
+		     _local_db_##type##_##field, SYM_##type##_FIELD_##field,  \
+		     (psaddr_t) 0 + (idx), (ptr), &(var));		      \
+  })
+
+#define DB_GET_FIELD_ADDRESS(var, ta, ptr, type, field, idx)		      \
+  ({ extern const uint32_t _local_db_##type##_##field[3];		      \
+    ((var) = (ptr), _td_locate_field ((ta), (ta)->ta_field_##type##_##field,  \
+				      _local_db_##type##_##field,	      \
+				      SYM_##type##_FIELD_##field,	      \
+				      (psaddr_t) 0 + (idx), &(var)));	      \
+  })
 
 extern td_err_e _td_locate_field (td_thragent_t *ta,
-				  db_desc_t desc, int descriptor_name,
-				  psaddr_t idx,
+				  db_desc_t desc, const db_desc_t desc_default, 
+				  int descriptor_name, psaddr_t idx,
 				  psaddr_t *address) attribute_hidden;
 
 
@@ -180,15 +186,19 @@ extern td_err_e _td_locate_field (td_thr
 /* Store in psaddr_t VAR the value of variable NAME[IDX] in the inferior.
    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_ERR								      \
-   : _td_fetch_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name, 	      \
-		      (psaddr_t) 0 + (idx), (ta)->ta_addr_##name, &(var)))
+  ({ extern const uint32_t _local_db_##name[3];				      \
+    (((ta)->ta_addr_##name == 0						      \
+      && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK)    \
+     ? TD_ERR								      \
+     : _td_fetch_value ((ta), (ta)->ta_var_##name, _local_db_##name,	      \
+			SYM_DESC_##name,				      \
+			(psaddr_t) 0 + (idx), (ta)->ta_addr_##name, &(var))); \
+  })
 
 /* Helper functions for those.  */
 extern td_err_e _td_fetch_value (td_thragent_t *ta,
-				 db_desc_t field, int descriptor_name,
+				 db_desc_t desc, const db_desc_t desc_default,
+				 int descriptor_name,
 				 psaddr_t idx, psaddr_t address,
 				 psaddr_t *result) attribute_hidden;
 extern td_err_e _td_fetch_value_local (td_thragent_t *ta,
@@ -199,10 +209,12 @@ extern td_err_e _td_fetch_value_local (t
 
 /* Store psaddr_t VALUE in ((TYPE) PTR)->FIELD[IDX] in the inferior.
    A target field smaller than psaddr_t is zero-extended.  */
-#define DB_PUT_FIELD(ta, ptr, type, field, idx, value) \
-  _td_store_value ((ta), (ta)->ta_field_##type##_##field, \
-		   SYM_##type##_FIELD_##field, \
-		   (psaddr_t) 0 + (idx), (ptr), (value))
+#define DB_PUT_FIELD(ta, ptr, type, field, idx, value)			      \
+  ({ extern const uint32_t _local_db_##type##_##field[3];		      \
+    _td_store_value ((ta), (ta)->ta_field_##type##_##field,		      \
+		     _local_db_##type##_##field, SYM_##type##_FIELD_##field,  \
+		     (psaddr_t) 0 + (idx), (ptr), (value));		      \
+  })
 
 #define DB_PUT_FIELD_LOCAL(ta, ptr, type, field, idx, value) \
   _td_store_value_local ((ta), (ta)->ta_field_##type##_##field, \
@@ -212,15 +224,19 @@ extern td_err_e _td_fetch_value_local (t
 /* Store psaddr_t VALUE in variable NAME[IDX] in the inferior.
    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_ERR								      \
-   : _td_store_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name, 	      \
-		      (psaddr_t) 0 + (idx), (ta)->ta_addr_##name, (value)))
+  ({ extern const uint32_t _local_db_##name[3];				      \
+    (((ta)->ta_addr_##name == 0						      \
+      && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK)    \
+     ? TD_ERR								      \
+     : _td_store_value ((ta), (ta)->ta_var_##name, _local_db_##name,	      \
+                        SYM_DESC_##name, (psaddr_t) 0 + (idx),		      \
+			(ta)->ta_addr_##name, (value)));		      \
+  })
 
 /* Helper functions for those.  */
 extern td_err_e _td_store_value (td_thragent_t *ta,
-				 db_desc_t field, int descriptor_name,
+				 db_desc_t desc, const db_desc_t desc_default,
+				 int descriptor_name,
 				 psaddr_t idx, psaddr_t address,
 				 psaddr_t value) attribute_hidden;
 extern td_err_e _td_store_value_local (td_thragent_t *ta,
-------------- next part --------------
2006-09-08  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* breakpoint.c (cover_target_enable_exception):
	(create_longjmp_breakpoint): Return success indicator.
	(breakpoint_re_set): Avoid libpthread outer `longjmp' breaks.
	* configure.ac: Check for `TD_MINIMALONLY' and `prxregset_t'.
	* configure: Updated.
	* config.in: Updated.
	* eval.c (evaluate_subexp_standard): New `UNOP_MEMVAL_TLS'.
	* exceptions.h (enum errors): New `TLS_UNSUPPORTED_XREG'.
	* expprint.c (print_subexp_standard): New `UNOP_MEMVAL_TLS'.
	(op_name_standard): New `UNOP_MEMVAL_TLS'.
	(dump_subexp_body_standard): New `UNOP_MEMVAL_TLS'.
	* expression.h (enum exp_opcode): New `UNOP_MEMVAL_TLS'.
	(union exp_element): New `objfile' type.
	* gdb_thread_db.h (td_err_e): Updated to recent glibc,
	including the new `TD_MINIMALONLY'.
	(prxregset_t): Stucture for accessing `pointer_guard'.
	(td_thr_getgregs): `prxregset_t' prototype update.
	(td_thr_setgregs): Likewise.
	* gdbthread.h (enum thread_xreg): New.
	(thread_get_field_at_offset): New.
	* i386-linux-nat.c (ps_get_thread_area): New function.
	(_initialize_i386_linux_nat): Provide `ps_get_thread_area'.
	* amd64-linux-nat.c (ps_get_thread_area): New function.
	(_initialize_amd64_linux_nat): Provide `ps_get_thread_area'.
	* inf-child.c (inf_child_get_thread_xreg): New function,
	get `pointer_guard' without libthread_db support.
	(inf_child_target): Fill-in target's `to_get_thread_xreg'.
	* infrun.c (process_event_stop_test): PTR_DEMANGLE() `longjmp' target.
	* linux-thread-db.c (minimal_thread_db_ops): New for minimal threads.
	(using_thread_db): Now expresses also the thread type/class.
	(td_ta_delete_p): New for undoing `td_ta_new_p'.
	(td_thr_getxregs_p): New to get `pointer_guard'.
	(td_thr_getxregsize_p) Likewise.
	(thread_db_load): Fill-in the needed new functions.
	(check_for_thread_db): Support detecting and upgrading-from
	`minimal_thread_db_ops'.  New sanity check on the loaded library.
	(thread_db_wait): Support the new thread type/classing.
	(minimal_thread_db_wait): `thread_db_wait' for `minimal_thread_db_ops'.
	(thread_db_create_inferior): Support the new thread type/classing.
	(thread_db_mourn_inferior): Likewise.
	(thread_db_ptid2thr_static): New.
	(thread_db_get_thread_local_address): No longer check if inferior is
	fully threaded.
	(thread_db_thr_get_xregoffset): New.
	(thread_db_get_thread_xreg): New.
	(init_thread_db_ops): Provide also `thread_db_get_thread_xreg'.
	(init_minimal_thread_db_ops): New, `minimal_thread_db_ops'.
	(_initialize_thread_db): Call also `init_minimal_thread_db_ops'.
	* parse.c (write_exp_elt_objfile): New `objfile' setter.
	(write_exp_msymbol): Support new `UNOP_MEMVAL_TLS'.
	(msym_text_tls_symbol_type, msym_data_tls_symbol_type,
	msym_unknown_tls_symbol_type, build_parse): New TLS types.
	(operator_length_standard): New `UNOP_MEMVAL_TLS'.
	* parser-defs.h (write_exp_elt_objfile): New `objfile' setter.
	* symtab.c (symtab_offsetof): New, as `offsetof'.
	* symtab.h (symtab_offsetof): Likewise.
	* dwarf2loc.c (dwarf_expr_tls_address): Code moved out to
	`target_translate_tls_address'.
	* target.h (target_translate_tls_address): Moved here.
	(target_ops): Support `to_get_thread_xreg' and
	`to_ps_get_thread_area_current'.
	* target.c (target_translate_tls_address): Moved here.
	Fix for separate debuginfo by `separate_debug_objfile_backlink'.
	Provided warnings for TLS `errno' on non-TLS targets.
	(update_current_target): Support `to_get_thread_xreg' and
	`to_ps_get_thread_area_current'.
	* thread.c (thread_get_field_at_offset): New, to access TLS base.
	* valops.c (value_at_lazy): Pass control to `value_at_lazy_tls'.
	(value_at_lazy_tls): Provide TLS `struct objfile *' storage.
	(value_fetch_lazy): Resolve TLS `struct objfile *' storage.
	(value_assign): Resolve TLS `struct objfile *' storage.
	* value.c (struct value, allocate_value, value_tls_objfile,
	set_value_tls_objfile): Provide TLS `struct objfile *' storage.
	* value.h (value_tls_objfile, set_value_tls_objfile,
	value_at_lazy_tls): Provide TLS `struct objfile *' storage.
	* Makefile.in: Updated dependencies.


2006-09-08  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.threads/tls-longjmp.exp: Test for TLS `PTR_DEMANGLE'.
	* gdb.threads/tls-longjmp.c: Likewise.
	* gdb.threads/tls-print.exp: Test for TLS symbols decoding.
	* gdb.threads/tls-print.c: Likewise.


Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.840
diff -u -p -r1.840 Makefile.in
--- gdb/Makefile.in	22 Aug 2006 19:08:31 -0000	1.840
+++ gdb/Makefile.in	8 Sep 2006 00:54:06 -0000
@@ -801,7 +801,8 @@ stabsread_h = stabsread.h
 stack_h = stack.h
 symfile_h = symfile.h
 symtab_h = symtab.h
-target_h = target.h $(bfd_h) $(symtab_h) $(dcache_h) $(memattr_h)
+target_h = target.h $(bfd_h) $(symtab_h) $(dcache_h) $(memattr_h) \
+	$(gdb_proc_service_h) $(gdbthread.h)
 terminal_h = terminal.h
 top_h = top.h
 tracepoint_h = tracepoint.h
@@ -1977,7 +1978,7 @@ exec.o: exec.c $(defs_h) $(frame_h) $(in
 	$(xcoffsolib_h) $(observer_h)
 expprint.o: expprint.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
 	$(value_h) $(language_h) $(parser_defs_h) $(user_regs_h) $(target_h) \
-	$(gdb_string_h) $(block_h)
+	$(gdb_string_h) $(block_h) $(objfiles_h)
 fbsd-nat.o: fbsd-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) $(regcache_h) \
 	$(regset_h) $(gdb_assert_h) $(gdb_string_h) $(elf_bfd_h) \
 	$(fbsd_nat_h)
@@ -2422,7 +2423,7 @@ osabi.o: osabi.c $(defs_h) $(gdb_assert_
 parse.o: parse.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
 	$(frame_h) $(expression_h) $(value_h) $(command_h) $(language_h) \
 	$(f_lang_h) $(parser_defs_h) $(gdbcmd_h) $(symfile_h) $(inferior_h) \
-	$(doublest_h) $(gdb_assert_h) $(block_h) $(source_h)
+	$(doublest_h) $(gdb_assert_h) $(block_h) $(source_h) $(objfiles_h)
 p-exp.o: p-exp.c $(defs_h) $(gdb_string_h) $(expression_h) $(value_h) \
 	$(parser_defs_h) $(language_h) $(p_lang_h) $(bfd_h) $(symfile_h) \
 	$(objfiles_h) $(block_h)
@@ -2750,7 +2751,8 @@ symtab.o: symtab.c $(defs_h) $(symtab_h)
 	$(gdb_stat_h) $(cp_abi_h) $(observer_h)
 target.o: target.c $(defs_h) $(gdb_string_h) $(target_h) $(gdbcmd_h) \
 	$(symtab_h) $(inferior_h) $(bfd_h) $(symfile_h) $(objfiles_h) \
-	$(gdb_wait_h) $(dcache_h) $(regcache_h) $(gdb_assert_h) $(gdbcore_h)
+	$(gdb_wait_h) $(dcache_h) $(regcache_h) $(gdb_assert_h) $(gdbcore_h) \
+	$(exceptions_h)
 thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \
 	$(environ_h) $(value_h) $(target_h) $(gdbthread_h) $(exceptions_h) \
 	$(command_h) $(gdbcmd_h) $(regcache_h) $(gdb_h) $(gdb_string_h) \
Index: gdb/amd64-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/amd64-linux-nat.c,v
retrieving revision 1.13
diff -u -p -r1.13 amd64-linux-nat.c
--- gdb/amd64-linux-nat.c	19 Aug 2006 15:15:18 -0000	1.13
+++ gdb/amd64-linux-nat.c	8 Sep 2006 00:54:06 -0000
@@ -367,6 +367,26 @@ ps_get_thread_area (const struct ps_proc
 }
 
 
+/* Query the base address of the current module of the specified thread.
+   Calls `ps_get_thread_area' but without specifying current `idx'.  */
+static ps_err_e
+amd64_linux_ps_get_thread_area_current (lwpid_t lwpid, void **base)
+{
+  int idx;
+
+  /* FIXME: For read_register ().  */
+#warning "FIXME"
+  gdb_assert (lwpid == ptid_get_pid (inferior_ptid));
+  if (gdbarch_ptr_bit (current_gdbarch) == 32)
+    idx = read_register (I386_GS_REGNUM) >> 3;
+  else
+    idx = FS;
+
+  /* We have no `const struct ps_prochandle *' available here
+     but fortunately our implementations do not use it.  */
+  return ps_get_thread_area (NULL, lwpid, idx, base);
+}
+
 static void (*super_post_startup_inferior) (ptid_t ptid);
 
 static void
@@ -406,6 +426,9 @@ _initialize_amd64_linux_nat (void)
   t->to_fetch_registers = amd64_linux_fetch_inferior_registers;
   t->to_store_registers = amd64_linux_store_inferior_registers;
 
+  /* Query the base address of the current module of the specified thread.  */
+  t->to_ps_get_thread_area_current = amd64_linux_ps_get_thread_area_current;
+
   /* Register the target.  */
   linux_nat_add_target (t);
 }
Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.229
diff -u -p -r1.229 breakpoint.c
--- gdb/breakpoint.c	8 Aug 2006 21:32:37 -0000	1.229
+++ gdb/breakpoint.c	8 Sep 2006 00:54:11 -0000
@@ -148,7 +148,7 @@ static int cover_target_enable_exception
 
 static void maintenance_info_breakpoints (char *, int);
 
-static void create_longjmp_breakpoint (char *);
+static struct breakpoint *create_longjmp_breakpoint (char *);
 
 static void create_overlay_event_breakpoint (char *);
 
@@ -4166,7 +4166,7 @@ create_internal_breakpoint (CORE_ADDR ad
 }
 
 
-static void
+static struct breakpoint *
 create_longjmp_breakpoint (char *func_name)
 {
   struct breakpoint *b;
@@ -4177,7 +4177,7 @@ create_longjmp_breakpoint (char *func_na
   else
     {
       if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL)
-	return;
+	return NULL;
  
       b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m), bp_longjmp);
     }
@@ -4186,6 +4186,7 @@ create_longjmp_breakpoint (char *func_na
   b->silent = 1;
   if (func_name)
     b->addr_string = xstrdup (func_name);
+  return b;
 }
 
 /* Call this routine when stepping and nexting to enable a breakpoint
@@ -7248,10 +7249,18 @@ breakpoint_re_set (void)
 
   if (GET_LONGJMP_TARGET_P ())
     {
-      create_longjmp_breakpoint ("longjmp");
-      create_longjmp_breakpoint ("_longjmp");
-      create_longjmp_breakpoint ("siglongjmp");
-      create_longjmp_breakpoint ("_siglongjmp");
+#warning "FIXME"
+      /* Do not break in the outer `longjmp' residing in libpthread.  */
+      if (create_longjmp_breakpoint ("__libc_longjmp") == NULL)
+	{
+	  create_longjmp_breakpoint ("longjmp");
+	  create_longjmp_breakpoint ("_longjmp");
+	}
+      if (create_longjmp_breakpoint ("__libc_siglongjmp") == NULL)
+	{
+	  create_longjmp_breakpoint ("siglongjmp");
+	  create_longjmp_breakpoint ("_siglongjmp");
+	}
       create_longjmp_breakpoint (NULL);
     }
   
Index: gdb/config.in
===================================================================
RCS file: /cvs/src/src/gdb/config.in,v
retrieving revision 1.84
diff -u -p -r1.84 config.in
--- gdb/config.in	8 Aug 2006 20:32:15 -0000	1.84
+++ gdb/config.in	8 Sep 2006 00:54:11 -0000
@@ -227,6 +227,9 @@
 /* Define if <sys/procfs.h> has prsysent_t. */
 #undef HAVE_PRSYSENT_T
 
+/* Define to 1 if the system has the type `prxregset_t'. */
+#undef HAVE_PRXREGSET_T
+
 /* Define if <sys/procfs.h> has pr_sigaction64_t. */
 #undef HAVE_PR_SIGACTION64_T
 
@@ -545,6 +548,12 @@
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
+/* Define if <thread_db.h> has the prxregset_t typedef. */
+#undef THREAD_DB_HAS_PRXREGSET_T
+
+/* Define if <thread_db.h> has the TD_MINIMALONLY error code. */
+#undef THREAD_DB_HAS_TD_MINIMALONLY
+
 /* Define if <thread_db.h> has the TD_NOTALLOC error code. */
 #undef THREAD_DB_HAS_TD_NOTALLOC
 
Index: gdb/configure
===================================================================
RCS file: /cvs/src/src/gdb/configure,v
retrieving revision 1.213
diff -u -p -r1.213 configure
--- gdb/configure	8 Aug 2006 20:32:15 -0000	1.213
+++ gdb/configure	8 Sep 2006 00:54:17 -0000
@@ -20858,6 +20858,147 @@ _ACEOF
 
 fi
 
+if test "x$ac_cv_header_thread_db_h" = "xyes"; then
+   echo "$as_me:$LINENO: checking whether <thread_db.h> has TD_MINIMALONLY" >&5
+echo $ECHO_N "checking whether <thread_db.h> has TD_MINIMALONLY... $ECHO_C" >&6
+if test "${gdb_cv_thread_db_h_has_td_minimalonly+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <thread_db.h>
+int
+main ()
+{
+int i = TD_MINIMALONLY;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  gdb_cv_thread_db_h_has_td_minimalonly=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gdb_cv_thread_db_h_has_td_minimalonly=no
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:$LINENO: result: $gdb_cv_thread_db_h_has_td_minimalonly" >&5
+echo "${ECHO_T}$gdb_cv_thread_db_h_has_td_minimalonly" >&6
+fi
+if test "x$gdb_cv_thread_db_h_has_td_minimalonly" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define THREAD_DB_HAS_TD_MINIMALONLY 1
+_ACEOF
+
+fi
+
+if test "x$ac_cv_header_thread_db_h" = "xyes"; then
+   echo "$as_me:$LINENO: checking for prxregset_t" >&5
+echo $ECHO_N "checking for prxregset_t... $ECHO_C" >&6
+if test "${ac_cv_type_prxregset_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <thread_db.h>
+
+int
+main ()
+{
+if ((prxregset_t *) 0)
+  return 0;
+if (sizeof (prxregset_t))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_prxregset_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_prxregset_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_prxregset_t" >&5
+echo "${ECHO_T}$ac_cv_type_prxregset_t" >&6
+if test $ac_cv_type_prxregset_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_PRXREGSET_T 1
+_ACEOF
+
+
+fi
+
+fi
+if test "x$ac_cv_type_prxregset_t" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define THREAD_DB_HAS_PRXREGSET_T 1
+_ACEOF
+
+fi
+
 if test "x$ac_cv_header_sys_syscall_h" = "xyes"; then
    echo "$as_me:$LINENO: checking whether <sys/syscall.h> has __NR_tkill" >&5
 echo $ECHO_N "checking whether <sys/syscall.h> has __NR_tkill... $ECHO_C" >&6
@@ -22335,7 +22476,7 @@ ac_x_header_dirs='
 /usr/openwin/share/include'
 
 if test "$ac_x_includes" = no; then
-  # Guess where to find include files, by looking for Intrinsic.h.
+  # Guess where to find include files, by looking for Xlib.h.
   # First, try using that file with no special directory specified.
   cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
@@ -22343,7 +22484,7 @@ _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-#include <X11/Intrinsic.h>
+#include <X11/Xlib.h>
 _ACEOF
 if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
   (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
@@ -22370,7 +22511,7 @@ else
 sed 's/^/| /' conftest.$ac_ext >&5
 
   for ac_dir in $ac_x_header_dirs; do
-  if test -r "$ac_dir/X11/Intrinsic.h"; then
+  if test -r "$ac_dir/X11/Xlib.h"; then
     ac_x_includes=$ac_dir
     break
   fi
@@ -22384,18 +22525,18 @@ if test "$ac_x_libraries" = no; then
   # See if we find them without any special options.
   # Don't add to $LIBS permanently.
   ac_save_LIBS=$LIBS
-  LIBS="-lXt $LIBS"
+  LIBS="-lX11 $LIBS"
   cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-#include <X11/Intrinsic.h>
+#include <X11/Xlib.h>
 int
 main ()
 {
-XtMalloc (0)
+XrmInitialize ()
   ;
   return 0;
 }
Index: gdb/configure.ac
===================================================================
RCS file: /cvs/src/src/gdb/configure.ac,v
retrieving revision 1.34
diff -u -p -r1.34 configure.ac
--- gdb/configure.ac	8 Aug 2006 20:26:23 -0000	1.34
+++ gdb/configure.ac	8 Sep 2006 00:54:18 -0000
@@ -1035,6 +1035,32 @@ if test "x$gdb_cv_thread_db_h_has_td_not
             [Define if <thread_db.h> has the TD_NOTALLOC error code.])
 fi
 
+dnl See if we have a thread_db header file that has TD_MINIMALONLY.
+if test "x$ac_cv_header_thread_db_h" = "xyes"; then
+   AC_CACHE_CHECK([whether <thread_db.h> has TD_MINIMALONLY],
+                  gdb_cv_thread_db_h_has_td_minimalonly,
+     AC_TRY_COMPILE(
+       [#include <thread_db.h>],
+       [int i = TD_MINIMALONLY;],
+       gdb_cv_thread_db_h_has_td_minimalonly=yes,
+       gdb_cv_thread_db_h_has_td_minimalonly=no
+     )
+   )
+fi
+if test "x$gdb_cv_thread_db_h_has_td_minimalonly" = "xyes"; then
+  AC_DEFINE(THREAD_DB_HAS_TD_MINIMALONLY, 1,
+            [Define if <thread_db.h> has the TD_MINIMALONLY error code.])
+fi
+
+dnl See if we have a thread_db header file that has prxregset_t.
+if test "x$ac_cv_header_thread_db_h" = "xyes"; then
+   AC_CHECK_TYPES(prxregset_t, [], [], [#include <thread_db.h>])
+fi
+if test "x$ac_cv_type_prxregset_t" = "xyes"; then
+  AC_DEFINE(THREAD_DB_HAS_PRXREGSET_T, 1,
+            [Define if <thread_db.h> has the prxregset_t typedef.])
+fi
+
 dnl See if we have a sys/syscall header file that has __NR_tkill.
 if test "x$ac_cv_header_sys_syscall_h" = "xyes"; then
    AC_CACHE_CHECK([whether <sys/syscall.h> has __NR_tkill],
Index: gdb/dwarf2loc.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2loc.c,v
retrieving revision 1.33
diff -u -p -r1.33 dwarf2loc.c
--- gdb/dwarf2loc.c	17 Dec 2005 22:33:59 -0000	1.33
+++ gdb/dwarf2loc.c	8 Sep 2006 00:54:19 -0000
@@ -189,86 +189,8 @@ static CORE_ADDR
 dwarf_expr_tls_address (void *baton, CORE_ADDR offset)
 {
   struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
-  volatile CORE_ADDR addr = 0;
 
-  if (target_get_thread_local_address_p ()
-      && gdbarch_fetch_tls_load_module_address_p (current_gdbarch))
-    {
-      ptid_t ptid = inferior_ptid;
-      struct objfile *objfile = debaton->objfile;
-      volatile struct gdb_exception ex;
-
-      TRY_CATCH (ex, RETURN_MASK_ALL)
-	{
-	  CORE_ADDR lm_addr;
-	  
-	  /* Fetch the load module address for this objfile.  */
-	  lm_addr = gdbarch_fetch_tls_load_module_address (current_gdbarch,
-	                                                   objfile);
-	  /* If it's 0, throw the appropriate exception.  */
-	  if (lm_addr == 0)
-	    throw_error (TLS_LOAD_MODULE_NOT_FOUND_ERROR,
-			 _("TLS load module not found"));
-
-	  addr = target_get_thread_local_address (ptid, lm_addr, offset);
-	}
-      /* If an error occurred, print TLS related messages here.  Otherwise,
-         throw the error to some higher catcher.  */
-      if (ex.reason < 0)
-	{
-	  int objfile_is_library = (objfile->flags & OBJF_SHARED);
-
-	  switch (ex.error)
-	    {
-	    case TLS_NO_LIBRARY_SUPPORT_ERROR:
-	      error (_("Cannot find thread-local variables in this thread library."));
-	      break;
-	    case TLS_LOAD_MODULE_NOT_FOUND_ERROR:
-	      if (objfile_is_library)
-		error (_("Cannot find shared library `%s' in dynamic"
-		         " linker's load module list"), objfile->name);
-	      else
-		error (_("Cannot find executable file `%s' in dynamic"
-		         " linker's load module list"), objfile->name);
-	      break;
-	    case TLS_NOT_ALLOCATED_YET_ERROR:
-	      if (objfile_is_library)
-		error (_("The inferior has not yet allocated storage for"
-		         " thread-local variables in\n"
-		         "the shared library `%s'\n"
-		         "for %s"),
-		       objfile->name, target_pid_to_str (ptid));
-	      else
-		error (_("The inferior has not yet allocated storage for"
-		         " thread-local variables in\n"
-		         "the executable `%s'\n"
-		         "for %s"),
-		       objfile->name, target_pid_to_str (ptid));
-	      break;
-	    case TLS_GENERIC_ERROR:
-	      if (objfile_is_library)
-		error (_("Cannot find thread-local storage for %s, "
-		         "shared library %s:\n%s"),
-		       target_pid_to_str (ptid),
-		       objfile->name, ex.message);
-	      else
-		error (_("Cannot find thread-local storage for %s, "
-		         "executable file %s:\n%s"),
-		       target_pid_to_str (ptid),
-		       objfile->name, ex.message);
-	      break;
-	    default:
-	      throw_exception (ex);
-	      break;
-	    }
-	}
-    }
-  /* It wouldn't be wrong here to try a gdbarch method, too; finding
-     TLS is an ABI-specific thing.  But we don't do that yet.  */
-  else
-    error (_("Cannot find thread-local variables on this target"));
-
-  return addr;
+  return target_translate_tls_address (debaton->objfile, offset);
 }
 
 /* Evaluate a location description, starting at DATA and with length
Index: gdb/eval.c
===================================================================
RCS file: /cvs/src/src/gdb/eval.c,v
retrieving revision 1.63
diff -u -p -r1.63 eval.c
--- gdb/eval.c	25 Jul 2006 04:24:50 -0000	1.63
+++ gdb/eval.c	8 Sep 2006 00:54:20 -0000
@@ -2019,6 +2019,18 @@ evaluate_subexp_standard (struct type *e
 	return value_at_lazy (exp->elts[pc + 1].type,
 			      value_as_address (arg1));
 
+    case UNOP_MEMVAL_TLS:
+      (*pos) += 3;
+      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+	goto nosideret;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+	return value_zero (exp->elts[pc + 2].type, lval_memory);
+      else
+	return value_at_lazy_tls (exp->elts[pc + 2].type,
+				  value_as_address (arg1),
+				  exp->elts[pc + 1].objfile);
+
     case UNOP_PREINCREMENT:
       arg1 = evaluate_subexp (expect_type, exp, pos, noside);
       if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
Index: gdb/exceptions.h
===================================================================
RCS file: /cvs/src/src/gdb/exceptions.h,v
retrieving revision 1.18
diff -u -p -r1.18 exceptions.h
--- gdb/exceptions.h	3 Feb 2006 21:50:25 -0000	1.18
+++ gdb/exceptions.h	8 Sep 2006 00:54:22 -0000
@@ -71,6 +71,9 @@ enum errors {
      more detail.  */
   TLS_GENERIC_ERROR,
 
+  /* Thread agent beneath is too old to support our requested xreg.  */
+  TLS_UNSUPPORTED_XREG,
+
   /* Add more errors here.  */
   NR_ERRORS
 };
Index: gdb/expprint.c
===================================================================
RCS file: /cvs/src/src/gdb/expprint.c,v
retrieving revision 1.24
diff -u -p -r1.24 expprint.c
--- gdb/expprint.c	7 Aug 2006 03:30:54 -0000	1.24
+++ gdb/expprint.c	8 Sep 2006 00:54:22 -0000
@@ -31,6 +31,7 @@
 #include "target.h"
 #include "gdb_string.h"
 #include "block.h"
+#include "objfiles.h"
 
 #ifdef HAVE_CTYPE_H
 #include <ctype.h>
@@ -414,6 +415,33 @@ print_subexp_standard (struct expression
 	fputs_filtered (")", stream);
       return;
 
+    case UNOP_MEMVAL_TLS:
+      (*pos) += 3;
+      if ((int) prec > (int) PREC_PREFIX)
+	fputs_filtered ("(", stream);
+      if (TYPE_CODE (exp->elts[pc + 2].type) == TYPE_CODE_FUNC &&
+	  exp->elts[pc + 4].opcode == OP_LONG)
+	{
+	  /* We have a minimal symbol fn, probably.  It's encoded
+	     as a UNOP_MEMVAL (function-type) of an OP_LONG (int, address).
+	     Swallow the OP_LONG (including both its opcodes); ignore
+	     its type; print the value in the type of the MEMVAL.  */
+	  (*pos) += 4;
+	  val = value_at_lazy (exp->elts[pc + 2].type,
+			       (CORE_ADDR) exp->elts[pc + 6].longconst);
+	  value_print (val, stream, 0, Val_no_prettyprint);
+	}
+      else
+	{
+	  fputs_filtered ("{", stream);
+	  type_print (exp->elts[pc + 2].type, "", stream, 0);
+	  fputs_filtered ("} ", stream);
+	  print_subexp (exp, pos, stream, PREC_PREFIX);
+	}
+      if ((int) prec > (int) PREC_PREFIX)
+	fputs_filtered (")", stream);
+      return;
+
     case BINOP_ASSIGN_MODIFY:
       opcode = exp->elts[pc + 1].opcode;
       (*pos) += 2;
@@ -694,6 +722,8 @@ op_name_standard (enum exp_opcode opcode
       return "UNOP_CAST";
     case UNOP_MEMVAL:
       return "UNOP_MEMVAL";
+    case UNOP_MEMVAL_TLS:
+      return "UNOP_MEMVAL_TLS";
     case UNOP_NEG:
       return "UNOP_NEG";
     case UNOP_LOGICAL_NOT:
@@ -999,6 +1029,16 @@ dump_subexp_body_standard (struct expres
       fprintf_filtered (stream, ")");
       elt = dump_subexp (exp, stream, elt + 2);
       break;
+    case UNOP_MEMVAL_TLS:
+      fprintf_filtered (stream, "TLS type @");
+      gdb_print_host_address (exp->elts[elt + 1].type, stream);
+      fprintf_filtered (stream, " (__thread /* \"%s\" */ ",
+                        (exp->elts[elt].objfile == NULL ? "(null)"
+			 : exp->elts[elt].objfile->name));
+      type_print (exp->elts[elt + 1].type, NULL, stream, 0);
+      fprintf_filtered (stream, ")");
+      elt = dump_subexp (exp, stream, elt + 3);
+      break;
     case OP_TYPE:
       fprintf_filtered (stream, "Type @");
       gdb_print_host_address (exp->elts[elt].type, stream);
Index: gdb/expression.h
===================================================================
RCS file: /cvs/src/src/gdb/expression.h,v
retrieving revision 1.18
diff -u -p -r1.18 expression.h
--- gdb/expression.h	17 Dec 2005 22:33:59 -0000	1.18
+++ gdb/expression.h	8 Sep 2006 00:54:22 -0000
@@ -234,6 +234,13 @@ enum exp_opcode
        following subexpression.  */
     UNOP_MEMVAL,
 
+    /* UNOP_MEMVAL_TLS is followed by a `struct objfile' pointer in the next
+       exp_element and a type pointer in the following exp_element.
+       With another UNOP_MEMVAL_TLS at the end, this makes four exp_elements.
+       It casts the contents of the word offsetted by the value of the
+       following subexpression from the TLS specified by `struct objfile'.  */
+    UNOP_MEMVAL_TLS,
+
     /* UNOP_... operate on one value from a following subexpression
        and replace it with a result.  They take no immediate arguments.  */
 
@@ -360,6 +367,7 @@ union exp_element
     struct type *type;
     struct internalvar *internalvar;
     struct block *block;
+    struct objfile *objfile;
   };
 
 struct expression
Index: gdb/gdb_thread_db.h
===================================================================
RCS file: /cvs/src/src/gdb/gdb_thread_db.h,v
retrieving revision 1.7
diff -u -p -r1.7 gdb_thread_db.h
--- gdb/gdb_thread_db.h	17 Dec 2005 22:33:59 -0000	1.7
+++ gdb/gdb_thread_db.h	8 Sep 2006 00:54:22 -0000
@@ -64,7 +64,11 @@ typedef enum
   TD_MALLOC,	  /* Out of memory.  */
   TD_PARTIALREG,  /* Not entire register set was read or written.  */
   TD_NOXREGS,	  /* X register set not available for given thread.  */
-  TD_NOTALLOC	  /* TLS memory not yet allocated.  */
+  TD_TLSDEFER,	  /* Thread has not yet allocated TLS for given module.  */
+  TD_NOTALLOC = TD_TLSDEFER,
+  TD_VERSION,	  /* Version if libpthread and libthread_db do not match.  */
+  TD_NOTLS,	  /* There is no TLS segment in the given module.  */
+  TD_MINIMALONLY  /* Single-threaded mode, only some features available.  */
 } td_err_e;
 
 
@@ -303,6 +307,13 @@ typedef struct td_thrinfo
 } td_thrinfo_t;
 
 
+/* Information exchanged by td_thr_getxregs().  */
+typedef struct prxregset
+{ 
+  psaddr_t pointer_guard;       /* Access tcbhead_t.pointer_guard.  */
+} prxregset_t;
+  
+
 
 /* Prototypes for exported library functions.  */
 
@@ -398,7 +409,8 @@ extern td_err_e td_thr_getgregs (const t
 				 prgregset_t __gregs);
 
 /* Retrieve extended register contents of process running thread TH.  */
-extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs);
+extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th,
+				 prxregset_t *__xregs);
 
 /* Get size of extended register set of process running thread TH.  */
 extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep);
@@ -413,7 +425,7 @@ extern td_err_e td_thr_setgregs (const t
 
 /* Set extended register contents of process running thread TH.  */
 extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th,
-				 const void *__addr);
+				 prxregset_t *__xregs);
 
 
 /* Enable reporting for EVENT for thread TH.  */
Index: gdb/gdbthread.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbthread.h,v
retrieving revision 1.13
diff -u -p -r1.13 gdbthread.h
--- gdb/gdbthread.h	17 Dec 2005 22:34:00 -0000	1.13
+++ gdb/gdbthread.h	8 Sep 2006 00:54:22 -0000
@@ -69,6 +69,11 @@ struct thread_info
   struct private_thread_info *private;
 };
 
+enum thread_xreg
+{
+  THREAD_XREG_GUARD_POINTER,
+};
+
 /* Create an empty thread list, or empty the existing one.  */
 extern void init_thread_list (void);
 
@@ -138,6 +143,11 @@ extern void load_infrun_state (ptid_t pt
 			       int       *current_line,
 			       struct symtab **current_symtab);
 
+/* Fetch `CORE_ADDR' type from the thread base of `ptid'
+   at base offset `field_offset'.  */
+extern CORE_ADDR thread_get_field_at_offset (ptid_t ptid,
+					     ptrdiff_t field_offset);
+
 /* Commands with a prefix of `thread'.  */
 extern struct cmd_list_element *thread_cmd_list;
 
Index: gdb/i386-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-linux-nat.c,v
retrieving revision 1.70
diff -u -p -r1.70 i386-linux-nat.c
--- gdb/i386-linux-nat.c	8 Aug 2006 21:32:37 -0000	1.70
+++ gdb/i386-linux-nat.c	8 Sep 2006 00:54:22 -0000
@@ -728,6 +728,23 @@ ps_get_thread_area (const struct ps_proc
 }
 
 
+/* Query the base address of the current module of the specified thread.
+   Calls `ps_get_thread_area' but without specifying current `idx'.  */
+static ps_err_e
+i386_linux_ps_get_thread_area_current (lwpid_t lwpid, void **base)
+{
+  int idx;
+
+  /* FIXME: For read_register ().  */
+#warning "FIXME"
+  gdb_assert (lwpid == ptid_get_pid (inferior_ptid));
+  idx = read_register (I386_GS_REGNUM) >> 3;
+
+  /* We have no `const struct ps_prochandle *' available here
+     but fortunately our implementations do not use it.  */
+  return ps_get_thread_area (NULL, lwpid, idx, base);
+}
+
 /* The instruction for a GNU/Linux system call is:
        int $0x80
    or 0xcd 0x80.  */
@@ -843,6 +860,9 @@ _initialize_i386_linux_nat (void)
   t->to_fetch_registers = i386_linux_fetch_inferior_registers;
   t->to_store_registers = i386_linux_store_inferior_registers;
 
+  /* Query the base address of the current module of the specified thread.  */
+  t->to_ps_get_thread_area_current = i386_linux_ps_get_thread_area_current;
+
   /* Register the target.  */
   linux_nat_add_target (t);
 }
Index: gdb/inf-child.c
===================================================================
RCS file: /cvs/src/src/gdb/inf-child.c,v
retrieving revision 1.8
diff -u -p -r1.8 inf-child.c
--- gdb/inf-child.c	17 Dec 2005 22:34:01 -0000	1.8
+++ gdb/inf-child.c	8 Sep 2006 00:54:22 -0000
@@ -28,6 +28,8 @@
 #include "target.h"
 #include "inferior.h"
 #include "gdb_string.h"
+#include "exceptions.h"
+#include "gdbthread.h"
 
 /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
    for all registers.  */
@@ -178,6 +180,75 @@ inf_child_pid_to_exec_file (int pid)
   return NULL;
 }
 
+/* Get the address of the thread xreg - extended register.
+   Currently only thread variable `tcbhead_t.pointer_guard' is supported.  */
+static CORE_ADDR
+inf_child_get_thread_xreg (ptid_t ptid, enum thread_xreg which)
+{
+  CORE_ADDR retval;
+  ptrdiff_t field_offset, field_offset_default;
+  volatile struct gdb_exception field_e;
+  const char *symbol_struct, *symbol_field;
+
+  field_e.reason = 0;
+
+  switch (which)
+    {
+    case THREAD_XREG_GUARD_POINTER:
+      /* Method #2: %gs direct read using symbols resolution from inferior.
+	 It needs glibc debuginfo / symbols, internal or external.  */
+      symbol_struct = "tcbhead_t";
+      symbol_field = "pointer_guard";
+      /* Method #3: %gs direct read using hardcoded binary offset.
+	 == offsetof (tcbhead_t, pointer_guard)  */
+      field_offset_default = 0x18;
+      break;
+
+    default:;
+      /* FALLTHRU */
+    }
+
+  if (symbol_struct != NULL && symbol_field != NULL)
+    {
+      TRY_CATCH (field_e, RETURN_MASK_ERROR)
+	{
+	  /* Method #2: Symbols resolution from inferior.  */
+	  field_offset = symtab_offsetof (symbol_struct, symbol_field);
+	}
+      if (field_e.reason < 0)
+	{
+	  /* Method #3: Hardcoded binary offset.  */
+	  field_offset = field_offset_default;
+	}
+
+      TRY_CATCH (field_e, RETURN_MASK_ERROR)
+	{
+	  /* Method #2/#3:  %gs direct read.  */
+	  retval = thread_get_field_at_offset (ptid, field_offset);
+	}
+      if (field_e.reason >= 0)
+	return retval;
+
+      switch (which)
+	{
+	case THREAD_XREG_GUARD_POINTER:
+	  /* We assume that we run on older glibc without any 'pointer_guard'.
+	     It is not correct, there we some glibcs between just missing
+	     the nptl_db support, `longjmp' `next' stepping will fail there.  */
+	  return 0;
+	  break;
+
+	default:;
+	  /* FALLTHRU */
+	}
+    }
+
+  if (field_e.reason < 0)
+    throw_exception (field_e);
+
+  throw_error (GENERIC_ERROR, _("TLS not supported on this target"));
+}
+
 struct target_ops *
 inf_child_target (void)
 {
@@ -213,6 +284,7 @@ inf_child_target (void)
   t->to_enable_exception_callback = inf_child_enable_exception_callback;
   t->to_get_current_exception_event = inf_child_get_current_exception_event;
   t->to_pid_to_exec_file = inf_child_pid_to_exec_file;
+  t->to_get_thread_xreg = inf_child_get_thread_xreg;
   t->to_stratum = process_stratum;
   t->to_has_all_memory = 1;
   t->to_has_memory = 1;
Index: gdb/infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.214
diff -u -p -r1.214 infrun.c
--- gdb/infrun.c	19 Aug 2006 03:19:00 -0000	1.214
+++ gdb/infrun.c	8 Sep 2006 00:54:25 -0000
@@ -2031,6 +2031,14 @@ process_event_stop_test:
 	    keep_going (ecs);
 	    return;
 	  }
+	if (target_get_thread_xreg_p ())
+	  {
+	    CORE_ADDR pointer_guard;
+
+	    pointer_guard = target_get_thread_xreg (inferior_ptid,
+	                                            THREAD_XREG_GUARD_POINTER);
+	    jmp_buf_pc ^= pointer_guard;
+	  }
 
 	/* Need to blow away step-resume breakpoint, as it
 	   interferes with us */
Index: gdb/linux-thread-db.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-thread-db.c,v
retrieving revision 1.19
diff -u -p -r1.19 linux-thread-db.c
--- gdb/linux-thread-db.c	2 Aug 2006 10:24:00 -0000	1.19
+++ gdb/linux-thread-db.c	8 Sep 2006 00:54:26 -0000
@@ -57,6 +57,9 @@
 
 /* This module's target vector.  */
 static struct target_ops thread_db_ops;
+#ifdef THREAD_DB_HAS_TD_MINIMALONLY
+static struct target_ops minimal_thread_db_ops;
+#endif
 
 /* The target vector that we call for things this module can't handle.  */
 static struct target_ops *target_beneath;
@@ -64,8 +67,10 @@ static struct target_ops *target_beneath
 /* Pointer to the next function on the objfile event chain.  */
 static void (*target_new_objfile_chain) (struct objfile * objfile);
 
-/* Non-zero if we're using this module's target vector.  */
-static int using_thread_db;
+/* Non-zero if we're using this module's target vector.
+   == &minimal_thread_db_ops if only in single-threaded mode as provided
+   by glibc `__pthread_initialize_minimal'.  */
+static struct target_ops *using_thread_db;
 
 /* Non-zero if we have determined the signals used by the threads
    library.  */
@@ -86,6 +91,7 @@ static td_err_e (*td_init_p) (void);
 
 static td_err_e (*td_ta_new_p) (struct ps_prochandle * ps,
 				td_thragent_t **ta);
+static td_err_e (*td_ta_delete_p) (td_thragent_t *ta);
 static td_err_e (*td_ta_map_id2thr_p) (const td_thragent_t *ta, thread_t pt,
 				       td_thrhandle_t *__th);
 static td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta,
@@ -112,6 +118,13 @@ static td_err_e (*td_thr_tls_get_addr_p)
 					  void *map_address,
 					  size_t offset, void **address);
 
+#ifdef THREAD_DB_HAS_PRXREGSET_T
+static td_err_e (*td_thr_getxregs_p) (const td_thrhandle_t *__th,
+				      prxregset_t *__xregs);
+static td_err_e (*td_thr_getxregsize_p) (const td_thrhandle_t *__th,
+					 int *__sizep);
+#endif
+
 /* Location of the thread creation event breakpoint.  The code at this
    location in the child process will be called by the pthread library
    whenever a new thread is created.  By setting a special breakpoint
@@ -387,6 +400,10 @@ thread_db_load (void)
   if (td_ta_new_p == NULL)
     return 0;
 
+  td_ta_delete_p = verbose_dlsym (handle, "td_ta_delete");
+  if (td_ta_delete_p == NULL)
+    return 0;
+
   td_ta_map_id2thr_p = verbose_dlsym (handle, "td_ta_map_id2thr");
   if (td_ta_map_id2thr_p == NULL)
     return 0;
@@ -421,6 +438,10 @@ thread_db_load (void)
   td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg");
   td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable");
   td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr");
+#ifdef THREAD_DB_HAS_PRXREGSET_T
+  td_thr_getxregs_p = dlsym (handle, "td_thr_getxregs");
+  td_thr_getxregsize_p = dlsym (handle, "td_thr_getxregsize");
+#endif
 
   return 1;
 }
@@ -589,7 +610,9 @@ check_for_thread_db (void)
       already_loaded = 1;
     }
 
-  if (using_thread_db)
+  /* If we would be using onl-y the &minimal_thread_db_ops, still try
+     to extend it.  */
+  if (using_thread_db == &thread_db_ops)
     /* Nothing to do.  The thread library was already detected and the
        target vector was already activated.  */
     return;
@@ -599,11 +622,46 @@ check_for_thread_db (void)
   if (!target_has_execution)
     return;
 
+  /* `LIBTHREAD_DB_SO' is not yet (or unsuccessfully) loaded.  */
+  if (td_ta_new_p == NULL || td_ta_delete_p == NULL)
+    return;
+
   /* Initialize the structure that identifies the child process.  */
   proc_handle.pid = GET_PID (inferior_ptid);
 
-  /* Now attempt to open a connection to the thread library.  */
-  err = td_ta_new_p (&proc_handle, &thread_agent);
+#ifdef THREAD_DB_HAS_TD_MINIMALONLY
+  if (using_thread_db == &minimal_thread_db_ops)
+    {
+      /* We already have the minimal connection type here.
+         Check if we cannot upgrade it.  */
+      td_thragent_t *thread_agent_new;
+
+      /* Now just check opening a connection to the thread library.  */
+      err = td_ta_new_p (&proc_handle, &thread_agent_new);
+      switch (err)
+	{
+	case TD_OK:
+	  break;
+
+	case TD_MINIMALONLY:
+	  td_ta_delete_p (thread_agent_new);
+	  return;
+
+	default:
+	  return;
+	}
+
+      /* Errors ignored.  */
+      td_ta_delete_p (thread_agent);
+      thread_agent = thread_agent_new;
+    }
+  else
+    {
+      /* Now attempt to open a connection to the thread library.  */
+      err = td_ta_new_p (&proc_handle, &thread_agent);
+    }
+#endif
+
   switch (err)
     {
     case TD_NOLIBTHREAD:
@@ -613,14 +671,35 @@ check_for_thread_db (void)
     case TD_OK:
       printf_unfiltered (_("[Thread debugging using libthread_db enabled]\n"));
 
+      /* We were already using &minimal_thread_db_ops.  */
+      if (using_thread_db != NULL)
+        {
+	  remove_thread_event_breakpoints ();
+	  unpush_target (using_thread_db);
+        }
+
       /* The thread library was detected.  Activate the thread_db target.  */
-      push_target (&thread_db_ops);
-      using_thread_db = 1;
+      using_thread_db = &thread_db_ops;
+      push_target (using_thread_db);
 
       enable_thread_event_reporting ();
       thread_db_find_new_threads ();
       break;
 
+#ifdef THREAD_DB_HAS_TD_MINIMALONLY
+    case TD_MINIMALONLY:
+      if (using_thread_db == &minimal_thread_db_ops)
+        break;
+
+      /* Only __pthread_initialize_minimal() minimal thread library found.  */
+      printf_unfiltered (_("[Single-thread debugging using libthread_db enabled]\n"));
+
+      /* Only minimal thread library was detected.  Activate the thread_db target.  */
+      using_thread_db = &minimal_thread_db_ops;
+      push_target (using_thread_db);
+      break;
+#endif /* THREAD_DB_HAS_TD_MINIMALONLY */
+
     default:
       warning (_("Cannot initialize thread debugging library: %s"),
 	       thread_db_err_str (err));
@@ -884,6 +963,15 @@ thread_db_wait (ptid_t ptid, struct targ
       return pid_to_ptid (GET_PID (ptid));
     }
 
+  if (ourstatus->kind == TARGET_WAITKIND_EXECD)
+    {
+      remove_thread_event_breakpoints ();
+      unpush_target (using_thread_db);
+      using_thread_db = 0;
+
+      return pid_to_ptid (GET_PID (ptid));
+    }
+
   if (ourstatus->kind == TARGET_WAITKIND_STOPPED
       && ourstatus->value.sig == TARGET_SIGNAL_TRAP)
     /* Check for a thread event.  */
@@ -904,6 +992,29 @@ thread_db_wait (ptid_t ptid, struct targ
   return ptid;
 }
 
+#ifdef THREAD_DB_HAS_TD_MINIMALONLY
+static ptid_t
+minimal_thread_db_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+  extern ptid_t trap_ptid;
+
+  ptid = target_beneath->to_wait (ptid, ourstatus);
+
+  if (ourstatus->kind == TARGET_WAITKIND_EXITED
+      || ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
+    return pid_to_ptid (-1);
+
+  if (ourstatus->kind == TARGET_WAITKIND_EXECD)
+    {
+      remove_thread_event_breakpoints ();
+      unpush_target (using_thread_db);
+      using_thread_db = 0;
+    }
+
+  return ptid;
+}
+#endif /* THREAD_DB_HAS_TD_MINIMALONLY */
+
 static LONGEST
 thread_db_xfer_partial (struct target_ops *ops, enum target_object object,
 			const char *annex, gdb_byte *readbuf,
@@ -942,7 +1053,7 @@ static void
 thread_db_create_inferior (char *exec_file, char *allargs, char **env,
 			   int from_tty)
 {
-  unpush_target (&thread_db_ops);
+  unpush_target (using_thread_db);
   using_thread_db = 0;
   target_beneath->to_create_inferior (exec_file, allargs, env, from_tty);
 }
@@ -976,7 +1087,7 @@ thread_db_mourn_inferior (void)
   remove_thread_event_breakpoints ();
 
   /* Detach thread_db target ops.  */
-  unpush_target (&thread_db_ops);
+  unpush_target (using_thread_db);
   using_thread_db = 0;
 }
 
@@ -1053,6 +1164,39 @@ thread_db_extra_thread_info (struct thre
   return NULL;
 }
 
+/* Map the given `ptid' even for &minimal_thread_db_ops inferiors.
+   WARNING: Returned pointer is a static variable!  */
+
+static td_thrhandle_t *
+thread_db_ptid2thr_static (ptid_t ptid)
+{
+  static td_thrhandle_t th;
+  struct thread_info *thread_info;
+  void *tls_base;
+  ps_err_e ps_err;
+
+  /* Get info about the thread.  */
+  thread_info = find_thread_pid (ptid);
+  if (thread_info != NULL)
+    {
+      /* Threaded program.  */
+      thread_db_map_id2thr (thread_info, 1);
+      return &thread_info->private->th;
+    }
+
+  /* We must fake `td_thrhandle_t' here for the case of `minimal_thread_db_ops'
+     inferior accessed by `thread_db_get_thread_local_address'
+     as `find_thread_pid' will not find such minimal thread.  */
+  ps_err = target_ps_get_thread_area_current (ptid_get_pid (ptid), &tls_base);
+  if (ps_err != PS_OK)
+    error (_("Cannot find thread %ld: %d"),
+	   (long) ptid_get_pid (ptid), (int) ps_err);
+
+  th.th_ta_p = thread_agent;
+  th.th_unique = tls_base;
+  return &th;
+}
+
 /* Get the address of the thread local variable in load module LM which
    is stored at OFFSET within the thread local storage for thread PTID.  */
 
@@ -1061,59 +1205,161 @@ thread_db_get_thread_local_address (ptid
 				    CORE_ADDR lm,
 				    CORE_ADDR offset)
 {
-  if (is_thread (ptid))
-    {
-      td_err_e err;
-      void *address;
-      struct thread_info *thread_info;
+  td_err_e err;
+  void *address;
+  td_thrhandle_t *thp;
 
-      /* glibc doesn't provide the needed interface.  */
-      if (!td_thr_tls_get_addr_p)
-	throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR,
-		     _("No TLS library support"));
+  /* glibc doesn't provide the needed interface.  */
+  if (!td_thr_tls_get_addr_p)
+    throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR,
+		 _("No TLS library support"));
 
-      /* Caller should have verified that lm != 0.  */
-      gdb_assert (lm != 0);
+  /* Caller should have verified that lm != 0.  */
+  gdb_assert (lm != 0);
 
-      /* Get info about the thread.  */
-      thread_info = find_thread_pid (ptid);
-      thread_db_map_id2thr (thread_info, 1);
+  /* Get info about the thread.  */
+  thp = thread_db_ptid2thr_static (ptid);
 
-      /* Finally, get the address of the variable.  */
-      err = td_thr_tls_get_addr_p (&thread_info->private->th,
-				   (void *)(size_t) lm,
-				   offset, &address);
+  /* Finally, get the address of the variable.  */
+  err = td_thr_tls_get_addr_p (thp, (void *) lm,
+			       offset, &address);
+
+  /* TODO: Handle manual TLS resolving  */
 
 #ifdef THREAD_DB_HAS_TD_NOTALLOC
-      /* The memory hasn't been allocated, yet.  */
-      if (err == TD_NOTALLOC)
-	  /* Now, if libthread_db provided the initialization image's
-	     address, we *could* try to build a non-lvalue value from
-	     the initialization image.  */
-        throw_error (TLS_NOT_ALLOCATED_YET_ERROR,
-                     _("TLS not allocated yet"));
+  /* The memory hasn't been allocated, yet.  */
+  if (err == TD_NOTALLOC)
+      /* Now, if libthread_db provided the initialization image's
+	 address, we *could* try to build a non-lvalue value from
+	 the initialization image.  */
+    throw_error (TLS_NOT_ALLOCATED_YET_ERROR,
+		 _("TLS not allocated yet"));
 #endif
 
-      /* Something else went wrong.  */
-      if (err != TD_OK)
-        throw_error (TLS_GENERIC_ERROR,
-                     (("%s")), thread_db_err_str (err));
+  /* Something else went wrong.  */
+  if (err != TD_OK)
+    throw_error (TLS_GENERIC_ERROR,
+		 (("%s")), thread_db_err_str (err));
 
-      /* Cast assuming host == target.  Joy.  */
-      /* Do proper sign extension for the target.  */
-      gdb_assert (exec_bfd);
-      return (bfd_get_sign_extend_vma (exec_bfd) > 0
-	      ? (CORE_ADDR) (intptr_t) address
-	      : (CORE_ADDR) (uintptr_t) address);
-    }
+  /* Cast assuming host == target.  Joy.  */
+  /* Do proper sign extension for the target.  */
+  gdb_assert (exec_bfd);
+  return (bfd_get_sign_extend_vma (exec_bfd) > 0
+	  ? (CORE_ADDR) (intptr_t) address
+	  : (CORE_ADDR) (uintptr_t) address);
 
+#warning "FIXME"
+  /* NOTREACHED */
   if (target_beneath->to_get_thread_local_address)
     return target_beneath->to_get_thread_local_address (ptid, lm, offset);
-  else
+  /* throw_error (TLS_GENERIC_ERROR, _("TLS not supported on this target")); */
+}
+
+#ifdef THREAD_DB_HAS_PRXREGSET_T
+static CORE_ADDR
+thread_db_thr_get_xregoffset (ptid_t ptid, ptrdiff_t xreg_offset)
+{
+  CORE_ADDR retval;
+  td_err_e err;
+  prxregset_t *xregs;
+  int xregsize;
+  td_thrhandle_t *thp;
+
+  /* glibc doesn't provide the needed interface.  */
+  if (!td_thr_getxregs_p || !td_thr_getxregsize_p)
+    throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR,
+		 _("No TLS library support"));
+
+  thp = thread_db_ptid2thr_static (ptid);
+
+  err = td_thr_getxregsize_p (thp, &xregsize);
+  if (err != TD_OK)
     throw_error (TLS_GENERIC_ERROR,
-	         _("TLS not supported on this target"));
+		 (("%s")), thread_db_err_str (err));
+
+  if (xregsize < xreg_offset + sizeof (retval))
+    throw_error (TLS_UNSUPPORTED_XREG,
+		 _("Thread library is not supporting xreg at offset %d."),
+		 (int) xreg_offset);
+
+  xregs = xmalloc (xregsize);
+
+  err = td_thr_getxregs_p (thp, xregs);
+  if (err != TD_OK)
+    {
+      free (xregs);
+      throw_error (TLS_GENERIC_ERROR,
+		   (("%s")), thread_db_err_str (err));
+    }
+  retval = (CORE_ADDR) *(psaddr_t *) (((char *) xregs) + xreg_offset);
+
+  free (xregs);
+
+  return retval;
 }
 
+/* Get the address of the thread xreg - extended register.
+   Currently only thread variable `tcbhead_t.pointer_guard' is supported.  */
+
+static CORE_ADDR
+thread_db_get_thread_xreg (ptid_t ptid, enum thread_xreg which)
+{
+  CORE_ADDR retval;
+  ptrdiff_t xreg_offset = -1;
+  volatile struct gdb_exception xreg_e;
+
+  switch (which)
+    {
+    case THREAD_XREG_GUARD_POINTER:
+      /* Method #1: libthread_db query.
+	 It needs glibc support for `thread_db_thr_get_xregoffset'.  */
+      xreg_offset = offsetof(prxregset_t, pointer_guard);
+      break;
+
+    default:;
+      /* PASSTHRU */
+    }
+
+  if (xreg_offset != -1)
+    {
+      TRY_CATCH (xreg_e, RETURN_MASK_ERROR)
+	{
+	  /* Method #1: libthread_db query.  */
+	  retval = thread_db_thr_get_xregoffset (ptid, xreg_offset);
+	}
+      if (xreg_e.reason >= 0)
+	return retval;
+    }
+
+  TRY_CATCH (xreg_e, RETURN_MASK_ERROR)
+    {
+      if (target_beneath->to_get_thread_xreg)
+	retval = target_beneath->to_get_thread_xreg (ptid, which);
+      else
+	throw_error (TLS_GENERIC_ERROR, _("TLS not supported on this target"));
+
+    }
+  if (xreg_e.reason >= 0)
+    return retval;
+
+  switch (which)
+    {
+    case THREAD_XREG_GUARD_POINTER:
+      /* We assume that we run on older glibc without any 'pointer_guard'.
+	 It is not correct, there we some glibcs between just missing
+	 the nptl_db support, `longjmp' `next' stepping will fail there.  */
+      return 0;
+
+    default:;
+      /* FALLTHRU */
+    }
+
+  throw_exception (xreg_e);
+  /* NOTREACHED */
+  /* throw_error (TLS_GENERIC_ERROR, _("TLS not supported on this target")); */
+}
+#endif /* THREAD_DB_HAS_PRXREGSET_T */
+
 static void
 init_thread_db_ops (void)
 {
@@ -1135,10 +1381,35 @@ init_thread_db_ops (void)
   thread_db_ops.to_has_thread_control = tc_schedlock;
   thread_db_ops.to_get_thread_local_address
     = thread_db_get_thread_local_address;
+#ifdef THREAD_DB_HAS_PRXREGSET_T
+  thread_db_ops.to_get_thread_xreg = thread_db_get_thread_xreg;
+#endif /* THREAD_DB_HAS_PRXREGSET_T */
   thread_db_ops.to_extra_thread_info = thread_db_extra_thread_info;
   thread_db_ops.to_magic = OPS_MAGIC;
 }
 
+#ifdef THREAD_DB_HAS_TD_MINIMALONLY
+static void
+init_minimal_thread_db_ops (void)
+{
+  minimal_thread_db_ops.to_shortname = "single-thread";
+  minimal_thread_db_ops.to_longname = "single-threaded (minimal threaded) child process.";
+  minimal_thread_db_ops.to_doc = "libpthread TLS support without threading.";
+  minimal_thread_db_ops.to_wait = minimal_thread_db_wait;
+  minimal_thread_db_ops.to_xfer_partial = thread_db_xfer_partial;
+  minimal_thread_db_ops.to_create_inferior = thread_db_create_inferior;
+  minimal_thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior;
+  minimal_thread_db_ops.to_stratum = thread_stratum;
+  minimal_thread_db_ops.to_has_thread_control = tc_schedlock;
+  minimal_thread_db_ops.to_get_thread_local_address
+    = thread_db_get_thread_local_address;
+#ifdef THREAD_DB_HAS_PRXREGSET_T
+  minimal_thread_db_ops.to_get_thread_xreg = thread_db_get_thread_xreg;
+#endif /* THREAD_DB_HAS_PRXREGSET_T */
+  minimal_thread_db_ops.to_magic = OPS_MAGIC;
+}
+#endif /* THREAD_DB_HAS_TD_MINIMALONLY */
+
 void
 _initialize_thread_db (void)
 {
@@ -1147,6 +1418,10 @@ _initialize_thread_db (void)
     {
       init_thread_db_ops ();
       add_target (&thread_db_ops);
+#ifdef THREAD_DB_HAS_TD_MINIMALONLY
+      init_minimal_thread_db_ops ();
+      add_target (&minimal_thread_db_ops);
+#endif
 
       /* Add ourselves to objfile event chain.  */
       target_new_objfile_chain = deprecated_target_new_objfile_hook;
Index: gdb/parse.c
===================================================================
RCS file: /cvs/src/src/gdb/parse.c,v
retrieving revision 1.53
diff -u -p -r1.53 parse.c
--- gdb/parse.c	6 Jul 2006 14:00:48 -0000	1.53
+++ gdb/parse.c	8 Sep 2006 00:54:29 -0000
@@ -53,6 +53,7 @@
 #include "gdb_assert.h"
 #include "block.h"
 #include "source.h"
+#include "objfiles.h"
 
 /* Standard set of definitions for printing, dumping, prefixifying,
  * and evaluating expressions.  */
@@ -219,6 +220,15 @@ write_exp_elt_block (struct block *b)
 }
 
 void
+write_exp_elt_objfile (struct objfile *objfile)
+{
+  union exp_element tmp;
+  memset (&tmp, 0, sizeof (union exp_element));
+  tmp.objfile = objfile;
+  write_exp_elt (tmp);
+}
+
+void
 write_exp_elt_longcst (LONGEST expelt)
 {
   union exp_element tmp;
@@ -378,6 +388,9 @@ write_exp_bitstring (struct stoken str)
 static struct type *msym_text_symbol_type;
 static struct type *msym_data_symbol_type;
 static struct type *msym_unknown_symbol_type;
+static struct type *msym_text_tls_symbol_type;
+static struct type *msym_data_tls_symbol_type;
+static struct type *msym_unknown_tls_symbol_type;
 
 void
 write_exp_msymbol (struct minimal_symbol *msymbol, 
@@ -385,6 +398,8 @@ write_exp_msymbol (struct minimal_symbol
 		   struct type *data_symbol_type)
 {
   CORE_ADDR addr;
+  int tls = SYMBOL_BFD_SECTION (msymbol)->flags & SEC_THREAD_LOCAL;
+  enum exp_opcode opcode = tls ? UNOP_MEMVAL_TLS : UNOP_MEMVAL;
 
   write_exp_elt_opcode (OP_LONG);
   /* Let's make the type big enough to hold a 64-bit address.  */
@@ -397,27 +412,49 @@ write_exp_msymbol (struct minimal_symbol
 
   write_exp_elt_opcode (OP_LONG);
 
-  write_exp_elt_opcode (UNOP_MEMVAL);
+  write_exp_elt_opcode (opcode);
+
+  if (opcode == UNOP_MEMVAL_TLS)
+    {
+      bfd *bfd = SYMBOL_BFD_SECTION (msymbol)->owner;
+      struct objfile *ofp;
+
+      ALL_OBJFILES (ofp)
+	if (ofp->obfd == bfd)
+	  break;
+      write_exp_elt_objfile (ofp);
+    }
+
   switch (msymbol->type)
     {
     case mst_text:
     case mst_file_text:
     case mst_solib_trampoline:
-      write_exp_elt_type (msym_text_symbol_type);
+      if (tls)
+	write_exp_elt_type (msym_text_tls_symbol_type);
+      else
+	write_exp_elt_type (msym_text_symbol_type);
       break;
 
     case mst_data:
     case mst_file_data:
     case mst_bss:
     case mst_file_bss:
-      write_exp_elt_type (msym_data_symbol_type);
+      if (tls)
+	write_exp_elt_type (msym_data_tls_symbol_type);
+      else
+	write_exp_elt_type (msym_data_symbol_type);
       break;
 
     default:
-      write_exp_elt_type (msym_unknown_symbol_type);
+      if (tls)
+	write_exp_elt_type (msym_unknown_tls_symbol_type);
+      else
+	write_exp_elt_type (msym_unknown_symbol_type);
       break;
     }
-  write_exp_elt_opcode (UNOP_MEMVAL);
+
+  write_exp_elt_opcode (opcode);
 }
 
 /* Recognize tokens that start with '$'.  These include:
@@ -904,6 +941,11 @@ operator_length_standard (struct express
       args = 1;
       break;
 
+    case UNOP_MEMVAL_TLS:
+      oplen = 4;
+      args = 1;
+      break;
+
     case UNOP_ABS:
     case UNOP_CAP:
     case UNOP_CHR:
@@ -1341,6 +1383,17 @@ build_parse (void)
     init_type (TYPE_CODE_INT, 1, 0,
 	       "<variable (not text or data), no debug info>",
 	       NULL);
+
+  msym_text_tls_symbol_type =
+    init_type (TYPE_CODE_FUNC, 1, 0, "<TLS-based text variable, no debug info>", NULL);
+  TYPE_TARGET_TYPE (msym_text_tls_symbol_type) = builtin_type_int;
+  msym_data_tls_symbol_type =
+    init_type (TYPE_CODE_INT, TARGET_INT_BIT / HOST_CHAR_BIT, 0,
+	       "<TLS-based data variable, no debug info>", NULL);
+  msym_unknown_tls_symbol_type =
+    init_type (TYPE_CODE_INT, 1, 0,
+	       "<TLS-based variable (not text or data), no debug info>",
+	       NULL);
 }
 
 /* This function avoids direct calls to fprintf 
Index: gdb/parser-defs.h
===================================================================
RCS file: /cvs/src/src/gdb/parser-defs.h,v
retrieving revision 1.20
diff -u -p -r1.20 parser-defs.h
--- gdb/parser-defs.h	17 Dec 2005 22:34:01 -0000	1.20
+++ gdb/parser-defs.h	8 Sep 2006 00:54:29 -0000
@@ -131,6 +131,8 @@ extern void write_exp_bitstring (struct 
 
 extern void write_exp_elt_block (struct block *);
 
+extern void write_exp_elt_objfile (struct objfile *objfile);
+
 extern void write_exp_msymbol (struct minimal_symbol *,
 			       struct type *, struct type *);
 
Index: gdb/symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.147
diff -u -p -r1.147 symtab.c
--- gdb/symtab.c	11 May 2006 09:29:52 -0000	1.147
+++ gdb/symtab.c	8 Sep 2006 00:54:31 -0000
@@ -42,6 +42,7 @@
 #include "filenames.h"		/* for FILENAME_CMP */
 #include "objc-lang.h"
 #include "ada-lang.h"
+#include "exceptions.h"
 
 #include "hashtab.h"
 
@@ -1828,6 +1829,50 @@ lookup_block_symbol (const struct block 
     }
 }
 
+/* Get offsetof (struct `symbol_struct', `symbol_field').  */
+ptrdiff_t
+symtab_offsetof (const char *symbol_struct, const char *symbol_field)
+{
+  struct symbol *sym;
+  struct type *type;
+  int i;
+  int bitpos;
+
+  sym = lookup_symbol (symbol_struct, NULL, VAR_DOMAIN, NULL, NULL);
+  if (sym == NULL)
+    throw_error (GENERIC_ERROR,
+		 _("Structure `%s' not found, needed for field `%s'"),
+		 symbol_struct, symbol_field);
+
+  type = sym->type;
+  CHECK_TYPEDEF (type);
+
+  /* Make sure this isn't C++.  */
+  if (TYPE_N_BASECLASSES (type) != 0)
+    throw_error (GENERIC_ERROR,
+		 _("Structure `%s' field `%s' invalid"),
+		 symbol_struct, symbol_field);
+
+  for (i = 0; i < TYPE_NFIELDS (type); i++)
+    {
+      char *this_name = TYPE_FIELD_NAME (type, i);
+
+      if (this_name && strcmp (symbol_field, this_name) == 0)
+        break;
+    }
+  if (i >= TYPE_NFIELDS (type))
+    throw_error (GENERIC_ERROR,
+		 _("Structure `%s' field `%s' not found"),
+		 symbol_struct, symbol_field);
+
+  bitpos = TYPE_FIELD_BITPOS (type, i);
+  if (bitpos % 8)
+    throw_error (GENERIC_ERROR,
+		 _("Structure `%s' field `%s' invalid bitpos %d %% 8 != 0"),
+		 symbol_struct, symbol_field, bitpos);
+  return bitpos / 8;
+}
+
 /* Find the symtab associated with PC and SECTION.  Look through the
    psymtabs and read in another symtab if necessary. */
 
Index: gdb/symtab.h
===================================================================
RCS file: /cvs/src/src/gdb/symtab.h,v
retrieving revision 1.97
diff -u -p -r1.97 symtab.h
--- gdb/symtab.h	18 Mar 2006 18:40:04 -0000	1.97
+++ gdb/symtab.h	8 Sep 2006 00:54:32 -0000
@@ -1060,6 +1060,10 @@ extern struct symbol *lookup_block_symbo
 					   const char *,
 					   const domain_enum);
 
+/* Get offsetof (struct `symbol_struct', `symbol_field').  */
+extern ptrdiff_t symtab_offsetof (const char *symbol_struct,
+				  const char *symbol_field);
+
 /* lookup a [struct, union, enum] by name, within a specified block */
 
 extern struct type *lookup_struct (char *, struct block *);
Index: gdb/target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.124
diff -u -p -r1.124 target.c
--- gdb/target.c	16 Aug 2006 18:31:03 -0000	1.124
+++ gdb/target.c	8 Sep 2006 00:54:34 -0000
@@ -39,6 +39,7 @@
 #include "regcache.h"
 #include "gdb_assert.h"
 #include "gdbcore.h"
+#include "exceptions.h"
 
 static void target_info (char *, int);
 
@@ -463,6 +464,8 @@ update_current_target (void)
       INHERIT (to_find_memory_regions, t);
       INHERIT (to_make_corefile_notes, t);
       INHERIT (to_get_thread_local_address, t);
+      INHERIT (to_get_thread_xreg, t);
+      INHERIT (to_ps_get_thread_area_current, t);
       INHERIT (to_magic, t);
     }
 #undef INHERIT
@@ -755,6 +758,107 @@ pop_target (void)
   internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
 }
 
+/* Using the objfile specified by `objfile', find the address for the
+   current thread's thread-local storage with offset OFFSET.  */
+CORE_ADDR
+target_translate_tls_address (struct objfile *objfile, CORE_ADDR offset)
+{
+  volatile CORE_ADDR addr = 0;
+
+  if (objfile->separate_debug_objfile_backlink != NULL)
+    objfile = objfile->separate_debug_objfile_backlink;
+
+  if ((target_get_thread_local_address_p ()
+      && gdbarch_fetch_tls_load_module_address_p (current_gdbarch)))
+    {
+      ptid_t ptid = inferior_ptid;
+      volatile struct gdb_exception ex;
+
+      TRY_CATCH (ex, RETURN_MASK_ALL)
+	{
+	  CORE_ADDR lm_addr;
+	  
+	  /* Fetch the load module address for this objfile.  */
+	  lm_addr = gdbarch_fetch_tls_load_module_address (current_gdbarch,
+	                                                   objfile);
+	  /* If it's 0, throw the appropriate exception.  */
+	  if (lm_addr == 0)
+	    throw_error (TLS_LOAD_MODULE_NOT_FOUND_ERROR,
+			 _("TLS load module not found"));
+
+	  addr = target_get_thread_local_address (ptid, lm_addr, offset);
+	}
+      /* If an error occurred, print TLS related messages here.  Otherwise,
+         throw the error to some higher catcher.  */
+      if (ex.reason < 0)
+	{
+	  int objfile_is_library = (objfile->flags & OBJF_SHARED);
+
+	  switch (ex.error)
+	    {
+	    case TLS_NO_LIBRARY_SUPPORT_ERROR:
+	      error (_("Cannot find thread-local variables in this thread library."));
+	      break;
+	    case TLS_LOAD_MODULE_NOT_FOUND_ERROR:
+	      if (objfile_is_library)
+		error (_("Cannot find shared library `%s' in dynamic"
+		         " linker's load module list"), objfile->name);
+	      else
+		error (_("Cannot find executable file `%s' in dynamic"
+		         " linker's load module list"), objfile->name);
+	      break;
+	    case TLS_NOT_ALLOCATED_YET_ERROR:
+	      if (objfile_is_library)
+		error (_("The inferior has not yet allocated storage for"
+		         " thread-local variables in\n"
+		         "the shared library `%s'\n"
+		         "for %s"),
+		       objfile->name, target_pid_to_str (ptid));
+	      else
+		error (_("The inferior has not yet allocated storage for"
+		         " thread-local variables in\n"
+		         "the executable `%s'\n"
+		         "for %s"),
+		       objfile->name, target_pid_to_str (ptid));
+	      break;
+	    case TLS_GENERIC_ERROR:
+	      if (objfile_is_library)
+		error (_("Cannot find thread-local storage for %s, "
+		         "shared library %s:\n%s"),
+		       target_pid_to_str (ptid),
+		       objfile->name, ex.message);
+	      else
+		error (_("Cannot find thread-local storage for %s, "
+		         "executable file %s:\n%s"),
+		       target_pid_to_str (ptid),
+		       objfile->name, ex.message);
+	      break;
+	    default:
+	      throw_exception (ex);
+	      break;
+	    }
+	}
+    }
+  /* It wouldn't be wrong here to try a gdbarch method, too; finding
+     TLS is an ABI-specific thing.  But we don't do that yet.  */
+  else
+    {
+      struct minimal_symbol *msymbol;
+
+      msymbol = lookup_minimal_symbol ("errno", NULL, NULL);
+      if (msymbol != NULL
+	  && SYMBOL_VALUE_ADDRESS (msymbol) == offset
+	  && SYMBOL_BFD_SECTION (msymbol)->owner == objfile->obfd)
+	error (_("TLS symbol `errno' not resolved for non-TLS program."
+		 " You should use symbol \"(*__errno_location ())\" or"
+		 " compile the program with `gcc -ggdb3' or `gcc -pthread'."
+		 " You may also upgrade glibc for `TD_MINIMALONLY'."));
+      error (_("Cannot find thread-local variables on this target"));
+    }
+
+  return addr;
+}
+
 #undef	MIN
 #define MIN(A, B) (((A) <= (B)) ? (A) : (B))
 
Index: gdb/target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.87
diff -u -p -r1.87 target.h
--- gdb/target.h	15 Aug 2006 18:46:25 -0000	1.87
+++ gdb/target.h	8 Sep 2006 00:54:35 -0000
@@ -56,6 +56,11 @@ struct bp_target_info;
 #include "dcache.h"
 #include "memattr.h"
 
+/* Defines ps_err_e.  */
+#include "gdb_proc_service.h"
+/* Defines enum thread_xreg.  */
+#include "gdbthread.h"
+
 enum strata
   {
     dummy_stratum,		/* The lowest of the low */
@@ -412,6 +417,13 @@ struct target_ops
 				   void *);
     char * (*to_make_corefile_notes) (bfd *, int *);
 
+    /* Get the address of the thread xreg - extended register.
+       Currently thread variable `tcbhead_t.pointer_guard' is supported.  */
+    CORE_ADDR (*to_get_thread_xreg) (ptid_t ptid, enum thread_xreg which);
+
+    /* Query the base address of the current module of the specified thread.  */
+    ps_err_e (*to_ps_get_thread_area_current) (lwpid_t lwpid, void **base);
+
     /* Return the thread-local address at OFFSET in the
        thread-local storage for the thread PTID and the shared library
        or executable file given by OBJFILE.  If that block of
@@ -1009,6 +1021,15 @@ extern void (*deprecated_target_new_objf
 #define target_get_thread_local_address_p() \
     (target_get_thread_local_address != NULL)
 
+/* Thread variables simulated as xregs.  */
+#define target_get_thread_xreg \
+    (current_target.to_get_thread_xreg)
+#define target_get_thread_xreg_p() \
+    (target_get_thread_xreg != NULL)
+
+#define target_ps_get_thread_area_current \
+    (current_target.to_ps_get_thread_area_current)
+
 /* Hook to call target dependent code just after inferior target process has
    started.  */
 
@@ -1131,6 +1152,11 @@ extern void target_preopen (int);
 
 extern void pop_target (void);
 
+/* Using the objfile specified by `objfile', find the address for the
+   current thread's thread-local storage with offset OFFSET.  */
+extern CORE_ADDR target_translate_tls_address (struct objfile *objfile,
+					       CORE_ADDR offset);
+
 /* Struct section_table maps address ranges to file sections.  It is
    mostly used with BFD files, but can be used without (e.g. for handling
    raw disks, or files not in formats handled by BFD).  */
Index: gdb/thread.c
===================================================================
RCS file: /cvs/src/src/gdb/thread.c,v
retrieving revision 1.48
diff -u -p -r1.48 thread.c
--- gdb/thread.c	17 Dec 2005 22:34:03 -0000	1.48
+++ gdb/thread.c	8 Sep 2006 00:54:35 -0000
@@ -36,6 +36,7 @@
 #include "regcache.h"
 #include "gdb.h"
 #include "gdb_string.h"
+#include "gdbcore.h"
 
 #include <ctype.h>
 #include <sys/types.h>
@@ -500,6 +501,32 @@ make_cleanup_restore_current_thread (pti
   return make_cleanup (do_restore_current_thread_cleanup, old);
 }
 
+/* Fetch `CORE_ADDR' type from the thread base of `ptid'
+   at base offset `field_offset'.  */
+
+CORE_ADDR
+thread_get_field_at_offset (ptid_t ptid, ptrdiff_t field_offset)
+{
+  CORE_ADDR addr;
+  gdb_byte buf[8];
+  int len = TYPE_LENGTH (builtin_type_void_func_ptr);
+  ps_err_e ps_err;
+  void *tls_base;
+
+  ps_err = target_ps_get_thread_area_current (ptid_get_pid (ptid), &tls_base);
+  if (ps_err != PS_OK)
+    error (_("Cannot find thread %ld: %d"),
+	   (long) ptid_get_pid (ptid), (int) ps_err);
+
+  /* Misuse this equivalence in GNU/Linux glibc nptl.  */
+  addr = (CORE_ADDR) tls_base;
+  addr += field_offset;
+
+  read_memory (addr, buf, len);
+
+  return extract_typed_address (buf, builtin_type_void_func_ptr);
+}
+
 /* Apply a GDB command to a list of threads.  List syntax is a whitespace
    seperated list of numbers, or ranges, or the keyword `all'.  Ranges consist
    of two numbers seperated by a hyphen.  Examples:
Index: gdb/valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.164
diff -u -p -r1.164 valops.c
--- gdb/valops.c	13 Jul 2006 04:31:42 -0000	1.164
+++ gdb/valops.c	8 Sep 2006 00:54:37 -0000
@@ -501,7 +501,8 @@ value_at (struct type *type, CORE_ADDR a
 /* Return a lazy value with type TYPE located at ADDR (cf. value_at).  */
 
 struct value *
-value_at_lazy (struct type *type, CORE_ADDR addr)
+value_at_lazy_tls (struct type *type, CORE_ADDR addr,
+		   struct objfile *tls_objfile)
 {
   struct value *val;
 
@@ -512,11 +513,19 @@ value_at_lazy (struct type *type, CORE_A
 
   VALUE_LVAL (val) = lval_memory;
   VALUE_ADDRESS (val) = addr;
+  if (tls_objfile != NULL)
+    set_value_tls_objfile (val, tls_objfile);
   set_value_lazy (val, 1);
 
   return val;
 }
 
+struct value *
+value_at_lazy (struct type *type, CORE_ADDR addr)
+{
+  return value_at_lazy_tls (type, addr, NULL);
+}
+
 /* Called only from the value_contents and value_contents_all()
    macros, if the current data for a variable needs to be loaded into
    value_contents(VAL).  Fetches the data from the user's process, and
@@ -538,7 +547,17 @@ value_fetch_lazy (struct value *val)
 
   struct type *type = value_type (val);
   if (length)
-    read_memory (addr, value_contents_all_raw (val), length);
+    {
+      struct objfile *tls_objfile = value_tls_objfile (val);
+
+      if (tls_objfile != NULL)
+	{
+	  /* `target_translate_tls_address' uses `inferior_ptid'.  */
+	  addr = target_translate_tls_address (tls_objfile, addr);
+	}
+
+      read_memory (addr, value_contents_all_raw (val), length);
+    }
 
   set_value_lazy (val, 0);
   return 0;
@@ -596,6 +615,7 @@ value_assign (struct value *toval, struc
 	CORE_ADDR changed_addr;
 	int changed_len;
         gdb_byte buffer[sizeof (LONGEST)];
+	struct objfile *tls_objfile = value_tls_objfile (toval);
 
 	if (value_bitsize (toval))
 	  {
@@ -624,6 +644,13 @@ value_assign (struct value *toval, struc
 	    dest_buffer = value_contents (fromval);
 	  }
 
+	if (tls_objfile != NULL)
+	  {
+	    /* `target_translate_tls_address' uses `inferior_ptid'.  */
+	    changed_addr = target_translate_tls_address (tls_objfile,
+							 changed_addr);
+	  }
+
 	write_memory (changed_addr, dest_buffer, changed_len);
 	if (deprecated_memory_changed_hook)
 	  deprecated_memory_changed_hook (changed_addr, changed_len);
Index: gdb/value.c
===================================================================
RCS file: /cvs/src/src/gdb/value.c,v
retrieving revision 1.36
diff -u -p -r1.36 value.c
--- gdb/value.c	31 Mar 2006 10:36:18 -0000	1.36
+++ gdb/value.c	8 Sep 2006 00:54:40 -0000
@@ -158,6 +158,9 @@ struct value
      actually exist in the program.  */
   char optimized_out;
 
+  /* TLS owner.  */
+  struct objfile *tls_objfile;
+
   /* Actual contents of the value.  For use of this value; setting it
      uses the stuff above.  Not valid if lazy is nonzero.  Target
      byte-order.  We force it to be aligned properly for any possible
@@ -230,6 +233,7 @@ allocate_value (struct type *type)
   VALUE_REGNUM (val) = -1;
   val->lazy = 0;
   val->optimized_out = 0;
+  val->tls_objfile = NULL;
   val->embedded_offset = 0;
   val->pointed_to_offset = 0;
   val->modifiable = 1;
@@ -344,6 +348,18 @@ set_value_lazy (struct value *value, int
   value->lazy = val;
 }
 
+struct objfile *
+value_tls_objfile (struct value *value)
+{
+  return value->tls_objfile;
+}
+
+void
+set_value_tls_objfile (struct value *value, struct objfile *tls_objfile)
+{
+  value->tls_objfile = tls_objfile;
+}
+
 const gdb_byte *
 value_contents (struct value *value)
 {
Index: gdb/value.h
===================================================================
RCS file: /cvs/src/src/gdb/value.h,v
retrieving revision 1.92
diff -u -p -r1.92 value.h
--- gdb/value.h	13 Jul 2006 04:31:42 -0000	1.92
+++ gdb/value.h	8 Sep 2006 00:54:40 -0000
@@ -154,6 +154,10 @@ extern void set_value_embedded_offset (s
 extern int value_lazy (struct value *);
 extern void set_value_lazy (struct value *value, int val);
 
+extern struct objfile *value_tls_objfile (struct value *value);
+extern void set_value_tls_objfile (struct value *value,
+				   struct objfile *tls_objfile);
+
 /* value_contents() and value_contents_raw() both return the address
    of the gdb buffer used to hold a copy of the contents of the lval.
    value_contents() is used when the contents of the buffer are needed
@@ -277,6 +281,8 @@ extern struct value *value_from_double (
 extern struct value *value_from_string (char *string);
 
 extern struct value *value_at (struct type *type, CORE_ADDR addr);
+extern struct value *value_at_lazy_tls (struct type *type, CORE_ADDR addr,
+					struct objfile *tls_objfile);
 extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr);
 
 extern struct value *value_from_register (struct type *type, int regnum,
Index: gdb/testsuite/gdb.threads/tls-longjmp.c
===================================================================
RCS file: gdb/testsuite/gdb.threads/tls-longjmp.c
diff -N gdb/testsuite/gdb.threads/tls-longjmp.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.threads/tls-longjmp.c	8 Sep 2006 00:54:43 -0000
@@ -0,0 +1,36 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2006 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+ 
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Please email any bugs, comments, and/or additions to this file to:
+   bug-gdb@prep.ai.mit.edu  */
+
+#include <stdio.h>
+#include <setjmp.h>
+
+int main()
+{
+  jmp_buf buf;
+  int val;
+
+  val = setjmp (buf);
+  printf ("%d\n", val);	/* after-longjmp */
+  if (val == 0)
+    longjmp (buf, 1);	/* perform-longjmp */
+
+  return 0;
+}
Index: gdb/testsuite/gdb.threads/tls-longjmp.exp
===================================================================
RCS file: gdb/testsuite/gdb.threads/tls-longjmp.exp
diff -N gdb/testsuite/gdb.threads/tls-longjmp.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.threads/tls-longjmp.exp	8 Sep 2006 00:54:43 -0000
@@ -0,0 +1,67 @@
+# Copyright 2006 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program 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 General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+set testfile tls-longjmp
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+proc test_body {compile_command} {
+    global srcdir
+    global subdir
+    global srcfile
+    global binfile
+
+    # The real test is for the part without `gdb_compile_pthreads' here.
+    # Nver use `-ggdb3' here (macro expansion), `-ggdb2' and lower is fine.
+    if  { [$compile_command "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+	untested "Couldn't compile test program"
+	return -1
+    }
+
+    # Get things started.
+
+    gdb_exit
+    gdb_start
+    gdb_reinitialize_dir $srcdir/$subdir
+    gdb_load ${binfile}
+
+    # For C programs, "start" should stop in main().
+
+    gdb_test "start" \
+	     "main \\(\\) at .*tls-longjmp.c.*" \
+	     "start"
+
+    gdb_test "tbreak [gdb_get_line_number perform-longjmp]" \
+	     "Breakpoint \[0-9\]+ at .*tls-longjmp.c.*" \
+	     "break at longjmp"
+
+    gdb_test "continue" \
+	     "Continuing..*main \\(\\) at .*tls-longjmp.c.* perform-longjmp .*" \
+	     "continue till longjmp"
+
+    # Do not use `step' as could step into the longjmp(3) implementation.
+    gdb_test "next" \
+	     ".* after-longjmp .*" \
+	     "next over longjmp"
+
+}
+
+test_body gdb_compile_pthreads
+test_body gdb_compile
Index: gdb/testsuite/gdb.threads/tls-print.c
===================================================================
RCS file: gdb/testsuite/gdb.threads/tls-print.c
diff -N gdb/testsuite/gdb.threads/tls-print.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.threads/tls-print.c	8 Sep 2006 00:54:43 -0000
@@ -0,0 +1,41 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2006 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+ 
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Please email any bugs, comments, and/or additions to this file to:
+   bug-gdb@prep.ai.mit.edu  */
+
+#include <stdio.h>
+
+int x;
+
+void bar()
+{
+  x--;
+}
+
+void foo()
+{
+  x++;
+}
+
+int main()
+{
+  foo();
+  bar();
+  return 0;
+}
Index: gdb/testsuite/gdb.threads/tls-print.exp
===================================================================
RCS file: gdb/testsuite/gdb.threads/tls-print.exp
diff -N gdb/testsuite/gdb.threads/tls-print.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.threads/tls-print.exp	8 Sep 2006 00:54:43 -0000
@@ -0,0 +1,49 @@
+# Copyright 2006 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program 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 General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+set testfile tls-print
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+# Never use `gdb_compile_pthreads' here.
+# Nver use `-ggdb3' here (macro expansion), `-ggdb2' and lower is fine.
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+    untested "Couldn't compile test program"
+    return -1
+}
+
+# Get things started.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# For C programs, "start" should stop in main().
+
+gdb_test "start" \
+         "main \\(\\) at .*tls-print.c.*" \
+         "start"
+
+# If it prints: Cannot find shared library `/usr/lib/debug/lib/libc-2.4.90.so.debug' in dynamic linker's load module list
+# there is missing the patch for `separate_debug_objfile_backlink'.
+
+gdb_test "print errno" \
+         "\\\$1 = \[0-9\].*" \
+         "print errno"


More information about the Libc-alpha mailing list