about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Versions.def3
-rw-r--r--linuxthreads_db/ChangeLog25
-rw-r--r--linuxthreads_db/Versions15
-rw-r--r--linuxthreads_db/td_ta_clear_event.c4
-rw-r--r--linuxthreads_db/td_ta_delete.c23
-rw-r--r--linuxthreads_db/td_ta_enable_stats.c5
-rw-r--r--linuxthreads_db/td_ta_event_addr.c4
-rw-r--r--linuxthreads_db/td_ta_event_getmsg.c4
-rw-r--r--linuxthreads_db/td_ta_get_nthreads.c4
-rw-r--r--linuxthreads_db/td_ta_get_ph.c4
-rw-r--r--linuxthreads_db/td_ta_get_stats.c5
-rw-r--r--linuxthreads_db/td_ta_map_id2thr.c22
-rw-r--r--linuxthreads_db/td_ta_map_lwp2thr.c69
-rw-r--r--linuxthreads_db/td_ta_new.c20
-rw-r--r--linuxthreads_db/td_ta_reset_stats.c5
-rw-r--r--linuxthreads_db/td_ta_set_event.c4
-rw-r--r--linuxthreads_db/td_ta_setconcurrency.c5
-rw-r--r--linuxthreads_db/td_ta_thr_iter.c28
-rw-r--r--linuxthreads_db/td_ta_tsd_iter.c32
-rw-r--r--linuxthreads_db/td_thr_get_info.c1
-rw-r--r--linuxthreads_db/thread_dbP.h25
22 files changed, 263 insertions, 48 deletions
diff --git a/ChangeLog b/ChangeLog
index 86ffc43be1..54e379d8d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+1999-11-03  Ulrich Drepper  <drepper@cygnus.com>
+
+	* Versions.def: Add version for libthread_db.
+
 1999-11-02  Andreas Jaeger  <aj@suse.de>
 
 	* manual/header.texi (Library Summary): The command @indexfonts
diff --git a/Versions.def b/Versions.def
index 4a3ee42774..82b0f1db01 100644
--- a/Versions.def
+++ b/Versions.def
@@ -81,3 +81,6 @@ ld.so {
   GLIBC_2.1 GLIBC_2.0
   GLIBC_2.1.1 GLIBC_2.1
 }
+libthread_db {
+  GLIBC_2.1.3
+}
diff --git a/linuxthreads_db/ChangeLog b/linuxthreads_db/ChangeLog
index 0922e9ed24..f2286c99b2 100644
--- a/linuxthreads_db/ChangeLog
+++ b/linuxthreads_db/ChangeLog
@@ -1,3 +1,28 @@
+1999-11-03  Ulrich Drepper  <drepper@cygnus.com>
+
+	* thread_dbP.h (ta_ok): New function.
+	* td_ta_new.c: Add new handle to list.
+	* td_ta_delete.c: Remove handle from list.
+	* td_ta_clear_event.c: Use ta_ok to check for correct ta parameter.
+	* td_ta_enable_stats.c: Likewise.
+	* td_ta_event_addr.c: Likewise.
+	* td_ta_event_getmsg.c: Likewise.
+	* td_ta_get_nthreads.c: Likewise.
+	* td_ta_get_ph.c: Likewise.
+	* td_ta_get_stats.c: Likewise.
+	* td_ta_map_id2thr.c: Likewise.
+	* td_ta_map_lwp2thr.c: Likewise.
+	* td_ta_reset_stats.c: Likewise.
+	* td_ta_set_event.c: Likewise.
+	* td_ta_setconcurrency.c: Likewise.
+	* td_ta_thr_iter.c: Likewise.
+
+	* td_ta_tsd_iter.c: Optimize memory retrieving.
+
+	* Versions: New file.
+
+	* td_thr_get_info.c (td_thr_get_info): Initialize ti_traceme.
+
 1999-11-02  Ulrich Drepper  <drepper@cygnus.com>
 
 	* td_ta_thr_iter.c (td_ta_thr_iter): Optimize a bit.  Read all
diff --git a/linuxthreads_db/Versions b/linuxthreads_db/Versions
new file mode 100644
index 0000000000..83b30ee6e9
--- /dev/null
+++ b/linuxthreads_db/Versions
@@ -0,0 +1,15 @@
+libthread_db {
+  GLIBC_2.1.3 {
+    # t*
+    td_init; td_log; td_ta_clear_event; td_ta_delete; td_ta_enable_stats;
+    td_ta_event_addr; td_ta_event_getmsg; td_ta_get_nthreads; td_ta_get_ph;
+    td_ta_get_stats; td_ta_map_id2thr; td_ta_map_lwp2thr; td_ta_new;
+    td_ta_reset_stats; td_ta_set_event; td_ta_setconcurrency;
+    td_ta_thr_iter; td_ta_tsd_iter; td_thr_clear_event; td_thr_dbresume;
+    td_thr_dbsuspend; td_thr_event_enable; td_thr_event_getmsg;
+    td_thr_get_info; td_thr_getfpregs; td_thr_getgregs; td_thr_getxregs;
+    td_thr_getxregsize; td_thr_set_event; td_thr_setfpregs; td_thr_setgregs;
+    td_thr_setprio; td_thr_setsigpending; td_thr_setxregs; td_thr_sigsetmask;
+    td_thr_tsd; td_thr_validate;
+  }
+}
diff --git a/linuxthreads_db/td_ta_clear_event.c b/linuxthreads_db/td_ta_clear_event.c
index ec7770eae1..02d83360fa 100644
--- a/linuxthreads_db/td_ta_clear_event.c
+++ b/linuxthreads_db/td_ta_clear_event.c
@@ -31,6 +31,10 @@ td_ta_clear_event (ta, event)
 
   LOG (__FUNCTION__);
 
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
   /* Write the new value into the thread data structure.  */
   if (ps_pdread (ta->ph, ta->pthread_threads_eventsp,
 		 &old_event, sizeof (td_thrhandle_t)) != PS_OK)
diff --git a/linuxthreads_db/td_ta_delete.c b/linuxthreads_db/td_ta_delete.c
index a8031f2d27..e983577665 100644
--- a/linuxthreads_db/td_ta_delete.c
+++ b/linuxthreads_db/td_ta_delete.c
@@ -28,6 +28,29 @@ td_ta_delete (td_thragent_t *ta)
 {
   LOG (__FUNCTION__);
 
+  /* Safety check.  */
+  if (ta == NULL || __td_agent_list == NULL)
+    return TD_BADTA;
+
+  /* Remove the handle from the list.  */
+  if (ta == __td_agent_list->ta)
+    /* It's the first element of the list.  */
+    __td_agent_list = __td_agent_list->next;
+  else
+    {
+      /* We have to search for it.  */
+      struct agent_list *runp = __td_agent_list;
+
+      while (runp->next != NULL && runp->next->ta != ta)
+	runp = runp->next;
+
+      if (runp->next == NULL)
+	/* It's not a valid decriptor since it is not in the list.  */
+	return TD_BADTA;
+
+      runp->next = runp->next->next;
+    }
+
   /* The handle was allocated in `td_ta_new'.  */
   free (ta);
 
diff --git a/linuxthreads_db/td_ta_enable_stats.c b/linuxthreads_db/td_ta_enable_stats.c
index eb3a338b29..abf4d200a9 100644
--- a/linuxthreads_db/td_ta_enable_stats.c
+++ b/linuxthreads_db/td_ta_enable_stats.c
@@ -26,5 +26,10 @@ td_ta_enable_stats (const td_thragent_t *ta, int enable)
 {
   /* XXX We have to figure out what has to be done.  */
   LOG (__FUNCTION__);
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
   return TD_OK;
 }
diff --git a/linuxthreads_db/td_ta_event_addr.c b/linuxthreads_db/td_ta_event_addr.c
index 4edd54c55d..7f217f1024 100644
--- a/linuxthreads_db/td_ta_event_addr.c
+++ b/linuxthreads_db/td_ta_event_addr.c
@@ -31,6 +31,10 @@ td_ta_event_addr (const td_thragent_t *ta, td_event_e event, td_notify_t *addr)
 
   LOG (__FUNCTION__);
 
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
   switch (event)
     {
     case TD_CREATE:
diff --git a/linuxthreads_db/td_ta_event_getmsg.c b/linuxthreads_db/td_ta_event_getmsg.c
index 6b56e0d5e7..4c635dc10d 100644
--- a/linuxthreads_db/td_ta_event_getmsg.c
+++ b/linuxthreads_db/td_ta_event_getmsg.c
@@ -34,6 +34,10 @@ td_ta_event_getmsg (const td_thragent_t *ta, td_event_msg_t *msg)
 
   LOG (__FUNCTION__);
 
+  /* 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.  */
   if (ps_pdread (ta->ph, ta->pthread_last_event,
 		 &addr, sizeof (void *)) != PS_OK)
diff --git a/linuxthreads_db/td_ta_get_nthreads.c b/linuxthreads_db/td_ta_get_nthreads.c
index 13d50329c1..9396250534 100644
--- a/linuxthreads_db/td_ta_get_nthreads.c
+++ b/linuxthreads_db/td_ta_get_nthreads.c
@@ -28,6 +28,10 @@ td_ta_get_nthreads (const td_thragent_t *ta, int *np)
 
   LOG (__FUNCTION__);
 
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
   /* Access the variable `__pthread_handles_num'.  */
   if (ps_pglobal_lookup (ta->ph, LIBPTHREAD_SO, "__pthread_handles_num",
 		         &addr) != PS_OK)
diff --git a/linuxthreads_db/td_ta_get_ph.c b/linuxthreads_db/td_ta_get_ph.c
index 538990fee4..b748916ba1 100644
--- a/linuxthreads_db/td_ta_get_ph.c
+++ b/linuxthreads_db/td_ta_get_ph.c
@@ -26,6 +26,10 @@ td_ta_get_ph (const td_thragent_t *ta, struct ps_prochandle **ph)
 {
   LOG (__FUNCTION__);
 
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
   *ph = ta->ph;
 
   return TD_OK;
diff --git a/linuxthreads_db/td_ta_get_stats.c b/linuxthreads_db/td_ta_get_stats.c
index d8f5fe294f..1741d8145f 100644
--- a/linuxthreads_db/td_ta_get_stats.c
+++ b/linuxthreads_db/td_ta_get_stats.c
@@ -26,5 +26,10 @@ td_ta_get_stats (const td_thragent_t *ta, td_ta_stats_t *statsp)
 {
   /* XXX We have to figure out what has to be done.  */
   LOG (__FUNCTION__);
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
   return TD_OK;
 }
diff --git a/linuxthreads_db/td_ta_map_id2thr.c b/linuxthreads_db/td_ta_map_id2thr.c
index ffbc8b2908..6fb1ba96aa 100644
--- a/linuxthreads_db/td_ta_map_id2thr.c
+++ b/linuxthreads_db/td_ta_map_id2thr.c
@@ -24,14 +24,21 @@
 td_err_e
 td_ta_map_id2thr (const td_thragent_t *ta, pthread_t pt, td_thrhandle_t *th)
 {
-  struct pthread_handle_struct *handles = ta->handles;
   struct pthread_handle_struct phc;
-  int pthread_threads_max = ta->pthread_threads_max;
+  struct _pthread_descr_struct pds;
+  int pthread_threads_max;
 
   LOG (__FUNCTION__);
 
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Make the following expression a bit smaller.  */
+  pthread_threads_max = ta->pthread_threads_max;
+
   /* We can compute the entry in the handle array we want.  */
-  if (ps_pdread (ta->ph, handles + pt % pthread_threads_max, &phc,
+  if (ps_pdread (ta->ph, ta->handles + pt % pthread_threads_max, &phc,
 		 sizeof (struct pthread_handle_struct)) != PS_OK)
     return TD_ERR;	/* XXX Other error value?  */
 
@@ -39,6 +46,15 @@ td_ta_map_id2thr (const td_thragent_t *ta, pthread_t pt, td_thrhandle_t *th)
   if (phc.h_descr == NULL)
     return TD_BADTH;
 
+  /* Next test: get the descriptor to see whether this is not an old
+     thread handle.  */
+  if (ps_pdread (ta->ph, phc.h_descr, &pds,
+		 sizeof (struct _pthread_descr_struct)) != PS_OK)
+    return TD_ERR;	/* XXX Other error value?  */
+
+  if (pds.p_tid != pt)
+    return TD_BADTH;
+
   /* Create the `td_thrhandle_t' object.  */
   th->th_ta_p = (td_thragent_t *) ta;
   th->th_unique = phc.h_descr;
diff --git a/linuxthreads_db/td_ta_map_lwp2thr.c b/linuxthreads_db/td_ta_map_lwp2thr.c
index 995620f023..f51bc18f16 100644
--- a/linuxthreads_db/td_ta_map_lwp2thr.c
+++ b/linuxthreads_db/td_ta_map_lwp2thr.c
@@ -24,38 +24,57 @@
 td_err_e
 td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
 {
-  struct pthread_handle_struct *handles = ta->handles;
   int pthread_threads_max = ta->pthread_threads_max;
+  size_t sizeof_descr = ta->sizeof_descr;
+  struct pthread_handle_struct phc[pthread_threads_max];
   size_t cnt;
+#ifdef ALL_THREADS_STOPPED
+  int num;
+#else
+# define num 1
+#endif
 
   LOG (__FUNCTION__);
 
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  /* Read all the descriptors.  */
+  if (ps_pdread (ta->ph, ta->handles, phc,
+		 sizeof (struct pthread_handle_struct) * pthread_threads_max)
+      != PS_OK)
+    return TD_ERR;	/* XXX Other error value?  */
+
+#ifdef ALL_THREADS_STOPPED
+  /* Read the number of currently active threads.  */
+  if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int)) != PS_OK)
+    return TD_ERR;	/* XXX Other error value?  */
+#endif
+
   /* Get the entries one after the other and find out whether the ID
      matches.  */
-  for (cnt = 0; cnt < pthread_threads_max; ++cnt, ++handles)
-    {
-      struct pthread_handle_struct phc;
-      struct _pthread_descr_struct pds;
-
-      if (ps_pdread (ta->ph, handles, &phc,
-		     sizeof (struct pthread_handle_struct)) != PS_OK)
-	return TD_ERR;	/* XXX Other error value?  */
-
-      if (phc.h_descr != NULL)
-	{
-	  if (ps_pdread (ta->ph, phc.h_descr, &pds,
-			 sizeof (struct _pthread_descr_struct)) != PS_OK)
-	    return TD_ERR;	/* XXX Other error value?  */
-
-	  if (pds.p_pid == lwpid)
-	    {
-	      /* Found it.  Now fill in the `td_thrhandle_t' object.  */
-	      th->th_ta_p = (td_thragent_t *) ta;
-	      th->th_unique = phc.h_descr;
-
-	      return TD_OK;
-	    }
-	}
+  for (cnt = 0; cnt < pthread_threads_max && num > 0; ++cnt)
+    if (phc[cnt].h_descr != NULL)
+      {
+	struct _pthread_descr_struct pds;
+
+#ifdef ALL_THREADS_STOPPED
+	/* First count this active thread.  */
+	--num;
+#endif
+
+	if (ps_pdread (ta->ph, phc[cnt].h_descr, &pds, sizeof_descr) != PS_OK)
+	  return TD_ERR;	/* XXX Other error value?  */
+
+	if (pds.p_pid == lwpid)
+	  {
+	    /* Found it.  Now fill in the `td_thrhandle_t' object.  */
+	    th->th_ta_p = (td_thragent_t *) ta;
+	    th->th_unique = phc[cnt].h_descr;
+
+	    return TD_OK;
+	  }
     }
 
   return TD_NOLWP;
diff --git a/linuxthreads_db/td_ta_new.c b/linuxthreads_db/td_ta_new.c
index 65535f8d14..8d6ee9a7c5 100644
--- a/linuxthreads_db/td_ta_new.c
+++ b/linuxthreads_db/td_ta_new.c
@@ -25,10 +25,16 @@
 #include "thread_dbP.h"
 
 
+/* Datatype for the list of known thread agents.  Normally there will
+   be exactly one so we don't spend much though on making it fast.  */
+struct agent_list *__td_agent_list;
+
+
 td_err_e
 td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
 {
   psaddr_t addr;
+  struct agent_list *elemp;
 
   LOG (__FUNCTION__);
 
@@ -130,5 +136,19 @@ td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
 	goto free_return;
     }
 
+  /* Now add the new agent descriptor to the list.  */
+  elemp = (struct agent_list *) malloc (sizeof (struct agent_list));
+  if (elemp == NULL)
+    {
+      /* Argh, now that everything else worked...  */
+      free (*ta);
+      return TD_MALLOC;
+    }
+
+  /* We don't care for thread-safety here.  */
+  elemp->ta = *ta;
+  elemp->next = __td_agent_list;
+  __td_agent_list = elemp;
+
   return TD_OK;
 }
diff --git a/linuxthreads_db/td_ta_reset_stats.c b/linuxthreads_db/td_ta_reset_stats.c
index 1ea1e713ab..11401b9502 100644
--- a/linuxthreads_db/td_ta_reset_stats.c
+++ b/linuxthreads_db/td_ta_reset_stats.c
@@ -26,5 +26,10 @@ td_ta_reset_stats (const td_thragent_t *ta)
 {
   /* XXX We have to figure out what has to be done.  */
   LOG (__FUNCTION__);
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
   return TD_OK;
 }
diff --git a/linuxthreads_db/td_ta_set_event.c b/linuxthreads_db/td_ta_set_event.c
index f783d7567e..4d87fe1b55 100644
--- a/linuxthreads_db/td_ta_set_event.c
+++ b/linuxthreads_db/td_ta_set_event.c
@@ -31,6 +31,10 @@ td_ta_set_event (ta, event)
 
   LOG (__FUNCTION__);
 
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
   /* Write the new value into the thread data structure.  */
   if (ps_pdread (ta->ph, ta->pthread_threads_eventsp,
 		 &old_event, sizeof (td_thrhandle_t)) != PS_OK)
diff --git a/linuxthreads_db/td_ta_setconcurrency.c b/linuxthreads_db/td_ta_setconcurrency.c
index eec9968810..5bb2601b47 100644
--- a/linuxthreads_db/td_ta_setconcurrency.c
+++ b/linuxthreads_db/td_ta_setconcurrency.c
@@ -26,5 +26,10 @@ td_ta_setconcurrency (const td_thragent_t *ta, int level)
 {
   /* This is something LinuxThreads does not support.  */
   LOG (__FUNCTION__);
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
   return TD_NOCAPAB;
 }
diff --git a/linuxthreads_db/td_ta_thr_iter.c b/linuxthreads_db/td_ta_thr_iter.c
index 1fe871f4c7..ecc86c7871 100644
--- a/linuxthreads_db/td_ta_thr_iter.c
+++ b/linuxthreads_db/td_ta_thr_iter.c
@@ -26,24 +26,38 @@ td_ta_thr_iter (const td_thragent_t *ta, 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)
 {
-  int pthread_threads_max = ta->pthread_threads_max;
-  size_t sizeof_descr = ta->sizeof_descr;
-  struct pthread_handle_struct phc[pthread_threads_max];
-  int num;
+  int pthread_threads_max;
+  size_t sizeof_descr;
+  struct pthread_handle_struct *phc;
   int cnt;
+#ifdef ALL_THREADS_STOPPED
+  int num;
+#else
+# define num 1
+#endif
 
   LOG (__FUNCTION__);
 
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  pthread_threads_max = ta->pthread_threads_max;
+  sizeof_descr = ta->sizeof_descr;
+  phc = (struct pthread_handle_struct *) alloca (sizeof (phc[0])
+						 * pthread_threads_max);
+
   /* Read all the descriptors.  */
   if (ps_pdread (ta->ph, ta->handles, phc,
 		 sizeof (struct pthread_handle_struct) * pthread_threads_max)
       != PS_OK)
     return TD_ERR;	/* XXX Other error value?  */
 
+#ifdef ALL_THREADS_STOPPED
   /* Read the number of currently active threads.  */
-  if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int))
-      != PS_OK)
+  if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int)) != PS_OK)
     return TD_ERR;	/* XXX Other error value?  */
+#endif
 
   /* Now get all descriptors, one after the other.  */
   for (cnt = 0; cnt < pthread_threads_max && num > 0; ++cnt)
@@ -52,8 +66,10 @@ td_ta_thr_iter (const td_thragent_t *ta, td_thr_iter_f *callback,
 	struct _pthread_descr_struct pds;
 	td_thrhandle_t th;
 
+#ifdef ALL_THREADS_STOPPED
 	/* First count this active thread.  */
 	--num;
+#endif
 
 	if (ps_pdread (ta->ph, phc[cnt].h_descr, &pds, sizeof_descr)
 	    != PS_OK)
diff --git a/linuxthreads_db/td_ta_tsd_iter.c b/linuxthreads_db/td_ta_tsd_iter.c
index 4eada2b2af..c58928c986 100644
--- a/linuxthreads_db/td_ta_tsd_iter.c
+++ b/linuxthreads_db/td_ta_tsd_iter.c
@@ -25,27 +25,31 @@ td_err_e
 td_ta_tsd_iter (const td_thragent_t *ta, td_key_iter_f *callback,
 		void *cbdata_p)
 {
-  struct pthread_key_struct *keys = ta->keys;
-  int pthread_keys_max = ta->pthread_keys_max;
+  struct pthread_key_struct *keys;
+  int pthread_keys_max;
   int cnt;
 
-  /* XXX We have to figure out what has to be done.  */
   LOG (__FUNCTION__);
 
-  /* Now get all descriptors, one after the other.  */
-  for (cnt = 0; cnt < pthread_keys_max; ++cnt, ++keys)
-    {
-      struct pthread_key_struct key;
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  pthread_keys_max = ta->pthread_keys_max;
+  keys = (struct pthread_key_struct *) alloca (sizeof (keys[0])
+					       * pthread_keys_max);
 
-      if (ps_pdread (ta->ph, keys, &key,
-		     sizeof (struct pthread_key_struct)) != PS_OK)
+  /* 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?  */
 
-      if (key.in_use
-	  /* Return with an error if the callback returns a nonzero value.  */
-	  && callback (cnt, key.destr, cbdata_p) != 0)
-	return TD_DBERR;
-    }
+  /* Now get all descriptors, one after the other.  */
+  for (cnt = 0; cnt < pthread_keys_max; ++cnt)
+    if (keys[cnt].in_use
+	/* Return with an error if the callback returns a nonzero value.  */
+	&& callback (cnt, keys[cnt].destr, cbdata_p) != 0)
+      return TD_DBERR;
 
   return TD_OK;
 }
diff --git a/linuxthreads_db/td_thr_get_info.c b/linuxthreads_db/td_thr_get_info.c
index 1e05d4c214..21f9f68d07 100644
--- a/linuxthreads_db/td_thr_get_info.c
+++ b/linuxthreads_db/td_thr_get_info.c
@@ -69,6 +69,7 @@ td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop)
   infop->ti_startfunc = pds.p_start_args.start_routine;
   memcpy (&infop->ti_events, &pds.p_eventbuf.eventmask,
 	  sizeof (td_thr_events_t));
+  infop->ti_traceme = pds.p_report_events != 0;
 
   return TD_OK;
 }
diff --git a/linuxthreads_db/thread_dbP.h b/linuxthreads_db/thread_dbP.h
index 60921834d9..7e9fb486c6 100644
--- a/linuxthreads_db/thread_dbP.h
+++ b/linuxthreads_db/thread_dbP.h
@@ -50,4 +50,29 @@ struct td_thragent
 };
 
 
+/* Type used internally to keep track of thread agent descriptors.  */
+struct agent_list
+{
+  td_thragent_t *ta;
+  struct agent_list *next;
+};
+
+/* List of all known descriptors.  */
+extern struct agent_list *__td_agent_list;
+
+/* Function used to test for correct thread agent pointer.  */
+static inline int
+ta_ok (const td_thragent_t *ta)
+{
+  struct agent_list *runp = __td_agent_list;
+
+  if (ta == NULL)
+    return 0;
+
+  while (runp != NULL && runp->ta != ta)
+    runp = runp->next;
+
+  return runp != NULL;
+}
+
 #endif /* thread_dbP.h */