revert 1.9. Not approved.
[deliverable/binutils-gdb.git] / gdb / infrun.c
index c00da0a882bacb7bd15fa012c96e17c4e6866b1d..8bf3012a6678d8b6e73453c9daecd005937c0a53 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"
@@ -92,17 +92,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.  */
@@ -270,7 +260,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, "\
@@ -306,6 +296,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;
@@ -439,13 +436,13 @@ static int follow_vfork_when_exec;
 
 static 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"};
+  /* ??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", NULL
+};
 
 static char *follow_fork_mode_string = NULL;
 \f
@@ -765,7 +762,12 @@ 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};
+{
+  schedlock_off,
+  schedlock_on,
+  schedlock_step,
+  NULL
+};
 
 static void
 set_schedlock_func (char *args, int from_tty, struct cmd_list_element *c)
@@ -806,6 +808,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
@@ -871,6 +885,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;
@@ -882,7 +898,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
            {
@@ -894,20 +910,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);
@@ -1034,9 +1049,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;
@@ -1250,8 +1267,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;
 
@@ -1312,8 +1328,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;
 
@@ -1341,7 +1356,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);
     }
 }
 
@@ -1351,6 +1369,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 */
@@ -1449,7 +1468,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
@@ -1537,12 +1562,12 @@ handle_inferior_event (struct execution_control_state *ecs)
        stop_signal = ecs->ws.value.sig;
        target_terminal_ours ();        /* Must do this before mourn anyway */
 
-       /* 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 */
+       /* 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 */
@@ -1751,6 +1776,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
@@ -1897,39 +1933,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 ();
       }
 
@@ -3208,6 +3249,13 @@ print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info)
     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. */
@@ -3215,6 +3263,21 @@ print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info)
       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 ();
@@ -3228,19 +3291,50 @@ print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info)
 
       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 ();
@@ -3252,6 +3346,7 @@ print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info)
       annotate_signal_string_end ();
       printf_filtered (".\n");
       gdb_flush (gdb_stdout);      
+#endif
       break;
     default:
       internal_error ("print_stop_reason: unrecognized enum value");
@@ -3277,14 +3372,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
@@ -3296,9 +3390,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)
@@ -3361,7 +3457,8 @@ 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;
@@ -3374,15 +3471,15 @@ The same program may be running in another process.\n");
              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 */
+               source_flag = SRC_LINE;   /* finished step, just print source line */
              else
-               source_flag = 1;    /* print location and source line */
+               source_flag = SRC_AND_LOC;    /* print location and source line */
              break;
            case PRINT_SRC_AND_LOC:
-             source_flag = 1;      /* print location and source line */
+             source_flag = SRC_AND_LOC;    /* print location and source line */
              break;
            case PRINT_SRC_ONLY:
-             source_flag = -1;
+             source_flag = SRC_LINE;
              break;
            case PRINT_NOTHING:
              do_frame_printing = 0;
@@ -3390,12 +3487,22 @@ The same program may be running in another process.\n");
            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 */
+            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);
 
This page took 0.029843 seconds and 4 git commands to generate.