gas/testsuite/
[deliverable/binutils-gdb.git] / gdb / infrun.c
index 27d78b13fd2d7d06faee4956c049358188572eef..1a8556775ac7afff589c4f78765bd18fb147549c 100644 (file)
@@ -9,7 +9,7 @@
 
    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 2 of the License, or
+   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,
@@ -18,9 +18,7 @@
    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, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "gdb_string.h"
@@ -80,11 +78,10 @@ static int currently_stepping (struct execution_control_state *ecs);
 
 static void xdb_handle_command (char *args, int from_tty);
 
-static int prepare_to_proceed (void);
+static int prepare_to_proceed (int);
 
 void _initialize_infrun (void);
 
-int inferior_ignoring_startup_exec_events = 0;
 int inferior_ignoring_leading_exec_events = 0;
 
 /* When set, stop the 'step' command if we enter a function which has
@@ -448,6 +445,11 @@ static CORE_ADDR singlestep_pc;
    thread here so that we can resume single-stepping it later.  */
 static ptid_t saved_singlestep_ptid;
 static int stepping_past_singlestep_breakpoint;
+
+/* Similarly, if we are stepping another thread past a breakpoint,
+   save the original thread here so that we can resume stepping it later.  */
+static ptid_t stepping_past_breakpoint_ptid;
+static int stepping_past_breakpoint;
 \f
 
 /* Things to clean up if we QUIT out of resume ().  */
@@ -537,10 +539,10 @@ how to step past a permanent breakpoint on this architecture.  Try using\n\
 a command like `return' or `jump' to continue execution."));
     }
 
-  if (SOFTWARE_SINGLE_STEP_P () && step)
+  if (step && gdbarch_software_single_step_p (current_gdbarch))
     {
       /* Do it the hard way, w/temp breakpoints */
-      if (SOFTWARE_SINGLE_STEP (get_current_frame ()))
+      if (gdbarch_software_single_step (current_gdbarch, get_current_frame ()))
         {
           /* ...and don't ask hardware to do it.  */
           step = 0;
@@ -645,7 +647,7 @@ clear_proceed_status (void)
 /* This should be suitable for any targets that support threads. */
 
 static int
-prepare_to_proceed (void)
+prepare_to_proceed (int step)
 {
   ptid_t wait_ptid;
   struct target_waitstatus wait_status;
@@ -653,42 +655,35 @@ prepare_to_proceed (void)
   /* Get the last target status returned by target_wait().  */
   get_last_target_status (&wait_ptid, &wait_status);
 
-  /* Make sure we were stopped either at a breakpoint, or because
-     of a Ctrl-C.  */
+  /* Make sure we were stopped at a breakpoint.  */
   if (wait_status.kind != TARGET_WAITKIND_STOPPED
-      || (wait_status.value.sig != TARGET_SIGNAL_TRAP
-         && wait_status.value.sig != TARGET_SIGNAL_INT))
+      || wait_status.value.sig != TARGET_SIGNAL_TRAP)
     {
       return 0;
     }
 
+  /* Switched over from WAIT_PID.  */
   if (!ptid_equal (wait_ptid, minus_one_ptid)
-      && !ptid_equal (inferior_ptid, wait_ptid))
+      && !ptid_equal (inferior_ptid, wait_ptid)
+      && breakpoint_here_p (read_pc_pid (wait_ptid)))
     {
-      /* Switched over from WAIT_PID.  */
-      CORE_ADDR wait_pc = read_pc_pid (wait_ptid);
-
-      if (wait_pc != read_pc ())
+      /* If stepping, remember current thread to switch back to.  */
+      if (step)
        {
-         /* Switch back to WAIT_PID thread.  */
-         inferior_ptid = wait_ptid;
-
-         /* FIXME: This stuff came from switch_to_thread() in
-            thread.c (which should probably be a public function).  */
-         reinit_frame_cache ();
-         registers_changed ();
-         stop_pc = wait_pc;
+         stepping_past_breakpoint = 1;
+         stepping_past_breakpoint_ptid = inferior_ptid;
        }
 
+      /* Switch back to WAIT_PID thread.  */
+      switch_to_thread (wait_ptid);
+
       /* We return 1 to indicate that there is a breakpoint here,
-         so we need to step over it before continuing to avoid
-         hitting it straight away. */
-      if (breakpoint_here_p (wait_pc))
-       return 1;
+        so we need to step over it before continuing to avoid
+        hitting it straight away. */
+      return 1;
     }
 
   return 0;
-
 }
 
 /* Record the pc of the program the last time it stopped.  This is
@@ -754,7 +749,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
      prepare_to_proceed checks the current thread against the thread
      that reported the most recent event.  If a step-over is required
      it returns TRUE and sets the current thread to the old thread. */
-  if (prepare_to_proceed () && breakpoint_here_p (read_pc ()))
+  if (prepare_to_proceed (step))
     oneproc = 1;
 
   if (oneproc)
@@ -828,7 +823,7 @@ start_remote (int from_tty)
 {
   init_thread_list ();
   init_wait_for_inferior ();
-  stop_soon = STOP_QUIETLY;
+  stop_soon = STOP_QUIETLY_REMOTE;
   trap_expected = 0;
 
   /* Always go on waiting for the target, regardless of the mode. */
@@ -875,6 +870,7 @@ init_wait_for_inferior (void)
   clear_proceed_status ();
 
   stepping_past_singlestep_breakpoint = 0;
+  stepping_past_breakpoint = 0;
 }
 \f
 /* This enum encodes possible reasons for doing a target_wait, so that
@@ -1144,8 +1140,8 @@ context_switch (struct execution_control_state *ecs)
                         &ecs->stepping_through_solib_catchpoints,
                         &ecs->current_line, &ecs->current_symtab);
     }
-  inferior_ptid = ecs->ptid;
-  reinit_frame_cache ();
+
+  switch_to_thread (ecs->ptid);
 }
 
 static void
@@ -1190,52 +1186,33 @@ adjust_pc_after_break (struct execution_control_state *ecs)
   breakpoint_pc = read_pc_pid (ecs->ptid) - gdbarch_decr_pc_after_break
                                            (current_gdbarch);
 
-  if (SOFTWARE_SINGLE_STEP_P ())
-    {
-      /* When using software single-step, a SIGTRAP can only indicate
-         an inserted breakpoint.  This actually makes things
-         easier.  */
-      if (singlestep_breakpoints_inserted_p)
-       /* When software single stepping, the instruction at [prev_pc]
-          is never a breakpoint, but the instruction following
-          [prev_pc] (in program execution order) always is.  Assume
-          that following instruction was reached and hence a software
-          breakpoint was hit.  */
-       write_pc_pid (breakpoint_pc, ecs->ptid);
-      else if (software_breakpoint_inserted_here_p (breakpoint_pc))
-       /* The inferior was free running (i.e., no single-step
-          breakpoints inserted) and it hit a software breakpoint.  */
-       write_pc_pid (breakpoint_pc, ecs->ptid);
-    }
-  else
+  /* Check whether there actually is a software breakpoint inserted
+     at that location.  */
+  if (software_breakpoint_inserted_here_p (breakpoint_pc))
     {
-      /* When using hardware single-step, a SIGTRAP is reported for
-         both a completed single-step and a software breakpoint.  Need
-         to differentiate between the two as the latter needs
-         adjusting but the former does not.
-
-         When the thread to be examined does not match the current thread
-         context we can't use currently_stepping, so assume no
-         single-stepping in this case.  */
-      if (ptid_equal (ecs->ptid, inferior_ptid) && currently_stepping (ecs))
-       {
-         if (prev_pc == breakpoint_pc
-             && software_breakpoint_inserted_here_p (breakpoint_pc))
-           /* Hardware single-stepped a software breakpoint (as
-              occures when the inferior is resumed with PC pointing
-              at not-yet-hit software breakpoint).  Since the
-              breakpoint really is executed, the inferior needs to be
-              backed up to the breakpoint address.  */
-           write_pc_pid (breakpoint_pc, ecs->ptid);
-       }
-      else
-       {
-         if (software_breakpoint_inserted_here_p (breakpoint_pc))
-           /* The inferior was free running (i.e., no hardware
-              single-step and no possibility of a false SIGTRAP) and
-              hit a software breakpoint.  */
-           write_pc_pid (breakpoint_pc, ecs->ptid);
-       }
+      /* When using hardware single-step, a SIGTRAP is reported for both
+        a completed single-step and a software breakpoint.  Need to
+        differentiate between the two, as the latter needs adjusting
+        but the former does not.
+
+        The SIGTRAP can be due to a completed hardware single-step only if 
+         - we didn't insert software single-step breakpoints
+         - the thread to be examined is still the current thread
+         - this thread is currently being stepped
+
+        If any of these events did not occur, we must have stopped due
+        to hitting a software breakpoint, and have to back up to the
+        breakpoint address.
+
+        As a special case, we could have hardware single-stepped a
+        software breakpoint.  In this case (prev_pc == breakpoint_pc),
+        we also need to back up to the breakpoint address.  */
+
+      if (singlestep_breakpoints_inserted_p
+         || !ptid_equal (ecs->ptid, inferior_ptid)
+         || !currently_stepping (ecs)
+         || prev_pc == breakpoint_pc)
+       write_pc_pid (breakpoint_pc, ecs->ptid);
     }
 }
 
@@ -1316,16 +1293,22 @@ handle_inferior_event (struct execution_control_state *ecs)
     case TARGET_WAITKIND_LOADED:
       if (debug_infrun)
         fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_LOADED\n");
-      /* Ignore gracefully during startup of the inferior, as it
-         might be the shell which has just loaded some objects,
-         otherwise add the symbols for the newly loaded objects.  */
-#ifdef SOLIB_ADD
+      /* Ignore gracefully during startup of the inferior, as it might
+         be the shell which has just loaded some objects, otherwise
+         add the symbols for the newly loaded objects.  Also ignore at
+         the beginning of an attach or remote session; we will query
+         the full list of libraries once the connection is
+         established.  */
       if (stop_soon == NO_STOP_QUIETLY)
        {
+         int breakpoints_were_inserted;
+
          /* Remove breakpoints, SOLIB_ADD might adjust
             breakpoint addresses via breakpoint_re_set.  */
+         breakpoints_were_inserted = breakpoints_inserted;
          if (breakpoints_inserted)
            remove_breakpoints ();
+         breakpoints_inserted = 0;
 
          /* Check for any newly added shared libraries if we're
             supposed to be adding them automatically.  Switch
@@ -1347,17 +1330,50 @@ handle_inferior_event (struct execution_control_state *ecs)
             exec/process stratum, instead relying on the target stack
             to propagate relevant changes (stop, section table
             changed, ...) up to other layers.  */
+#ifdef SOLIB_ADD
          SOLIB_ADD (NULL, 0, &current_target, auto_solib_add);
+#else
+         solib_add (NULL, 0, &current_target, auto_solib_add);
+#endif
          target_terminal_inferior ();
 
+         /* Try to reenable shared library breakpoints, additional
+            code segments in shared libraries might be mapped in now. */
+         re_enable_breakpoints_in_shlibs ();
+
+         /* If requested, stop when the dynamic linker notifies
+            gdb of events.  This allows the user to get control
+            and place breakpoints in initializer routines for
+            dynamically loaded objects (among other things).  */
+         if (stop_on_solib_events)
+           {
+             stop_stepping (ecs);
+             return;
+           }
+
+         /* NOTE drow/2007-05-11: This might be a good place to check
+            for "catch load".  */
+
          /* Reinsert breakpoints and continue.  */
-         if (breakpoints_inserted)
-           insert_breakpoints ();
+         if (breakpoints_were_inserted)
+           {
+             insert_breakpoints ();
+             breakpoints_inserted = 1;
+           }
        }
-#endif
-      resume (0, TARGET_SIGNAL_0);
-      prepare_to_wait (ecs);
-      return;
+
+      /* If we are skipping through a shell, or through shared library
+        loading that we aren't interested in, resume the program.  If
+        we're running the program normally, also resume.  But stop if
+        we're attaching or setting up a remote connection.  */
+      if (stop_soon == STOP_QUIETLY || stop_soon == NO_STOP_QUIETLY)
+       {
+         resume (0, TARGET_SIGNAL_0);
+         prepare_to_wait (ecs);
+         return;
+       }
+
+      break;
 
     case TARGET_WAITKIND_SPURIOUS:
       if (debug_infrun)
@@ -1379,7 +1395,7 @@ handle_inferior_event (struct execution_control_state *ecs)
                                           (LONGEST) ecs->ws.value.integer));
       gdb_flush (gdb_stdout);
       target_mourn_inferior ();
-      singlestep_breakpoints_inserted_p = 0;   /* SOFTWARE_SINGLE_STEP_P() */
+      singlestep_breakpoints_inserted_p = 0;
       stop_print_frame = 0;
       stop_stepping (ecs);
       return;
@@ -1399,7 +1415,7 @@ handle_inferior_event (struct execution_control_state *ecs)
       target_mourn_inferior ();
 
       print_stop_reason (SIGNAL_EXITED, stop_signal);
-      singlestep_breakpoints_inserted_p = 0;   /* SOFTWARE_SINGLE_STEP_P() */
+      singlestep_breakpoints_inserted_p = 0;
       stop_stepping (ecs);
       return;
 
@@ -1555,8 +1571,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 
   if (stepping_past_singlestep_breakpoint)
     {
-      gdb_assert (SOFTWARE_SINGLE_STEP_P ()
-                 && singlestep_breakpoints_inserted_p);
+      gdb_assert (singlestep_breakpoints_inserted_p);
       gdb_assert (ptid_equal (singlestep_ptid, ecs->ptid));
       gdb_assert (!ptid_equal (singlestep_ptid, saved_singlestep_ptid));
 
@@ -1588,6 +1603,37 @@ handle_inferior_event (struct execution_control_state *ecs)
 
   stepping_past_singlestep_breakpoint = 0;
 
+  if (stepping_past_breakpoint)
+    {
+      stepping_past_breakpoint = 0;
+
+      /* If we stopped for some other reason than single-stepping, ignore
+        the fact that we were supposed to switch back.  */
+      if (stop_signal == TARGET_SIGNAL_TRAP)
+       {
+         if (debug_infrun)
+           fprintf_unfiltered (gdb_stdlog,
+                               "infrun: stepping_past_breakpoint\n");
+
+         /* Pull the single step breakpoints out of the target.  */
+         if (singlestep_breakpoints_inserted_p)
+           {
+             remove_single_step_breakpoints ();
+             singlestep_breakpoints_inserted_p = 0;
+           }
+
+         /* Note: We do not call context_switch at this point, as the
+            context is already set up for stepping the original thread.  */
+         switch_to_thread (stepping_past_breakpoint_ptid);
+         /* Suppress spurious "Switching to ..." message.  */
+         previous_inferior_ptid = inferior_ptid;
+
+         resume (1, TARGET_SIGNAL_0);
+         prepare_to_wait (ecs);
+         return;
+       }
+    }
+
   /* See if a thread hit a thread-specific breakpoint that was meant for
      another thread.  If so, then step that thread past the breakpoint,
      and continue it.  */
@@ -1605,7 +1651,7 @@ handle_inferior_event (struct execution_control_state *ecs)
          if (!breakpoint_thread_match (stop_pc, ecs->ptid))
            thread_hop_needed = 1;
        }
-      else if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
+      else if (singlestep_breakpoints_inserted_p)
        {
          /* We have not context switched yet, so this should be true
             no matter which thread hit the singlestep breakpoint.  */
@@ -1676,7 +1722,7 @@ handle_inferior_event (struct execution_control_state *ecs)
          /* Saw a breakpoint, but it was hit by the wrong thread.
             Just continue. */
 
-         if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
+         if (singlestep_breakpoints_inserted_p)
            {
              /* Pull the single step breakpoints out of the target. */
              remove_single_step_breakpoints ();
@@ -1725,7 +1771,7 @@ handle_inferior_event (struct execution_control_state *ecs)
              return;
            }
        }
-      else if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
+      else if (singlestep_breakpoints_inserted_p)
        {
          sw_single_step_trap_p = 1;
          ecs->random_signal = 0;
@@ -1747,7 +1793,7 @@ handle_inferior_event (struct execution_control_state *ecs)
        deprecated_context_hook (pid_to_thread_id (ecs->ptid));
     }
 
-  if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)
+  if (singlestep_breakpoints_inserted_p)
     {
       /* Pull the single step breakpoints out of the target. */
       remove_single_step_breakpoints ();
@@ -1882,7 +1928,8 @@ handle_inferior_event (struct execution_control_state *ecs)
          && (stop_signal == TARGET_SIGNAL_ILL
              || stop_signal == TARGET_SIGNAL_SEGV
              || stop_signal == TARGET_SIGNAL_EMT))
-      || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP)
+      || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP
+      || stop_soon == STOP_QUIETLY_REMOTE)
     {
       if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap)
        {
@@ -1895,7 +1942,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 
       /* This is originated from start_remote(), start_inferior() and
          shared libraries hook functions.  */
-      if (stop_soon == STOP_QUIETLY)
+      if (stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_REMOTE)
        {
           if (debug_infrun)
            fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
@@ -2821,6 +2868,7 @@ insert_step_resume_breakpoint_at_frame (struct frame_info *return_frame)
 {
   struct symtab_and_line sr_sal;
 
+  gdb_assert (return_frame != NULL);
   init_sal (&sr_sal);          /* initialize to zeros */
 
   sr_sal.pc = gdbarch_addr_bits_remove
@@ -3180,6 +3228,18 @@ Further execution is probably impossible.\n"));
          switch (bpstat_ret)
            {
            case PRINT_UNKNOWN:
+             /* If we had hit a shared library event breakpoint,
+                bpstat_print would print out this message.  If we hit
+                an OS-level shared library event, do the same
+                thing.  */
+             if (last.kind == TARGET_WAITKIND_LOADED)
+               {
+                 printf_filtered (_("Stopped due to shared library event\n"));
+                 source_flag = SRC_LINE;       /* something bogus */
+                 do_frame_printing = 0;
+                 break;
+               }
+
              /* FIXME: cagney/2002-12-01: Given that a frame ID does
                 (or should) carry around the function and does (or
                 should) use that when doing a frame comparison.  */
This page took 0.032217 seconds and 4 git commands to generate.