* gdbint.texinfo (POP_FRAME): Document use by return_command.
[deliverable/binutils-gdb.git] / gdb / infrun.c
index cc8c1bfc960b828f0cbfe59b12cc8ee2a4636670..e934c9ddca97cd47265a1ec5031727efe7387651 100644 (file)
@@ -1,5 +1,5 @@
 /* Target-struct-independent code to start (run) and stop an inferior process.
-   Copyright 1986-1989, 1991-1999 Free Software Foundation, Inc.
+   Copyright 1986-1989, 1991-2000 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -25,7 +25,7 @@
 #include "frame.h"
 #include "inferior.h"
 #include "breakpoint.h"
-#include "wait.h"
+#include "gdb_wait.h"
 #include "gdbcore.h"
 #include "gdbcmd.h"
 #include "target.h"
@@ -46,7 +46,7 @@ static void sig_print_info (enum target_signal);
 
 static void sig_print_header (void);
 
-static void resume_cleanups (int);
+static void resume_cleanups (void *);
 
 static int hook_stop_stub (void *);
 
@@ -73,10 +73,6 @@ static void follow_vfork (int parent_pid, int child_pid);
 static void set_schedlock_func (char *args, int from_tty,
                                struct cmd_list_element * c);
 
-static int is_internal_shlib_eventpoint (struct breakpoint * ep);
-
-static int stopped_for_internal_shlib_event (bpstat bs);
-
 struct execution_control_state;
 
 static int currently_stepping (struct execution_control_state *ecs);
@@ -88,6 +84,11 @@ 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
+   no line number information.  The normal behavior is that we step
+   over such function.  */
+int step_stop_if_no_debug = 0;
+
 /* In asynchronous mode, but simulating synchronous execution. */
 
 int sync_execution = 0;
@@ -96,17 +97,7 @@ int sync_execution = 0;
    when the inferior stopped in a different thread than it had been
    running in.  */
 
-static int switched_from_inferior_pid;
-
-/* This will be true for configurations that may actually report an
-   inferior pid different from the original.  At present this is only
-   true for HP-UX native.  */
-
-#ifndef MAY_SWITCH_FROM_INFERIOR_PID
-#define MAY_SWITCH_FROM_INFERIOR_PID (0)
-#endif
-
-static int may_switch_from_inferior_pid = MAY_SWITCH_FROM_INFERIOR_PID;
+static int previous_inferior_pid;
 
 /* This is true for configurations that may follow through execl() and
    similar functions.  At present this is only true for HP-UX native.  */
@@ -274,7 +265,7 @@ static int use_thread_step_needed = USE_THREAD_STEP_NEEDED;
 #ifndef SKIP_PERMANENT_BREAKPOINT 
 #define SKIP_PERMANENT_BREAKPOINT (default_skip_permanent_breakpoint)
 static void
-default_skip_permanent_breakpoint ()
+default_skip_permanent_breakpoint (void)
 {
   error_begin ();
   fprintf_filtered (gdb_stderr, "\
@@ -310,6 +301,13 @@ a command like `return' or `jump' to continue execution.\n");
 #define HAVE_CONTINUABLE_WATCHPOINT 1
 #endif
 
+#ifndef CANNOT_STEP_HW_WATCHPOINTS
+#define CANNOT_STEP_HW_WATCHPOINTS 0
+#else
+#undef  CANNOT_STEP_HW_WATCHPOINTS
+#define CANNOT_STEP_HW_WATCHPOINTS 1
+#endif
+
 /* Tables of how to react to signals; the user sets them.  */
 
 static unsigned char *signal_stop;
@@ -441,17 +439,25 @@ pending_follow;
    follow-fork-mode.) */
 static int follow_vfork_when_exec;
 
-static char *follow_fork_mode_kind_names[] =
+static const char follow_fork_mode_ask[] = "ask";
+static const char follow_fork_mode_both[] = "both";
+static const char follow_fork_mode_child[] = "child";
+static const char follow_fork_mode_parent[] = "parent";
+
+static const char *follow_fork_mode_kind_names[] =
 {
-/* ??rehrauer:  The "both" option is broken, by what may be a 10.20
-   kernel problem.  It's also not terribly useful without a GUI to
-   help the user drive two debuggers.  So for now, I'm disabling
-   the "both" option.
-   "parent", "child", "both", "ask" };
- */
-  "parent", "child", "ask"};
+  follow_fork_mode_ask,
+  /* ??rehrauer: The "both" option is broken, by what may be a 10.20
+     kernel problem.  It's also not terribly useful without a GUI to
+     help the user drive two debuggers.  So for now, I'm disabling the
+     "both" option. */
+  /* follow_fork_mode_both, */
+  follow_fork_mode_child,
+  follow_fork_mode_parent,
+  NULL
+};
 
-static char *follow_fork_mode_string = NULL;
+static const char *follow_fork_mode_string = follow_fork_mode_parent;
 \f
 
 static void
@@ -462,23 +468,19 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked,
   int followed_child = 0;
 
   /* Which process did the user want us to follow? */
-  char *follow_mode =
-    savestring (follow_fork_mode_string, strlen (follow_fork_mode_string));
+  const char *follow_mode = follow_fork_mode_string;
 
   /* Or, did the user not know, and want us to ask? */
-  if (STREQ (follow_fork_mode_string, "ask"))
+  if (follow_fork_mode_string == follow_fork_mode_ask)
     {
-      char requested_mode[100];
-
-      free (follow_mode);
-      error ("\"ask\" mode NYI");
-      follow_mode = savestring (requested_mode, strlen (requested_mode));
+      internal_error ("follow_inferior_fork: \"ask\" mode not implemented");
+      /* follow_mode = follow_fork_mode_...; */
     }
 
   /* If we're to be following the parent, then detach from child_pid.
      We're already following the parent, so need do nothing explicit
      for it. */
-  if (STREQ (follow_mode, "parent"))
+  if (follow_mode == follow_fork_mode_parent)
     {
       followed_parent = 1;
 
@@ -503,7 +505,7 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked,
 
   /* If we're to be following the child, then attach to it, detach
      from inferior_pid, and set inferior_pid to child_pid. */
-  else if (STREQ (follow_mode, "child"))
+  else if (follow_mode == follow_fork_mode_child)
     {
       char child_pid_spelling[100];    /* Arbitrary length. */
 
@@ -565,7 +567,7 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked,
 
   /* If we're to be following both parent and child, then fork ourselves,
      and attach the debugger clone to the child. */
-  else if (STREQ (follow_mode, "both"))
+  else if (follow_mode == follow_fork_mode_both)
     {
       char pid_suffix[100];    /* Arbitrary length. */
 
@@ -621,8 +623,6 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked,
 
   pending_follow.fork_event.saw_parent_fork = 0;
   pending_follow.fork_event.saw_child_fork = 0;
-
-  free (follow_mode);
 }
 
 static void
@@ -646,7 +646,7 @@ follow_vfork (int parent_pid, int child_pid)
       pending_follow.fork_event.saw_child_exec = 0;
       pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
       follow_exec (inferior_pid, pending_follow.execd_pathname);
-      free (pending_follow.execd_pathname);
+      xfree (pending_follow.execd_pathname);
     }
 }
 
@@ -759,17 +759,22 @@ static int singlestep_breakpoints_inserted_p = 0;
 /* Things to clean up if we QUIT out of resume ().  */
 /* ARGSUSED */
 static void
-resume_cleanups (int arg)
+resume_cleanups (void *ignore)
 {
   normal_stop ();
 }
 
-static char schedlock_off[] = "off";
-static char schedlock_on[] = "on";
-static char schedlock_step[] = "step";
-static char *scheduler_mode = schedlock_off;
-static char *scheduler_enums[] =
-{schedlock_off, schedlock_on, schedlock_step};
+static const char schedlock_off[] = "off";
+static const char schedlock_on[] = "on";
+static const char schedlock_step[] = "step";
+static const char *scheduler_mode = schedlock_off;
+static const char *scheduler_enums[] =
+{
+  schedlock_off,
+  schedlock_on,
+  schedlock_step,
+  NULL
+};
 
 static void
 set_schedlock_func (char *args, int from_tty, struct cmd_list_element *c)
@@ -798,8 +803,7 @@ void
 resume (int step, enum target_signal sig)
 {
   int should_resume = 1;
-  struct cleanup *old_cleanups = make_cleanup ((make_cleanup_func)
-                                              resume_cleanups, 0);
+  struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
   QUIT;
 
 #ifdef CANNOT_STEP_BREAKPOINT
@@ -810,6 +814,18 @@ resume (int step, enum target_signal sig)
     step = 0;
 #endif
 
+  /* Some targets (e.g. Solaris x86) have a kernel bug when stepping
+     over an instruction that causes a page fault without triggering
+     a hardware watchpoint. The kernel properly notices that it shouldn't
+     stop, because the hardware watchpoint is not triggered, but it forgets
+     the step request and continues the program normally.
+     Work around the problem by removing hardware watchpoints if a step is
+     requested, GDB will check for a hardware watchpoint trigger after the
+     step anyway.  */
+  if (CANNOT_STEP_HW_WATCHPOINTS && step && breakpoints_inserted)
+    remove_hw_watchpoints ();
+     
+
   /* Normally, by the time we reach `resume', the breakpoints are either
      removed or inserted, as appropriate.  The exception is if we're sitting
      at a permanent breakpoint; we need to step over it, but permanent
@@ -875,6 +891,8 @@ resume (int step, enum target_signal sig)
 
   if (should_resume)
     {
+      int resume_pid;
+
       if (use_thread_step_needed && thread_step_needed)
        {
          /* We stopped on a BPT instruction;
@@ -886,7 +904,7 @@ resume (int step, enum target_signal sig)
            {
              /* Breakpoint deleted: ok to do regular resume
                 where all the threads either step or continue. */
-             target_resume (-1, step, sig);
+             resume_pid = -1;
            }
          else
            {
@@ -898,20 +916,19 @@ resume (int step, enum target_signal sig)
                  trap_expected = 1;
                  step = 1;
                }
-
-             target_resume (inferior_pid, step, sig);
+             resume_pid = inferior_pid;
            }
        }
       else
        {
          /* Vanilla resume. */
-
          if ((scheduler_mode == schedlock_on) ||
              (scheduler_mode == schedlock_step && step != 0))
-           target_resume (inferior_pid, step, sig);
+           resume_pid = inferior_pid;
          else
-           target_resume (-1, step, sig);
+           resume_pid = -1;
        }
+      target_resume (resume_pid, step, sig);
     }
 
   discard_cleanups (old_cleanups);
@@ -928,7 +945,7 @@ clear_proceed_status (void)
   step_range_start = 0;
   step_range_end = 0;
   step_frame_address = 0;
-  step_over_calls = -1;
+  step_over_calls = STEP_OVER_UNDEBUGGABLE;
   stop_after_trap = 0;
   stop_soon_quietly = 0;
   proceed_to_finish = 0;
@@ -1038,9 +1055,11 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
       int temp = insert_breakpoints ();
       if (temp)
        {
-         print_sys_errmsg ("ptrace", temp);
+         print_sys_errmsg ("insert_breakpoints", temp);
          error ("Cannot insert breakpoints.\n\
-The same program may be running in another process.");
+The same program may be running in another process,\n\
+or you may have requested too many hardware\n\
+breakpoints and/or watchpoints.\n");
        }
 
       breakpoints_inserted = 1;
@@ -1094,7 +1113,7 @@ start_remote (void)
 
   /* Always go on waiting for the target, regardless of the mode. */
   /* FIXME: cagney/1999-09-23: At present it isn't possible to
-     indicate th wait_for_inferior that a target should timeout if
+     indicate to wait_for_inferior that a target should timeout if
      nothing is returned (instead of just blocking).  Because of this,
      targets expecting an immediate response need to, internally, set
      things up so that the target_wait() is forced to eventually
@@ -1164,6 +1183,24 @@ enum infwait_states
   infwait_nonstep_watch_state
 };
 
+/* Why did the inferior stop? Used to print the appropriate messages
+   to the interface from within handle_inferior_event(). */
+enum inferior_stop_reason
+{
+  /* We don't know why. */
+  STOP_UNKNOWN,
+  /* Step, next, nexti, stepi finished. */
+  END_STEPPING_RANGE,
+  /* Found breakpoint. */
+  BREAKPOINT_HIT,
+  /* Inferior terminated by signal. */
+  SIGNAL_EXITED,
+  /* Inferior exited. */
+  EXITED,
+  /* Inferior received signal, and user asked to be notified. */
+  SIGNAL_RECEIVED
+};
+
 /* This structure contains what used to be local variables in
    wait_for_inferior.  Probably many of them can return to being
    locals in handle_inferior_event.  */
@@ -1206,6 +1243,7 @@ static void step_over_function (struct execution_control_state *ecs);
 static void stop_stepping (struct execution_control_state *ecs);
 static void prepare_to_wait (struct execution_control_state *ecs);
 static void keep_going (struct execution_control_state *ecs);
+static void print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info);
 
 /* Wait for control to return from inferior to debugger.
    If inferior gets a signal, we may decide to start it up again
@@ -1235,8 +1273,7 @@ wait_for_inferior (void)
   thread_step_needed = 0;
 
   /* We'll update this if & when we switch to a new thread. */
-  if (may_switch_from_inferior_pid)
-    switched_from_inferior_pid = inferior_pid;
+  previous_inferior_pid = inferior_pid;
 
   overlay_cache_invalid = 1;
 
@@ -1277,8 +1314,7 @@ struct execution_control_state async_ecss;
 struct execution_control_state *async_ecs;
 
 void
-fetch_inferior_event (client_data)
-     void *client_data;
+fetch_inferior_event (void *client_data)
 {
   static struct cleanup *old_cleanups;
 
@@ -1297,8 +1333,7 @@ fetch_inferior_event (client_data)
       thread_step_needed = 0;
 
       /* We'll update this if & when we switch to a new thread. */
-      if (may_switch_from_inferior_pid)
-       switched_from_inferior_pid = inferior_pid;
+      previous_inferior_pid = inferior_pid;
 
       overlay_cache_invalid = 1;
 
@@ -1326,7 +1361,10 @@ fetch_inferior_event (client_data)
         if there are any. */
       do_exec_cleanups (old_cleanups);
       normal_stop ();
-      inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+      if (step_multi && stop_step)
+       inferior_event_handler (INF_EXEC_CONTINUE, NULL);
+      else
+       inferior_event_handler (INF_EXEC_COMPLETE, NULL);
     }
 }
 
@@ -1336,6 +1374,7 @@ fetch_inferior_event (client_data)
 void
 init_execution_control_state (struct execution_control_state *ecs)
 {
+  /* ecs->another_trap? */
   ecs->random_signal = 0;
   ecs->remove_breakpoints_on_following_step = 0;
   ecs->handling_longjmp = 0;   /* FIXME */
@@ -1397,7 +1436,7 @@ handle_inferior_event (struct execution_control_state *ecs)
        insert_breakpoints ();
 
        /* We need to restart all the threads now,
-        * unles we're running in scheduler-locked mode. 
+        * unless we're running in scheduler-locked mode. 
         * FIXME: shouldn't we look at currently_stepping ()?
         */
        if (scheduler_mode == schedlock_on)
@@ -1434,7 +1473,13 @@ handle_inferior_event (struct execution_control_state *ecs)
       {
        add_thread (ecs->pid);
 
+#ifdef UI_OUT
+       ui_out_text (uiout, "[New ");
+       ui_out_text (uiout, target_pid_or_tid_to_str (ecs->pid));
+       ui_out_text (uiout, "]\n");
+#else
        printf_filtered ("[New %s]\n", target_pid_or_tid_to_str (ecs->pid));
+#endif
 
 #if 0
        /* NOTE: This block is ONLY meant to be invoked in case of a
@@ -1503,12 +1548,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 
       case TARGET_WAITKIND_EXITED:
        target_terminal_ours ();        /* Must do this before mourn anyway */
-       annotate_exited (ecs->ws.value.integer);
-       if (ecs->ws.value.integer)
-         printf_filtered ("\nProgram exited with code 0%o.\n",
-                          (unsigned int) ecs->ws.value.integer);
-       else
-         printf_filtered ("\nProgram exited normally.\n");
+       print_stop_reason (EXITED, ecs->ws.value.integer);
 
        /* Record the exit code in the convenience variable $_exitcode, so
           that the user can inspect this again later.  */
@@ -1526,27 +1566,15 @@ handle_inferior_event (struct execution_control_state *ecs)
        stop_print_frame = 0;
        stop_signal = ecs->ws.value.sig;
        target_terminal_ours ();        /* Must do this before mourn anyway */
-       annotate_signalled ();
-
-       /* This looks pretty bogus to me.  Doesn't TARGET_WAITKIND_SIGNALLED
-          mean it is already dead?  This has been here since GDB 2.8, so
-          perhaps it means rms didn't understand unix waitstatuses?
-          For the moment I'm just kludging around this in remote.c
-          rather than trying to change it here --kingdon, 5 Dec 1994.  */
-       target_kill ();         /* kill mourns as well */
-
-       printf_filtered ("\nProgram terminated with signal ");
-       annotate_signal_name ();
-       printf_filtered ("%s", target_signal_to_name (stop_signal));
-       annotate_signal_name_end ();
-       printf_filtered (", ");
-       annotate_signal_string ();
-       printf_filtered ("%s", target_signal_to_string (stop_signal));
-       annotate_signal_string_end ();
-       printf_filtered (".\n");
-
-       printf_filtered ("The program no longer exists.\n");
-       gdb_flush (gdb_stdout);
+
+       /* Note: By definition of TARGET_WAITKIND_SIGNALLED, we shouldn't
+          reach here unless the inferior is dead.  However, for years
+          target_kill() was called here, which hints that fatal signals aren't
+          really fatal on some systems.  If that's true, then some changes
+          may be needed. */
+       target_mourn_inferior ();
+
+       print_stop_reason (SIGNAL_EXITED, stop_signal);
        singlestep_breakpoints_inserted_p = 0;  /*SOFTWARE_SINGLE_STEP_P */
        stop_stepping (ecs);
        return;
@@ -1687,7 +1715,7 @@ handle_inferior_event (struct execution_control_state *ecs)
        /* This causes the eventpoints and symbol table to be reset.  Must
           do this now, before trying to determine whether to stop. */
        follow_exec (inferior_pid, pending_follow.execd_pathname);
-       free (pending_follow.execd_pathname);
+       xfree (pending_follow.execd_pathname);
 
        stop_pc = read_pc_pid (ecs->pid);
        ecs->saved_inferior_pid = inferior_pid;
@@ -1753,6 +1781,17 @@ handle_inferior_event (struct execution_control_state *ecs)
       case TARGET_WAITKIND_STOPPED:
        stop_signal = ecs->ws.value.sig;
        break;
+
+       /* We had an event in the inferior, but we are not interested
+          in handling it at this level. The lower layers have already
+          done what needs to be done, if anything. This case can
+          occur only when the target is async or extended-async. One
+          of the circumstamces for this to happen is when the
+          inferior produces output for the console. The inferior has
+          not stopped, and we are ignoring the event. */
+      case TARGET_WAITKIND_IGNORE:
+       ecs->wait_some_more = 1;
+       return;
       }
 
     /* We may want to consider not doing a resume here in order to give
@@ -1899,39 +1938,44 @@ handle_inferior_event (struct execution_control_state *ecs)
        /* It's a SIGTRAP or a signal we're interested in.  Switch threads,
           and fall into the rest of wait_for_inferior().  */
 
-       /* Save infrun state for the old thread.  */
-       save_infrun_state (inferior_pid, prev_pc,
-                          prev_func_start, prev_func_name,
-                          trap_expected, step_resume_breakpoint,
-                          through_sigtramp_breakpoint,
-                          step_range_start, step_range_end,
-                          step_frame_address, ecs->handling_longjmp,
-                          ecs->another_trap,
-                          ecs->stepping_through_solib_after_catch,
-                          ecs->stepping_through_solib_catchpoints,
-                          ecs->stepping_through_sigtramp);
-
-       if (may_switch_from_inferior_pid)
-         switched_from_inferior_pid = inferior_pid;
+       /* Caution: it may happen that the new thread (or the old one!)
+          is not in the thread list.  In this case we must not attempt
+          to "switch context", or we run the risk that our context may
+          be lost.  This may happen as a result of the target module
+          mishandling thread creation.  */
+
+       if (in_thread_list (inferior_pid) && in_thread_list (ecs->pid))
+         { /* Perform infrun state context switch: */
+           /* Save infrun state for the old thread.  */
+           save_infrun_state (inferior_pid, prev_pc,
+                              prev_func_start, prev_func_name,
+                              trap_expected, step_resume_breakpoint,
+                              through_sigtramp_breakpoint,
+                              step_range_start, step_range_end,
+                              step_frame_address, ecs->handling_longjmp,
+                              ecs->another_trap,
+                              ecs->stepping_through_solib_after_catch,
+                              ecs->stepping_through_solib_catchpoints,
+                              ecs->stepping_through_sigtramp);
+
+           /* Load infrun state for the new thread.  */
+           load_infrun_state (ecs->pid, &prev_pc,
+                              &prev_func_start, &prev_func_name,
+                              &trap_expected, &step_resume_breakpoint,
+                              &through_sigtramp_breakpoint,
+                              &step_range_start, &step_range_end,
+                              &step_frame_address, &ecs->handling_longjmp,
+                              &ecs->another_trap,
+                              &ecs->stepping_through_solib_after_catch,
+                              &ecs->stepping_through_solib_catchpoints,
+                              &ecs->stepping_through_sigtramp);
+         }
 
        inferior_pid = ecs->pid;
 
-       /* Load infrun state for the new thread.  */
-       load_infrun_state (inferior_pid, &prev_pc,
-                          &prev_func_start, &prev_func_name,
-                          &trap_expected, &step_resume_breakpoint,
-                          &through_sigtramp_breakpoint,
-                          &step_range_start, &step_range_end,
-                          &step_frame_address, &ecs->handling_longjmp,
-                          &ecs->another_trap,
-                          &ecs->stepping_through_solib_after_catch,
-                          &ecs->stepping_through_solib_catchpoints,
-                          &ecs->stepping_through_sigtramp);
-
        if (context_hook)
          context_hook (pid_to_thread_id (ecs->pid));
 
-       printf_filtered ("[Switching to %s]\n", target_pid_to_str (ecs->pid));
        flush_cached_frames ();
       }
 
@@ -2186,17 +2230,7 @@ handle_inferior_event (struct execution_control_state *ecs)
          {
            printed = 1;
            target_terminal_ours_for_output ();
-           annotate_signal ();
-           printf_filtered ("\nProgram received signal ");
-           annotate_signal_name ();
-           printf_filtered ("%s", target_signal_to_name (stop_signal));
-           annotate_signal_name_end ();
-           printf_filtered (", ");
-           annotate_signal_string ();
-           printf_filtered ("%s", target_signal_to_string (stop_signal));
-           annotate_signal_string_end ();
-           printf_filtered (".\n");
-           gdb_flush (gdb_stdout);
+           print_stop_reason (SIGNAL_RECEIVED, stop_signal);
          }
        if (signal_stop[stop_signal])
          {
@@ -2245,6 +2279,8 @@ handle_inferior_event (struct execution_control_state *ecs)
            the HP-UX maintainer to furnish a fix that doesn't break other
            platforms.  --JimB, 20 May 1999 */
        check_sigtramp2 (ecs);
+       keep_going (ecs);
+       return;
       }
 
     /* Handle cases caused by hitting a breakpoint.  */
@@ -2427,7 +2463,6 @@ handle_inferior_event (struct execution_control_state *ecs)
               dynamically loaded objects (among other things).  */
            if (stop_on_solib_events)
              {
-               stop_print_frame = 0;
                stop_stepping (ecs);
                return;
              }
@@ -2582,7 +2617,7 @@ handle_inferior_event (struct execution_control_state *ecs)
        loader dynamic symbol resolution code, we keep on single stepping
        until we exit the run time loader code and reach the callee's
        address.  */
-    if (step_over_calls < 0 && IN_SOLIB_DYNSYM_RESOLVE_CODE (stop_pc))
+    if (step_over_calls == STEP_OVER_UNDEBUGGABLE && IN_SOLIB_DYNSYM_RESOLVE_CODE (stop_pc))
       {
        CORE_ADDR pc_after_resolver = SKIP_SOLIB_RESOLVER (stop_pc);
 
@@ -2703,19 +2738,34 @@ handle_inferior_event (struct execution_control_state *ecs)
       {
        /* It's a subroutine call.  */
 
-       if (step_over_calls == 0)
+       if (step_over_calls == STEP_OVER_NONE)
          {
            /* I presume that step_over_calls is only 0 when we're
               supposed to be stepping at the assembly language level
               ("stepi").  Just stop.  */
            stop_step = 1;
+           print_stop_reason (END_STEPPING_RANGE, 0);
            stop_stepping (ecs);
            return;
          }
 
-       if (step_over_calls > 0 || IGNORE_HELPER_CALL (stop_pc))
+       if (step_over_calls == STEP_OVER_ALL || IGNORE_HELPER_CALL (stop_pc))
          {
            /* We're doing a "next".  */
+
+           if (IN_SIGTRAMP (stop_pc, ecs->stop_func_name)
+               && INNER_THAN (step_frame_address, read_sp()))
+             /* We stepped out of a signal handler, and into its
+                 calling trampoline.  This is misdetected as a
+                 subroutine call, but stepping over the signal
+                 trampoline isn't such a bad idea.  In order to do
+                 that, we have to ignore the value in
+                 step_frame_address, since that doesn't represent the
+                 frame that'll reach when we return from the signal
+                 trampoline.  Otherwise we'll probably continue to the
+                 end of the program.  */
+             step_frame_address = 0;
+
            step_over_function (ecs);
            keep_going (ecs);
            return;
@@ -2765,6 +2815,18 @@ handle_inferior_event (struct execution_control_state *ecs)
              return;
            }
        }
+
+       /* If we have no line number and the step-stop-if-no-debug
+          is set, we stop the step so that the user has a chance to
+          switch in assembly mode.  */
+       if (step_over_calls == STEP_OVER_UNDEBUGGABLE && step_stop_if_no_debug)
+         {
+           stop_step = 1;
+           print_stop_reason (END_STEPPING_RANGE, 0);
+           stop_stepping (ecs);
+           return;
+         }
+
        step_over_function (ecs);
        keep_going (ecs);
        return;
@@ -2780,6 +2842,7 @@ handle_inferior_event (struct execution_control_state *ecs)
        /* It is stepi or nexti.  We always want to stop stepping after
           one instruction.  */
        stop_step = 1;
+       print_stop_reason (END_STEPPING_RANGE, 0);
        stop_stepping (ecs);
        return;
       }
@@ -2825,6 +2888,7 @@ handle_inferior_event (struct execution_control_state *ecs)
           when we do "s" in a function with no line numbers,
           or can this happen as a result of a return or longjmp?).  */
        stop_step = 1;
+       print_stop_reason (END_STEPPING_RANGE, 0);
        stop_stepping (ecs);
        return;
       }
@@ -2837,6 +2901,7 @@ handle_inferior_event (struct execution_control_state *ecs)
           That is said to make things like for (;;) statements work
           better.  */
        stop_step = 1;
+       print_stop_reason (END_STEPPING_RANGE, 0);
        stop_stepping (ecs);
        return;
       }
@@ -2856,6 +2921,7 @@ handle_inferior_event (struct execution_control_state *ecs)
           in which after skipping the prologue we better stop even though
           we will be in mid-line.  */
        stop_step = 1;
+       print_stop_reason (END_STEPPING_RANGE, 0);
        stop_stepping (ecs);
        return;
       }
@@ -2962,6 +3028,7 @@ step_into_function (struct execution_control_state *ecs)
     {
       /* We are already there: stop now.  */
       stop_step = 1;
+       print_stop_reason (END_STEPPING_RANGE, 0);
       stop_stepping (ecs);
       return;
     }
@@ -3011,7 +3078,7 @@ step_over_function (struct execution_control_state *ecs)
   step_resume_breakpoint =
     set_momentary_breakpoint (sr_sal, get_current_frame (), bp_step_resume);
 
-  if (!IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc))
+  if (step_frame_address && !IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc))
     step_resume_breakpoint->frame = step_frame_address;
 
   if (breakpoints_inserted)
@@ -3198,38 +3265,126 @@ prepare_to_wait (struct execution_control_state *ecs)
   ecs->wait_some_more = 1;
 }
 
-/* This function returns TRUE if ep is an internal breakpoint
-   set to catch generic shared library (aka dynamically-linked
-   library) events.  (This is *NOT* the same as a catchpoint for a
-   shlib event.  The latter is something a user can set; this is
-   something gdb sets for its own use, and isn't ever shown to a
-   user.) */
-static int
-is_internal_shlib_eventpoint (struct breakpoint *ep)
-{
-  return
-    (ep->type == bp_shlib_event)
-    ;
-}
-
-/* This function returns TRUE if bs indicates that the inferior
-   stopped due to a shared library (aka dynamically-linked library)
-   event. */
-
-static int
-stopped_for_internal_shlib_event (bpstat bs)
+/* Print why the inferior has stopped. We always print something when
+   the inferior exits, or receives a signal. The rest of the cases are
+   dealt with later on in normal_stop() and print_it_typical().  Ideally
+   there should be a call to this function from handle_inferior_event()
+   each time stop_stepping() is called.*/
+static void
+print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info)
 {
-  /* Note that multiple eventpoints may've caused the stop.  Any
-     that are associated with shlib events will be accepted. */
-  for (; bs != NULL; bs = bs->next)
+  switch (stop_reason)
     {
-      if ((bs->breakpoint_at != NULL)
-         && is_internal_shlib_eventpoint (bs->breakpoint_at))
-       return 1;
+    case STOP_UNKNOWN:
+      /* We don't deal with these cases from handle_inferior_event()
+         yet. */
+      break;
+    case END_STEPPING_RANGE:
+      /* We are done with a step/next/si/ni command. */
+      /* For now print nothing. */
+#ifdef UI_OUT
+      /* Print a message only if not in the middle of doing a "step n"
+        operation for n > 1 */
+      if (!step_multi || !stop_step)
+       if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+         ui_out_field_string (uiout, "reason", "end-stepping-range");
+#endif
+      break;
+    case BREAKPOINT_HIT:
+      /* We found a breakpoint. */
+      /* For now print nothing. */
+      break;
+    case SIGNAL_EXITED:
+      /* The inferior was terminated by a signal. */
+#ifdef UI_OUT
+      annotate_signalled ();
+      if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+       ui_out_field_string (uiout, "reason", "exited-signalled");
+      ui_out_text (uiout, "\nProgram terminated with signal ");
+      annotate_signal_name ();
+      ui_out_field_string (uiout, "signal-name", target_signal_to_name (stop_info));
+      annotate_signal_name_end ();
+      ui_out_text (uiout, ", ");
+      annotate_signal_string ();
+      ui_out_field_string (uiout, "signal-meaning", target_signal_to_string (stop_info));
+      annotate_signal_string_end ();
+      ui_out_text (uiout, ".\n");
+      ui_out_text (uiout, "The program no longer exists.\n");
+#else
+      annotate_signalled ();
+      printf_filtered ("\nProgram terminated with signal ");
+      annotate_signal_name ();
+      printf_filtered ("%s", target_signal_to_name (stop_info));
+      annotate_signal_name_end ();
+      printf_filtered (", ");
+      annotate_signal_string ();
+      printf_filtered ("%s", target_signal_to_string (stop_info));
+      annotate_signal_string_end ();
+      printf_filtered (".\n");
+
+      printf_filtered ("The program no longer exists.\n");
+      gdb_flush (gdb_stdout);
+#endif
+      break;
+    case EXITED:
+      /* The inferior program is finished. */
+#ifdef UI_OUT
+      annotate_exited (stop_info);
+      if (stop_info)
+       {
+         if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+           ui_out_field_string (uiout, "reason", "exited");
+         ui_out_text (uiout, "\nProgram exited with code ");
+         ui_out_field_fmt (uiout, "exit-code", "0%o", (unsigned int) stop_info);
+         ui_out_text (uiout, ".\n");
+       }
+      else
+       {
+         if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+           ui_out_field_string (uiout, "reason", "exited-normally");
+         ui_out_text (uiout, "\nProgram exited normally.\n");
+       }
+#else
+      annotate_exited (stop_info);
+      if (stop_info)
+       printf_filtered ("\nProgram exited with code 0%o.\n",
+                        (unsigned int) stop_info);
+      else
+       printf_filtered ("\nProgram exited normally.\n");
+#endif
+      break;
+    case SIGNAL_RECEIVED:
+      /* Signal received. The signal table tells us to print about
+         it. */
+#ifdef UI_OUT
+      annotate_signal ();
+      ui_out_text (uiout, "\nProgram received signal ");
+      annotate_signal_name ();
+      ui_out_field_string (uiout, "signal-name", target_signal_to_name (stop_info));
+      annotate_signal_name_end ();
+      ui_out_text (uiout, ", ");
+      annotate_signal_string ();
+      ui_out_field_string (uiout, "signal-meaning", target_signal_to_string (stop_info));
+      annotate_signal_string_end ();
+      ui_out_text (uiout, ".\n");
+#else
+      annotate_signal ();
+      printf_filtered ("\nProgram received signal ");
+      annotate_signal_name ();
+      printf_filtered ("%s", target_signal_to_name (stop_info));
+      annotate_signal_name_end ();
+      printf_filtered (", ");
+      annotate_signal_string ();
+      printf_filtered ("%s", target_signal_to_string (stop_info));
+      annotate_signal_string_end ();
+      printf_filtered (".\n");
+      gdb_flush (gdb_stdout);      
+#endif
+      break;
+    default:
+      internal_error ("print_stop_reason: unrecognized enum value");
+      break;
     }
-
-  /* If we get here, then no candidate was found. */
-  return 0;
 }
 \f
 
@@ -3250,14 +3405,13 @@ normal_stop (void)
 
      (Note that there's no point in saying anything if the inferior
      has exited!) */
-  if (may_switch_from_inferior_pid
-      && (switched_from_inferior_pid != inferior_pid)
+  if ((previous_inferior_pid != inferior_pid)
       && target_has_execution)
     {
       target_terminal_ours_for_output ();
-      printf_filtered ("[Switched to %s]\n",
+      printf_filtered ("[Switching to %s]\n",
                       target_pid_or_tid_to_str (inferior_pid));
-      switched_from_inferior_pid = inferior_pid;
+      previous_inferior_pid = inferior_pid;
     }
 
   /* Make sure that the current_frame's pc is correct.  This
@@ -3269,9 +3423,11 @@ normal_stop (void)
   if (breakpoints_failed)
     {
       target_terminal_ours_for_output ();
-      print_sys_errmsg ("ptrace", breakpoints_failed);
+      print_sys_errmsg ("While inserting breakpoints", breakpoints_failed);
       printf_filtered ("Stopped; cannot insert breakpoints.\n\
-The same program may be running in another process.\n");
+The same program may be running in another process,\n\
+or you may have requested too many hardware breakpoints\n\
+and/or watchpoints.\n");
     }
 
   if (target_has_execution && breakpoints_inserted)
@@ -3305,19 +3461,11 @@ The same program may be running in another process.\n");
 
   target_terminal_ours ();
 
-  /* Did we stop because the user set the stop_on_solib_events
-     variable?  (If so, we report this as a generic, "Stopped due
-     to shlib event" message.) */
-  if (stopped_for_internal_shlib_event (stop_bpstat))
-    {
-      printf_filtered ("Stopped due to shared library event\n");
-    }
-
   /* Look up the hook_stop and run it if it exists.  */
 
-  if (stop_command && stop_command->hook)
+  if (stop_command && stop_command->hook_pre)
     {
-      catch_errors (hook_stop_stub, stop_command->hook,
+      catch_errors (hook_stop_stub, stop_command->hook_pre,
                    "Error while running hook_stop:\n", RETURN_MASK_ALL);
     }
 
@@ -3342,36 +3490,54 @@ The same program may be running in another process.\n");
          bpstat_print() contains the logic deciding in detail
          what to print, based on the event(s) that just occurred. */
 
-      if (stop_print_frame)
+      if (stop_print_frame
+         && selected_frame)
        {
          int bpstat_ret;
          int source_flag;
+         int do_frame_printing = 1;
 
          bpstat_ret = bpstat_print (stop_bpstat);
-         /* bpstat_print() returned one of:
-            -1: Didn't print anything
-            0: Printed preliminary "Breakpoint n, " message, desires
-            location tacked on
-            1: Printed something, don't tack on location */
-
-         if (bpstat_ret == -1)
-           if (stop_step
-               && step_frame_address == FRAME_FP (get_current_frame ())
-               && step_start_function == find_pc_function (stop_pc))
-             source_flag = -1; /* finished step, just print source line */
-           else
-             source_flag = 1;  /* print location and source line */
-         else if (bpstat_ret == 0)     /* hit bpt, desire location */
-           source_flag = 1;    /* print location and source line */
-         else                  /* bpstat_ret == 1, hit bpt, do not desire location */
-           source_flag = -1;   /* just print source line */
+         switch (bpstat_ret)
+           {
+           case PRINT_UNKNOWN:
+             if (stop_step
+                 && step_frame_address == FRAME_FP (get_current_frame ())
+                 && step_start_function == find_pc_function (stop_pc))
+               source_flag = SRC_LINE;   /* finished step, just print source line */
+             else
+               source_flag = SRC_AND_LOC;    /* print location and source line */
+             break;
+           case PRINT_SRC_AND_LOC:
+             source_flag = SRC_AND_LOC;    /* print location and source line */
+             break;
+           case PRINT_SRC_ONLY:
+             source_flag = SRC_LINE;
+             break;
+           case PRINT_NOTHING:
+             do_frame_printing = 0;
+             break;
+           default:
+             internal_error ("Unknown value.");
+           }
+#ifdef UI_OUT
+         /* For mi, have the same behavior every time we stop:
+             print everything but the source line. */
+         if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+           source_flag = LOC_AND_ADDRESS;
+#endif
 
+#ifdef UI_OUT
+         if (interpreter_p && strcmp (interpreter_p, "mi") == 0)
+           ui_out_field_int (uiout, "thread-id", pid_to_thread_id (inferior_pid));
+#endif
          /* The behavior of this routine with respect to the source
             flag is:
-            -1: Print only source line
-            0: Print only location
-            1: Print location and source line */
-         show_and_print_stack_frame (selected_frame, -1, source_flag);
+            SRC_LINE: Print only source line
+            LOCATION: Print only location
+            SRC_AND_LOC: Print location and source line */
+         if (do_frame_printing)
+           show_and_print_stack_frame (selected_frame, -1, source_flag);
 
          /* Display the auto-display expressions.  */
          do_displays ();
@@ -3725,7 +3891,7 @@ xdb_handle_command (char *args, int from_tty)
          else
            printf_filtered ("Invalid signal handling flag.\n");
          if (argBuf)
-           free (argBuf);
+           xfree (argBuf);
        }
     }
   do_cleanups (old_chain);
@@ -3750,7 +3916,7 @@ signals_info (char *signum_exp, int from_tty)
        {
          /* No, try numeric.  */
          oursig =
-           target_signal_from_command (parse_and_eval_address (signum_exp));
+           target_signal_from_command (parse_and_eval_long (signum_exp));
        }
       sig_print_info (oursig);
       return;
@@ -3785,7 +3951,7 @@ struct inferior_status
   CORE_ADDR step_range_start;
   CORE_ADDR step_range_end;
   CORE_ADDR step_frame_address;
-  int step_over_calls;
+  enum step_over_calls_kind step_over_calls;
   CORE_ADDR step_resume_break_address;
   int stop_after_trap;
   int stop_soon_quietly;
@@ -3816,9 +3982,9 @@ xmalloc_inferior_status (void)
 static void
 free_inferior_status (struct inferior_status *inf_status)
 {
-  free (inf_status->registers);
-  free (inf_status->stop_registers);
-  free (inf_status);
+  xfree (inf_status->registers);
+  xfree (inf_status->stop_registers);
+  xfree (inf_status);
 }
 
 void
@@ -3965,6 +4131,18 @@ restore_inferior_status (struct inferior_status *inf_status)
   free_inferior_status (inf_status);
 }
 
+static void
+do_restore_inferior_status_cleanup (void *sts)
+{
+  restore_inferior_status (sts);
+}
+
+struct cleanup *
+make_cleanup_restore_inferior_status (struct inferior_status *inf_status)
+{
+  return make_cleanup (do_restore_inferior_status_cleanup, inf_status);
+}
+
 void
 discard_inferior_status (struct inferior_status *inf_status)
 {
@@ -3973,20 +4151,6 @@ discard_inferior_status (struct inferior_status *inf_status)
   free_inferior_status (inf_status);
 }
 
-static void
-set_follow_fork_mode_command (char *arg, int from_tty,
-                             struct cmd_list_element *c)
-{
-  if (!STREQ (arg, "parent") &&
-      !STREQ (arg, "child") &&
-      !STREQ (arg, "both") &&
-      !STREQ (arg, "ask"))
-    error ("follow-fork-mode must be one of \"parent\", \"child\", \"both\" or \"ask\".");
-
-  if (follow_fork_mode_string != NULL)
-    free (follow_fork_mode_string);
-  follow_fork_mode_string = savestring (arg, strlen (arg));
-}
 \f
 static void
 build_infrun (void)
@@ -4118,7 +4282,7 @@ to the user would be loading/unloading of a new library.\n",
   c = add_set_enum_cmd ("follow-fork-mode",
                        class_run,
                        follow_fork_mode_kind_names,
-                       (char *) &follow_fork_mode_string,
+                       &follow_fork_mode_string,
 /* ??rehrauer:  The "both" option is broken, by what may be a 10.20
    kernel problem.  It's also not terribly useful without a GUI to
    help the user drive two debuggers.  So for now, I'm disabling
@@ -4149,11 +4313,9 @@ By default, the debugger will follow the parent process.",
 /*  c->function.sfunc = ; */
   add_show_from_set (c, &showlist);
 
-  set_follow_fork_mode_command ("parent", 0, NULL);
-
   c = add_set_enum_cmd ("scheduler-locking", class_run,
                        scheduler_enums,        /* array of string names */
-                       (char *) &scheduler_mode,       /* current mode  */
+                       &scheduler_mode,        /* current mode  */
                        "Set mode for locking scheduler during execution.\n\
 off  == no locking (threads may preempt at any time)\n\
 on   == full locking (no thread except the current thread may run)\n\
@@ -4164,4 +4326,13 @@ step == scheduler locked during every single-step operation.\n\
 
   c->function.sfunc = set_schedlock_func;      /* traps on target vector */
   add_show_from_set (c, &showlist);
+
+  c = add_set_cmd ("step-mode", class_run,
+                  var_boolean, (char*) &step_stop_if_no_debug,
+"Set mode of the step operation. When set, doing a step over a\n\
+function without debug line information will stop at the first\n\
+instruction of that function. Otherwise, the function is skipped and\n\
+the step command stops at a different source line.",
+                       &setlist);
+  add_show_from_set (c, &showlist);
 }
This page took 0.036193 seconds and 4 git commands to generate.