This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: Handle early debugging in NPTL applications


This is the last of a series of patches to fix staticthreads.exp for NPTL.
It is a mostly trivial patch, but deserves an explanation, because there's
one bit of it I'm not sure is right... and that relies in turn on a glibc
patch I haven't posted yet.

When debugging LinuxThreads using libthread_db, if the main thread had not
been initialized yet, libthread_db would fake up a description of it
that sufficed for GDB's purposes.  By and large this worked OK.  We
could accurately predict e.g. its thread ID, since the first thread in
LinuxThreads always had TID == 16384.

Now, for NPTL, this is a bit harder.  The TID is the value of pthread_self
which in turn points to the struct pthread for the thread.  If libpthread
hasn't initialised itself yet, we have no idea where this will end up!

Right now NPTL libthread_db contains similar fake-up code.  But it's
insufficiently complete; we'll read uninitialized data or registers
from the target and get inexplicable errors later on.  And we can't
easily extend the fakery because then one thread will mysteriously
appear to change TID.

I spent a bit of time thinking about this and I think the most sensible
behavior is to report that there are zero threads at this point,
but that things are others A-OK.  Then, if the global event mask
requests thread creation events, report a "creation" event for the
main thread when libpthread has been initialized.  Then everything
just works: we push libthread_db early, it proxies to linux-nat
until the library is ready, and then takes over.

Other opinions on the approach welcomed before I submit that change
to glibc!

The patch itself goes through linux-thread-db.c making sure that
we behave sanely when there are no threads.  It turns out that
the only function needing a change was thread_db_wait, which needs
to not attempt to convert PTIDs to include thread IDs if there
aren't any threads yet; I didn't want to weaken the error when
we failed to find a matching thread in other circumstances, so
I added a special-case for the thread list being empty.

A couple of other functions didn't look like they would handle
this case correctly, but at the same time, they were dead code;
there's no way to get to thread_db_create_inferior because
the target is always unpushed before running, ditto attach,
and the futzing around with proc_handle.pid is unnecessary
since mourning clears it.

Any comments on the approach or the patch?

-- 
Daniel Jacobowitz
CodeSourcery

2006-02-27  Daniel Jacobowitz  <dan@codesourcery.com>

	* src/gdb/linux-thread-db.c (thread_db_attach): Delete.
	(thread_db_detach): Typo fix.  Call target_mourn_inferior
	instead of fixing up proc_handle.
	(have_threads_callback, have_threads): New functions.
	(thread_db_wait): Remove dead proc_handle.pid check.  Only
	translate PTIDs if we have registered threads.
	(thread_db_create_inferior, thread_db_post_startup_inferior): Delete.
	(init_thread_db_ops): Don't set to_attach, to_create_inferior,
	or to_post_startup_inferior.

Index: src/gdb/linux-thread-db.c
===================================================================
--- src.orig/gdb/linux-thread-db.c	2006-02-27 11:37:10.000000000 -0500
+++ src/gdb/linux-thread-db.c	2006-02-27 11:37:14.000000000 -0500
@@ -766,23 +766,6 @@ attach_thread (ptid_t ptid, const td_thr
 }
 
 static void
-thread_db_attach (char *args, int from_tty)
-{
-  target_beneath->to_attach (args, from_tty);
-
-  /* Destroy thread info; it's no longer valid.  */
-  init_thread_list ();
-
-  /* The child process is now the actual multi-threaded
-     program.  Snatch its process ID...  */
-  proc_handle.pid = GET_PID (inferior_ptid);
-
-  /* ...and perform the remaining initialization steps.  */
-  enable_thread_event_reporting ();
-  thread_db_find_new_threads ();
-}
-
-static void
 detach_thread (ptid_t ptid, int verbose)
 {
   struct thread_info *thread_info;
@@ -808,14 +791,13 @@ thread_db_detach (char *args, int from_t
   disable_thread_event_reporting ();
 
   /* There's no need to save & restore inferior_ptid here, since the
-     inferior is supposed to be survive this function call.  */
+     inferior is not supposed to survive this function call.  */
   inferior_ptid = lwp_from_thread (inferior_ptid);
 
-  /* Forget about the child's process ID.  We shouldn't need it
-     anymore.  */
-  proc_handle.pid = 0;
-
   target_beneath->to_detach (args, from_tty);
+
+  /* Should this be done by detach_command?  */
+  target_mourn_inferior ();
 }
 
 static int
@@ -926,6 +908,21 @@ check_event (ptid_t ptid)
   while (loop);
 }
 
+/* Return 1 if any threads have been registered.  There may be none
+   if libthread_db is not fully initialized yet.  */
+
+static int
+have_threads_callback (struct thread_info *thread, void *dummy)
+{
+  return 1;
+}
+
+static int
+have_threads (void)
+{
+  return iterate_over_threads (have_threads_callback, NULL) != NULL;
+}
+
 static ptid_t
 thread_db_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 {
@@ -936,12 +933,6 @@ thread_db_wait (ptid_t ptid, struct targ
 
   ptid = target_beneath->to_wait (ptid, ourstatus);
 
-  if (proc_handle.pid == 0)
-    /* The current child process isn't the actual multi-threaded
-       program yet, so don't try to do any special thread-specific
-       post-processing and bail out early.  */
-    return ptid;
-
   if (ourstatus->kind == TARGET_WAITKIND_EXITED)
     return pid_to_ptid (-1);
 
@@ -950,18 +941,22 @@ thread_db_wait (ptid_t ptid, struct targ
     /* Check for a thread event.  */
     check_event (ptid);
 
-  if (!ptid_equal (trap_ptid, null_ptid))
-    trap_ptid = thread_from_lwp (trap_ptid);
+  if (have_threads ())
+    {
+      /* Change ptids back into the higher level PID + TID format.  If
+	 the thread is dead and no longer on the thread list, we will
+	 get back a dead ptid.  This can occur if the thread death
+	 event gets postponed by other simultaneous events.  In such a
+	 case, we want to just ignore the event and continue on.  */
+
+      if (!ptid_equal (trap_ptid, null_ptid))
+	trap_ptid = thread_from_lwp (trap_ptid);
+
+      ptid = thread_from_lwp (ptid);
+      if (GET_PID (ptid) == -1)
+	ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+    }
 
-  /* Change the ptid back into the higher level PID + TID format.
-     If the thread is dead and no longer on the thread list, we will 
-     get back a dead ptid.  This can occur if the thread death event
-     gets postponed by other simultaneous events.  In such a case, 
-     we want to just ignore the event and continue on.  */
-  ptid = thread_from_lwp (ptid);
-  if (GET_PID (ptid) == -1)
-    ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
-  
   return ptid;
 }
 
@@ -1075,30 +1070,6 @@ thread_db_kill (void)
 }
 
 static void
-thread_db_create_inferior (char *exec_file, char *allargs, char **env,
-			   int from_tty)
-{
-  unpush_target (&thread_db_ops);
-  using_thread_db = 0;
-  target_beneath->to_create_inferior (exec_file, allargs, env, from_tty);
-}
-
-static void
-thread_db_post_startup_inferior (ptid_t ptid)
-{
-  if (proc_handle.pid == 0)
-    {
-      /* The child process is now the actual multi-threaded
-         program.  Snatch its process ID...  */
-      proc_handle.pid = GET_PID (ptid);
-
-      /* ...and perform the remaining initialization steps.  */
-      enable_thread_event_reporting ();
-      thread_db_find_new_threads ();
-    }
-}
-
-static void
 thread_db_mourn_inferior (void)
 {
   /* Forget about the child's process ID.  We shouldn't need it
@@ -1302,7 +1273,6 @@ init_thread_db_ops (void)
   thread_db_ops.to_shortname = "multi-thread";
   thread_db_ops.to_longname = "multi-threaded child process.";
   thread_db_ops.to_doc = "Threads and pthreads support.";
-  thread_db_ops.to_attach = thread_db_attach;
   thread_db_ops.to_detach = thread_db_detach;
   thread_db_ops.to_resume = thread_db_resume;
   thread_db_ops.to_wait = thread_db_wait;
@@ -1310,8 +1280,6 @@ init_thread_db_ops (void)
   thread_db_ops.to_store_registers = thread_db_store_registers;
   thread_db_ops.to_xfer_partial = thread_db_xfer_partial;
   thread_db_ops.to_kill = thread_db_kill;
-  thread_db_ops.to_create_inferior = thread_db_create_inferior;
-  thread_db_ops.to_post_startup_inferior = thread_db_post_startup_inferior;
   thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior;
   thread_db_ops.to_thread_alive = thread_db_thread_alive;
   thread_db_ops.to_find_new_threads = thread_db_find_new_threads;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]