about summary refs log tree commit diff
path: root/nptl_db
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2003-09-09 07:01:01 +0000
committerRoland McGrath <roland@gnu.org>2003-09-09 07:01:01 +0000
commit7f08f55a9f88d23fcfbf1fed00f4d5a094e5fffc (patch)
tree5796d7f5d713c3c264a70a6039b0ba52e262b06f /nptl_db
parent416be7f049391ce421d9b12a2c3b81bb3cad9f58 (diff)
downloadglibc-7f08f55a9f88d23fcfbf1fed00f4d5a094e5fffc.tar.gz
glibc-7f08f55a9f88d23fcfbf1fed00f4d5a094e5fffc.tar.xz
glibc-7f08f55a9f88d23fcfbf1fed00f4d5a094e5fffc.zip
* sysdeps/unix/sysv/linux/speed.c
	(cfsetospeed): Only set c_ospeed under [_HAVE_STRUCT_TERMIOS_C_OSPEED].
	(cfsetispeed): Only set c_ispeed under [_HAVE_STRUCT_TERMIOS_C_ISPEED].
	* sysdeps/unix/sysv/linux/bits/termios.h
	(_HAVE_STRUCT_TERMIOS_C_ISPEED, _HAVE_STRUCT_TERMIOS_C_OSPEED): Define.
	* sysdeps/unix/sysv/linux/alpha/bits/termios.h: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/bits/termios.h: Likewise.
Diffstat (limited to 'nptl_db')
-rw-r--r--nptl_db/ChangeLog61
-rw-r--r--nptl_db/Makefile5
-rw-r--r--nptl_db/db_info.c98
-rw-r--r--nptl_db/fetch-value.c283
-rw-r--r--nptl_db/proc_service.h100
-rw-r--r--nptl_db/structs.def86
-rw-r--r--nptl_db/td_symbol_list.c33
-rw-r--r--nptl_db/td_ta_clear_event.c65
-rw-r--r--nptl_db/td_ta_event_addr.c36
-rw-r--r--nptl_db/td_ta_event_getmsg.c91
-rw-r--r--nptl_db/td_ta_get_nthreads.c21
-rw-r--r--nptl_db/td_ta_map_lwp2thr.c179
-rw-r--r--nptl_db/td_ta_new.c60
-rw-r--r--nptl_db/td_ta_set_event.c65
-rw-r--r--nptl_db/td_ta_thr_iter.c137
-rw-r--r--nptl_db/td_ta_tsd_iter.c60
-rw-r--r--nptl_db/td_thr_clear_event.c67
-rw-r--r--nptl_db/td_thr_event_enable.c12
-rw-r--r--nptl_db/td_thr_event_getmsg.c92
-rw-r--r--nptl_db/td_thr_get_info.c80
-rw-r--r--nptl_db/td_thr_getfpregs.c23
-rw-r--r--nptl_db/td_thr_getgregs.c27
-rw-r--r--nptl_db/td_thr_set_event.c67
-rw-r--r--nptl_db/td_thr_setfpregs.c23
-rw-r--r--nptl_db/td_thr_setgregs.c23
-rw-r--r--nptl_db/td_thr_tls_get_addr.c34
-rw-r--r--nptl_db/td_thr_tlsbase.c39
-rw-r--r--nptl_db/td_thr_tsd.c81
-rw-r--r--nptl_db/td_thr_validate.c62
-rw-r--r--nptl_db/thread_db.h6
-rw-r--r--nptl_db/thread_dbP.h239
31 files changed, 1647 insertions, 608 deletions
diff --git a/nptl_db/ChangeLog b/nptl_db/ChangeLog
index 32781ec6f8..da38cee035 100644
--- a/nptl_db/ChangeLog
+++ b/nptl_db/ChangeLog
@@ -1,3 +1,64 @@
+2003-09-08  Roland McGrath  <roland@redhat.com>
+
+	* td_thr_get_info.c (td_thr_get_info): Cast th_unique to thread_t.
+
+2003-08-22  Roland McGrath  <roland@redhat.com>
+
+	* fetch-value.c (_td_check_sizeof, _td_locate_field): Return
+	TD_NOCAPAB for PS_NOSYM, instead of vanilla TD_ERR.
+	* td_thr_tls_get_addr.c (td_thr_tls_get_addr): Return TD_NOAPLIC when
+	DB_GET_FIELD returns TD_NOCAPAB.
+
+	* thread_db.h (td_thr_tls_get_addr): Use psaddr_t in signature.
+	* structs.def [USE_TLS]: Add DB_STRUCT_FIELD (link_map, l_tls_modid).
+	* db_info.c (link_map): Typedef it.
+	* td_thr_tls_get_addr.c (td_thr_tls_get_addr): Rewritten.
+
+2003-08-14  Roland McGrath  <roland@redhat.com>
+
+	* thread_dbP.h: Mostly rewritten with many new macros and decls.
+	* td_ta_new.c (td_ta_new): Don't cache a lot of symbol values.
+	* structs.def: New file.
+	* db_info.c: New file.
+	* td_symbol_list.c (symbol_list_arr): Define with structs.def macros.
+	* td_ta_clear_event.c: Rewritten.
+	* td_ta_event_addr.c: Rewritten.
+	* td_ta_event_getmsg.c: Rewritten.
+	* td_ta_get_nthreads.c: Rewritten.
+	* td_ta_map_lwp2thr.c: New file.
+	* td_ta_set_event.c: Rewritten.
+	* td_ta_thr_iter.c: Rewritten.
+	* td_ta_tsd_iter.c: Rewritten.
+	* td_thr_clear_event.c: Rewritten.
+	* td_thr_event_enable.c: Rewritten.
+	* td_thr_event_getmsg.c: Rewritten.
+	* td_thr_get_info.c: Rewritten.
+	* td_thr_getfpregs.c: Rewritten.
+	* td_thr_getgregs.c: Rewritten.
+	* td_thr_set_event.c: Rewritten.
+	* td_thr_setfpregs.c: Rewritten.
+	* td_thr_setgregs.c: Rewritten.
+	* td_thr_tlsbase.c: Rewritten.
+	* td_thr_tsd.c: Rewritten.
+	* td_thr_validate.c: Rewritten.
+	* Makefile (distribute): Add them.
+	* fetch-value.c: New file.
+	* Makefile (libthread_db-routines): Add it.
+
+	* thread_db.h (td_err_e): Comment fix.
+
+2003-08-05  Roland McGrath  <roland@redhat.com>
+
+	* thread_dbP.h (td_lookup): Add attribute_hidden to decl.
+
+2003-08-04  Roland McGrath  <roland@redhat.com>
+
+	* td_ta_clear_event.c (td_ta_clear_event): Fix sizes in ps_* calls.
+
+2003-06-23  Roland McGrath  <roland@redhat.com>
+
+	* proc_service.h: Cosmetic and comment fixes.
+
 2003-06-19  Roland McGrath  <roland@redhat.com>
 
 	* td_thr_event_enable.c (td_thr_event_enable): Use proper type `bool'
diff --git a/nptl_db/Makefile b/nptl_db/Makefile
index d6dcec5aea..5c73ff28f2 100644
--- a/nptl_db/Makefile
+++ b/nptl_db/Makefile
@@ -42,14 +42,15 @@ libthread_db-routines = td_init td_log td_ta_new td_ta_delete \
 			td_thr_clear_event td_thr_event_getmsg \
 			td_ta_set_event td_ta_event_getmsg \
 			td_ta_clear_event td_symbol_list \
-			td_thr_tlsbase td_thr_tls_get_addr
+			td_thr_tlsbase td_thr_tls_get_addr \
+			fetch-value
 
 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
+distribute = thread_dbP.h shlib-versions proc_service.h db_info.c structs.def
 include ../Rules
 
 # Depend on libc.so so a DT_NEEDED is generated in the shared objects.
diff --git a/nptl_db/db_info.c b/nptl_db/db_info.c
new file mode 100644
index 0000000000..aa485369b2
--- /dev/null
+++ b/nptl_db/db_info.c
@@ -0,0 +1,98 @@
+/* This file is included by pthread_create.c to define in libpthread
+   all the magic symbols required by libthread_db.
+
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <tls.h>
+
+typedef struct pthread pthread;
+typedef struct pthread_key_struct pthread_key_struct;
+typedef struct pthread_key_data pthread_key_data;
+typedef struct
+{
+  struct pthread_key_data data[PTHREAD_KEY_2NDLEVEL_SIZE];
+}
+pthread_key_data_level2;
+
+typedef struct
+{
+  union dtv dtv[UINT32_MAX / 2 / sizeof (union dtv)]; /* No constant bound.  */
+} dtv;
+
+typedef struct link_map link_map;
+
+
+#define schedparam_sched_priority schedparam.sched_priority
+
+#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, \
+		  8 * sizeof (obj)[0], sizeof (obj) / sizeof (obj)[0], \
+		  offset);
+
+#if TLS_TCB_AT_TP
+# define dtvp header.dtv
+#elif TLS_DTV_AT_TP
+/* Special case hack.  */
+DESC (_thread_db_pthread_dtvp,
+      TLS_PRE_TCB_SIZE + offsetof (tcbhead_t, dtv), union dtv)
+#endif
+
+
+#define DB_STRUCT(type) \
+  const uint32_t _thread_db_sizeof_##type = sizeof (type);
+#define DB_STRUCT_FIELD(type, field) \
+  DESC (_thread_db_##type##_##field, \
+	offsetof (type, field), ((type *) 0)->field)
+#define DB_STRUCT_ARRAY_FIELD(type, field) \
+  ARRAY_DESC (_thread_db_##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_SYMBOL(name)	/* Nothing.  */
+#include "structs.def"
+#undef DB_STRUCT
+#undef DB_STRUCT_FIELD
+#undef DB_SYMBOL
+#undef DB_VARIABLE
+#undef DESC
+
+
+
+#ifdef DB_THREAD_SELF
+# ifdef DB_THREAD_SELF_INCLUDE
+#  include DB_THREAD_SELF_INCLUDE
+# endif
+
+/* This macro is defined in the machine's tls.h using the three below.  */
+# 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, \
+		  bits, (scale), (regofs));
+# define REGISTER(bits, regofs, bias) \
+  DB_DEFINE_DESC (_thread_db_register##bits, bits, (uint32_t)(bias), (regofs));
+
+DB_THREAD_SELF
+#endif
diff --git a/nptl_db/fetch-value.c b/nptl_db/fetch-value.c
new file mode 100644
index 0000000000..9d40b61691
--- /dev/null
+++ b/nptl_db/fetch-value.c
@@ -0,0 +1,283 @@
+/* Helper routines for libthread_db.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <byteswap.h>
+#include <assert.h>
+
+td_err_e
+_td_check_sizeof (td_thragent_t *ta, uint32_t *sizep, int sizep_name)
+{
+  if (*sizep == 0)
+    {
+      psaddr_t descptr;
+      ps_err_e err = td_lookup (ta->ph, sizep_name, &descptr);
+      if (err == PS_NOSYM)
+	return TD_NOCAPAB;
+      if (err == PS_OK)
+	err = ps_pdread (ta->ph, descptr, sizep, sizeof *sizep);
+      if (err != PS_OK)
+	return TD_ERR;
+      if (*sizep & 0xff000000U)
+	*sizep = bswap_32 (*sizep);
+    }
+  return TD_OK;
+}
+
+td_err_e
+_td_locate_field (td_thragent_t *ta,
+		  db_desc_t desc, int descriptor_name,
+		  psaddr_t idx, psaddr_t *address)
+{
+  uint32_t elemsize;
+
+  if (DB_DESC_SIZE (desc) == 0)
+    {
+      /* 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)
+	return TD_NOCAPAB;
+      if (err == PS_OK)
+	err = ps_pdread (ta->ph, descptr, desc, DB_SIZEOF_DESC);
+      if (err != PS_OK)
+	return TD_ERR;
+      if (DB_DESC_SIZE (desc) == 0)
+	return TD_DBERR;
+      if (DB_DESC_SIZE (desc) & 0xff000000U)
+	{
+	  /* Byte-swap these words, though we leave the size word
+	     in native order as the handy way to distinguish.  */
+	  DB_DESC_OFFSET (desc) = bswap_32 (DB_DESC_OFFSET (desc));
+	  DB_DESC_NELEM (desc) = bswap_32 (DB_DESC_NELEM (desc));
+	}
+    }
+
+  if (idx != 0 && idx - (psaddr_t) 0 > DB_DESC_NELEM (desc))
+    /* This is an internal indicator to callers with nonzero IDX
+       that the IDX value is too big.  */
+    return TD_NOAPLIC;
+
+  elemsize = DB_DESC_SIZE (desc);
+  if (elemsize & 0xff000000U)
+    elemsize = bswap_32 (elemsize);
+
+  *address += DB_DESC_OFFSET (desc) + (elemsize / 8 * (idx - (psaddr_t) 0));
+  return TD_OK;
+}
+
+td_err_e
+_td_fetch_value (td_thragent_t *ta,
+		 db_desc_t desc, 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);
+  if (terr != TD_OK)
+    return terr;
+
+  if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
+    {
+      uint8_t value;
+      err = ps_pdread (ta->ph, address, &value, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == 32)
+    {
+      uint32_t value;
+      err = ps_pdread (ta->ph, address, &value, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == 64)
+    {
+      uint64_t value;
+      if (sizeof (psaddr_t) < 8)
+	return TD_NOCAPAB;
+      err = ps_pdread (ta->ph, address, &value, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (32))
+    {
+      uint32_t value;
+      err = ps_pdread (ta->ph, address, &value, sizeof value);
+      value = bswap_32 (value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (64))
+    {
+      uint64_t value;
+      if (sizeof (psaddr_t) < 8)
+	return TD_NOCAPAB;
+      err = ps_pdread (ta->ph, address, &value, sizeof value);
+      value = bswap_64 (value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else
+    return TD_DBERR;
+
+  return err == PS_OK ? TD_OK : TD_ERR;
+}
+
+
+td_err_e
+_td_store_value (td_thragent_t *ta,
+		 uint32_t desc[2], 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);
+  if (terr != TD_OK)
+    return terr;
+
+  if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
+    {
+      uint8_t value = widened_value - (psaddr_t) 0;
+      err = ps_pdwrite (ta->ph, address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == 32)
+    {
+      uint32_t value = widened_value - (psaddr_t) 0;
+      err = ps_pdwrite (ta->ph, address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == 64)
+    {
+      uint64_t value = widened_value - (psaddr_t) 0;
+      if (sizeof (psaddr_t) < 8)
+	return TD_NOCAPAB;
+      err = ps_pdwrite (ta->ph, address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (32))
+    {
+      uint32_t value = widened_value - (psaddr_t) 0;
+      value = bswap_32 (value);
+      err = ps_pdwrite (ta->ph, address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (64))
+    {
+      uint64_t value = widened_value - (psaddr_t) 0;
+      if (sizeof (psaddr_t) < 8)
+	return TD_NOCAPAB;
+      value = bswap_64 (value);
+      err = ps_pdwrite (ta->ph, address, &value, sizeof value);
+    }
+  else
+    return TD_DBERR;
+
+  return err == PS_OK ? TD_OK : TD_ERR;
+}
+
+td_err_e
+_td_fetch_value_local (td_thragent_t *ta,
+		       db_desc_t desc, int descriptor_name, psaddr_t idx,
+		       void *address,
+		       psaddr_t *result)
+{
+  td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
+  if (terr != TD_OK)
+    return terr;
+
+  if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
+    {
+      uint8_t value;
+      memcpy (&value, address, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == 32)
+    {
+      uint32_t value;
+      memcpy (&value, address, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == 64)
+    {
+      uint64_t value;
+      if (sizeof (psaddr_t) < 8)
+	return TD_NOCAPAB;
+      memcpy (&value, address, sizeof value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (32))
+    {
+      uint32_t value;
+      memcpy (&value, address, sizeof value);
+      value = bswap_32 (value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (64))
+    {
+      uint64_t value;
+      if (sizeof (psaddr_t) < 8)
+	return TD_NOCAPAB;
+      memcpy (&value, address, sizeof value);
+      value = bswap_64 (value);
+      *result = (psaddr_t) 0 + value;
+    }
+  else
+    return TD_DBERR;
+
+  return TD_OK;
+}
+
+
+td_err_e
+_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);
+  if (terr != TD_OK)
+    return terr;
+
+  if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
+    {
+      uint8_t value = widened_value - (psaddr_t) 0;
+      memcpy (address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == 32)
+    {
+      uint32_t value = widened_value - (psaddr_t) 0;
+      memcpy (address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == 64)
+    {
+      uint64_t value = widened_value - (psaddr_t) 0;
+      if (sizeof (psaddr_t) < 8)
+	return TD_NOCAPAB;
+      memcpy (address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (32))
+    {
+      uint32_t value = widened_value - (psaddr_t) 0;
+      value = bswap_32 (value);
+      memcpy (address, &value, sizeof value);
+    }
+  else if (DB_DESC_SIZE (desc) == bswap_32 (64))
+    {
+      uint64_t value = widened_value - (psaddr_t) 0;
+      if (sizeof (psaddr_t) < 8)
+	return TD_NOCAPAB;
+      value = bswap_64 (value);
+      memcpy (address, &value, sizeof value);
+    }
+  else
+    return TD_DBERR;
+
+  return TD_OK;
+}
diff --git a/nptl_db/proc_service.h b/nptl_db/proc_service.h
index 9963c3aecd..d49e87ab30 100644
--- a/nptl_db/proc_service.h
+++ b/nptl_db/proc_service.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+/* Callback interface for libthread_db, functions users must define.
+   Copyright (C) 1999,2002,2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -19,55 +20,68 @@
 /* The definitions in this file must correspond to those in the debugger.  */
 #include <sys/procfs.h>
 
+/* Functions in this interface return one of these status codes.  */
 typedef enum
 {
-  PS_OK,          /* generic "call succeeded" */
-  PS_ERR,         /* generic. */
-  PS_BADPID,      /* bad process handle */
-  PS_BADLID,      /* bad lwp identifier */
-  PS_BADADDR,     /* bad address */
-  PS_NOSYM,       /* p_lookup() could not find given symbol */
-        PS_NOFREGS
-  /*
-   * FPU register set not available for given
-   * lwp
-   */
-}       ps_err_e;
-
-
-struct ps_prochandle;		/* user defined. */
-
-
-extern ps_err_e ps_pdread(struct ps_prochandle *,
-                        psaddr_t, void *, size_t);
-extern ps_err_e ps_pdwrite(struct ps_prochandle *,
-                        psaddr_t, const void *, size_t);
-extern ps_err_e ps_ptread(struct ps_prochandle *,
-                        psaddr_t, void *, size_t);
-extern ps_err_e ps_ptwrite(struct ps_prochandle *,
-                        psaddr_t, const void *, size_t);
-
-extern ps_err_e ps_pglobal_lookup(struct ps_prochandle *,
-        const char *object_name, const char *sym_name, psaddr_t *sym_addr);
-
-
-extern ps_err_e ps_lgetregs(struct ps_prochandle *,
-                        lwpid_t, prgregset_t);
-extern ps_err_e ps_lsetregs(struct ps_prochandle *,
-                        lwpid_t, const prgregset_t);
-extern ps_err_e ps_lgetfpregs(struct ps_prochandle *,
-                        lwpid_t, prfpregset_t *);
-extern ps_err_e ps_lsetfpregs(struct ps_prochandle *,
-                        lwpid_t, const prfpregset_t *);
-
+  PS_OK,		/* Generic "call succeeded".  */
+  PS_ERR,		/* Generic error. */
+  PS_BADPID,		/* Bad process handle.  */
+  PS_BADLID,		/* Bad LWP identifier.  */
+  PS_BADADDR,		/* Bad address.  */
+  PS_NOSYM,		/* Could not find given symbol.  */
+  PS_NOFREGS		/* FPU register set not available for given LWP.  */
+} ps_err_e;
+
+
+/* This type is opaque in this interface.
+   It's defined by the user of libthread_db.  */
+struct ps_prochandle;
+
+
+/* Read or write process memory at the given address.  */
+extern ps_err_e ps_pdread (struct ps_prochandle *,
+			   psaddr_t, void *, size_t);
+extern ps_err_e ps_pdwrite (struct ps_prochandle *,
+			    psaddr_t, const void *, size_t);
+extern ps_err_e ps_ptread (struct ps_prochandle *,
+			   psaddr_t, void *, size_t);
+extern ps_err_e ps_ptwrite (struct ps_prochandle *,
+			    psaddr_t, const void *, size_t);
+
+
+/* Get and set the given LWP's general or FPU register set.  */
+extern ps_err_e ps_lgetregs (struct ps_prochandle *,
+			     lwpid_t, prgregset_t);
+extern ps_err_e ps_lsetregs (struct ps_prochandle *,
+			     lwpid_t, const prgregset_t);
+extern ps_err_e ps_lgetfpregs (struct ps_prochandle *,
+			       lwpid_t, prfpregset_t *);
+extern ps_err_e ps_lsetfpregs (struct ps_prochandle *,
+			       lwpid_t, const prfpregset_t *);
+
+/* Return the PID of the process.  */
 extern pid_t ps_getpid (struct ps_prochandle *);
 
+/* Fetch the special per-thread address associated with the given LWP.
+   This call is only used on a few platforms (most use a normal register).
+   The meaning of the `int' parameter is machine-dependent.  */
+extern ps_err_e ps_get_thread_area (const struct ps_prochandle *,
+				    lwpid_t, int, psaddr_t *);
+
+
+/* Look up the named symbol in the named DSO in the symbol tables
+   associated with the process being debugged, filling in *SYM_ADDR
+   with the corresponding run-time address.  */
+extern ps_err_e ps_pglobal_lookup (struct ps_prochandle *,
+				   const char *object_name,
+				   const char *sym_name,
+				   psaddr_t *sym_addr);
 
+
+/* Stop or continue the entire process.  */
 extern ps_err_e ps_pstop (const struct ps_prochandle *);
 extern ps_err_e ps_pcontinue (const struct ps_prochandle *);
 
+/* Stop or continue the given LWP alone.  */
 extern ps_err_e ps_lstop (const struct ps_prochandle *, lwpid_t);
 extern ps_err_e ps_lcontinue (const struct ps_prochandle *, lwpid_t);
-
-extern ps_err_e ps_get_thread_area (const struct ps_prochandle *, lwpid_t,
-				    int, psaddr_t *);
diff --git a/nptl_db/structs.def b/nptl_db/structs.def
new file mode 100644
index 0000000000..c8b31bb7f5
--- /dev/null
+++ b/nptl_db/structs.def
@@ -0,0 +1,86 @@
+/* List of types and symbols in libpthread examined by libthread_db.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef DB_STRUCT_ARRAY_FIELD
+# define DB_STRUCT_ARRAY_FIELD(type, field) DB_STRUCT_FIELD (type, field)
+# define DB_ARRAY_VARIABLE(name) DB_VARIABLE (name)
+# define STRUCTS_DEF_DEFAULTS 1
+#endif
+
+DB_STRUCT (pthread)
+DB_STRUCT_FIELD (pthread, list)
+DB_STRUCT_FIELD (pthread, report_events)
+DB_STRUCT_FIELD (pthread, tid)
+DB_STRUCT_FIELD (pthread, start_routine)
+DB_STRUCT_FIELD (pthread, cancelhandling)
+DB_STRUCT_FIELD (pthread, schedpolicy)
+DB_STRUCT_FIELD (pthread, schedparam_sched_priority)
+DB_STRUCT_FIELD (pthread, specific)
+DB_STRUCT_FIELD (pthread, eventbuf)
+DB_STRUCT_FIELD (pthread, eventbuf_eventmask)
+DB_STRUCT_ARRAY_FIELD (pthread, eventbuf_eventmask_event_bits)
+DB_STRUCT_FIELD (pthread, nextevent)
+
+DB_STRUCT (list_t)
+DB_STRUCT_FIELD (list_t, next)
+DB_STRUCT_FIELD (list_t, prev)
+
+DB_STRUCT (td_thr_events_t)
+DB_STRUCT_ARRAY_FIELD (td_thr_events_t, event_bits)
+
+DB_STRUCT (td_eventbuf_t)
+DB_STRUCT_FIELD (td_eventbuf_t, eventnum)
+DB_STRUCT_FIELD (td_eventbuf_t, eventdata)
+
+DB_SYMBOL (stack_used)
+DB_SYMBOL (__stack_user)
+DB_SYMBOL (nptl_version)
+DB_SYMBOL (__nptl_create_event)
+DB_SYMBOL (__nptl_death_event)
+DB_SYMBOL (__nptl_threads_events)
+DB_VARIABLE (__nptl_nthreads)
+DB_VARIABLE (__nptl_last_event)
+
+DB_ARRAY_VARIABLE (__pthread_keys)
+DB_STRUCT (pthread_key_struct)
+DB_STRUCT_FIELD (pthread_key_struct, seq)
+DB_STRUCT_FIELD (pthread_key_struct, destr)
+
+DB_STRUCT (pthread_key_data)
+DB_STRUCT_FIELD (pthread_key_data, seq)
+DB_STRUCT_FIELD (pthread_key_data, data)
+DB_STRUCT (pthread_key_data_level2)
+DB_STRUCT_ARRAY_FIELD (pthread_key_data_level2, data)
+
+#if USE_TLS
+DB_STRUCT_FIELD (link_map, l_tls_modid)
+#endif
+
+#if !defined IS_IN_libpthread || USE_TLS
+DB_STRUCT_ARRAY_FIELD (dtv, dtv)
+#endif
+#if !defined IS_IN_libpthread || TLS_TCB_AT_TP
+DB_STRUCT_FIELD (pthread, dtvp)
+#endif
+
+#ifdef STRUCTS_DEF_DEFAULTS
+# undef DB_STRUCT_ARRAY_FIELD
+# undef DB_ARRAY_VARIABLE
+# undef STRUCTS_DEF_DEFAULTS
+#endif
diff --git a/nptl_db/td_symbol_list.c b/nptl_db/td_symbol_list.c
index 252faa418d..061767eb74 100644
--- a/nptl_db/td_symbol_list.c
+++ b/nptl_db/td_symbol_list.c
@@ -25,17 +25,26 @@
 
 static const char *symbol_list_arr[] =
 {
-  [SYM_PTHREAD_THREADS_EVENTS] = "__nptl_threads_events",
-  [SYM_PTHREAD_LAST_EVENT] = "__nptl_last_event",
-  [SYM_PTHREAD_NTHREADS] = "__nptl_nthreads",
-  [SYM_PTHREAD_STACK_USED] = "stack_used",
-  [SYM_PTHREAD_STACK_USER] = "__stack_user",
-  [SYM_PTHREAD_KEYS] = "__pthread_keys",
-  [SYM_PTHREAD_KEYS_MAX] = "__pthread_pthread_keys_max",
-  [SYM_PTHREAD_SIZEOF_DESCR] = "__pthread_pthread_sizeof_descr",
-  [SYM_PTHREAD_CREATE_EVENT] = "__nptl_create_event",
-  [SYM_PTHREAD_DEATH_EVENT] = "__nptl_death_event",
-  [SYM_PTHREAD_VERSION] = "nptl_version",
+# define DB_STRUCT(type) \
+  [SYM_SIZEOF_##type] = "_thread_db_sizeof_" #type,
+# define DB_STRUCT_FIELD(type, field) \
+  [SYM_##type##_FIELD_##field] = "_thread_db_" #type "_" #field,
+# define DB_SYMBOL(name) \
+  [SYM_##name] = #name,
+# define DB_VARIABLE(name) \
+  [SYM_##name] = #name, \
+  [SYM_DESC_##name] = "_thread_db_" #name,
+# include "structs.def"
+# undef DB_STRUCT
+# undef DB_SYMBOL
+# undef DB_VARIABLE
+
+  [SYM_TH_UNIQUE_CONST_THREAD_AREA] = "_thread_db_const_thread_area",
+  [SYM_TH_UNIQUE_REGISTER64] = "_thread_db_register64",
+  [SYM_TH_UNIQUE_REGISTER32] = "_thread_db_register32",
+  [SYM_TH_UNIQUE_REGISTER32_THREAD_AREA] = "_thread_db_register32_thread_area",
+  [SYM_TH_UNIQUE_REGISTER64_THREAD_AREA] = "_thread_db_register64_thread_area",
+
   [SYM_NUM_MESSAGES] = NULL
 };
 
@@ -47,7 +56,7 @@ td_symbol_list (void)
 }
 
 
-int
+ps_err_e
 td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr)
 {
   assert (idx >= 0 && idx < SYM_NUM_MESSAGES);
diff --git a/nptl_db/td_ta_clear_event.c b/nptl_db/td_ta_clear_event.c
index 611281fbaa..d45d75ba83 100644
--- a/nptl_db/td_ta_clear_event.c
+++ b/nptl_db/td_ta_clear_event.c
@@ -1,5 +1,5 @@
 /* Globally disable events.
-   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -22,31 +22,58 @@
 
 
 td_err_e
-td_ta_clear_event (ta, event)
-     const td_thragent_t *ta;
+td_ta_clear_event (ta_arg, event)
+     const td_thragent_t *ta_arg;
      td_thr_events_t *event;
 {
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t eventmask;
+  void *copy;
+
   LOG ("td_ta_clear_event");
 
   /* Test whether the TA parameter is ok.  */
   if (! ta_ok (ta))
     return TD_BADTA;
 
-  /* Write the new value into the thread data structure.  */
-  td_thr_events_t old_event;
-  if (ps_pdread (ta->ph, ta->pthread_threads_eventsp,
-		 &old_event, sizeof (td_thrhandle_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
-
-  /* Remove the set bits in.  */
-  int i;
-  for (i = 0; i < TD_EVENTSIZE; ++i)
-    old_event.event_bits[i] &= ~event->event_bits[i];
-
-  /* Write the new value into the thread data structure.  */
-  if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp,
-		  &old_event, sizeof (td_thrhandle_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  /* Fetch the old event mask from the inferior and modify it in place.  */
+  err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t);
+  if (err == TD_OK)
+    {
+      uint32_t idx;
+      for (idx = 0; idx < TD_EVENTSIZE; ++idx)
+	{
+	  psaddr_t word;
+	  uint32_t mask;
+	  err = DB_GET_FIELD_LOCAL (word, ta, copy,
+				    td_thr_events_t, event_bits, idx);
+	  if (err != TD_OK)
+	    break;
+	  mask = (uintptr_t) word;
+	  mask &= ~event->event_bits[idx];
+	  word = (psaddr_t) (uintptr_t) mask;
+	  err = DB_PUT_FIELD_LOCAL (ta, copy,
+				    td_thr_events_t, event_bits, idx, word);
+	  if (err != TD_OK)
+	    break;
+	}
+      if (err == TD_NOAPLIC)
+	{
+	  err = TD_OK;
+	  while (idx < TD_EVENTSIZE)
+	    if (event->event_bits[idx++] != 0)
+	      {
+		err = TD_NOEVENT;
+		break;
+	      }
+	}
+      if (err == TD_OK)
+	/* Now write it back to the inferior.  */
+	err = DB_PUT_STRUCT (ta, eventmask, td_thr_events_t, copy);
+    }
 
-  return TD_OK;
+  return err;
 }
diff --git a/nptl_db/td_ta_event_addr.c b/nptl_db/td_ta_event_addr.c
index 906835dc73..37196e643f 100644
--- a/nptl_db/td_ta_event_addr.c
+++ b/nptl_db/td_ta_event_addr.c
@@ -1,5 +1,5 @@
 /* Get event address.
-   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -22,10 +22,12 @@
 
 
 td_err_e
-td_ta_event_addr (const td_thragent_t *ta, td_event_e event, td_notify_t *addr)
+td_ta_event_addr (const td_thragent_t *ta_arg,
+		  td_event_e event, td_notify_t *addr)
 {
-  td_err_e res = TD_NOEVENT;
-  int idx = -1;
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t taddr;
 
   LOG ("td_ta_event_addr");
 
@@ -36,34 +38,24 @@ td_ta_event_addr (const td_thragent_t *ta, td_event_e event, td_notify_t *addr)
   switch (event)
     {
     case TD_CREATE:
-      idx = SYM_PTHREAD_CREATE_EVENT;
+      err = DB_GET_SYMBOL (taddr, ta, __nptl_create_event);
       break;
 
     case TD_DEATH:
-      idx = SYM_PTHREAD_DEATH_EVENT;
+      err = DB_GET_SYMBOL (taddr, ta, __nptl_death_event);
       break;
 
     default:
       /* Event cannot be handled.  */
-      break;
+      return TD_NOEVENT;
     }
 
-  /* Now get the address.  */
-  if (idx != -1)
+  if (err == TD_OK)
     {
-      psaddr_t taddr;
-
-      if (td_lookup (ta->ph, idx, &taddr) == PS_OK)
-	{
-	  /* Success, we got the address.  */
-	  addr->type = NOTIFY_BPT;
-	  addr->u.bptaddr = taddr;
-
-	  res = TD_OK;
-	}
-      else
-	res = TD_ERR;
+      /* Success, we got the address.  */
+      addr->type = NOTIFY_BPT;
+      addr->u.bptaddr = taddr;
     }
 
-  return res;
+  return err;
 }
diff --git a/nptl_db/td_ta_event_getmsg.c b/nptl_db/td_ta_event_getmsg.c
index bab44cddda..6e68ff4ff2 100644
--- a/nptl_db/td_ta_event_getmsg.c
+++ b/nptl_db/td_ta_event_getmsg.c
@@ -25,76 +25,81 @@
 
 
 td_err_e
-td_ta_event_getmsg (const td_thragent_t *ta, td_event_msg_t *msg)
+td_ta_event_getmsg (const td_thragent_t *ta_arg, td_event_msg_t *msg)
 {
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t eventbuf, eventnum, eventdata;
+  psaddr_t thp, next;
+  void *copy;
+
   /* XXX I cannot think of another way but using a static variable.  */
   /* XXX Use at least __thread once it is possible.  */
   static td_thrhandle_t th;
 
-  LOG ("td_ta_event_getmsg");
+  LOG ("td_thr_event_getmsg");
 
   /* Test whether the TA parameter is ok.  */
   if (! ta_ok (ta))
     return TD_BADTA;
 
   /* Get the pointer to the thread descriptor with the last event.  */
-  psaddr_t addr;
-  if (ps_pdread (ta->ph, ta->pthread_last_event,
-		 &addr, sizeof (struct pthread *)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  err = DB_GET_VALUE (thp, ta, __nptl_last_event, 0);
+  if (err != TD_OK)
+    return err;
 
-  if (addr == 0)
+  if (thp == 0)
     /* Nothing waiting.  */
     return TD_NOMSG;
 
-  /* Read the event structure from the target.  */
-  td_eventbuf_t event;
-  if (ps_pdread (ta->ph, (char *) addr + offsetof (struct pthread, eventbuf),
-		 &event, sizeof (td_eventbuf_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
-
+  /* Copy the event message buffer in from the inferior.  */
+  err = DB_GET_FIELD_ADDRESS (eventbuf, ta, thp, pthread, eventbuf, 0);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, ta, eventbuf, td_eventbuf_t);
+  if (err != TD_OK)
+    return err;
+
+  /* Read the event details from the target thread.  */
+  err = DB_GET_FIELD_LOCAL (eventnum, ta, copy, td_eventbuf_t, eventnum, 0);
+  if (err != TD_OK)
+    return err;
   /* If the structure is on the list there better be an event recorded.  */
-  if (event.eventnum == TD_EVENT_NONE)
+  if ((int) (uintptr_t) eventnum == TD_EVENT_NONE)
     return TD_DBERR;
 
+  /* Fill the user's data structure.  */
+  err = DB_GET_FIELD_LOCAL (eventdata, ta, copy, td_eventbuf_t, eventdata, 0);
+  if (err != TD_OK)
+    return err;
+
   /* Generate the thread descriptor.  */
   th.th_ta_p = (td_thragent_t *) ta;
-  th.th_unique = addr;
+  th.th_unique = thp;
 
   /* Fill the user's data structure.  */
-  msg->event = event.eventnum;
+  msg->msg.data = (uintptr_t) eventdata;
+  msg->event = (uintptr_t) eventnum;
   msg->th_p = &th;
-  msg->msg.data = (uintptr_t) event.eventdata;
 
   /* And clear the event message in the target.  */
-  memset (&event, '\0', sizeof (td_eventbuf_t));
-  if (ps_pdwrite (ta->ph, (char *) addr + offsetof (struct pthread, eventbuf),
-		  &event, sizeof (td_eventbuf_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  memset (copy, 0, ta->ta_sizeof_td_eventbuf_t);
+  err = DB_PUT_STRUCT (ta, eventbuf, td_eventbuf_t, copy);
+  if (err != TD_OK)
+    return err;
 
   /* Get the pointer to the next descriptor with an event.  */
-  psaddr_t next;
-  if (ps_pdread (ta->ph, (char *) addr + offsetof (struct pthread, nextevent),
-		 &next, sizeof (struct pthread *)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
-
-  if (next == addr)
-    return TD_DBERR;
+  err = DB_GET_FIELD (next, ta, thp, pthread, nextevent, 0);
+  if (err != TD_OK)
+    return err;
 
   /* Store the pointer in the list head variable.  */
-  if (ps_pdwrite (ta->ph, ta->pthread_last_event,
-		  &next, sizeof (struct pthread *)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
-
-  if (next != NULL)
-    {
-      /* Clear the next pointer in the current descriptor.  */
-      next = NULL;
-      if (ps_pdwrite (ta->ph,
-		      (char *) addr + offsetof (struct pthread, nextevent),
-		      &next, sizeof (struct pthread *)) != PS_OK)
-	return TD_ERR;	/* XXX Other error value?  */
-    }
-
-  return TD_OK;
+  err = DB_PUT_VALUE (ta, __nptl_last_event, 0, next);
+  if (err != TD_OK)
+    return err;
+
+  if (next != 0)
+    /* Clear the next pointer in the current descriptor.  */
+    err = DB_PUT_FIELD (ta, thp, pthread, nextevent, 0, 0);
+
+  return err;
 }
diff --git a/nptl_db/td_ta_get_nthreads.c b/nptl_db/td_ta_get_nthreads.c
index cfe93d1b19..ffe78bd57e 100644
--- a/nptl_db/td_ta_get_nthreads.c
+++ b/nptl_db/td_ta_get_nthreads.c
@@ -1,5 +1,5 @@
 /* Get the number of threads in the process.
-   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -21,21 +21,22 @@
 #include "thread_dbP.h"
 
 td_err_e
-td_ta_get_nthreads (const td_thragent_t *ta, int *np)
+td_ta_get_nthreads (const td_thragent_t *ta_arg, int *np)
 {
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t n;
+
   LOG ("td_ta_get_nthreads");
 
   /* Test whether the TA parameter is ok.  */
   if (! ta_ok (ta))
     return TD_BADTA;
 
-  /* Access the variable `__pthread_handles_num'.  */
-  psaddr_t addr;
-  if (td_lookup (ta->ph, SYM_PTHREAD_NTHREADS, &addr) != PS_OK)
-     return TD_ERR;	/* XXX Other error value?  */
-
-  if (ps_pdread (ta->ph, addr, np, sizeof (int)) != PS_OK)
-     return TD_ERR;	/* XXX Other error value?  */
+  /* Access the variable in the inferior that tells us.  */
+  err = DB_GET_VALUE (n, ta, __nptl_nthreads, 0);
+  if (err == TD_OK)
+    *np = (uintptr_t) n;
 
-  return TD_OK;
+  return err;
 }
diff --git a/nptl_db/td_ta_map_lwp2thr.c b/nptl_db/td_ta_map_lwp2thr.c
new file mode 100644
index 0000000000..1e47528314
--- /dev/null
+++ b/nptl_db/td_ta_map_lwp2thr.c
@@ -0,0 +1,179 @@
+/* Which thread is running on an LWP?
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "thread_dbP.h"
+#include <stdlib.h>
+#include <byteswap.h>
+#include <sys/procfs.h>
+
+
+td_err_e
+td_ta_map_lwp2thr (const td_thragent_t *ta_arg,
+		   lwpid_t lwpid, td_thrhandle_t *th)
+{
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  ps_err_e err;
+  td_err_e terr;
+  prgregset_t regs;
+  psaddr_t addr;
+
+  LOG ("td_ta_map_lwp2thr");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  if (ta->ta_howto == ta_howto_unknown)
+    {
+      /* We need to read in from the inferior the instructions what to do.  */
+      psaddr_t howto;
+
+      err = td_lookup (ta->ph, SYM_TH_UNIQUE_CONST_THREAD_AREA, &howto);
+      if (err == PS_OK)
+	{
+	  err = ps_pdread (ta->ph, howto,
+			   &ta->ta_howto_data.const_thread_area,
+ 			   sizeof ta->ta_howto_data.const_thread_area);
+	  if (err != PS_OK)
+	    return TD_ERR;
+	  ta->ta_howto = ta_howto_const_thread_area;
+	  if (ta->ta_howto_data.const_thread_area & 0xff000000U)
+	    ta->ta_howto_data.const_thread_area
+	      = bswap_32 (ta->ta_howto_data.const_thread_area);
+	}
+      else
+	{
+	  switch (sizeof (regs[0]))
+	    {
+	    case 8:
+	      err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER64, &howto);
+	      if (err == PS_OK)
+		ta->ta_howto = ta_howto_reg;
+	      else if (err == PS_NOSYM)
+		{
+		  err = td_lookup (ta->ph,
+				   SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
+				   &howto);
+		  if (err == PS_OK)
+		    ta->ta_howto = ta_howto_reg_thread_area;
+		}
+	      break;
+
+	    case 4:
+	      err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER32, &howto);
+	      if (err == PS_OK)
+		ta->ta_howto = ta_howto_reg;
+	      else if (err == PS_NOSYM)
+		{
+		  err = td_lookup (ta->ph,
+				   SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
+				   &howto);
+		  if (err == PS_OK)
+		    ta->ta_howto = ta_howto_reg_thread_area;
+		}
+	      break;
+
+	    default:
+	      abort ();
+	      return TD_DBERR;
+	    }
+
+	  if (err != PS_OK)
+	    return TD_DBERR;
+
+	  /* For either of these methods we read in the same descriptor.  */
+	  err = ps_pdread (ta->ph, howto,
+			   ta->ta_howto_data.reg, DB_SIZEOF_DESC);
+	  if (err != PS_OK)
+	    return TD_ERR;
+	  if (DB_DESC_SIZE (ta->ta_howto_data.reg) == 0)
+	    return TD_DBERR;
+	  if (DB_DESC_SIZE (ta->ta_howto_data.reg) & 0xff000000U)
+	    {
+	      /* Byte-swap these words, though we leave the size word
+		 in native order as the handy way to distinguish.  */
+	      DB_DESC_OFFSET (ta->ta_howto_data.reg)
+		= bswap_32 (DB_DESC_OFFSET (ta->ta_howto_data.reg));
+	      DB_DESC_NELEM (ta->ta_howto_data.reg)
+		= bswap_32 (DB_DESC_NELEM (ta->ta_howto_data.reg));
+	    }
+	}
+    }
+
+  switch (ta->ta_howto)
+    {
+    case ta_howto_unknown:
+      return TD_DBERR;
+
+    default:
+      abort ();
+      return TD_DBERR;
+
+    case ta_howto_reg:
+      /* On most machines, we are just looking at a register.  */
+      if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
+	return TD_ERR;
+      terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg, -1,
+				    0, regs, &addr);
+      if (terr != TD_OK)
+	return terr;
+      /* In this descriptor the nelem word is overloaded as the bias.  */
+      addr += (int32_t) DB_DESC_NELEM (ta->ta_howto_data.reg);
+      th->th_unique = addr;
+      break;
+
+    case ta_howto_const_thread_area:
+      /* Some hosts don't have this call and this case won't be used.  */
+# pragma weak ps_get_thread_area
+      if (&ps_get_thread_area == NULL)
+	return TD_NOCAPAB;
+
+       /* A la x86-64, there is a constant magic index for get_thread_area.  */
+       if (ps_get_thread_area (ta->ph, lwpid,
+			       ta->ta_howto_data.const_thread_area,
+			       &th->th_unique) != PS_OK)
+	 return TD_ERR;	/* XXX Other error value?  */
+       break;
+
+     case ta_howto_reg_thread_area:
+      if (&ps_get_thread_area == NULL)
+	return TD_NOCAPAB;
+
+       /* A la i386, there is a register with an index for get_thread_area.  */
+       if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
+	 return TD_ERR;
+       terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg_thread_area, -1,
+				     0, regs, &addr);
+      if (terr != TD_OK)
+	return terr;
+      /* In this descriptor the nelem word is overloaded as scale factor.  */
+      if (ps_get_thread_area
+	  (ta->ph, lwpid,
+	   ((addr - (psaddr_t) 0)
+	    >> DB_DESC_NELEM (ta->ta_howto_data.reg_thread_area)),
+	   &th->th_unique) != PS_OK)
+	return TD_ERR;	/* XXX Other error value?  */
+      break;
+    }
+
+  /* Found it.  Now complete the `td_thrhandle_t' object.  */
+  th->th_ta_p = (td_thragent_t *) ta;
+
+  return TD_OK;
+}
diff --git a/nptl_db/td_ta_new.c b/nptl_db/td_ta_new.c
index de564edfd8..f84049af34 100644
--- a/nptl_db/td_ta_new.c
+++ b/nptl_db/td_ta_new.c
@@ -1,5 +1,5 @@
 /* Attach to target process.
-   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -34,30 +34,23 @@ LIST_HEAD (__td_agent_list);
 td_err_e
 td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
 {
-  psaddr_t addr;
   psaddr_t versaddr;
   char versbuf[sizeof (VERSION)];
 
   LOG ("td_ta_new");
 
-  /* Get the global event mask.  This is one of the variables which
-     are new in the thread library to enable debugging.  If it is
-     not available we cannot debug.  */
-  if (td_lookup (ps, SYM_PTHREAD_THREADS_EVENTS, &addr) != PS_OK)
-    return TD_NOLIBTHREAD;
-
   /* Check whether the versions match.  */
-  if (td_lookup (ps, SYM_PTHREAD_VERSION, &versaddr) != PS_OK)
-    return TD_VERSION;
+  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 (versbuf[sizeof (versbuf) - 1] != '\0' || strcmp (versbuf, VERSION) != 0)
+  if (memcmp (versbuf, VERSION, sizeof VERSION) != 0)
     /* Not the right version.  */
     return TD_VERSION;
 
   /* Fill in the appropriate information.  */
-  *ta = (td_thragent_t *) malloc (sizeof (td_thragent_t));
+  *ta = (td_thragent_t *) calloc (1, sizeof (td_thragent_t));
   if (*ta == NULL)
     return TD_MALLOC;
 
@@ -65,49 +58,6 @@ td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
      back into the debugger.  */
   (*ta)->ph = ps;
 
-  /* Remember the address.  */
-  (*ta)->pthread_threads_eventsp = (td_thr_events_t *) addr;
-
-  /* Get the pointer to the variable pointing to the thread descriptor
-     with the last event.  */
-  if (td_lookup (ps, SYM_PTHREAD_LAST_EVENT, &(*ta)->pthread_last_event)
-      != PS_OK)
-    {
-    free_return:
-      free (*ta);
-      return TD_ERR;
-    }
-
-
-  if (td_lookup (ps, SYM_PTHREAD_STACK_USER, &addr) != PS_OK)
-    goto free_return;
-  /* Cast to the right type.  */
-  (*ta)->stack_user = (list_t *) addr;
-
-  if (td_lookup (ps, SYM_PTHREAD_STACK_USED, &addr) != PS_OK)
-    goto free_return;
-  /* Cast to the right type.  */
-  (*ta)->stack_used = (list_t *) addr;
-
-
-  if (td_lookup (ps, SYM_PTHREAD_KEYS, &addr) != PS_OK)
-    goto free_return;
-  /* Cast to the right type.  */
-  (*ta)->keys = (struct pthread_key_struct *) addr;
-
-
-  /* Similarly for the maximum number of thread local data keys.  */
-  if (td_lookup (ps, SYM_PTHREAD_KEYS_MAX, &addr) != PS_OK
-      || ps_pdread (ps, addr, &(*ta)->pthread_keys_max, sizeof (int)) != PS_OK)
-    goto free_return;
-
-
-  /* And for the size of the second level arrays for the keys.  */
-  if (td_lookup (ps, SYM_PTHREAD_SIZEOF_DESCR, &addr) != PS_OK
-      || ps_pdread (ps, addr, &(*ta)->sizeof_descr, sizeof (int)) != PS_OK)
-    goto free_return;
-
-
   /* Now add the new agent descriptor to the list.  */
   list_add (&(*ta)->list, &__td_agent_list);
 
diff --git a/nptl_db/td_ta_set_event.c b/nptl_db/td_ta_set_event.c
index 5e2cca795d..4fcc934a6b 100644
--- a/nptl_db/td_ta_set_event.c
+++ b/nptl_db/td_ta_set_event.c
@@ -1,5 +1,5 @@
 /* Globally enable events.
-   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -22,31 +22,58 @@
 
 
 td_err_e
-td_ta_set_event (ta, event)
-     const td_thragent_t *ta;
+td_ta_set_event (ta_arg, event)
+     const td_thragent_t *ta_arg;
      td_thr_events_t *event;
 {
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t eventmask;
+  void *copy;
+
   LOG ("td_ta_set_event");
 
   /* Test whether the TA parameter is ok.  */
   if (! ta_ok (ta))
     return TD_BADTA;
 
-  /* Write the new value into the thread data structure.  */
-  td_thr_events_t old_event;
-  if (ps_pdread (ta->ph, ta->pthread_threads_eventsp,
-		 &old_event, sizeof (td_thrhandle_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
-
-  /* Or the new bits in.  */
-  int i;
-  for (i = 0; i < TD_EVENTSIZE; ++i)
-    old_event.event_bits[i] |= event->event_bits[i];
-
-  /* Write the new value into the thread data structure.  */
-  if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp,
-		  &old_event, sizeof (td_thrhandle_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  /* Fetch the old event mask from the inferior and modify it in place.  */
+  err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t);
+  if (err == TD_OK)
+    {
+      uint32_t idx;
+      for (idx = 0; idx < TD_EVENTSIZE; ++idx)
+	{
+	  psaddr_t word;
+	  uint32_t mask;
+	  err = DB_GET_FIELD_LOCAL (word, ta, copy,
+				    td_thr_events_t, event_bits, idx);
+	  if (err != TD_OK)
+	    break;
+	  mask = (uintptr_t) word;
+	  mask |= event->event_bits[idx];
+	  word = (psaddr_t) (uintptr_t) mask;
+	  err = DB_PUT_FIELD_LOCAL (ta, copy,
+				    td_thr_events_t, event_bits, idx, word);
+	  if (err != TD_OK)
+	    break;
+	}
+      if (err == TD_NOAPLIC)
+	{
+	  err = TD_OK;
+	  while (idx < TD_EVENTSIZE)
+	    if (event->event_bits[idx++] != 0)
+	      {
+		err = TD_NOEVENT;
+		break;
+	      }
+	}
+      if (err == TD_OK)
+	/* Now write it back to the inferior.  */
+	err = DB_PUT_STRUCT (ta, eventmask, td_thr_events_t, copy);
+    }
 
-  return TD_OK;
+  return err;
 }
diff --git a/nptl_db/td_ta_thr_iter.c b/nptl_db/td_ta_thr_iter.c
index 6348a97d14..18c5f2e76d 100644
--- a/nptl_db/td_ta_thr_iter.c
+++ b/nptl_db/td_ta_thr_iter.c
@@ -19,102 +19,108 @@
    02111-1307 USA.  */
 
 #include "thread_dbP.h"
-#include <nptl/descr.h>
 
 
 static td_err_e
-iterate_thread_list (const td_thragent_t *ta, td_thr_iter_f *callback,
+iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback,
 		     void *cbdata_p, td_thr_state_e state, int ti_pri,
-		     psaddr_t head)
+		     psaddr_t head, int fake_empty)
 {
-  list_t list;
-  td_err_e result = TD_OK;
+  td_err_e err;
+  psaddr_t next, ofs;
+  void *copy;
 
   /* Test the state.
      XXX This is incomplete.  Normally this test should be in the loop.  */
   if (state != TD_THR_ANY_STATE)
     return TD_OK;
 
-  if (ps_pdread (ta->ph, head, &list, sizeof (list_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  err = DB_GET_FIELD (next, ta, head, list_t, next, 0);
+  if (err != TD_OK)
+    return err;
 
-  if (list.next == 0 && list.prev == 0 && head == ta->stack_user)
+  if (next == 0 && fake_empty)
     {
       /* __pthread_initialize_minimal has not run.
 	 There is just the main thread to return.  */
       td_thrhandle_t th;
-      td_err_e err = td_ta_map_lwp2thr (ta, ps_getpid (ta->ph), &th);
-      return (err != TD_OK ? err
-	      : callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK);
+      err = td_ta_map_lwp2thr (ta, ps_getpid (ta->ph), &th);
+      if (err == TD_OK)
+	err = callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK;
+      return err;
     }
 
-  while (list.next != head)
+  /* Cache the offset from struct pthread to its list_t member.  */
+  err = DB_GET_FIELD_ADDRESS (ofs, ta, 0, pthread, list, 0);
+  if (err != TD_OK)
+    return err;
+
+  if (ta->ta_sizeof_pthread == 0)
     {
-      psaddr_t addr = ((psaddr_t) list.next - offsetof (struct pthread, list));
+      err = _td_check_sizeof (ta, &ta->ta_sizeof_pthread, SYM_SIZEOF_pthread);
+      if (err != TD_OK)
+	return err;
+    }
+  copy = __alloca (ta->ta_sizeof_pthread);
 
-      int schedpolicy;
-      if (ps_pdread (ta->ph, &((struct pthread *) addr)->schedpolicy,
-		     &schedpolicy, sizeof (int)) != PS_OK)
-	{
-	  result = TD_ERR;	/* XXX Other error value?  */
-	  break;
-	}
+  while (next != head)
+    {
+      psaddr_t addr, schedpolicy, schedprio;
 
-      struct sched_param schedparam;
-      if (ps_pdread (ta->ph, &((struct pthread *) addr)->schedparam,
-		     &schedparam, sizeof (struct sched_param)) != PS_OK)
-	{
-	  result = TD_ERR;	/* XXX Other error value?  */
-	  break;
-	}
+      addr = next - (ofs - (psaddr_t) 0);
+      if (next == 0 || addr == 0) /* Sanity check.  */
+	return TD_DBERR;
+
+      /* Copy the whole descriptor in once so we can access the several
+	 fields locally.  Excess copying in one go is much better than
+	 multiple ps_pdread calls.  */
+      if (ps_pdread (ta->ph, addr, copy, ta->ta_sizeof_pthread) != PS_OK)
+	return TD_ERR;
+
+      err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread,
+				schedpolicy, 0);
+      if (err != TD_OK)
+	break;
+      err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread,
+				schedparam_sched_priority, 0);
+      if (err != TD_OK)
+	break;
 
-      /* Now test whether this thread matches the specified
-	 conditions.  */
+      /* Now test whether this thread matches the specified conditions.  */
 
       /* Only if the priority level is as high or higher.  */
-      int descr_pri = (schedpolicy == SCHED_OTHER
-		       ? 0 : schedparam.sched_priority);
+      int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER
+		       ? 0 : (uintptr_t) schedprio);
       if (descr_pri >= ti_pri)
 	{
-	  /* XXX For now we ignore threads which are not running anymore.
-	     The reason is that gdb tries to get the registers and fails.
-	     In future we should have a special mode of the thread library
-	     in which we keep the process around until the actual join
-	     operation happened.  */
-	  int cancelhandling;
-	  if (ps_pdread (ta->ph, &((struct pthread *) addr)->cancelhandling,
-			 &cancelhandling, sizeof (int)) != PS_OK)
-	    {
-	      result = TD_ERR;	/* XXX Other error value?  */
-	      break;
-	    }
-
-	  if ((cancelhandling & TERMINATED_BITMASK) == 0)
-	    {
-	      /* Yep, it matches.  Call the callback function.  */
-	      td_thrhandle_t th;
-	      th.th_ta_p = (td_thragent_t *) ta;
-	      th.th_unique = addr;
-	      if (callback (&th, cbdata_p) != 0)
-		return TD_DBERR;
-	    }
+	  /* Yep, it matches.  Call the callback function.  */
+	  td_thrhandle_t th;
+	  th.th_ta_p = (td_thragent_t *) ta;
+	  th.th_unique = addr;
+	  if (callback (&th, cbdata_p) != 0)
+	    return TD_DBERR;
 	}
 
       /* Get the pointer to the next element.  */
-      if (ps_pdread (ta->ph, &((struct pthread *) addr)->list,
-		     &list, sizeof (list_t)) != PS_OK)
-	return TD_ERR;	/* XXX Other error value?  */
+      err = DB_GET_FIELD_LOCAL (next, ta, copy + (ofs - (psaddr_t) 0), list_t,
+				next, 0);
+      if (err != TD_OK)
+	break;
     }
 
-  return result;
+  return err;
 }
 
 
 td_err_e
-td_ta_thr_iter (const td_thragent_t *ta, td_thr_iter_f *callback,
+td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback,
 		void *cbdata_p, td_thr_state_e state, int ti_pri,
 		sigset_t *ti_sigmask_p, unsigned int ti_user_flags)
 {
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  psaddr_t list;
+
   LOG ("td_ta_thr_iter");
 
   /* Test whether the TA parameter is ok.  */
@@ -127,13 +133,16 @@ td_ta_thr_iter (const td_thragent_t *ta, td_thr_iter_f *callback,
      threads for which the thread library allocated the stacks.  We
      have to iterate over both lists separately.  We start with the
      list of threads with user-defined stacks.  */
-  td_err_e result = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
-					 ta->stack_user);
+
+  err = DB_GET_SYMBOL (list, ta, __stack_user);
+  if (err == TD_OK)
+    err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, list, 1);
 
   /* And the threads with stacks allocated by the implementation.  */
-  if (result == TD_OK)
-    result = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
-				  ta->stack_used);
+  if (err == TD_OK)
+    err = DB_GET_SYMBOL (list, ta, stack_used);
+  if (err == TD_OK)
+    err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, list, 0);
 
-  return result;
+  return err;
 }
diff --git a/nptl_db/td_ta_tsd_iter.c b/nptl_db/td_ta_tsd_iter.c
index cbc2f37c51..9cfb1e8de0 100644
--- a/nptl_db/td_ta_tsd_iter.c
+++ b/nptl_db/td_ta_tsd_iter.c
@@ -1,5 +1,5 @@
 /* Iterate over a process's thread-specific data.
-   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999,2000,2001,2002,2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -22,32 +22,60 @@
 #include <alloca.h>
 
 td_err_e
-td_ta_tsd_iter (const td_thragent_t *ta, td_key_iter_f *callback,
+td_ta_tsd_iter (const td_thragent_t *ta_arg, td_key_iter_f *callback,
 		void *cbdata_p)
 {
+  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
+  td_err_e err;
+  void *keys;
+  size_t keys_nb, keys_elemsize;
+  psaddr_t addr;
+  uint32_t idx;
+
   LOG ("td_ta_tsd_iter");
 
   /* Test whether the TA parameter is ok.  */
   if (! ta_ok (ta))
     return TD_BADTA;
 
-  int pthread_keys_max = ta->pthread_keys_max;
-  struct pthread_key_struct *keys;
-  keys = (struct pthread_key_struct *) alloca (sizeof (keys[0])
-					       * pthread_keys_max);
+  /* This makes sure we have the size information on hand.  */
+  addr = 0;
+  err = _td_locate_field (ta,
+			  ta->ta_var___pthread_keys, SYM_DESC___pthread_keys,
+			  (psaddr_t) 0 + 1, &addr);
+  if (err != TD_OK)
+    return err;
 
-  /* Read all the information about the keys.  */
-  if (ps_pdread (ta->ph, ta->keys, keys,
-		 sizeof (keys[0]) * pthread_keys_max) != PS_OK)
-	return TD_ERR;	/* XXX Other error value?  */
+  /* Now copy in the entire array of key descriptors.  */
+  keys_elemsize = (addr - (psaddr_t) 0) / 8;
+  keys_nb = keys_elemsize * DB_DESC_NELEM (ta->ta_var___pthread_keys);
+  keys = __alloca (keys_nb);
+  err = DB_GET_SYMBOL (addr, ta, __pthread_keys);
+  if (err != TD_OK)
+    return err;
+  if (ps_pdread (ta->ph, addr, keys, keys_nb) != PS_OK)
+    return TD_ERR;
 
   /* Now get all descriptors, one after the other.  */
-  int cnt;
-  for (cnt = 0; cnt < pthread_keys_max; ++cnt)
-    if (!KEY_UNUSED (keys[cnt].seq)
-	/* Return with an error if the callback returns a nonzero value.  */
-	&& callback (cnt, keys[cnt].destr, cbdata_p) != 0)
-      return TD_DBERR;
+  for (idx = 0; idx < DB_DESC_NELEM (ta->ta_var___pthread_keys); ++idx)
+    {
+      psaddr_t seq, destr;
+      err = DB_GET_FIELD_LOCAL (seq, ta, keys, pthread_key_struct, seq, 0);
+      if (err != TD_OK)
+	return err;
+      if (((uintptr_t) seq) & 1)
+	{
+	  err = DB_GET_FIELD_LOCAL (destr, ta, keys, pthread_key_struct,
+				    destr, 0);
+	  if (err != TD_OK)
+	    return err;
+	  /* Return with an error if the callback returns a nonzero value.  */
+	  if (callback ((thread_key_t) idx, destr, cbdata_p) != 0)
+	    return TD_DBERR;
+	}
+      /* Advance to the next element in the copied array.  */
+      keys += keys_elemsize;
+    }
 
   return TD_OK;
 }
diff --git a/nptl_db/td_thr_clear_event.c b/nptl_db/td_thr_clear_event.c
index e729b52706..fc999df9c2 100644
--- a/nptl_db/td_thr_clear_event.c
+++ b/nptl_db/td_thr_clear_event.c
@@ -1,5 +1,5 @@
 /* Disable specific event for thread.
-   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -28,27 +28,50 @@ td_thr_clear_event (th, event)
      const td_thrhandle_t *th;
      td_thr_events_t *event;
 {
+  td_err_e err;
+  psaddr_t eventmask;
+  void *copy;
+
   LOG ("td_thr_clear_event");
 
-  /* Write the new value into the thread data structure.  */
-  td_thr_events_t old_event;
-  if (ps_pdread (th->th_ta_p->ph,
-		 ((char *) th->th_unique
-		  + offsetof (struct pthread, eventbuf.eventmask)),
-		 &old_event, sizeof (td_thrhandle_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
-
-  /* Remove the set bits in.  */
-  int i;
-  for (i = 0; i < TD_EVENTSIZE; ++i)
-    old_event.event_bits[i] &= ~event->event_bits[i];
-
-  /* Write the new value into the thread data structure.  */
-  if (ps_pdwrite (th->th_ta_p->ph,
-		  ((char *) th->th_unique
-		   + offsetof (struct pthread, eventbuf.eventmask)),
-		  &old_event, sizeof (td_thrhandle_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
-
-  return TD_OK;
+  /* Fetch the old event mask from the inferior and modify it in place.  */
+  err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
+			      th->th_unique, pthread, eventbuf_eventmask, 0);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t);
+  if (err == TD_OK)
+    {
+      uint32_t idx;
+      for (idx = 0; idx < TD_EVENTSIZE; ++idx)
+	{
+	  psaddr_t word;
+	  uint32_t mask;
+	  err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy,
+				    td_thr_events_t, event_bits, idx);
+	  if (err != TD_OK)
+	    break;
+	  mask = (uintptr_t) word;
+	  mask &= ~event->event_bits[idx];
+	  word = (psaddr_t) (uintptr_t) mask;
+	  err = DB_PUT_FIELD_LOCAL (th->th_ta_p, copy,
+				    td_thr_events_t, event_bits, idx, word);
+	  if (err != TD_OK)
+	    break;
+	}
+      if (err == TD_NOAPLIC)
+	{
+	  err = TD_OK;
+	  while (idx < TD_EVENTSIZE)
+	    if (event->event_bits[idx++] != 0)
+	      {
+		err = TD_NOEVENT;
+		break;
+	      }
+	}
+      if (err == TD_OK)
+	/* Now write it back to the inferior.  */
+	err = DB_PUT_STRUCT (th->th_ta_p, eventmask, td_thr_events_t, copy);
+    }
+
+  return err;
 }
diff --git a/nptl_db/td_thr_event_enable.c b/nptl_db/td_thr_event_enable.c
index badaab04d1..a02be5da44 100644
--- a/nptl_db/td_thr_event_enable.c
+++ b/nptl_db/td_thr_event_enable.c
@@ -18,8 +18,6 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <stddef.h>
-
 #include "thread_dbP.h"
 
 
@@ -31,12 +29,6 @@ td_thr_event_enable (th, onoff)
   LOG ("td_thr_event_enable");
 
   /* Write the new value into the thread data structure.  */
-  const bool value = onoff != 0;
-  if (ps_pdwrite (th->th_ta_p->ph,
-		  ((char *) th->th_unique
-		   + offsetof (struct pthread, report_events)),
-		  &value, sizeof value) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
-
-  return TD_OK;
+  return DB_PUT_FIELD (th->th_ta_p, th->th_unique, pthread, report_events, 0,
+		       (psaddr_t) 0 + (onoff != 0));
 }
diff --git a/nptl_db/td_thr_event_getmsg.c b/nptl_db/td_thr_event_getmsg.c
index 9008633289..70ea6953ed 100644
--- a/nptl_db/td_thr_event_getmsg.c
+++ b/nptl_db/td_thr_event_getmsg.c
@@ -18,60 +18,71 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <stddef.h>
-#include <string.h>
-
 #include "thread_dbP.h"
+#include <assert.h>
 
 
 td_err_e
 td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg)
 {
-  td_eventbuf_t event;
+  td_err_e err;
+  psaddr_t eventbuf, eventnum, eventdata;
+  psaddr_t thp, prevp;
+  void *copy;
 
   LOG ("td_thr_event_getmsg");
 
-  /* Read the event structure from the target.  */
-  if (ps_pdread (th->th_ta_p->ph,
-		 ((char *) th->th_unique
-		  + offsetof (struct pthread, eventbuf)),
-		 &event, sizeof (td_eventbuf_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  /* Copy the event message buffer in from the inferior.  */
+  err = DB_GET_FIELD_ADDRESS (eventbuf, th->th_ta_p, th->th_unique, pthread,
+			      eventbuf, 0);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, th->th_ta_p, eventbuf, td_eventbuf_t);
+  if (err != TD_OK)
+    return err;
 
   /* Check whether an event occurred.  */
-  if (event.eventnum == TD_EVENT_NONE)
+  err = DB_GET_FIELD_LOCAL (eventnum, th->th_ta_p, copy,
+			    td_eventbuf_t, eventnum, 0);
+  if (err != TD_OK)
+    return err;
+  if ((int) (uintptr_t) eventnum == TD_EVENT_NONE)
     /* Nothing.  */
     return TD_NOMSG;
 
   /* Fill the user's data structure.  */
-  msg->event = event.eventnum;
+  err = DB_GET_FIELD_LOCAL (eventdata, th->th_ta_p, copy,
+			    td_eventbuf_t, eventdata, 0);
+  if (err != TD_OK)
+    return err;
+
+  msg->msg.data = (uintptr_t) eventdata;
+  msg->event = (uintptr_t) eventnum;
   msg->th_p = th;
-  msg->msg.data = (uintptr_t) event.eventdata;
 
   /* And clear the event message in the target.  */
-  memset (&event, '\0', sizeof (td_eventbuf_t));
-  if (ps_pdwrite (th->th_ta_p->ph,
-		  ((char *) th->th_unique
-		   + offsetof (struct pthread, eventbuf)),
-		  &event, sizeof (td_eventbuf_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  memset (copy, 0, th->th_ta_p->ta_sizeof_td_eventbuf_t);
+  err = DB_PUT_STRUCT (th->th_ta_p, eventbuf, td_eventbuf_t, copy);
+  if (err != TD_OK)
+    return err;
 
   /* Get the pointer to the thread descriptor with the last event.
      If it doesn't match TH, then walk down the list until we find it.
      We must splice it out of the list so that there is no dangling
      pointer to it later when it dies.  */
-  psaddr_t thp, prevp = th->th_ta_p->pthread_last_event;
-  if (ps_pdread (th->th_ta_p->ph,
-		 prevp, &thp, sizeof (struct pthread *)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  err = DB_GET_SYMBOL (prevp, th->th_ta_p, __nptl_last_event);
+  if (err != TD_OK)
+    return err;
+  err = DB_GET_VALUE (thp, th->th_ta_p, __nptl_last_event, 0);
+  if (err != TD_OK)
+    return err;
 
-  psaddr_t next;
   while (thp != 0)
     {
-      if (ps_pdread (th->th_ta_p->ph,
-		     (char *) thp + offsetof (struct pthread, nextevent),
-		     &next, sizeof (struct pthread *)) != PS_OK)
-	return TD_ERR;	/* XXX Other error value?  */
+      psaddr_t next;
+      err = DB_GET_FIELD (next, th->th_ta_p, th->th_unique, pthread,
+			  nextevent, 0);
+      if (err != TD_OK)
+	return err;
 
       if (next == thp)
 	return TD_DBERR;
@@ -79,24 +90,27 @@ td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg)
       if (thp == th->th_unique)
 	{
 	  /* PREVP points at this thread, splice it out.  */
-	  if (prevp == (char *) next + offsetof (struct pthread, nextevent))
+	  psaddr_t next_nextp;
+	  err = DB_GET_FIELD_ADDRESS (next_nextp, th->th_ta_p, next, pthread,
+				      nextevent, 0);
+	  assert (err == TD_OK); /* We used this field before.  */
+	  if (prevp == next_nextp)
 	    return TD_DBERR;
 
-	  if (ps_pdwrite (th->th_ta_p->ph, prevp, &next, sizeof next) != PS_OK)
-	    return TD_ERR;	/* XXX Other error value?  */
+	  err = _td_store_value (th->th_ta_p,
+				 th->th_ta_p->ta_var___nptl_last_event, -1,
+				 0, prevp, next);
+	  if (err != TD_OK)
+	    return err;
 
 	  /* Now clear this thread's own next pointer so it's not dangling
 	     when the thread resumes and then chains on for its next event.  */
-	  next = NULL;
-	  if (ps_pdwrite (th->th_ta_p->ph,
-			  (char *) thp + offsetof (struct pthread, nextevent),
-			  &next, sizeof next) != PS_OK)
-	    return TD_ERR;	/* XXX Other error value?  */
-
-	  return TD_OK;
+	  return DB_PUT_FIELD (th->th_ta_p, thp, pthread, nextevent, 0, 0);
 	}
 
-      prevp = (char *) thp + offsetof (struct pthread, nextevent);
+      err = DB_GET_FIELD_ADDRESS (prevp, th->th_ta_p, thp, pthread,
+				  nextevent, 0);
+      assert (err == TD_OK); /* We used this field before.  */
       thp = next;
     }
 
diff --git a/nptl_db/td_thr_get_info.c b/nptl_db/td_thr_get_info.c
index 985c8d7a94..bb13888045 100644
--- a/nptl_db/td_thr_get_info.c
+++ b/nptl_db/td_thr_get_info.c
@@ -26,39 +26,85 @@
 td_err_e
 td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop)
 {
+  td_err_e err;
+  void *copy;
+  psaddr_t tls, schedpolicy, schedprio, cancelhandling, tid, report_events;
+
   LOG ("td_thr_get_info");
 
-  /* Get the thread descriptor.  */
-  struct pthread pds;
-  if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds,
-		 sizeof (struct pthread)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  /* Copy the whole descriptor in once so we can access the several
+     fields locally.  Excess copying in one go is much better than
+     multiple ps_pdread calls.  */
+  err = DB_GET_STRUCT (copy, th->th_ta_p, th->th_unique, pthread);
+  if (err != TD_OK)
+    return err;
+
+  err = DB_GET_FIELD_ADDRESS (tls, th->th_ta_p, th->th_unique,
+			      pthread, specific, 0);
+  if (err != TD_OK)
+    return err;
+
+  err = DB_GET_FIELD_LOCAL (schedpolicy, th->th_ta_p, copy, pthread,
+			    schedpolicy, 0);
+  if (err != TD_OK)
+    return err;
+  err = DB_GET_FIELD_LOCAL (schedprio, th->th_ta_p, copy, pthread,
+			    schedparam_sched_priority, 0);
+  if (err != TD_OK)
+    return err;
+  err = DB_GET_FIELD_LOCAL (tid, th->th_ta_p, copy, pthread, tid, 0);
+  if (err != TD_OK)
+    return err;
+  err = DB_GET_FIELD_LOCAL (cancelhandling, th->th_ta_p, copy, pthread,
+			    cancelhandling, 0);
+  if (err != TD_OK)
+    return err;
+  err = DB_GET_FIELD_LOCAL (report_events, th->th_ta_p, copy, pthread,
+			    report_events, 0);
+  if (err != TD_OK)
+    return err;
 
   /* Fill in information.  Clear first to provide reproducable
      results for the fields we do not fill in.  */
   memset (infop, '\0', sizeof (td_thrinfo_t));
 
-  infop->ti_tid = th->th_unique;
-  infop->ti_tls = (char *) pds.specific;
-  infop->ti_pri = (pds.schedpolicy == SCHED_OTHER
-		   ? 0 : pds.schedparam.sched_priority);
+  infop->ti_tid = (thread_t) th->th_unique;
+  infop->ti_tls = (char *) tls;
+  infop->ti_pri = ((uintptr_t) schedpolicy == SCHED_OTHER
+		   ? 0 : (uintptr_t) schedprio);
   infop->ti_type = TD_THR_USER;
 
-  if ((pds.cancelhandling & EXITING_BITMASK) == 0)
+  if ((((int) (uintptr_t) cancelhandling) & EXITING_BITMASK) == 0)
     /* XXX For now there is no way to get more information.  */
     infop->ti_state = TD_THR_ACTIVE;
-  else if ((pds.cancelhandling & TERMINATED_BITMASK) == 0)
+  else if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0)
     infop->ti_state = TD_THR_ZOMBIE;
   else
     infop->ti_state = TD_THR_UNKNOWN;
 
   /* Initialization which are the same in both cases.  */
-  infop->ti_lid = pds.tid ?: ps_getpid (th->th_ta_p->ph);
   infop->ti_ta_p = th->th_ta_p;
-  infop->ti_startfunc = pds.start_routine;
-  memcpy (&infop->ti_events, &pds.eventbuf.eventmask,
-	  sizeof (td_thr_events_t));
-  infop->ti_traceme = pds.report_events != false;
+  infop->ti_lid = tid == 0 ? ps_getpid (th->th_ta_p->ph) : (uintptr_t) tid;
+  infop->ti_traceme = report_events != 0;
+
+  err = DB_GET_FIELD_LOCAL (infop->ti_startfunc, th->th_ta_p, copy, pthread,
+			    start_routine, 0);
+  if (err == TD_OK)
+    {
+      uint32_t idx;
+      for (idx = 0; idx < TD_EVENTSIZE; ++idx)
+	{
+	  psaddr_t word;
+	  err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy, pthread,
+				    eventbuf_eventmask_event_bits, idx);
+	  if (err != TD_OK)
+	    break;
+	  infop->ti_events.event_bits[idx] = (uintptr_t) word;
+	}
+      if (err == TD_NOAPLIC)
+	memset (&infop->ti_events.event_bits[idx], 0,
+		(TD_EVENTSIZE - idx) * sizeof infop->ti_events.event_bits[0]);
+    }
 
-  return TD_OK;
+  return err;
 }
diff --git a/nptl_db/td_thr_getfpregs.c b/nptl_db/td_thr_getfpregs.c
index 8b68b93480..7760512ebb 100644
--- a/nptl_db/td_thr_getfpregs.c
+++ b/nptl_db/td_thr_getfpregs.c
@@ -24,27 +24,28 @@
 td_err_e
 td_thr_getfpregs (const td_thrhandle_t *th, prfpregset_t *regset)
 {
+  psaddr_t cancelhandling, tid;
+  td_err_e err;
+
   LOG ("td_thr_getfpregs");
 
   /* We have to get the state and the PID for this thread.  */
-  int cancelhandling;
-  if (ps_pdread (th->th_ta_p->ph,
-		 &((struct pthread *) th->th_unique)->cancelhandling,
-		 &cancelhandling, sizeof (int)) != PS_OK)
-    return TD_ERR;
+  err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
+		      cancelhandling, 0);
+  if (err != TD_OK)
+    return err;
 
   /* If the thread already terminated we return all zeroes.  */
-  if (cancelhandling & TERMINATED_BITMASK)
+  if (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK)
     memset (regset, '\0', sizeof (*regset));
   /* Otherwise get the register content through the callback.  */
   else
     {
-      pid_t tid;
+      err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
+      if (err != TD_OK)
+	return err;
 
-      if (ps_pdread (th->th_ta_p->ph,
-		     &((struct pthread *) th->th_unique)->tid,
-		     &tid, sizeof (pid_t)) != PS_OK
-	  || ps_lgetfpregs (th->th_ta_p->ph, tid, regset) != PS_OK)
+      if (ps_lgetfpregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK)
 	return TD_ERR;
     }
 
diff --git a/nptl_db/td_thr_getgregs.c b/nptl_db/td_thr_getgregs.c
index 90959c8f25..4c2373ef6c 100644
--- a/nptl_db/td_thr_getgregs.c
+++ b/nptl_db/td_thr_getgregs.c
@@ -22,29 +22,30 @@
 
 
 td_err_e
-td_thr_getgregs (const td_thrhandle_t *th, prgregset_t gregs)
+td_thr_getgregs (const td_thrhandle_t *th, prgregset_t regset)
 {
+  psaddr_t cancelhandling, tid;
+  td_err_e err;
+
   LOG ("td_thr_getgregs");
 
   /* We have to get the state and the PID for this thread.  */
-  int cancelhandling;
-  if (ps_pdread (th->th_ta_p->ph,
-		 &((struct pthread *) th->th_unique)->cancelhandling,
-		 &cancelhandling, sizeof (int)) != PS_OK)
-    return TD_ERR;
+  err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
+		      cancelhandling, 0);
+  if (err != TD_OK)
+    return err;
 
   /* If the thread already terminated we return all zeroes.  */
-  if (cancelhandling & TERMINATED_BITMASK)
-    memset (gregs, '\0', sizeof (prgregset_t));
+  if (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK)
+    memset (regset, '\0', sizeof (*regset));
   /* Otherwise get the register content through the callback.  */
   else
     {
-      pid_t tid;
+      err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
+      if (err != TD_OK)
+	return err;
 
-      if (ps_pdread (th->th_ta_p->ph,
-		     &((struct pthread *) th->th_unique)->tid,
-		     &tid, sizeof (pid_t)) != PS_OK
-	  || ps_lgetregs (th->th_ta_p->ph, tid, gregs) != PS_OK)
+      if (ps_lgetregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK)
 	return TD_ERR;
     }
 
diff --git a/nptl_db/td_thr_set_event.c b/nptl_db/td_thr_set_event.c
index 656728c438..2bb0b9d1f8 100644
--- a/nptl_db/td_thr_set_event.c
+++ b/nptl_db/td_thr_set_event.c
@@ -1,5 +1,5 @@
 /* Enable specific event for thread.
-   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -28,27 +28,50 @@ td_thr_set_event (th, event)
      const td_thrhandle_t *th;
      td_thr_events_t *event;
 {
+  td_err_e err;
+  psaddr_t eventmask;
+  void *copy;
+
   LOG ("td_thr_set_event");
 
-  /* Write the new value into the thread data structure.  */
-  td_thr_events_t old_event;
-  if (ps_pdread (th->th_ta_p->ph,
-		 ((char *) th->th_unique
-		  + offsetof (struct pthread, eventbuf.eventmask)),
-		 &old_event, sizeof (td_thrhandle_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
-
-  /* Or the new bits in.  */
-  int i;
-  for (i = 0; i < TD_EVENTSIZE; ++i)
-    old_event.event_bits[i] |= event->event_bits[i];
-
-  /* Write the new value into the thread data structure.  */
-  if (ps_pdwrite (th->th_ta_p->ph,
-		  ((char *) th->th_unique
-		   + offsetof (struct pthread, eventbuf.eventmask)),
-		  &old_event, sizeof (td_thrhandle_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
-
-  return TD_OK;
+  /* Fetch the old event mask from the inferior and modify it in place.  */
+  err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
+			      th->th_unique, pthread, eventbuf_eventmask, 0);
+  if (err == TD_OK)
+    err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t);
+  if (err == TD_OK)
+    {
+      uint32_t idx;
+      for (idx = 0; idx < TD_EVENTSIZE; ++idx)
+	{
+	  psaddr_t word;
+	  uint32_t mask;
+	  err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy,
+				    td_thr_events_t, event_bits, idx);
+	  if (err != TD_OK)
+	    break;
+	  mask = (uintptr_t) word;
+	  mask |= event->event_bits[idx];
+	  word = (psaddr_t) (uintptr_t) mask;
+	  err = DB_PUT_FIELD_LOCAL (th->th_ta_p, copy,
+				    td_thr_events_t, event_bits, idx, word);
+	  if (err != TD_OK)
+	    break;
+	}
+      if (err == TD_NOAPLIC)
+	{
+	  err = TD_OK;
+	  while (idx < TD_EVENTSIZE)
+	    if (event->event_bits[idx++] != 0)
+	      {
+		err = TD_NOEVENT;
+		break;
+	      }
+	}
+      if (err == TD_OK)
+	/* Now write it back to the inferior.  */
+	err = DB_PUT_STRUCT (th->th_ta_p, eventmask, td_thr_events_t, copy);
+    }
+
+  return err;
 }
diff --git a/nptl_db/td_thr_setfpregs.c b/nptl_db/td_thr_setfpregs.c
index fe36445c49..01bdb53231 100644
--- a/nptl_db/td_thr_setfpregs.c
+++ b/nptl_db/td_thr_setfpregs.c
@@ -24,24 +24,25 @@
 td_err_e
 td_thr_setfpregs (const td_thrhandle_t *th, const prfpregset_t *fpregs)
 {
+  psaddr_t cancelhandling, tid;
+  td_err_e err;
+
   LOG ("td_thr_setfpregs");
 
   /* We have to get the state and the PID for this thread.  */
-  int cancelhandling;
-  if (ps_pdread (th->th_ta_p->ph,
-		 &((struct pthread *) th->th_unique)->cancelhandling,
-		 &cancelhandling, sizeof (int)) != PS_OK)
-    return TD_ERR;
+  err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
+		      cancelhandling, 0);
+  if (err != TD_OK)
+    return err;
 
   /* Only set the registers if the thread hasn't yet terminated.  */
-  if ((cancelhandling & TERMINATED_BITMASK) == 0)
+  if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0)
     {
-      pid_t tid;
+      err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
+      if (err != TD_OK)
+	return err;
 
-      if (ps_pdread (th->th_ta_p->ph,
-		     &((struct pthread *) th->th_unique)->tid,
-		     &tid, sizeof (pid_t)) != PS_OK
-	  || ps_lsetfpregs (th->th_ta_p->ph, tid, fpregs) != PS_OK)
+      if (ps_lsetfpregs (th->th_ta_p->ph, (uintptr_t) tid, fpregs) != PS_OK)
 	return TD_ERR;
     }
 
diff --git a/nptl_db/td_thr_setgregs.c b/nptl_db/td_thr_setgregs.c
index f20c78f426..2a9ce7e01c 100644
--- a/nptl_db/td_thr_setgregs.c
+++ b/nptl_db/td_thr_setgregs.c
@@ -24,24 +24,25 @@
 td_err_e
 td_thr_setgregs (const td_thrhandle_t *th, prgregset_t gregs)
 {
+  psaddr_t cancelhandling, tid;
+  td_err_e err;
+
   LOG ("td_thr_setgregs");
 
   /* We have to get the state and the PID for this thread.  */
-  int cancelhandling;
-  if (ps_pdread (th->th_ta_p->ph,
-		 &((struct pthread *) th->th_unique)->cancelhandling,
-		 &cancelhandling, sizeof (int)) != PS_OK)
-    return TD_ERR;
+  err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
+		      cancelhandling, 0);
+  if (err != TD_OK)
+    return err;
 
   /* Only set the registers if the thread hasn't yet terminated.  */
-  if ((cancelhandling & TERMINATED_BITMASK) == 0)
+  if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0)
     {
-      pid_t tid;
+      err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
+      if (err != TD_OK)
+	return err;
 
-      if (ps_pdread (th->th_ta_p->ph,
-		     &((struct pthread *) th->th_unique)->tid,
-		     &tid, sizeof (pid_t)) != PS_OK
-	  || ps_lsetregs (th->th_ta_p->ph, tid, gregs) != PS_OK)
+      if (ps_lsetregs (th->th_ta_p->ph, tid - (psaddr_t) 0, gregs) != PS_OK)
 	return TD_ERR;
     }
 
diff --git a/nptl_db/td_thr_tls_get_addr.c b/nptl_db/td_thr_tls_get_addr.c
index c900cac8e0..e7d2322723 100644
--- a/nptl_db/td_thr_tls_get_addr.c
+++ b/nptl_db/td_thr_tls_get_addr.c
@@ -22,24 +22,22 @@
 #include "thread_dbP.h"
 
 td_err_e
-td_thr_tls_get_addr (const td_thrhandle_t *th __attribute__ ((unused)),
-		     void *map_address __attribute__ ((unused)),
-		     size_t offset __attribute__ ((unused)),
-		     void **address __attribute__ ((unused)))
+td_thr_tls_get_addr (const td_thrhandle_t *th,
+		     psaddr_t map_address, size_t offset, psaddr_t *address)
 {
-#if USE_TLS
-  /* Read the module ID from the link_map.  */
-  size_t modid;
-  if (ps_pdread (th->th_ta_p->ph,
-		 &((struct link_map *) map_address)->l_tls_modid,
-		 &modid, sizeof modid) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  td_err_e err;
+  psaddr_t modid;
 
-  td_err_e result = td_thr_tlsbase (th, modid, address);
-  if (result == TD_OK)
-    *address += offset;
-  return result;
-#else
-  return TD_ERR;
-#endif
+  /* Get the TLS module ID from the `struct link_map' in the inferior.  */
+  err = DB_GET_FIELD (modid, th->th_ta_p, map_address, link_map,
+		      l_tls_modid, 0);
+  if (err == TD_NOCAPAB)
+    return TD_NOAPLIC;
+  if (err == TD_OK)
+    {
+      err = td_thr_tlsbase (th, (uintptr_t) modid, address);
+      if (err == TD_OK)
+	*address += offset;
+    }
+  return err;
 }
diff --git a/nptl_db/td_thr_tlsbase.c b/nptl_db/td_thr_tlsbase.c
index ff8f1c7504..c57009a73c 100644
--- a/nptl_db/td_thr_tlsbase.c
+++ b/nptl_db/td_thr_tlsbase.c
@@ -19,49 +19,32 @@
 
 #include "thread_dbP.h"
 
-/* Value used for dtv entries for which the allocation is delayed.  */
-# define TLS_DTV_UNALLOCATED	((void *) -1l)
-
 td_err_e
 td_thr_tlsbase (const td_thrhandle_t *th,
 		unsigned long int modid,
 		psaddr_t *base)
 {
+  td_err_e err;
+  psaddr_t dtv, dtvptr;
+
   if (modid < 1)
     return TD_NOTLS;
 
-#if USE_TLS
-  union dtv pdtv, *dtvp;
-
-  LOG ("td_thr_tlsbase");
-
-  psaddr_t dtvpp = th->th_unique;
-#if TLS_TCB_AT_TP
-  dtvpp += offsetof (struct pthread, header.dtv);
-#elif TLS_DTV_AT_TP
-  dtvpp += TLS_PRE_TCB_SIZE + offsetof (tcbhead_t, dtv);
-#else
-# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined."
-#endif
-
   /* Get the DTV pointer from the thread descriptor.  */
-  if (ps_pdread (th->th_ta_p->ph, dtvpp, &dtvp, sizeof dtvp) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  err = DB_GET_FIELD (dtv, th->th_ta_p, th->th_unique, pthread, dtvp, 0);
+  if (err != TD_OK)
+    return err;
 
   /* Get the corresponding entry in the DTV.  */
-  if (ps_pdread (th->th_ta_p->ph, dtvp + modid,
-		 &pdtv, sizeof (union dtv)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  err = DB_GET_FIELD (dtvptr, th->th_ta_p, dtv, dtv, dtv, modid);
+  if (err != TD_OK)
+    return err;
 
   /* It could be that the memory for this module is not allocated for
      the given thread.  */
-  if (pdtv.pointer == TLS_DTV_UNALLOCATED)
+  if ((uintptr_t) dtvptr & 1)
     return TD_TLSDEFER;
 
-  *base = (char *) pdtv.pointer;
-
+  *base = dtvptr;
   return TD_OK;
-#else
-  return TD_ERR;
-#endif
 }
diff --git a/nptl_db/td_thr_tsd.c b/nptl_db/td_thr_tsd.c
index d1a54537ff..08f617b7d2 100644
--- a/nptl_db/td_thr_tsd.c
+++ b/nptl_db/td_thr_tsd.c
@@ -1,5 +1,5 @@
 /* Get a thread-specific data pointer for a thread.
-   Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
 
@@ -24,48 +24,73 @@
 td_err_e
 td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data)
 {
-  LOG ("td_thr_tsd");
+  td_err_e err;
+  psaddr_t tk_seq, level1, level2, seq, value;
+  void *copy;
+  uint32_t pthread_key_2ndlevel_size, idx1st, idx2nd;
 
-  /* Check correct value of key.  */
-  if (tk >= th->th_ta_p->pthread_keys_max)
-    return TD_BADKEY;
+  LOG ("td_thr_tsd");
 
   /* Get the key entry.  */
-  uintptr_t seq;
-  if (ps_pdread (th->th_ta_p->ph, &th->th_ta_p->keys[tk].seq, &seq,
-		 sizeof (uintptr_t)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  err = DB_GET_VALUE (tk_seq, th->th_ta_p, __pthread_keys, tk);
+  if (err == TD_NOAPLIC)
+    return TD_BADKEY;
+  if (err != TD_OK)
+    return err;
 
   /* Fail if this key is not at all used.  */
-  if (KEY_UNUSED (seq))
+  if (((uintptr_t) tk_seq & 1) == 0)
     return TD_BADKEY;
 
-  /* Compute the indeces.  */
-  int pthread_key_2ndlevel_size = th->th_ta_p->pthread_key_2ndlevel_size;
-  unsigned int idx1st = tk / pthread_key_2ndlevel_size;
-  unsigned int idx2nd = tk % pthread_key_2ndlevel_size;
+  /* This makes sure we have the size information on hand.  */
+  err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, 0, pthread_key_data_level2,
+			      data, 1);
+  if (err != TD_OK)
+    return err;
 
-  struct pthread_key_data *level1;
-  if (ps_pdread (th->th_ta_p->ph,
-		 &((struct pthread *) th->th_unique)->specific[idx1st],
-		 &level1, sizeof (level1)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  /* Compute the indeces.  */
+  pthread_key_2ndlevel_size
+    = DB_DESC_NELEM (th->th_ta_p->ta_field_pthread_key_data_level2_data);
+  idx1st = tk / pthread_key_2ndlevel_size;
+  idx2nd = tk % pthread_key_2ndlevel_size;
+
+  /* Now fetch the first level pointer.  */
+  err = DB_GET_FIELD (level1, th->th_ta_p, th->th_unique, pthread,
+		      specific, idx1st);
+  if (err == TD_NOAPLIC)
+    return TD_DBERR;
+  if (err != TD_OK)
+    return err;
 
   /* Check the pointer to the second level array.  */
-  if (level1 == NULL)
+  if (level1 == 0)
     return TD_NOTSD;
 
-  struct pthread_key_data level2;
-  if (ps_pdread (th->th_ta_p->ph, &level1[idx2nd], &level2,
-		 sizeof (level2)) != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
+  /* Locate the element within the second level array.  */
+  err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p,
+			      level1, pthread_key_data_level2, data, idx2nd);
+  if (err == TD_NOAPLIC)
+    return TD_DBERR;
+  if (err != TD_OK)
+    return err;
+
+  /* Now copy in that whole structure.  */
+  err = DB_GET_STRUCT (copy, th->th_ta_p, level2, pthread_key_data);
+  if (err != TD_OK)
+    return err;
 
   /* Check whether the data is valid.  */
-  if (level2.seq != seq)
+  err = DB_GET_FIELD_LOCAL (seq, th->th_ta_p, copy, pthread_key_data, seq, 0);
+  if (err != TD_OK)
+    return err;
+  if (seq != tk_seq)
     return TD_NOTSD;
 
-  if (level2.data != NULL)
-    *data = level2.data;
+  /* Finally, fetch the value.  */
+  err = DB_GET_FIELD_LOCAL (value, th->th_ta_p, copy, pthread_key_data,
+			    data, 0);
+  if (err == TD_OK)
+    *data = value;
 
-  return TD_OK;
+  return err;
 }
diff --git a/nptl_db/td_thr_validate.c b/nptl_db/td_thr_validate.c
index 28fec6a00e..e0b05f52e7 100644
--- a/nptl_db/td_thr_validate.c
+++ b/nptl_db/td_thr_validate.c
@@ -24,43 +24,53 @@
 static td_err_e
 check_thread_list (const td_thrhandle_t *th, psaddr_t head)
 {
-  list_t list;
-  td_err_e result = TD_NOTHR;
-
-  if (ps_pdread (th->th_ta_p->ph, head, &list.next, sizeof (list.next))
-      != PS_OK)
-    return TD_ERR;	/* XXX Other error value?  */
-
-  while (list.next != head)
-    if ((psaddr_t) list.next - offsetof (struct pthread, list)
-	== th->th_unique)
-      {
-	result = TD_OK;
-	break;
-      }
-    else if (ps_pdread (th->th_ta_p->ph, list.next, &list.next,
-			sizeof (list.next)) != PS_OK)
-      {
-	result = TD_ERR;	/* XXX Other error value?  */
-	break;
-      }
-
-  return result;
+  td_err_e err;
+  psaddr_t next, ofs;
+
+  err = DB_GET_FIELD (next, th->th_ta_p, head, list_t, next, 0);
+  if (err == TD_OK)
+    {
+      if (next == 0)
+	return TD_NOTHR;
+      err = DB_GET_FIELD_ADDRESS (ofs, th->th_ta_p, 0, pthread, list, 0);
+    }
+
+  while (err == TD_OK)
+    {
+      if (next == head)
+	return TD_NOTHR;
+
+      if (next - (ofs - (psaddr_t) 0) == th->th_unique)
+	return TD_OK;
+
+      err = DB_GET_FIELD (next, th->th_ta_p, next, list_t, next, 0);
+    }
+
+  return err;
 }
 
 
 td_err_e
 td_thr_validate (const td_thrhandle_t *th)
 {
+  td_err_e err;
+  psaddr_t list;
+
   LOG ("td_thr_validate");
 
   /* First check the list with threads using user allocated stacks.  */
-  td_err_e result = check_thread_list (th, th->th_ta_p->stack_user);
+  err = DB_GET_SYMBOL (list, th->th_ta_p, __stack_user);
+  if (err == TD_OK)
+    err = check_thread_list (th, list);
 
   /* If our thread is not on this list search the list with stack
      using implementation allocated stacks.  */
-  if (result == TD_NOTHR)
-    result = check_thread_list (th, th->th_ta_p->stack_used);
+  if (err == TD_NOTHR)
+    {
+      err = DB_GET_SYMBOL (list, th->th_ta_p, stack_used);
+      if (err == TD_OK)
+	err = check_thread_list (th, list);
+    }
 
-  return result;
+  return err;
 }
diff --git a/nptl_db/thread_db.h b/nptl_db/thread_db.h
index 6328e16e76..433b54fd5d 100644
--- a/nptl_db/thread_db.h
+++ b/nptl_db/thread_db.h
@@ -56,7 +56,7 @@ 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 TLS segment in the given module.  */
+  TD_NOTLS	  /* There is no TLS segment in the given module.  */
 } td_err_e;
 
 
@@ -412,8 +412,8 @@ extern td_err_e td_thr_tlsbase (const td_thrhandle_t *__th,
 
 /* Get address of thread local variable.  */
 extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th,
-				     void *__map_address, size_t __offset,
-				     void **__address);
+				     psaddr_t __map_address, size_t __offset,
+				     psaddr_t *__address);
 
 
 /* Enable reporting for EVENT for thread TH.  */
diff --git a/nptl_db/thread_dbP.h b/nptl_db/thread_dbP.h
index 4407143af0..4546d24c23 100644
--- a/nptl_db/thread_dbP.h
+++ b/nptl_db/thread_dbP.h
@@ -1,30 +1,54 @@
-/* Private header for thread debug library.  */
+/* Private header for thread debug library
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
 #ifndef _THREAD_DBP_H
 #define _THREAD_DBP_H	1
 
 #include <stdbool.h>
+#include <stdint.h>
 #include <string.h>
+#include <stdlib.h>
 #include <unistd.h>
+#include <assert.h>
 #include "proc_service.h"
 #include "thread_db.h"
-#include "../nptl/pthreadP.h"
-#include <list.h>
-
+#include "../nptl/pthreadP.h"  	/* This is for *_BITMASK only.  */
 
 /* Indeces for the symbol names.  */
 enum
   {
-    SYM_PTHREAD_THREADS_EVENTS = 0,
-    SYM_PTHREAD_LAST_EVENT,
-    SYM_PTHREAD_NTHREADS,
-    SYM_PTHREAD_STACK_USED,
-    SYM_PTHREAD_STACK_USER,
-    SYM_PTHREAD_KEYS,
-    SYM_PTHREAD_KEYS_MAX,
-    SYM_PTHREAD_SIZEOF_DESCR,
-    SYM_PTHREAD_CREATE_EVENT,
-    SYM_PTHREAD_DEATH_EVENT,
-    SYM_PTHREAD_VERSION,
+# define DB_STRUCT(type)		SYM_SIZEOF_##type,
+# define DB_STRUCT_FIELD(type, field)	SYM_##type##_FIELD_##field,
+# define DB_SYMBOL(name)		SYM_##name,
+# define DB_VARIABLE(name)		SYM_##name, SYM_DESC_##name,
+# include "structs.def"
+# undef DB_STRUCT
+# undef DB_STRUCT_FIELD
+# undef DB_SYMBOL
+# undef DB_VARIABLE
+
+    SYM_TH_UNIQUE_CONST_THREAD_AREA,
+    SYM_TH_UNIQUE_REGISTER64,
+    SYM_TH_UNIQUE_REGISTER32,
+    SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
+    SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
+
     SYM_NUM_MESSAGES
   };
 
@@ -32,50 +56,68 @@ enum
 /* Comment out the following for less verbose output.  */
 #ifndef NDEBUG
 # define LOG(c) if (__td_debug) __libc_write (2, c "\n", strlen (c "\n"))
-extern int __td_debug;
+extern int __td_debug attribute_hidden;
 #else
 # define LOG(c)
 #endif
 
 
+#define DB_DESC_SIZE(desc)	((desc)[0])
+#define DB_DESC_NELEM(desc)	((desc)[1])
+#define DB_DESC_OFFSET(desc)	((int32_t) (desc)[2])
+#define DB_SIZEOF_DESC		(3 * sizeof (uint32_t))
+#define DB_DEFINE_DESC(name, size, nelem, offset) \
+  const uint32_t name[3] = { (size), (nelem), (offset) }
+typedef uint32_t db_desc_t[3];
+
+
 /* Handle for a process.  This type is opaque.  */
 struct td_thragent
 {
+  /* Chain on the list of all agent structures.  */
+  list_t list;
+
   /* Delivered by the debugger and we have to pass it back in the
      proc callbacks.  */
   struct ps_prochandle *ph;
 
-  /* Some cached information.  */
-
-  /* Lists of running threads.  */
-  psaddr_t stack_used;
-  psaddr_t stack_user;
-
-  /* Address of the `pthread_keys' array.  */
-  struct pthread_key_struct *keys;
-
-  /* Maximum number of thread-local data keys.  */
-  int pthread_keys_max;
-
-  /* Size of 2nd level array for thread-local data keys.  */
-  int pthread_key_2ndlevel_size;
-
-  /* Sizeof struct _pthread_descr_struct.  */
-  int sizeof_descr;
-
-  /* Pointer to the `__pthread_threads_events' variable in the target.  */
-  psaddr_t pthread_threads_eventsp;
-
-  /* Pointer to the `__pthread_last_event' variable in the target.  */
-  psaddr_t pthread_last_event;
-
-  /* List head the queue agent structures.  */
-  list_t list;
+  /* Cached values read from the inferior.  */
+# define DB_STRUCT(type) \
+  uint32_t ta_sizeof_##type;
+# define DB_STRUCT_FIELD(type, field) \
+  db_desc_t ta_field_##type##_##field;
+# define DB_SYMBOL(name) \
+  psaddr_t ta_addr_##name;
+# define DB_VARIABLE(name) \
+  psaddr_t ta_addr_##name; \
+  db_desc_t ta_var_##name;
+# include "structs.def"
+# undef DB_STRUCT
+# undef DB_STRUCT_FIELD
+# undef DB_SYMBOL
+# undef DB_VARIABLE
+
+  /* The method of locating a thread's th_unique value.  */
+  enum
+    {
+      ta_howto_unknown,
+      ta_howto_reg,
+      ta_howto_reg_thread_area,
+      ta_howto_const_thread_area
+    } ta_howto;
+  union
+  {
+    uint32_t const_thread_area;	/* Constant argument to ps_get_thread_area.  */
+    /* These are as if the descriptor of the field in prregset_t,
+       but DB_DESC_NELEM is overloaded as follows: */
+    db_desc_t reg;		/* Signed bias applied to register value.  */
+    db_desc_t reg_thread_area;	/* Bits to scale down register value.  */
+  } ta_howto_data;
 };
 
 
 /* List of all known descriptors.  */
-extern list_t __td_agent_list;
+extern list_t __td_agent_list attribute_hidden;
 
 
 /* Function used to test for correct thread agent pointer.  */
@@ -93,6 +135,115 @@ ta_ok (const td_thragent_t *ta)
 
 
 /* Internal wrapper around ps_pglobal_lookup.  */
-extern int td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr);
+extern ps_err_e td_lookup (struct ps_prochandle *ps,
+			   int idx, psaddr_t *sym_addr) attribute_hidden;
+
+
+
+
+/* Store in psaddr_t VAR the address of inferior's symbol NAME.  */
+#define DB_GET_SYMBOL(var, ta, name)					      \
+  (((ta)->ta_addr_##name == 0						      \
+    && td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK)      \
+   ? TD_ERR : ((var) = (ta)->ta_addr_##name, TD_OK))
+
+/* 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 td_err_e _td_locate_field (td_thragent_t *ta,
+				  db_desc_t desc, int descriptor_name,
+				  psaddr_t idx,
+				  psaddr_t *address) attribute_hidden;
+
+
+/* Like DB_GET_FIELD, but PTR is a local pointer to a structure that
+   has already been copied in from the inferior.  */
+#define DB_GET_FIELD_LOCAL(var, ta, ptr, type, field, idx) \
+  _td_fetch_value_local ((ta), (ta)->ta_field_##type##_##field, \
+		         SYM_##type##_FIELD_##field, \
+			 (psaddr_t) 0 + (idx), (ptr), &(var))
+
+/* 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)))
+
+/* Helper functions for those.  */
+extern td_err_e _td_fetch_value (td_thragent_t *ta,
+				 db_desc_t field, 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,
+				       db_desc_t field,
+				       int descriptor_name,
+				       psaddr_t idx, void *address,
+				       psaddr_t *result) attribute_hidden;
+
+/* 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_LOCAL(ta, ptr, type, field, idx, value) \
+  _td_store_value_local ((ta), (ta)->ta_field_##type##_##field, \
+			 SYM_##type##_FIELD_##field, \
+			 (psaddr_t) 0 + (idx), (ptr), (value))
+
+/* 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)))
+
+/* Helper functions for those.  */
+extern td_err_e _td_store_value (td_thragent_t *ta,
+				 db_desc_t field, 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,
+				       db_desc_t field, int descriptor_name,
+				       psaddr_t idx, void *address,
+				       psaddr_t value) attribute_hidden;
+
+#define DB_GET_STRUCT(var, ta, ptr, type)				      \
+  ({ td_err_e _err = TD_OK;						      \
+     if ((ta)->ta_sizeof_##type == 0)					      \
+       _err = _td_check_sizeof ((ta), &(ta)->ta_sizeof_##type,		      \
+				      SYM_SIZEOF_##type);		      \
+     if (_err == TD_OK)							      \
+       _err = ps_pdread ((ta)->ph, (ptr),				      \
+			 (var) = __alloca ((ta)->ta_sizeof_##type),	      \
+			 (ta)->ta_sizeof_##type)			      \
+	 == PS_OK ? TD_OK : TD_ERR;					      \
+     else								      \
+       (var) = NULL; 							      \
+     _err;								      \
+  })
+#define DB_PUT_STRUCT(ta, ptr, type, copy)				      \
+  ({ assert ((ta)->ta_sizeof_##type != 0);				      \
+     ps_pdwrite ((ta)->ph, (ptr), (copy), (ta)->ta_sizeof_##type)	      \
+       == PS_OK ? TD_OK : TD_ERR;					      \
+  })
+
+extern td_err_e _td_check_sizeof (td_thragent_t *ta, uint32_t *sizep,
+				  int sizep_name) attribute_hidden;
 
 #endif /* thread_dbP.h */