* linux-low.c (linux_kill_one_lwp): Assume the lwp is stopped.
authorPedro Alves <palves@redhat.com>
Sun, 2 May 2010 00:47:34 +0000 (00:47 +0000)
committerPedro Alves <palves@redhat.com>
Sun, 2 May 2010 00:47:34 +0000 (00:47 +0000)
(linux_kill): Stop all lwps here.  Don't delete the main lwp here.
(linux_detach_one_lwp): Assume the lwp is stopped.
(any_thread_of): Delete.
(linux_detach): Stop all lwps here.  Don't blindly delete all
breakpoints.
(delete_lwp_callback): New.
(linux_mourn): Delete all lwps of the process that is gone.
(linux_wait_1): Don't delete the last lwp of the process here.
* mem-break.h (mark_breakpoints_out): Declare.
* mem-break.c (mark_breakpoints_out): New.
(free_all_breakpoints): Use it.
* server.c (handle_target_event): If the process is gone, mark
breakpoints out.
* thread-db.c (struct thread_db) <create_bp>: New field.
(thread_db_enable_reporting): Fix prototype.  Store a thread event
breakpoint reference in the thread_db struct.
(thread_db_load_search): Clear the thread_db object.
(try_thread_db_load_1): Ditto.
(switch_to_process): New.
(disable_thread_event_reporting): Use it.
(remove_thread_event_breakpoints): New.
(thread_db_detach, thread_db_mourn): Use it.

gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c
gdb/gdbserver/mem-break.c
gdb/gdbserver/mem-break.h
gdb/gdbserver/server.c
gdb/gdbserver/thread-db.c

index 15f2176df36513bbc9f78fa9b1fc28b8b182058e..a1f479857b45fe20131d0d698b61543e65801267 100644 (file)
@@ -1,3 +1,29 @@
+2010-05-02  Pedro Alves  <pedro@codesourcery.com>
+
+       * linux-low.c (linux_kill_one_lwp): Assume the lwp is stopped.
+       (linux_kill): Stop all lwps here.  Don't delete the main lwp here.
+       (linux_detach_one_lwp): Assume the lwp is stopped.
+       (any_thread_of): Delete.
+       (linux_detach): Stop all lwps here.  Don't blindly delete all
+       breakpoints.
+       (delete_lwp_callback): New.
+       (linux_mourn): Delete all lwps of the process that is gone.
+       (linux_wait_1): Don't delete the last lwp of the process here.
+       * mem-break.h (mark_breakpoints_out): Declare.
+       * mem-break.c (mark_breakpoints_out): New.
+       (free_all_breakpoints): Use it.
+       * server.c (handle_target_event): If the process is gone, mark
+       breakpoints out.
+       * thread-db.c (struct thread_db) <create_bp>: New field.
+       (thread_db_enable_reporting): Fix prototype.  Store a thread event
+       breakpoint reference in the thread_db struct.
+       (thread_db_load_search): Clear the thread_db object.
+       (try_thread_db_load_1): Ditto.
+       (switch_to_process): New.
+       (disable_thread_event_reporting): Use it.
+       (remove_thread_event_breakpoints): New.
+       (thread_db_detach, thread_db_mourn): Use it.
+
 2010-05-01  Pedro Alves  <pedro@codesourcery.com>
 
        * linux-low.c (linux_enable_event_reporting): New.
index 302f702857853d682b6817f91ae0b96aa57dc71e..65a87f68ed85780fb75f5b093e7a13948315d823 100644 (file)
@@ -739,11 +739,6 @@ linux_kill_one_lwp (struct inferior_list_entry *entry, void *args)
       return 0;
     }
 
-  /* If we're killing a running inferior, make sure it is stopped
-     first, as PTRACE_KILL will not work otherwise.  */
-  if (!lwp->stopped)
-    send_sigstop (lwp);
-
   do
     {
       ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0);
@@ -768,6 +763,10 @@ linux_kill (int pid)
   if (process == NULL)
     return -1;
 
+  /* If we're killing a running inferior, make sure it is stopped
+     first, as PTRACE_KILL will not work otherwise.  */
+  stop_all_lwps ();
+
   find_inferior (&all_threads, linux_kill_one_lwp, &pid);
 
   /* See the comment in linux_kill_one_lwp.  We did not kill the first
@@ -779,11 +778,6 @@ linux_kill (int pid)
     fprintf (stderr, "lk_1: killing lwp %ld, for pid: %d\n",
             lwpid_of (lwp), pid);
 
-  /* If we're killing a running inferior, make sure it is stopped
-     first, as PTRACE_KILL will not work otherwise.  */
-  if (!lwp->stopped)
-    send_sigstop (lwp);
-
   do
     {
       ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0);
@@ -792,9 +786,11 @@ linux_kill (int pid)
       lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
     } while (lwpid > 0 && WIFSTOPPED (wstat));
 
-  delete_lwp (lwp);
-
   the_target->mourn (process);
+
+  /* Since we presently can only stop all lwps of all processes, we
+     need to unstop lwps of other processes.  */
+  unstop_all_lwps (NULL);
   return 0;
 }
 
@@ -808,28 +804,6 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
   if (ptid_get_pid (entry->id) != pid)
     return 0;
 
-  /* If we're detaching from a running inferior, make sure it is
-     stopped first, as PTRACE_DETACH will not work otherwise.  */
-  if (!lwp->stopped)
-    {
-      int lwpid = lwpid_of (lwp);
-
-      stopping_threads = 1;
-      send_sigstop (lwp);
-
-      /* If this detects a new thread through a clone event, the new
-        thread is appended to the end of the lwp list, so we'll
-        eventually detach from it.  */
-      wait_for_sigstop (&lwp->head);
-      stopping_threads = 0;
-
-      /* If LWP exits while we're trying to stop it, there's nothing
-        left to do.  */
-      lwp = find_lwp_pid (pid_to_ptid (lwpid));
-      if (lwp == NULL)
-       return 0;
-    }
-
   /* If this process is stopped but is expecting a SIGSTOP, then make
      sure we take care of that now.  This isn't absolutely guaranteed
      to collect the SIGSTOP, but is fairly likely to.  */
@@ -838,8 +812,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
       int wstat;
       /* Clear stop_expected, so that the SIGSTOP will be reported.  */
       lwp->stop_expected = 0;
-      if (lwp->stopped)
-       linux_resume_one_lwp (lwp, 0, 0, NULL);
+      linux_resume_one_lwp (lwp, 0, 0, NULL);
       linux_wait_for_event (lwp->head.id, &wstat, __WALL);
     }
 
@@ -854,17 +827,6 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
   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;
-}
-
 static int
 linux_detach (int pid)
 {
@@ -874,17 +836,37 @@ linux_detach (int pid)
   if (process == NULL)
     return -1;
 
+  /* Stop all threads before detaching.  First, ptrace requires that
+     the thread is stopped to sucessfully detach.  Second, thread_db
+     may need to uninstall thread event breakpoints from memory, which
+     only works with a stopped process anyway.  */
+  stop_all_lwps ();
+
 #ifdef USE_THREAD_DB
   thread_db_detach (process);
 #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);
 
   the_target->mourn (process);
+
+  /* Since we presently can only stop all lwps of all processes, we
+     need to unstop lwps of other processes.  */
+  unstop_all_lwps (NULL);
+  return 0;
+}
+
+/* Remove all LWPs that belong to process PROC from the lwp list.  */
+
+static int
+delete_lwp_callback (struct inferior_list_entry *entry, void *proc)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+  struct process_info *process = proc;
+
+  if (pid_of (lwp) == pid_of (process))
+    delete_lwp (lwp);
+
   return 0;
 }
 
@@ -897,6 +879,8 @@ linux_mourn (struct process_info *process)
   thread_db_mourn (process);
 #endif
 
+  find_inferior (&all_lwps, delete_lwp_callback, process);
+
   /* Freeing all private data.  */
   priv = process->private;
   free (priv->arch_private);
@@ -1695,10 +1679,6 @@ retry:
     {
       if (WIFEXITED (w) || WIFSIGNALED (w))
        {
-         delete_lwp (event_child);
-
-         current_inferior = NULL;
-
          if (WIFEXITED (w))
            {
              ourstatus->kind = TARGET_WAITKIND_EXITED;
index c796948ec88d06a7ac0f74faecd574e60e4bae53..3d7382ecdeaa3320a7f1e4410bf7e7ab23ce990f 100644 (file)
@@ -716,16 +716,24 @@ delete_all_breakpoints (void)
     delete_breakpoint_1 (proc, proc->breakpoints);
 }
 
-/* Release all breakpoints, but do not try to un-insert them from the
-   inferior.  */
+/* Clear the "inserted" flag in all breakpoints.  */
 
 void
-free_all_breakpoints (struct process_info *proc)
+mark_breakpoints_out (struct process_info *proc)
 {
   struct raw_breakpoint *raw_bp;
 
   for (raw_bp = proc->raw_breakpoints; raw_bp != NULL; raw_bp = raw_bp->next)
     raw_bp->inserted = 0;
+}
+
+/* Release all breakpoints, but do not try to un-insert them from the
+   inferior.  */
+
+void
+free_all_breakpoints (struct process_info *proc)
+{
+  mark_breakpoints_out (proc);
 
   /* Note: use PROC explicitly instead of deferring to
      delete_all_breakpoints --- CURRENT_INFERIOR may already have been
index b9fcf651c4c7f52027fabe82fd15d0b0ae97f2c7..0bd86b5d89bbc5bb50ed4f3ff553c7fef611a8fe 100644 (file)
@@ -103,6 +103,10 @@ void set_breakpoint_data (const unsigned char *bp_data, int bp_len);
 
 void delete_all_breakpoints (void);
 
+/* Clear the "inserted" flag in all breakpoints of PROC.  */
+
+void mark_breakpoints_out (struct process_info *proc);
+
 /* Delete all breakpoints, but do not try to un-insert them from the
    inferior.  */
 
index 460cb46beca1d91fbb3e75fef330203b34062686..ffca3977f39b6dd61c53f340b4fd01a98a84b0cc 100644 (file)
@@ -3031,7 +3031,10 @@ handle_target_event (int err, gdb_client_data client_data)
 
       if (last_status.kind == TARGET_WAITKIND_EXITED
          || last_status.kind == TARGET_WAITKIND_SIGNALLED)
-       mourn_inferior (process);
+       {
+         mark_breakpoints_out (process);
+         mourn_inferior (process);
+       }
 
       if (forward_event)
        {
index 8e7d7a9361a4813b491f6c510e35141ade3ce868..7dec30dafabb60079b818d9329f877fa19c2799b 100644 (file)
@@ -52,6 +52,16 @@ struct thread_db
   void *handle;
 #endif
 
+  /* Thread creation event breakpoint.  The code at this location in
+     the child process will be called by the pthread library whenever
+     a new thread is created.  By setting a special breakpoint at this
+     location, GDB can detect when a new thread is created.  We obtain
+     this location via the td_ta_event_addr call.  Note that if the
+     running kernel supports tracing clones, then we don't need to use
+     (and in fact don't use) this magic thread event breakpoint to
+     learn about threads.  */
+  struct breakpoint *td_create_bp;
+
   /* Addresses of libthread_db functions.  */
   td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta);
   td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
@@ -205,7 +215,7 @@ thread_db_create_event (CORE_ADDR where)
 }
 
 static int
-thread_db_enable_reporting ()
+thread_db_enable_reporting (void)
 {
   td_thr_events_t events;
   td_notify_t notify;
@@ -239,8 +249,9 @@ thread_db_enable_reporting ()
               thread_db_err_str (err));
       return 0;
     }
-  set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
-                    thread_db_create_event);
+  thread_db->td_create_bp
+    = set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
+                        thread_db_create_event);
 
   return 1;
 }
@@ -501,6 +512,8 @@ thread_db_load_search (void)
   if (proc->private->thread_db != NULL)
     fatal ("unexpected: proc->private->thread_db != NULL");
 
+  memset (&tdb, 0, sizeof (tdb));
+
   tdb.td_ta_new_p = &td_ta_new;
 
   /* Attempt to open a connection to the thread library.  */
@@ -544,6 +557,8 @@ try_thread_db_load_1 (void *handle)
   if (proc->private->thread_db != NULL)
     fatal ("unexpected: proc->private->thread_db != NULL");
 
+  memset (&tdb, 0, sizeof (tdb));
+
   tdb.handle = handle;
 
   /* Initialize pointers to the dynamic library functions we will use.
@@ -766,6 +781,16 @@ any_thread_of (struct inferior_list_entry *entry, void *args)
   return 0;
 }
 
+static void
+switch_to_process (struct process_info *proc)
+{
+  int pid = pid_of (proc);
+
+  current_inferior =
+    (struct thread_info *) find_inferior (&all_threads,
+                                         any_thread_of, &pid);
+}
+
 /* Disconnect from libthread_db and free resources.  */
 
 static void
@@ -785,15 +810,10 @@ disable_thread_event_reporting (struct process_info *proc)
 
       if (td_ta_clear_event_p != NULL)
        {
-         struct thread_info *saved_inferior;
+         struct thread_info *saved_inferior = current_inferior;
          td_thr_events_t events;
-         int pid;
 
-         pid = pid_of (proc);
-         saved_inferior = current_inferior;
-         current_inferior =
-           (struct thread_info *) find_inferior (&all_threads,
-                                                 any_thread_of, &pid);
+         switch_to_process (proc);
 
          /* Set the process wide mask saying we aren't interested
             in any events anymore.  */
@@ -805,10 +825,34 @@ disable_thread_event_reporting (struct process_info *proc)
     }
 }
 
+static void
+remove_thread_event_breakpoints (struct process_info *proc)
+{
+  struct thread_db *thread_db = proc->private->thread_db;
+
+  if (thread_db->td_create_bp != NULL)
+    {
+      struct thread_info *saved_inferior = current_inferior;
+
+      switch_to_process (proc);
+
+      delete_breakpoint (thread_db->td_create_bp);
+      thread_db->td_create_bp = NULL;
+
+      current_inferior = saved_inferior;
+    }
+}
+
 void
 thread_db_detach (struct process_info *proc)
 {
-  disable_thread_event_reporting (proc);
+  struct thread_db *thread_db = proc->private->thread_db;
+
+  if (thread_db)
+    {
+      disable_thread_event_reporting (proc);
+      remove_thread_event_breakpoints (proc);
+    }
 }
 
 /* Disconnect from libthread_db and free resources.  */