Fix gdbserver detach crash

Pedro Alves pedro@codesourcery.com
Mon Dec 28 16:10:00 GMT 2009


This gdbserver patch:

2009-12-28  Pedro Alves  <pedro@codesourcery.com>

	gdb/gdbserver/
	* linux-low.c (linux_remove_process): Remove `detaching'
	parameter.  Don't release/detach from thread_db here.
	(linux_kill): Release/detach from thread_db here, ...
	(linux_detach): ... and here, before actually detaching.
	(linux_wait_1): ... and here, when a process exits.
	* thread-db.c (any_thread_of): New.
	(thread_db_free): Switch the current inferior to a thread of the
	passed in process.

fixes a gdbserver crash Joel reported on IRC:

 <brobecke>: (Using the) pthread_cond_wait.c (test). To reproduce; connect gdb, break on break_me, cont, and then detach.

#0  0x0000000000408324 in look_up_one_symbol (
    name=0x7f04271723a2 "__nptl_threads_events", addrp=0x7fff2faf8df8)
    at /.amd/nas/homes/brobecke/act/gdb-public/gdb/gdbserver/remote-utils.c:1374
#1  0x000000000041a353 in ps_pglobal_lookup (ph=0x7fff2faf7ad0, 
    obj=0x7f0427172261 "libpthread.so.0", 
    name=0x7f04271723a2 "__nptl_threads_events", sym_addr=0x62fd00)
    at /.amd/nas/homes/brobecke/act/gdb-public/gdb/gdbserver/proc-service.c:68
#2  0x00007f042717160d in td_ta_clear_event () from /lib/libthread_db.so.1
#3  0x000000000041a1dd in thread_db_free (proc=0x62f190, detaching=1)
    at /.amd/nas/homes/brobecke/act/gdb-public/gdb/gdbserver/thread-db.c:785
#4  0x00000000004113b1 in linux_remove_process (process=0x62f190, detaching=1)
    at /.amd/nas/homes/brobecke/act/gdb-public/gdb/gdbserver/linux-low.c:266
#5  0x000000000041234b in linux_detach (pid=32447)
    at /.amd/nas/homes/brobecke/act/gdb-public/gdb/gdbserver/linux-low.c:829

linux_detach deletes all lwps and threads before calling linux_remove_process,
leaving the current_inferior global (and by consequence, the
current_process function) dangling.  Note that look_up_one_symbol and
proc-service.c rely on the current process: I've added the missing
inferior switching to thread_db_free.  I think all code paths ended up
with the right current inferior by accident, but (readability, maintainability,
and cleanliness wise) we better not rely on that when we have an
explicit `struct process *' parameter (in thread_db_free).

We should be detaching from thread_db before actually detaching from
all lwps, like gdb itself does.  For kill/process exit, I just added
explicit thread_db_free calls, instead of introducing a target_mourn
concept.

Tested on x86_64-linux, native gdbserver.  I'm applying it in a bit.

-- 
Pedro Alves

---
 gdb/gdbserver/linux-low.c |   22 ++++++++++++++--------
 gdb/gdbserver/thread-db.c |   20 ++++++++++++++++++++
 2 files changed, 34 insertions(+), 8 deletions(-)

Index: src/gdb/gdbserver/linux-low.c
===================================================================
--- src.orig/gdb/gdbserver/linux-low.c	2009-12-28 14:18:23.000000000 +0000
+++ src/gdb/gdbserver/linux-low.c	2009-12-28 15:16:24.000000000 +0000
@@ -258,14 +258,10 @@ linux_add_process (int pid, int attached
    also freeing all private data.  */
 
 static void
-linux_remove_process (struct process_info *process, int detaching)
+linux_remove_process (struct process_info *process)
 {
   struct process_info_private *priv = process->private;
 
-#ifdef USE_THREAD_DB
-  thread_db_free (process, detaching);
-#endif
-
   free (priv->arch_private);
   free (priv);
   remove_process (process);
@@ -736,8 +732,11 @@ linux_kill (int pid)
       lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
     } while (lwpid > 0 && WIFSTOPPED (wstat));
 
+#ifdef USE_THREAD_DB
+  thread_db_free (process, 0);
+#endif
   delete_lwp (lwp);
-  linux_remove_process (process, 0);
+  linux_remove_process (process);
   return 0;
 }
 
@@ -821,12 +820,16 @@ linux_detach (int pid)
   if (process == NULL)
     return -1;
 
+#ifdef USE_THREAD_DB
+  thread_db_free (process, 1);
+#endif
+
   current_inferior =
     (struct thread_info *) find_inferior (&all_threads, any_thread_of, &pid);
 
   delete_all_breakpoints ();
   find_inferior (&all_threads, linux_detach_one_lwp, &pid);
-  linux_remove_process (process, 1);
+  linux_remove_process (process);
   return 0;
 }
 
@@ -1451,8 +1454,11 @@ retry:
 	  int pid = pid_of (lwp);
 	  struct process_info *process = find_process_pid (pid);
 
+#ifdef USE_THREAD_DB
+	  thread_db_free (process, 0);
+#endif
 	  delete_lwp (lwp);
-	  linux_remove_process (process, 0);
+	  linux_remove_process (process);
 
 	  current_inferior = NULL;
 
Index: src/gdb/gdbserver/thread-db.c
===================================================================
--- src.orig/gdb/gdbserver/thread-db.c	2009-12-28 14:38:18.000000000 +0000
+++ src/gdb/gdbserver/thread-db.c	2009-12-28 15:18:17.000000000 +0000
@@ -755,6 +755,17 @@ thread_db_init (int use_events)
   return 0;
 }
 
+static int
+any_thread_of (struct inferior_list_entry *entry, void *args)
+{
+  int *pid_p = args;
+
+  if (ptid_get_pid (entry->id) == *pid_p)
+    return 1;
+
+  return 0;
+}
+
 /* Disconnect from libthread_db and free resources.  */
 
 void
@@ -763,6 +774,8 @@ thread_db_free (struct process_info *pro
   struct thread_db *thread_db = proc->private->thread_db;
   if (thread_db)
     {
+      struct thread_info *saved_inferior;
+      int pid;
       td_err_e (*td_ta_delete_p) (td_thragent_t *);
       td_err_e (*td_ta_clear_event_p) (const td_thragent_t *ta,
 				       td_thr_events_t *event);
@@ -775,6 +788,12 @@ thread_db_free (struct process_info *pro
       td_ta_clear_event_p = &td_ta_clear_event;
 #endif
 
+      pid = pid_of (proc);
+      saved_inferior = current_inferior;
+      current_inferior =
+	(struct thread_info *) find_inferior (&all_threads,
+					      any_thread_of, &pid);
+
       if (detaching && td_ta_clear_event_p != NULL)
 	{
 	  td_thr_events_t events;
@@ -794,6 +813,7 @@ thread_db_free (struct process_info *pro
 
       free (thread_db);
       proc->private->thread_db = NULL;
+      current_inferior = saved_inferior;
     }
 }
 



More information about the Gdb-patches mailing list