gdb/
authorPedro Alves <palves@redhat.com>
Thu, 28 May 2009 17:19:58 +0000 (17:19 +0000)
committerPedro Alves <palves@redhat.com>
Thu, 28 May 2009 17:19:58 +0000 (17:19 +0000)
2009-05-28  Pedro Alves  <pedro@codesourcery.com>

* infrun.c (handle_inferior_event): When thread hoping, switch
inferior_ptid to the event thread before removing breakpoints from
the target.  If not stopping, also try to revert back to a thread
that was doing a "next".  Check if that thread still exists before
resuming.
(currently_stepping_thread): Delete and merge with ...
(currently_stepping): ... this.
(currently_stepping_callback): Rename to ...
(currently_stepping_or_nexting_callback): ... this, and also
return true if the thread was stepping over a call (has a
step-resume breakpoint).

gdb/testsuite/
2009-05-28  Pedro Alves  <pedro@codesourcery.com>

* gdb.threads/threxit-hop-specific.c: New.
* gdb.threads/threxit-hop-specific.exp: New.
* gdb.threads/thread-execl.c: New.
* gdb.threads/thread-execl.exp: New.

gdb/ChangeLog
gdb/infrun.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.threads/thread-execl.c [new file with mode: 0644]
gdb/testsuite/gdb.threads/thread-execl.exp [new file with mode: 0644]
gdb/testsuite/gdb.threads/threxit-hop-specific.c [new file with mode: 0644]
gdb/testsuite/gdb.threads/threxit-hop-specific.exp [new file with mode: 0644]

index f57cea2d34ba2d76e8a29d6b383ee5125f69fb93..f3a579b80b737503242c3c132f21ce6632189ac2 100644 (file)
@@ -1,3 +1,17 @@
+2009-05-28  Pedro Alves  <pedro@codesourcery.com>
+
+       * infrun.c (handle_inferior_event): When thread hoping, switch
+       inferior_ptid to the event thread before removing breakpoints from
+       the target.  If not stopping, also try to revert back to a thread
+       that was doing a "next".  Check if that thread still exists before
+       resuming.
+       (currently_stepping_thread): Delete and merge with ...
+       (currently_stepping): ... this.
+       (currently_stepping_callback): Rename to ...
+       (currently_stepping_or_nexting_callback): ... this, and also
+       return true if the thread was stepping over a call (has a
+       step-resume breakpoint).
+
 2009-05-28  Tom Tromey  <tromey@redhat.com>
 
        * python/python.c (gdbpy_parameter): Rename.  Fix error message.
index 381d208a064fb1bb25197aa5d8e3b6976cd70524..88a1c4e0f058fc283fde3303d5eef8a889af0be3 100644 (file)
@@ -75,7 +75,8 @@ static void set_schedlock_func (char *args, int from_tty,
 
 static int currently_stepping (struct thread_info *tp);
 
-static int currently_stepping_callback (struct thread_info *tp, void *data);
+static int currently_stepping_or_nexting_callback (struct thread_info *tp,
+                                                  void *data);
 
 static void xdb_handle_command (char *args, int from_tty);
 
@@ -2896,6 +2897,11 @@ targets should add new threads to the thread list themselves in non-stop mode.")
          if (debug_infrun)
            fprintf_unfiltered (gdb_stdlog, "infrun: thread_hop_needed\n");
 
+         /* Switch context before touching inferior memory, the
+            previous thread may have exited.  */
+         if (!ptid_equal (inferior_ptid, ecs->ptid))
+           context_switch (ecs->ptid);
+
          /* Saw a breakpoint, but it was hit by the wrong thread.
             Just continue. */
 
@@ -2922,9 +2928,6 @@ targets should add new threads to the thread list themselves in non-stop mode.")
            error (_("Cannot step over breakpoint hit in wrong thread"));
          else
            {                   /* Single step */
-             if (!ptid_equal (inferior_ptid, ecs->ptid))
-               context_switch (ecs->ptid);
-
              if (!non_stop)
                {
                  /* Only need to require the next event from this
@@ -3483,7 +3486,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
   if (!non_stop)
     {
       struct thread_info *tp;
-      tp = iterate_over_threads (currently_stepping_callback,
+      tp = iterate_over_threads (currently_stepping_or_nexting_callback,
                                 ecs->event_thread);
       if (tp)
        {
@@ -3498,6 +3501,21 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
              return;
            }
 
+         /* If the stepping thread exited, then don't try reverting
+            back to it, just keep going.  We need to query the target
+            in case it doesn't support thread exit events.  */
+         if (is_exited (tp->ptid)
+             || !target_thread_alive (tp->ptid))
+           {
+             if (debug_infrun)
+               fprintf_unfiltered (gdb_stdlog, "\
+infrun: not switching back to stepped thread, it has vanished\n");
+
+             delete_thread (tp->ptid);
+             keep_going (ecs);
+             return;
+           }
+
          /* Otherwise, we no longer expect a trap in the current thread.
             Clear the trap_expected flag before switching back -- this is
             what keep_going would do as well, if we called it.  */
@@ -3931,28 +3949,29 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
   keep_going (ecs);
 }
 
-/* Are we in the middle of stepping?  */
+/* Is thread TP in the middle of single-stepping?  */
 
 static int
-currently_stepping_thread (struct thread_info *tp)
+currently_stepping (struct thread_info *tp)
 {
-  return (tp->step_range_end && tp->step_resume_breakpoint == NULL)
-        || tp->trap_expected
-        || tp->stepping_through_solib_after_catch;
+  return ((tp->step_range_end && tp->step_resume_breakpoint == NULL)
+         || tp->trap_expected
+         || tp->stepping_through_solib_after_catch
+         || bpstat_should_step ());
 }
 
-static int
-currently_stepping_callback (struct thread_info *tp, void *data)
-{
-  /* Return true if any thread *but* the one passed in "data" is
-     in the middle of stepping.  */
-  return tp != data && currently_stepping_thread (tp);
-}
+/* Returns true if any thread *but* the one passed in "data" is in the
+   middle of stepping or of handling a "next".  */
 
 static int
-currently_stepping (struct thread_info *tp)
+currently_stepping_or_nexting_callback (struct thread_info *tp, void *data)
 {
-  return currently_stepping_thread (tp) || bpstat_should_step ();
+  if (tp == data)
+    return 0;
+
+  return (tp->step_range_end
+         || tp->trap_expected
+         || tp->stepping_through_solib_after_catch);
 }
 
 /* Inferior has stepped into a subroutine call with source code that
index c4b0fab23a27557db27f525822ad4d772bb90e5b..c444806ea231f71b1b3394d0fc3361a1b5217b3d 100644 (file)
@@ -1,3 +1,10 @@
+2009-05-28  Pedro Alves  <pedro@codesourcery.com>
+
+       * gdb.threads/threxit-hop-specific.c: New.
+       * gdb.threads/threxit-hop-specific.exp: New.
+       * gdb.threads/thread-execl.c: New.
+       * gdb.threads/thread-execl.exp: New.
+
 2009-05-27  Tom Tromey  <tromey@redhat.com>
            Thiago Jung Bauermann  <bauerman@br.ibm.com>
 
diff --git a/gdb/testsuite/gdb.threads/thread-execl.c b/gdb/testsuite/gdb.threads/thread-execl.c
new file mode 100644 (file)
index 0000000..ec23535
--- /dev/null
@@ -0,0 +1,48 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2009 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <pthread.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static const char *image;
+
+void *
+thread_execler (void *arg)
+{
+  /* Exec ourselves again.  */
+  if (execl (image, image, NULL) == -1)
+    {
+      perror ("execl");
+      abort ();
+    }
+
+  return NULL;
+}
+
+int
+main (int argc, char **argv)
+{
+  pthread_t thread;
+
+  image = argv[0];
+
+  pthread_create (&thread, NULL, thread_execler, NULL);
+  pthread_join (thread, NULL);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/thread-execl.exp b/gdb/testsuite/gdb.threads/thread-execl.exp
new file mode 100644 (file)
index 0000000..24bdab6
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright (C) 2009 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test that GDB doesn't get stuck when stepping over an exec call done
+# by a thread other than the main thread.
+
+# There's no support for exec events in the remote protocol.
+if { [is_remote target] } {
+    return 0
+}
+
+set testfile "thread-execl"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+        executable [list debug "incdir=${objdir}"]] != "" } {
+    return -1
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+runto_main
+
+# Get ourselves to the thread that execs
+gdb_breakpoint "thread_execler"
+gdb_test "continue" ".*thread_execler.*" "continue to thread start"
+
+# Now set a breakpoint at `main', and step over the execl call.  The
+# breakpoint at main should be reached.  GDB should not try to revert
+# back to the old thread from the old image and resume stepping it
+# (since it is gone).
+gdb_breakpoint "main"
+gdb_test "next" ".*main.*" "get to main in new image"
+
+return 0
diff --git a/gdb/testsuite/gdb.threads/threxit-hop-specific.c b/gdb/testsuite/gdb.threads/threxit-hop-specific.c
new file mode 100644 (file)
index 0000000..9f033d5
--- /dev/null
@@ -0,0 +1,48 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2009 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <pthread.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+void *
+thread_function (void *arg)
+{
+  /* We'll next over this, with scheduler-locking off.  */
+  pthread_exit (NULL);
+}
+
+void
+hop_me (void)
+{
+}
+
+int
+main (int argc, char **argv)
+{
+  pthread_t thread;
+
+  pthread_create (&thread, NULL, thread_function, NULL);
+  pthread_join (thread, NULL); /* wait for exit */
+
+  /* The main thread should be able to hop over the breakpoint set
+     here...  */
+  hop_me (); /* set thread specific breakpoint here */
+
+  /* ... and reach here.  */
+  exit (0); /* set exit breakpoint here */
+}
diff --git a/gdb/testsuite/gdb.threads/threxit-hop-specific.exp b/gdb/testsuite/gdb.threads/threxit-hop-specific.exp
new file mode 100644 (file)
index 0000000..1049c49
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright (C) 2009 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test that GDB doesn't get stuck when thread hoping over a thread
+# specific breakpoint when the selected thread has gone away.
+
+set testfile "threxit-hop-specific"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+        executable [list debug "incdir=${objdir}"]] != "" } {
+    return -1
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+gdb_load ${binfile}
+
+runto_main
+
+# Get ourselves to the thread that exits
+gdb_breakpoint "thread_function"
+gdb_test "continue" ".*thread_function.*" "continue to thread start"
+
+# Set a thread specific breakpoint somewhere the main thread will pass
+# by, but make it specific to the thread that is going to exit.  Step
+# over the pthread_exit call.  GDB should still be able to step over
+# the thread specific breakpoint, and reach the other breakpoint,
+# which is not thread specific.
+set bpthrline [gdb_get_line_number "set thread specific breakpoint here"]
+gdb_test "break $bpthrline thread 2" \
+    "Breakpoint .*$srcfile.*$bpthrline.*" \
+    "set thread specific breakpoint"
+
+set bpexitline [gdb_get_line_number "set exit breakpoint here"]
+gdb_breakpoint "$bpexitline"
+
+gdb_test "next" \
+    ".*set exit breakpoint here.*" \
+    "get past the thread specific breakpoint"
+
+return 0