gdb/
[deliverable/binutils-gdb.git] / gdb / infrun.c
index d914f0adaf68b041293ea8c785491cd1c7ff4b7a..150bf4c93a1d314bfefdee9cad42ce185eb91fa2 100644 (file)
@@ -230,13 +230,6 @@ show_stop_on_solib_events (struct ui_file *file, int from_tty,
 
 int stop_after_trap;
 
-/* Nonzero means expecting a trap and caller will handle it themselves.
-   It is used after attach, due to attaching to a process;
-   when running in the shell before the child program has been exec'd;
-   and when running some kinds of remote stuff (FIXME?).  */
-
-enum stop_kind stop_soon;
-
 /* Save register contents here when about to pop a stack dummy frame,
    if-and-only-if proceed_to_finish is set.
    Thus this contains the return value from the called function (assuming
@@ -338,7 +331,6 @@ follow_inferior_reset_breakpoints (void)
 static void
 follow_exec (ptid_t pid, char *execd_pathname)
 {
-  ptid_t saved_pid = pid;
   struct target_ops *tgt;
   struct thread_info *th = inferior_thread ();
 
@@ -377,9 +369,8 @@ follow_exec (ptid_t pid, char *execd_pathname)
      inferior has essentially been killed & reborn. */
 
   gdb_flush (gdb_stdout);
-  generic_mourn_inferior ();
-  /* Because mourn_inferior resets inferior_ptid. */
-  inferior_ptid = saved_pid;
+
+  breakpoint_init_inferior (inf_execd);
 
   if (gdb_sysroot && *gdb_sysroot)
     {
@@ -638,7 +629,7 @@ displaced_step_dump_bytes (struct ui_file *file,
 static int
 displaced_step_prepare (ptid_t ptid)
 {
-  struct cleanup *old_cleanups;
+  struct cleanup *old_cleanups, *ignore_cleanups;
   struct regcache *regcache = get_thread_regcache (ptid);
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
   CORE_ADDR original, copy;
@@ -690,6 +681,9 @@ displaced_step_prepare (ptid_t ptid)
 
   displaced_step_clear ();
 
+  old_cleanups = save_inferior_ptid ();
+  inferior_ptid = ptid;
+
   original = regcache_read_pc (regcache);
 
   copy = gdbarch_displaced_step_location (gdbarch);
@@ -697,8 +691,8 @@ displaced_step_prepare (ptid_t ptid)
 
   /* Save the original contents of the copy area.  */
   displaced_step_saved_copy = xmalloc (len);
-  old_cleanups = make_cleanup (free_current_contents,
-                               &displaced_step_saved_copy);
+  ignore_cleanups = make_cleanup (free_current_contents,
+                                 &displaced_step_saved_copy);
   read_memory (copy, displaced_step_saved_copy, len);
   if (debug_displaced)
     {
@@ -708,7 +702,7 @@ displaced_step_prepare (ptid_t ptid)
     };
 
   closure = gdbarch_displaced_step_copy_insn (gdbarch,
-                                              original, copy, regcache);
+                                             original, copy, regcache);
 
   /* We don't support the fully-simulated case at present.  */
   gdb_assert (closure);
@@ -718,11 +712,13 @@ displaced_step_prepare (ptid_t ptid)
   /* Resume execution at the copy.  */
   regcache_write_pc (regcache, copy);
 
-  discard_cleanups (old_cleanups);
+  discard_cleanups (ignore_cleanups);
+
+  do_cleanups (old_cleanups);
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: displaced pc to 0x%s\n",
-                        paddr_nz (copy));
+                       paddr_nz (copy));
 
   /* Save the information we need to fix things up if the step
      succeeds.  */
@@ -793,27 +789,71 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
 
   do_cleanups (old_cleanups);
 
+  displaced_step_ptid = null_ptid;
+
   /* Are there any pending displaced stepping requests?  If so, run
      one now.  */
-  if (displaced_step_request_queue)
+  while (displaced_step_request_queue)
     {
       struct displaced_step_request *head;
       ptid_t ptid;
+      CORE_ADDR actual_pc;
 
       head = displaced_step_request_queue;
       ptid = head->ptid;
       displaced_step_request_queue = head->next;
       xfree (head);
 
-      if (debug_displaced)
-       fprintf_unfiltered (gdb_stdlog,
-                           "displaced: stepping queued %s now\n",
-                           target_pid_to_str (ptid));
+      context_switch (ptid);
+
+      actual_pc = read_pc ();
+
+      if (breakpoint_here_p (actual_pc))
+       {
+         if (debug_displaced)
+           fprintf_unfiltered (gdb_stdlog,
+                               "displaced: stepping queued %s now\n",
+                               target_pid_to_str (ptid));
 
+         displaced_step_prepare (ptid);
 
-      displaced_step_ptid = null_ptid;
-      displaced_step_prepare (ptid);
-      target_resume (ptid, 1, TARGET_SIGNAL_0);
+         if (debug_displaced)
+           {
+             gdb_byte buf[4];
+
+             fprintf_unfiltered (gdb_stdlog, "displaced: run 0x%s: ",
+                                 paddr_nz (actual_pc));
+             read_memory (actual_pc, buf, sizeof (buf));
+             displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
+           }
+
+         target_resume (ptid, 1, TARGET_SIGNAL_0);
+
+         /* Done, we're stepping a thread.  */
+         break;
+       }
+      else
+       {
+         int step;
+         struct thread_info *tp = inferior_thread ();
+
+         /* The breakpoint we were sitting under has since been
+            removed.  */
+         tp->trap_expected = 0;
+
+         /* Go back to what we were trying to do.  */
+         step = currently_stepping (tp);
+
+         if (debug_displaced)
+           fprintf_unfiltered (gdb_stdlog, "breakpoint is gone %s: step(%d)\n",
+                               target_pid_to_str (tp->ptid), step);
+
+         target_resume (ptid, step, TARGET_SIGNAL_0);
+         tp->stop_signal = TARGET_SIGNAL_0;
+
+         /* This request was discarded.  See if there's any other
+            thread waiting for its turn.  */
+       }
     }
 }
 
@@ -1097,7 +1137,10 @@ clear_proceed_status (void)
 {
   if (!ptid_equal (inferior_ptid, null_ptid))
     {
-      struct thread_info *tp = inferior_thread ();
+      struct thread_info *tp;
+      struct inferior *inferior;
+
+      tp = inferior_thread ();
 
       tp->trap_expected = 0;
       tp->step_range_start = 0;
@@ -1112,10 +1155,12 @@ clear_proceed_status (void)
       /* Discard any remaining commands or status from previous
         stop.  */
       bpstat_clear (&tp->stop_bpstat);
+
+      inferior = current_inferior ();
+      inferior->stop_soon = NO_STOP_QUIETLY;
     }
 
   stop_after_trap = 0;
-  stop_soon = NO_STOP_QUIETLY;
   breakpoint_proceeded = 1;    /* We're about to proceed... */
 
   if (stop_registers)
@@ -1351,8 +1396,11 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
 void
 start_remote (int from_tty)
 {
+  struct inferior *inferior;
   init_wait_for_inferior ();
-  stop_soon = STOP_QUIETLY_REMOTE;
+
+  inferior = current_inferior ();
+  inferior->stop_soon = STOP_QUIETLY_REMOTE;
 
   /* Always go on waiting for the target, regardless of the mode. */
   /* FIXME: cagney/1999-09-23: At present it isn't possible to
@@ -1568,8 +1616,6 @@ wait_for_inferior (int treat_exec_as_sigtrap)
       else
        ecs->ptid = target_wait (waiton_ptid, &ecs->ws);
 
-      ecs->event_thread = find_thread_pid (ecs->ptid);
-
       if (treat_exec_as_sigtrap && ecs->ws.kind == TARGET_WAITKIND_EXECD)
         {
           xfree (ecs->ws.value.execd_pathname);
@@ -1645,16 +1691,17 @@ fetch_inferior_event (void *client_data)
        thread.  */
     context_switch (ecs->ptid);
 
-  ecs->event_thread = find_thread_pid (ecs->ptid);
-
   /* Now figure out what to do with the result of the result.  */
   handle_inferior_event (ecs);
 
   if (!ecs->wait_some_more)
     {
+      struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
+
       delete_step_thread_step_resume_breakpoint ();
 
-      if (stop_soon == NO_STOP_QUIETLY)
+      /* We may not find an inferior if this was a process exit.  */
+      if (inf == NULL || inf->stop_soon == NO_STOP_QUIETLY)
        normal_stop ();
 
       if (target_has_execution
@@ -1782,9 +1829,16 @@ adjust_pc_after_break (struct execution_control_state *ecs)
   breakpoint_pc = regcache_read_pc (regcache)
                  - gdbarch_decr_pc_after_break (gdbarch);
 
-  /* Check whether there actually is a software breakpoint inserted
-     at that location.  */
-  if (software_breakpoint_inserted_here_p (breakpoint_pc))
+  /* Check whether there actually is a software breakpoint inserted at
+     that location.
+
+     If in non-stop mode, a race condition is possible where we've
+     removed a breakpoint, but stop events for that breakpoint were
+     already queued and arrive later.  To suppress those spurious
+     SIGTRAPs, we keep a list of such breakpoint locations for a bit,
+     and retire them after a number of stop events are reported.  */
+  if (software_breakpoint_inserted_here_p (breakpoint_pc)
+      || (non_stop && moribund_breakpoint_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
@@ -1844,8 +1898,18 @@ handle_inferior_event (struct execution_control_state *ecs)
   int stopped_by_watchpoint;
   int stepped_after_stopped_by_watchpoint = 0;
   struct symtab_and_line stop_pc_sal;
+  enum stop_kind stop_soon;
 
-  breakpoint_retire_moribund ();
+  if (ecs->ws.kind != TARGET_WAITKIND_EXITED
+      && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
+      && ecs->ws.kind != TARGET_WAITKIND_IGNORE)
+    {
+      struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
+      gdb_assert (inf);
+      stop_soon = inf->stop_soon;
+    }
+  else
+    stop_soon = NO_STOP_QUIETLY;
 
   /* Cache the last pid/waitstatus. */
   target_last_wait_ptid = ecs->ptid;
@@ -1854,10 +1918,6 @@ handle_inferior_event (struct execution_control_state *ecs)
   /* Always clear state belonging to the previous time we stopped.  */
   stop_stack_dummy = 0;
 
-  adjust_pc_after_break (ecs);
-
-  reinit_frame_cache ();
-
   /* If it's a new process, add it to the thread database */
 
   ecs->new_thread_event = (!ptid_equal (ecs->ptid, inferior_ptid)
@@ -1868,8 +1928,18 @@ handle_inferior_event (struct execution_control_state *ecs)
       && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
     add_thread (ecs->ptid);
 
+  ecs->event_thread = find_thread_pid (ecs->ptid);
+
+  /* Dependent on valid ECS->EVENT_THREAD.  */
+  adjust_pc_after_break (ecs);
+
+  /* Dependent on the current PC value modified by adjust_pc_after_break.  */
+  reinit_frame_cache ();
+
   if (ecs->ws.kind != TARGET_WAITKIND_IGNORE)
     {
+      breakpoint_retire_moribund ();
+
       /* Mark the non-executing threads accordingly.  */
       if (!non_stop
          || ecs->ws.kind == TARGET_WAITKIND_EXITED
@@ -2073,32 +2143,23 @@ handle_inferior_event (struct execution_control_state *ecs)
        savestring (ecs->ws.value.execd_pathname,
                    strlen (ecs->ws.value.execd_pathname));
 
-      /* This causes the eventpoints and symbol table to be reset.  Must
-         do this now, before trying to determine whether to stop. */
-      follow_exec (inferior_ptid, pending_follow.execd_pathname);
-      xfree (pending_follow.execd_pathname);
-
-      stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
-
-      {
-       /* The breakpoints module may need to touch the inferior's
-          memory.  Switch to the (stopped) event ptid
-          momentarily.  */
-       ptid_t saved_inferior_ptid = inferior_ptid;
-       inferior_ptid = ecs->ptid;
-
-       ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
-
-       ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
-       inferior_ptid = saved_inferior_ptid;
-      }
-
       if (!ptid_equal (ecs->ptid, inferior_ptid))
        {
          context_switch (ecs->ptid);
          reinit_frame_cache ();
        }
 
+      stop_pc = read_pc ();
+
+      /* This causes the eventpoints and symbol table to be reset.
+         Must do this now, before trying to determine whether to
+         stop.  */
+      follow_exec (inferior_ptid, pending_follow.execd_pathname);
+      xfree (pending_follow.execd_pathname);
+
+      ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+      ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
+
       /* If no catchpoint triggered for this, then keep going.  */
       if (ecs->random_signal)
        {
@@ -2620,7 +2681,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
          another signal besides SIGTRAP, so check here as well as
          above.''
 
-         If someone ever tries to get get call dummys on a
+         If someone ever tries to get call dummys on a
          non-executable stack to work (where the target would stop
          with something like a SIGSEGV), then those tests might need
          to be re-instated.  Given, however, that the tests were only
@@ -2673,7 +2734,10 @@ process_event_stop_test:
          target_terminal_ours_for_output ();
          print_stop_reason (SIGNAL_RECEIVED, ecs->event_thread->stop_signal);
        }
-      if (signal_stop_state (ecs->event_thread->stop_signal))
+      /* Always stop on signals if we're just gaining control of the
+        program.  */
+      if (stop_soon != NO_STOP_QUIETLY
+         || signal_stop_state (ecs->event_thread->stop_signal))
        {
          stop_stepping (ecs);
          return;
@@ -3128,7 +3192,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
       if (real_stop_pc != 0)
        ecs->stop_func_start = real_stop_pc;
 
-      if (in_solib_dynsym_resolve_code (ecs->stop_func_start))
+      if (real_stop_pc != 0 && in_solib_dynsym_resolve_code (real_stop_pc))
        {
          struct symtab_and_line sr_sal;
          init_sal (&sr_sal);
@@ -3972,9 +4036,7 @@ hook_stop_stub (void *cmd)
 int
 signal_stop_state (int signo)
 {
-  /* Always stop on signals if we're just gaining control of the
-     program.  */
-  return signal_stop[signo] || stop_soon != NO_STOP_QUIETLY;
+  return signal_stop[signo];
 }
 
 int
@@ -4064,11 +4126,7 @@ handle_command (char *args, int from_tty)
 
   /* Break the command line up into args. */
 
-  argv = buildargv (args);
-  if (argv == NULL)
-    {
-      nomem (0);
-    }
+  argv = gdb_buildargv (args);
   old_chain = make_cleanup_freeargv (argv);
 
   /* Walk through the args, looking for signal oursigs, signal names, and
@@ -4225,13 +4283,12 @@ xdb_handle_command (char *args, int from_tty)
   char **argv;
   struct cleanup *old_chain;
 
+  if (args == NULL)
+    error_no_arg (_("xdb command"));
+
   /* Break the command line up into args. */
 
-  argv = buildargv (args);
-  if (argv == NULL)
-    {
-      nomem (0);
-    }
+  argv = gdb_buildargv (args);
   old_chain = make_cleanup_freeargv (argv);
   if (argv[1] != (char *) NULL)
     {
@@ -4376,6 +4433,7 @@ save_inferior_status (int restore_stack_info)
 {
   struct inferior_status *inf_status = XMALLOC (struct inferior_status);
   struct thread_info *tp = inferior_thread ();
+  struct inferior *inf = current_inferior ();
 
   inf_status->stop_signal = tp->stop_signal;
   inf_status->stop_pc = stop_pc;
@@ -4388,7 +4446,7 @@ save_inferior_status (int restore_stack_info)
   inf_status->step_frame_id = tp->step_frame_id;
   inf_status->step_over_calls = tp->step_over_calls;
   inf_status->stop_after_trap = stop_after_trap;
-  inf_status->stop_soon = stop_soon;
+  inf_status->stop_soon = inf->stop_soon;
   /* Save original bpstat chain here; replace it with copy of chain.
      If caller's caller is walking the chain, they'll be happier if we
      hand them back the original chain when restore_inferior_status is
@@ -4430,6 +4488,7 @@ void
 restore_inferior_status (struct inferior_status *inf_status)
 {
   struct thread_info *tp = inferior_thread ();
+  struct inferior *inf = current_inferior ();
 
   tp->stop_signal = inf_status->stop_signal;
   stop_pc = inf_status->stop_pc;
@@ -4442,7 +4501,7 @@ restore_inferior_status (struct inferior_status *inf_status)
   tp->step_frame_id = inf_status->step_frame_id;
   tp->step_over_calls = inf_status->step_over_calls;
   stop_after_trap = inf_status->stop_after_trap;
-  stop_soon = inf_status->stop_soon;
+  inf->stop_soon = inf_status->stop_soon;
   bpstat_clear (&tp->stop_bpstat);
   tp->stop_bpstat = inf_status->stop_bpstat;
   breakpoint_proceeded = inf_status->breakpoint_proceeded;
This page took 0.036033 seconds and 4 git commands to generate.