28857cc
2005-02-11  Jeff Johnston  <jjohnstn@redhat.com>
28857cc
28857cc
	* target.h (target_waitstatus): Add new step_thread_exit flag.
28857cc
	* infrun.c (init_execution_control_state): Initialize step_thread_exit.
28857cc
	(handle_inferior_event): If step_thread_exit flag is set, print
28857cc
	out special message and reset flag.
28857cc
	(currently_stepping): Do not return true if step_thread_exit flag
28857cc
	is set.
28857cc
	* linux-nat.c (resume_callback): Use second parameter to notify
28857cc
	if the resume should be a PTRACE_SINGLESTEP or PTRACE_CONT.
28857cc
	(stop_and_resume_callback): Pass on data parameter to resume_callback.
28857cc
	(linux_nat_resume): Don't attempt to resume if lp is NULL.
28857cc
	(linux_nat_wait): Do not wait on step_lp as first wait.  After
28857cc
	wait, check if step_lp has an event or not.  If the step lwp has
28857cc
	exited, issue a stop on the first non-step_lp lwp in the lwp list.
28857cc
	Change the delayed stop code to not ignore an intentional stop.
28857cc
	If we see an event on an lwp which isn't the step_lp, verify if
28857cc
	the step_lp has exited or not.  Set the step_thread_exit flag if
28857cc
	we have verified that the step_lp is gone.
28857cc
	* testsuite/gdb.threads/step-thread-exit.c: New testcase.
28857cc
	* testsuite/gdb.threads/step-thread-exit.exp: Ditto.
28857cc
	
9231e41
Index: gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.c
9231e41
===================================================================
9231e41
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
fef19e0
+++ gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.c	2006-07-12 03:18:47.000000000 -0300
fef19e0
@@ -0,0 +1,50 @@
28857cc
+/* This testcase is part of GDB, the GNU debugger.
28857cc
+
28857cc
+   Copyright 2005 Free Software Foundation, Inc.
28857cc
+
28857cc
+   This program is free software; you can redistribute it and/or modify
28857cc
+   it under the terms of the GNU General Public License as published by
28857cc
+   the Free Software Foundation; either version 2 of the License, or
28857cc
+   (at your option) any later version.
28857cc
+
28857cc
+   This program is distributed in the hope that it will be useful,
28857cc
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
28857cc
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28857cc
+   GNU General Public License for more details.
28857cc
+
28857cc
+   You should have received a copy of the GNU General Public License
28857cc
+   along with this program; if not, write to the Free Software
28857cc
+   Foundation, Inc., 59 Temple Place - Suite 330,
28857cc
+   Boston, MA 02111-1307, USA.  */
28857cc
+
28857cc
+#include <pthread.h>
28857cc
+#include <stdio.h>
28857cc
+#include <stdlib.h>
28857cc
+#include <unistd.h>
28857cc
+
28857cc
+void *thread_function (void *ptr)
28857cc
+{
28857cc
+  int *x = (int *)ptr;
28857cc
+  printf("In thread_function, *x is %d\n", *x);
28857cc
+} /* thread_function_end */
28857cc
+
fef19e0
+volatile int repeat = 0;
fef19e0
+
28857cc
+main()
28857cc
+{
28857cc
+  int ret;
28857cc
+  pthread_t th;
28857cc
+  int i = 3;
28857cc
+
28857cc
+  ret = pthread_create (&th, NULL, thread_function, &i);
fef19e0
+  do
fef19e0
+    {
fef19e0
+      repeat = 0;
fef19e0
+      sleep (3);  /* sleep */
fef19e0
+    }
fef19e0
+  while (repeat);
28857cc
+  pthread_join (th, NULL);
28857cc
+  return 0;
28857cc
+}
28857cc
+
28857cc
+
9231e41
Index: gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.exp
9231e41
===================================================================
9231e41
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
fef19e0
+++ gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.exp	2006-07-12 03:22:30.000000000 -0300
fef19e0
@@ -0,0 +1,113 @@
28857cc
+# This testcase is part of GDB, the GNU debugger.
28857cc
+
28857cc
+# Copyright 2005 Free Software Foundation, Inc.
28857cc
+
28857cc
+# This program is free software; you can redistribute it and/or modify
28857cc
+# it under the terms of the GNU General Public License as published by
28857cc
+# the Free Software Foundation; either version 2 of the License, or
28857cc
+# (at your option) any later version.
28857cc
+#
28857cc
+# This program is distributed in the hope that it will be useful,
28857cc
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
28857cc
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28857cc
+# GNU General Public License for more details.
28857cc
+#
28857cc
+# You should have received a copy of the GNU General Public License
28857cc
+# along with this program; if not, write to the Free Software
28857cc
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
28857cc
+
28857cc
+# Check that GDB can step over a thread exit.
28857cc
+
28857cc
+if $tracelevel {
28857cc
+    strace $tracelevel
28857cc
+}
28857cc
+
28857cc
+set prms_id 0
28857cc
+set bug_id 0
28857cc
+
28857cc
+set testfile "step-thread-exit"
28857cc
+set srcfile ${testfile}.c
28857cc
+set binfile ${objdir}/${subdir}/${testfile}
28857cc
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } {
28857cc
+    return -1
28857cc
+}
28857cc
+
28857cc
+gdb_exit
28857cc
+gdb_start
28857cc
+gdb_reinitialize_dir $srcdir/$subdir
28857cc
+gdb_load ${binfile}
28857cc
+
28857cc
+# Reset the debug file directory so we can't debug within the C library
28857cc
+gdb_test "set debug-file-directory ." "" ""
28857cc
+
28857cc
+#
28857cc
+# Run to `main' where we begin our tests.
28857cc
+#
28857cc
+
28857cc
+if ![runto_main] then {
28857cc
+    gdb_suppress_tests
28857cc
+}
28857cc
+
28857cc
+set sleep_line [expr [gdb_get_line_number "sleep"]]
28857cc
+set end_line [expr [gdb_get_line_number "thread_function_end"]]
28857cc
+
28857cc
+gdb_breakpoint "$end_line"
28857cc
+gdb_test "continue" "Break.*thread_function.*" "continue to thread_function 1"
28857cc
+
28857cc
+# Keep nexting until we cause the thread to exit.  We expect the main
28857cc
+# thread to be stopped and a message printed to tell us we have stepped
28857cc
+# over the thread exit.
28857cc
+set test "step over thread exit 1"
28857cc
+gdb_test_multiple "next" "$test" {
28857cc
+  -re "\}.*$gdb_prompt $" {
28857cc
+     send_gdb "next\n"
28857cc
+     exp_continue
28857cc
+  }
fef19e0
+  -re "Stepped over thread exit.*Program received signal SIGSTOP.*$gdb_prompt $" {
fef19e0
+     pass "$test"
28857cc
+  }
28857cc
+  -re "start_thread.*$gdb_prompt $" {
28857cc
+     send_gdb "next\n"
28857cc
+     exp_continue
28857cc
+  }
28857cc
+}
28857cc
+
28857cc
+gdb_test "bt" ".*sleep.*main.*$sleep_line.*" "backtrace after step 1"
28857cc
+
28857cc
+runto_main
28857cc
+gdb_breakpoint "$sleep_line"
28857cc
+gdb_breakpoint "$end_line"
fef19e0
+set test "continue to thread_function 2"
fef19e0
+gdb_test_multiple "continue" "$test" {
fef19e0
+    -re "Break.*thread_function.*$gdb_prompt $" {
fef19e0
+	pass $test
fef19e0
+    }
fef19e0
+    -re "Break.*$sleep_line.*$gdb_prompt $" {
fef19e0
+	gdb_test "set repeat=1" "" ""
fef19e0
+	send_gdb "continue\n"
fef19e0
+	exp_continue
fef19e0
+    }
fef19e0
+}
28857cc
+
28857cc
+# Keep nexting until we cause the thread to exit.  In this case, we
28857cc
+# expect the breakpoint in the main thread to have already triggered
28857cc
+# and so we should stop there with a message that we stepped over
28857cc
+# the thread exit.
28857cc
+set test "step over thread exit 2"
28857cc
+gdb_test_multiple "next" "$test" {
28857cc
+  -re "\}.*$gdb_prompt $" {
28857cc
+     send_gdb "next\n"
28857cc
+     exp_continue
28857cc
+  }
fef19e0
+  -re "Stepped over thread exit.*Break.*$sleep_line.*$gdb_prompt $" {
fef19e0
+     pass "$test (breakpoint hit)"
fef19e0
+  }
fef19e0
+  -re "Stepped over thread exit.*$gdb_prompt $" {
fef19e0
+     pass "$test (breakpoint not hit)"
28857cc
+  }
28857cc
+  -re "start_thread.*$gdb_prompt $" {
28857cc
+     send_gdb "next\n"
28857cc
+     exp_continue
28857cc
+  }
28857cc
+}
28857cc
+
9231e41
Index: gdb-6.5/gdb/infrun.c
9231e41
===================================================================
fef19e0
--- gdb-6.5.orig/gdb/infrun.c	2006-07-12 01:54:29.000000000 -0300
fef19e0
+++ gdb-6.5/gdb/infrun.c	2006-07-12 03:22:41.000000000 -0300
9231e41
@@ -1088,6 +1088,7 @@ init_execution_control_state (struct exe
28857cc
   ecs->current_symtab = ecs->sal.symtab;
28857cc
   ecs->infwait_state = infwait_normal_state;
28857cc
   ecs->waiton_ptid = pid_to_ptid (-1);
28857cc
+  ecs->ws.step_thread_exit = 0;
28857cc
   ecs->wp = &(ecs->ws);
28857cc
 }
28857cc
 
9231e41
@@ -1307,6 +1308,16 @@ handle_inferior_event (struct execution_
28857cc
       ui_out_text (uiout, "]\n");
28857cc
     }
28857cc
 
28857cc
+  /* Check if were stepping a thread and we stepped over the exit.
28857cc
+     In such a case, we will have found another event to process.
28857cc
+     Clear any stepping state and process that event.  */
28857cc
+  if (ecs->ws.step_thread_exit)
28857cc
+    {
28857cc
+      printf_unfiltered ("[Stepped over thread exit]\n");
28857cc
+      clear_proceed_status ();
28857cc
+      ecs->ws.step_thread_exit = 0;
28857cc
+    }
28857cc
+
28857cc
   switch (ecs->ws.kind)
28857cc
     {
28857cc
     case TARGET_WAITKIND_LOADED:
fef19e0
@@ -2697,11 +2708,12 @@ process_event_stop_test:
28857cc
 static int
28857cc
 currently_stepping (struct execution_control_state *ecs)
28857cc
 {
28857cc
-  return ((!ecs->handling_longjmp
28857cc
-	   && ((step_range_end && step_resume_breakpoint == NULL)
28857cc
-	       || trap_expected))
28857cc
-	  || ecs->stepping_through_solib_after_catch
28857cc
-	  || bpstat_should_step ());
28857cc
+  return (!ecs->ws.step_thread_exit 
28857cc
+	  && ((!ecs->handling_longjmp
28857cc
+	      && ((step_range_end && step_resume_breakpoint == NULL)
28857cc
+	          || trap_expected))
28857cc
+	     || ecs->stepping_through_solib_after_catch
28857cc
+	     || bpstat_should_step ()));
28857cc
 }
28857cc
 
28857cc
 /* Subroutine call with source code we should not step over.  Do step
9231e41
Index: gdb-6.5/gdb/linux-nat.c
9231e41
===================================================================
fef19e0
--- gdb-6.5.orig/gdb/linux-nat.c	2006-07-12 01:54:29.000000000 -0300
fef19e0
+++ gdb-6.5/gdb/linux-nat.c	2006-07-12 03:22:42.000000000 -0300
fef19e0
@@ -1137,18 +1137,21 @@ linux_nat_detach (char *args, int from_t
28857cc
 static int
28857cc
 resume_callback (struct lwp_info *lp, void *data)
28857cc
 {
28857cc
+  int step = (data != NULL);
28857cc
+
28857cc
   if (lp->stopped && lp->status == 0)
28857cc
     {
28857cc
       struct thread_info *tp;
28857cc
 
9231e41
       linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
9231e41
-			    0, TARGET_SIGNAL_0);
9231e41
+			    step, TARGET_SIGNAL_0);
28857cc
       if (debug_linux_nat)
28857cc
 	fprintf_unfiltered (gdb_stdlog,
28857cc
-			    "RC:  PTRACE_CONT %s, 0, 0 (resume sibling)\n",
28857cc
+			    "RC:  %s %s, 0, 0 (resume sibling)\n",
28857cc
+			    step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
28857cc
 			    target_pid_to_str (lp->ptid));
28857cc
       lp->stopped = 0;
28857cc
-      lp->step = 0;
28857cc
+      lp->step = step;
28857cc
     }
28857cc
 
28857cc
   return 0;
fef19e0
@@ -1259,13 +1262,17 @@ linux_nat_resume (ptid_t ptid, int step,
28857cc
   if (resume_all)
28857cc
     iterate_over_lwps (resume_callback, NULL);
28857cc
 
9231e41
-  linux_ops->to_resume (ptid, step, signo);
28857cc
-  if (debug_linux_nat)
28857cc
-    fprintf_unfiltered (gdb_stdlog,
28857cc
-			"LLR: %s %s, %s (resume event thread)\n",
28857cc
-			step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
28857cc
-			target_pid_to_str (ptid),
28857cc
-			signo ? strsignal (signo) : "0");
28857cc
+  if (lp)
28857cc
+    {
9231e41
+      linux_ops->to_resume (ptid, step, signo);
28857cc
+
28857cc
+      if (debug_linux_nat)
9231e41
+	fprintf_unfiltered (gdb_stdlog,
28857cc
+			    "LLR: %s %s, %s (resume event thread)\n",
28857cc
+			    step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
28857cc
+			    target_pid_to_str (ptid),
28857cc
+			    signo ? strsignal (signo) : "0");
28857cc
+    }
28857cc
 }
28857cc
 
28857cc
 /* Issue kill to specified lwp.  */
fef19e0
@@ -1863,7 +1870,7 @@ stop_and_resume_callback (struct lwp_inf
28857cc
       for (ptr = lwp_list; ptr; ptr = ptr->next)
28857cc
 	if (lp == ptr)
28857cc
 	  {
28857cc
-	    resume_callback (lp, NULL);
28857cc
+	    resume_callback (lp, data);
28857cc
 	    resume_set_callback (lp, NULL);
28857cc
 	  }
28857cc
     }
fef19e0
@@ -1874,8 +1881,10 @@ static ptid_t
28857cc
 linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
28857cc
 {
28857cc
   struct lwp_info *lp = NULL;
28857cc
+  struct lwp_info *step_lp = NULL;
28857cc
   int options = 0;
28857cc
   int status = 0;
28857cc
+  int intentional_stop = 0;
28857cc
   pid_t pid = PIDGET (ptid);
28857cc
   sigset_t flush_mask;
28857cc
 
fef19e0
@@ -1913,14 +1922,12 @@ retry:
28857cc
      gets the expected trap so we don't want to wait on any LWP.
28857cc
      This has ramifications when adjustment of the PC is required which can be
28857cc
      different after a breakpoint vs a step (e.g. x86).  */
28857cc
-  lp = iterate_over_lwps (find_singlestep_lwp_callback, NULL);
28857cc
-  if (lp) {
28857cc
+  step_lp = iterate_over_lwps (find_singlestep_lwp_callback, NULL);
28857cc
+  if (step_lp) {
28857cc
     if (debug_linux_nat)
28857cc
       fprintf_unfiltered (gdb_stdlog,
28857cc
                          "LLW: Found step lwp %s.\n",
28857cc
-                         target_pid_to_str (lp->ptid));
28857cc
-    ptid = lp->ptid;
28857cc
-    pid = PIDGET (ptid);
28857cc
+                         target_pid_to_str (step_lp->ptid));
28857cc
   }
28857cc
 
28857cc
   /* If any pid, check if there is a LWP with a wait status pending.  */
fef19e0
@@ -2161,8 +2168,9 @@ retry:
28857cc
 	    }
28857cc
 
28857cc
 	  /* Make sure we don't report a SIGSTOP that we sent
28857cc
-	     ourselves in an attempt to stop an LWP.  */
28857cc
-	  if (lp->signalled
28857cc
+	     ourselves in an attempt to stop an LWP, unless we
28857cc
+	     intentionally want to see the SIGSTOP.  */
28857cc
+	  if (lp->signalled && !intentional_stop
28857cc
 	      && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP)
28857cc
 	    {
28857cc
 	      if (debug_linux_nat)
fef19e0
@@ -2196,6 +2204,20 @@ retry:
28857cc
 
28857cc
       if (pid == -1)
28857cc
 	{
28857cc
+	  lp = NULL;
28857cc
+	  if (step_lp && errno == ECHILD)
28857cc
+	    {
28857cc
+	      /* We have stepped over a thread exit.  We want to stop
28857cc
+	         the first existing lwp we find and report a stop event.  */
28857cc
+	      for (lp = lwp_list; lp && lp == step_lp; lp = lp->next)
28857cc
+		; /* empty */
28857cc
+	    }
28857cc
+	  if (lp != NULL)
28857cc
+	    {
28857cc
+  	      stop_callback (lp, NULL);
28857cc
+	      intentional_stop = 1;
28857cc
+	    }
28857cc
+
28857cc
 	  /* Alternate between checking cloned and uncloned processes.  */
28857cc
 	  options ^= __WCLONE;
28857cc
 
fef19e0
@@ -2268,6 +2290,42 @@ retry:
28857cc
     fprintf_unfiltered (gdb_stdlog, "LLW: Candidate event %s in %s.\n",
28857cc
 			status_to_str (status), target_pid_to_str (lp->ptid));
28857cc
 
28857cc
+  /* Check if there is any LWP that is being single-stepped.  We need to
28857cc
+     wait specifically on such an LWP because the higher-level code is
28857cc
+     expecting a step operation to find an event on the stepped LWP.
28857cc
+     It is possible for other events to occur before the step operation
28857cc
+     gets the expected trap so we don't want to wait on any LWP.
28857cc
+     This has ramifications when adjustment of the PC is required which can be
28857cc
+     different after a breakpoint vs a step (e.g. x86).  */
28857cc
+  if (step_lp && step_lp != lp)
28857cc
+    {
28857cc
+      struct lwp_info *ptr;
28857cc
+      int arg = 1;
28857cc
+      if (debug_linux_nat)
28857cc
+        fprintf_unfiltered (gdb_stdlog,
28857cc
+                           "LLW: Found step lwp %s.\n",
28857cc
+                           target_pid_to_str (step_lp->ptid));
28857cc
+      stop_and_resume_callback (step_lp, &arg;;
28857cc
+      for (ptr = lwp_list; ptr; ptr = ptr->next)
28857cc
+        if (step_lp == ptr)
28857cc
+          break;
28857cc
+
28857cc
+      if (ptr)
28857cc
+        {
28857cc
+          if (debug_linux_nat)
28857cc
+            fprintf_unfiltered (gdb_stdlog,
28857cc
+                               "LLW: Continuing step lwp %s.\n",
28857cc
+                               target_pid_to_str (step_lp->ptid));
28857cc
+          ptid = step_lp->ptid;
28857cc
+          pid = PIDGET (ptid);
28857cc
+          lp->status = status; 
28857cc
+          status = 0;
28857cc
+          options = WNOHANG | (step_lp->cloned ? __WCLONE : 0);
28857cc
+          pid = GET_LWP (ptid);
28857cc
+          goto retry;
28857cc
+        }
28857cc
+    }
28857cc
+
28857cc
   /* Now stop all other LWP's ...  */
28857cc
   iterate_over_lwps (stop_callback, NULL);
28857cc
 
fef19e0
@@ -2306,6 +2364,10 @@ retry:
28857cc
   else
28857cc
     store_waitstatus (ourstatus, status);
28857cc
 
28857cc
+  /* If we were stepping a thread and it exited, mark this.  */
28857cc
+  if (step_lp && step_lp != lp)
28857cc
+    ourstatus->step_thread_exit = 1;
28857cc
+
9231e41
   return lp->ptid;
28857cc
 }
28857cc
 
9231e41
Index: gdb-6.5/gdb/target.h
9231e41
===================================================================
fef19e0
--- gdb-6.5.orig/gdb/target.h	2006-07-12 01:54:29.000000000 -0300
fef19e0
+++ gdb-6.5/gdb/target.h	2006-07-12 03:22:40.000000000 -0300
9231e41
@@ -136,6 +136,7 @@ enum target_waitkind
28857cc
 struct target_waitstatus
28857cc
   {
28857cc
     enum target_waitkind kind;
28857cc
+    int step_thread_exit;  /* non-zero if we step over a thread exit.  */
28857cc
 
28857cc
     /* Forked child pid, execd pathname, exit status or signal number.  */
28857cc
     union