common/filestuff.c (make_cleanup_close): Update comment.
[deliverable/binutils-gdb.git] / gdb / infrun.c
index 84890b4d2d591bb89ca7bd76bce391734f221314..cf9137031979b0339c5bc620a3a7f9a68207152e 100644 (file)
@@ -1178,7 +1178,7 @@ follow_exec (ptid_t ptid, char *execd_pathname)
     {
       char *name = exec_file_find (execd_pathname, NULL);
 
-      execd_pathname = alloca (strlen (name) + 1);
+      execd_pathname = (char *) alloca (strlen (name) + 1);
       strcpy (execd_pathname, name);
       xfree (name);
     }
@@ -1692,7 +1692,8 @@ displaced_step_clear (struct displaced_step_inferior_state *displaced)
 static void
 displaced_step_clear_cleanup (void *arg)
 {
-  struct displaced_step_inferior_state *state = arg;
+  struct displaced_step_inferior_state *state
+    = (struct displaced_step_inferior_state *) arg;
 
   displaced_step_clear (state);
 }
@@ -1789,7 +1790,7 @@ displaced_step_prepare_throw (ptid_t ptid)
   len = gdbarch_max_insn_length (gdbarch);
 
   /* Save the original contents of the copy area.  */
-  displaced->step_saved_copy = xmalloc (len);
+  displaced->step_saved_copy = (gdb_byte *) xmalloc (len);
   ignore_cleanups = make_cleanup (free_current_contents,
                                  &displaced->step_saved_copy);
   status = target_read_memory (copy, displaced->step_saved_copy, len);
@@ -2166,13 +2167,15 @@ resume_cleanups (void *ignore)
 static const char schedlock_off[] = "off";
 static const char schedlock_on[] = "on";
 static const char schedlock_step[] = "step";
+static const char schedlock_replay[] = "replay";
 static const char *const scheduler_enums[] = {
   schedlock_off,
   schedlock_on,
   schedlock_step,
+  schedlock_replay,
   NULL
 };
-static const char *scheduler_mode = schedlock_off;
+static const char *scheduler_mode = schedlock_replay;
 static void
 show_scheduler_mode (struct ui_file *file, int from_tty,
                     struct cmd_list_element *c, const char *value)
@@ -2238,6 +2241,13 @@ user_visible_resume_ptid (int step)
         resume.  */
       resume_ptid = inferior_ptid;
     }
+  else if ((scheduler_mode == schedlock_replay)
+          && target_record_will_replay (minus_one_ptid, execution_direction))
+    {
+      /* User-settable 'scheduler' mode requires solo thread resume in replay
+        mode.  */
+      resume_ptid = inferior_ptid;
+    }
   else if (!sched_multi && target_supports_multi_process ())
     {
       /* Resume all threads of the current process (and none of other
@@ -2702,6 +2712,33 @@ resume (enum gdb_signal sig)
 \f
 /* Proceeding.  */
 
+/* See infrun.h.  */
+
+/* Counter that tracks number of user visible stops.  This can be used
+   to tell whether a command has proceeded the inferior past the
+   current location.  This allows e.g., inferior function calls in
+   breakpoint commands to not interrupt the command list.  When the
+   call finishes successfully, the inferior is standing at the same
+   breakpoint as if nothing happened (and so we don't call
+   normal_stop).  */
+static ULONGEST current_stop_id;
+
+/* See infrun.h.  */
+
+ULONGEST
+get_stop_id (void)
+{
+  return current_stop_id;
+}
+
+/* Called when we report a user visible stop.  */
+
+static void
+new_stop_id (void)
+{
+  current_stop_id++;
+}
+
 /* Clear out all variables saying what to do when inferior is continued.
    First do this, then set the ones you want, then call `proceed'.  */
 
@@ -2776,6 +2813,18 @@ clear_proceed_status_thread (struct thread_info *tp)
 void
 clear_proceed_status (int step)
 {
+  /* With scheduler-locking replay, stop replaying other threads if we're
+     not replaying the user-visible resume ptid.
+
+     This is a convenience feature to not require the user to explicitly
+     stop replaying the other threads.  We're assuming that the user's
+     intent is to resume tracing the recorded process.  */
+  if (!non_stop && scheduler_mode == schedlock_replay
+      && target_record_is_replaying (minus_one_ptid)
+      && !target_record_will_replay (user_visible_resume_ptid (step),
+                                    execution_direction))
+    target_record_stop_replaying ();
+
   if (!non_stop)
     {
       struct thread_info *tp;
@@ -2863,7 +2912,10 @@ schedlock_applies (struct thread_info *tp)
 {
   return (scheduler_mode == schedlock_on
          || (scheduler_mode == schedlock_step
-             && tp->control.stepping_command));
+             && tp->control.stepping_command)
+         || (scheduler_mode == schedlock_replay
+             && target_record_will_replay (minus_one_ptid,
+                                           execution_direction)));
 }
 
 /* Basic routine for continuing the program in various fashions.
@@ -3854,12 +3906,17 @@ fetch_inferior_event (void *client_data)
 
          if (should_notify_stop)
            {
+             int proceeded = 0;
+
              /* We may not find an inferior if this was a process exit.  */
              if (inf == NULL || inf->control.stop_soon == NO_STOP_QUIETLY)
-               normal_stop ();
+               proceeded = normal_stop ();
 
-             inferior_event_handler (INF_EXEC_COMPLETE, NULL);
-             cmd_done = 1;
+             if (!proceeded)
+               {
+                 inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+                 cmd_done = 1;
+               }
            }
        }
     }
@@ -5094,8 +5151,14 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
         fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_NO_HISTORY\n");
       /* Reverse execution: target ran out of history info.  */
 
+      /* Switch to the stopped thread.  */
+      if (!ptid_equal (ecs->ptid, inferior_ptid))
+       context_switch (ecs->ptid);
+      if (debug_infrun)
+       fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
+
       delete_just_stopped_threads_single_step_breakpoints ();
-      stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+      stop_pc = regcache_read_pc (get_thread_regcache (inferior_ptid));
       observer_notify_no_history ();
       stop_waiting (ecs);
       return;
@@ -7773,7 +7836,7 @@ print_stop_location (struct target_waitstatus *ws)
 static void
 restore_current_uiout_cleanup (void *arg)
 {
-  struct ui_out *saved_uiout = arg;
+  struct ui_out *saved_uiout = (struct ui_out *) arg;
 
   current_uiout = saved_uiout;
 }
@@ -7829,15 +7892,83 @@ maybe_remove_breakpoints (void)
     }
 }
 
-/* Here to return control to GDB when the inferior stops for real.
-   Print appropriate messages, remove breakpoints, give terminal our modes.
+/* The execution context that just caused a normal stop.  */
 
-   STOP_PRINT_FRAME nonzero means print the executing frame
-   (pc, function, args, file, line number and line text).
-   BREAKPOINTS_FAILED nonzero means stop was due to error
-   attempting to insert breakpoints.  */
+struct stop_context
+{
+  /* The stop ID.  */
+  ULONGEST stop_id;
 
-void
+  /* The event PTID.  */
+
+  ptid_t ptid;
+
+  /* If stopp for a thread event, this is the thread that caused the
+     stop.  */
+  struct thread_info *thread;
+
+  /* The inferior that caused the stop.  */
+  int inf_num;
+};
+
+/* Returns a new stop context.  If stopped for a thread event, this
+   takes a strong reference to the thread.  */
+
+static struct stop_context *
+save_stop_context (void)
+{
+  struct stop_context *sc = XNEW (struct stop_context);
+
+  sc->stop_id = get_stop_id ();
+  sc->ptid = inferior_ptid;
+  sc->inf_num = current_inferior ()->num;
+
+  if (!ptid_equal (inferior_ptid, null_ptid))
+    {
+      /* Take a strong reference so that the thread can't be deleted
+        yet.  */
+      sc->thread = inferior_thread ();
+      sc->thread->refcount++;
+    }
+  else
+    sc->thread = NULL;
+
+  return sc;
+}
+
+/* Release a stop context previously created with save_stop_context.
+   Releases the strong reference to the thread as well. */
+
+static void
+release_stop_context_cleanup (void *arg)
+{
+  struct stop_context *sc = (struct stop_context *) arg;
+
+  if (sc->thread != NULL)
+    sc->thread->refcount--;
+  xfree (sc);
+}
+
+/* Return true if the current context no longer matches the saved stop
+   context.  */
+
+static int
+stop_context_changed (struct stop_context *prev)
+{
+  if (!ptid_equal (prev->ptid, inferior_ptid))
+    return 1;
+  if (prev->inf_num != current_inferior ()->num)
+    return 1;
+  if (prev->thread != NULL && prev->thread->state != THREAD_STOPPED)
+    return 1;
+  if (get_stop_id () != prev->stop_id)
+    return 1;
+  return 0;
+}
+
+/* See infrun.h.  */
+
+int
 normal_stop (void)
 {
   struct target_waitstatus last;
@@ -7847,6 +7978,8 @@ normal_stop (void)
 
   get_last_target_status (&last_ptid, &last);
 
+  new_stop_id ();
+
   /* If an exception is thrown from this point on, make sure to
      propagate GDB's knowledge of the executing state to the
      frontend/user running state.  A QUIT is an easy exception to see
@@ -7966,9 +8099,27 @@ normal_stop (void)
 
   /* Look up the hook_stop and run it (CLI internally handles problem
      of stop_command's pre-hook not existing).  */
-  if (stop_command)
-    catch_errors (hook_stop_stub, stop_command,
-                 "Error while running hook_stop:\n", RETURN_MASK_ALL);
+  if (stop_command != NULL)
+    {
+      struct stop_context *saved_context = save_stop_context ();
+      struct cleanup *old_chain
+       = make_cleanup (release_stop_context_cleanup, saved_context);
+
+      catch_errors (hook_stop_stub, stop_command,
+                   "Error while running hook_stop:\n", RETURN_MASK_ALL);
+
+      /* If the stop hook resumes the target, then there's no point in
+        trying to notify about the previous stop; its context is
+        gone.  Likewise if the command switches thread or inferior --
+        the observers would print a stop for the wrong
+        thread/inferior.  */
+      if (stop_context_changed (saved_context))
+       {
+         do_cleanups (old_chain);
+         return 1;
+       }
+      do_cleanups (old_chain);
+    }
 
   /* Notify observers about the stop.  This is where the interpreters
      print the stop event.  */
@@ -7993,6 +8144,8 @@ normal_stop (void)
      longer needed.  Keeping those around slows down things linearly.
      Note that this never removes the current inferior.  */
   prune_inferiors ();
+
+  return 0;
 }
 
 static int
@@ -8506,7 +8659,7 @@ save_infcall_suspend_state (void)
       size_t len = TYPE_LENGTH (type);
       struct cleanup *back_to;
 
-      siginfo_data = xmalloc (len);
+      siginfo_data = (gdb_byte *) xmalloc (len);
       back_to = make_cleanup (xfree, siginfo_data);
 
       if (target_read (&current_target, TARGET_OBJECT_SIGNAL_INFO, NULL,
@@ -8575,7 +8728,7 @@ restore_infcall_suspend_state (struct infcall_suspend_state *inf_state)
 static void
 do_restore_infcall_suspend_state_cleanup (void *state)
 {
-  restore_infcall_suspend_state (state);
+  restore_infcall_suspend_state ((struct infcall_suspend_state *) state);
 }
 
 struct cleanup *
@@ -8717,7 +8870,7 @@ restore_infcall_control_state (struct infcall_control_state *inf_status)
 static void
 do_restore_infcall_control_state_cleanup (void *sts)
 {
-  restore_infcall_control_state (sts);
+  restore_infcall_control_state ((struct infcall_control_state *) sts);
 }
 
 struct cleanup *
@@ -8751,7 +8904,7 @@ discard_infcall_control_state (struct infcall_control_state *inf_status)
 static void
 restore_inferior_ptid (void *arg)
 {
-  ptid_t *saved_ptid_ptr = arg;
+  ptid_t *saved_ptid_ptr = (ptid_t *) arg;
 
   inferior_ptid = *saved_ptid_ptr;
   xfree (arg);
@@ -9059,10 +9212,13 @@ By default, the debugger will use the same inferior."),
                        scheduler_enums, &scheduler_mode, _("\
 Set mode for locking scheduler during execution."), _("\
 Show mode for locking scheduler during execution."), _("\
-off  == no locking (threads may preempt at any time)\n\
-on   == full locking (no thread except the current thread may run)\n\
-step == scheduler locked during stepping commands (step, next, stepi, nexti).\n\
-       In this mode, other threads may run during other commands."),
+off    == no locking (threads may preempt at any time)\n\
+on     == full locking (no thread except the current thread may run)\n\
+          This applies to both normal execution and replay mode.\n\
+step   == scheduler locked during stepping commands (step, next, stepi, nexti).\n\
+          In this mode, other threads may run during other commands.\n\
+          This applies to both normal execution and replay mode.\n\
+replay == scheduler locked in replay mode and unlocked during normal execution."),
                        set_schedlock_func,     /* traps on target vector */
                        show_scheduler_mode,
                        &setlist, &showlist);
This page took 0.02915 seconds and 4 git commands to generate.