* config/i386/nm-nbsd.h (FLOAT_INFO): Comment out.
[deliverable/binutils-gdb.git] / gdb / infrun.c
index cd6962984e09dd57f334f341a9f71ac6cc5da285..623e1da8b9ac859f374a1719fae3b7c94d1d4e79 100644 (file)
@@ -1,5 +1,5 @@
 /* Target-struct-independent code to start (run) and stop an inferior process.
-   Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994
+   Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996
    Free Software Foundation, Inc.
 
 This file is part of GDB.
@@ -16,10 +16,10 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
-#include <string.h>
+#include "gdb_string.h"
 #include <ctype.h>
 #include "symtab.h"
 #include "frame.h"
@@ -72,6 +72,21 @@ static int hook_stop_stub PARAMS ((char *));
 #define        SKIP_TRAMPOLINE_CODE(pc)        0
 #endif
 
+/* Dynamic function trampolines are similar to solib trampolines in that they
+   are between the caller and the callee.  The difference is that when you
+   enter a dynamic trampoline, you can't determine the callee's address.  Some
+   (usually complex) code needs to run in the dynamic trampoline to figure out
+   the callee's address.  This macro is usually called twice.  First, when we
+   enter the trampoline (looks like a normal function call at that point).  It
+   should return the PC of a point within the trampoline where the callee's
+   address is known.  Second, when we hit the breakpoint, this routine returns
+   the callee's address.  At that point, things proceed as per a step resume
+   breakpoint.  */
+
+#ifndef DYNAMIC_TRAMPOLINE_NEXTPC
+#define DYNAMIC_TRAMPOLINE_NEXTPC(pc) 0
+#endif
+
 /* For SVR4 shared libraries, each call goes through a small piece of
    trampoline code in the ".plt" section.  IN_SOLIB_CALL_TRAMPOLINE evaluates
    to nonzero if we are current stopped in one of these. */
@@ -136,6 +151,10 @@ static struct symbol *step_start_function;
 
 static int trap_expected;
 
+/* Nonzero if we want to give control to the user when we're notified
+   of shared library events by the dynamic linker.  */
+static int stop_on_solib_events;
+
 #ifdef HP_OS_BUG
 /* Nonzero if the next time we try to continue the inferior, it will
    step one instruction and generate a spurious trace trap.
@@ -479,6 +498,10 @@ wait_for_inferior ()
       else
        pid = target_wait (-1, &w);
 
+#ifdef HAVE_NONSTEPPABLE_WATCHPOINT
+    have_waited:
+#endif
+
       flush_cached_frames ();
 
       /* If it's a new process, add it to the thread database */
@@ -501,24 +524,6 @@ wait_for_inferior ()
          continue;
        }
 
-      stop_signal = w.value.sig;
-
-      stop_pc = read_pc_pid (pid);
-
-      if (STOPPED_BY_WATCHPOINT (w))
-       {
-         write_pc (stop_pc - DECR_PC_AFTER_BREAK);
-
-         remove_breakpoints ();
-         target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */
-
-         if (target_wait_hook)
-           target_wait_hook (pid, &w);
-         else
-           target_wait (pid, &w);
-         insert_breakpoints ();
-       }
-
       switch (w.kind)
        {
        case TARGET_WAITKIND_LOADED:
@@ -543,6 +548,12 @@ wait_for_inferior ()
                             (unsigned int)w.value.integer);
          else
            printf_filtered ("\nProgram exited normally.\n");
+
+         /* Record the exit code in the convenience variable $_exitcode, so
+            that the user can inspect this again later.  */
+         set_internalvar (lookup_internalvar ("_exitcode"),
+                          value_from_longest (builtin_type_int, 
+                                              (LONGEST) w.value.integer));
          gdb_flush (gdb_stdout);
          target_mourn_inferior ();
 #ifdef NO_SINGLE_STEP
@@ -587,6 +598,10 @@ wait_for_inferior ()
          break;
        }
 
+      stop_signal = w.value.sig;
+
+      stop_pc = read_pc_pid (pid);
+
       /* See if a thread hit a thread-specific breakpoint that was meant for
         another thread.  If so, then step that thread past the breakpoint,
         and continue it.  */
@@ -599,7 +614,7 @@ wait_for_inferior ()
          if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, pid))
            {
              /* Saw a breakpoint, but it was hit by the wrong thread.  Just continue. */
-             write_pc (stop_pc - DECR_PC_AFTER_BREAK);
+             write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, pid);
 
              remove_breakpoints ();
              target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */
@@ -611,7 +626,9 @@ wait_for_inferior ()
              else
                target_wait (pid, &w);
              insert_breakpoints ();
-             target_resume (pid, 0, TARGET_SIGNAL_0);
+
+             /* We need to restart all the threads now.  */
+             target_resume (-1, 0, TARGET_SIGNAL_0);
              continue;
            }
        }
@@ -660,32 +677,28 @@ wait_for_inferior ()
          /* 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, handling_longjmp,
+                            another_trap);
+
          inferior_pid = 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, &handling_longjmp,
+                            &another_trap);
          printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid));
 
          flush_cached_frames ();
-         trap_expected = 0;
-         if (step_resume_breakpoint)
-           {
-             delete_breakpoint (step_resume_breakpoint);
-             step_resume_breakpoint = NULL;
-           }
-
-         /* Not sure whether we need to blow this away too,
-            but probably it is like the step-resume
-            breakpoint.  */
-         if (through_sigtramp_breakpoint)
-           {
-             delete_breakpoint (through_sigtramp_breakpoint);
-             through_sigtramp_breakpoint = NULL;
-           }
-         prev_pc = 0;
-         prev_func_name = NULL;
-         step_range_start = 0;
-         step_range_end = 0;
-         step_frame_address = 0;
-         handling_longjmp = 0;
-         another_trap = 0;
        }
 
 #ifdef NO_SINGLE_STEP
@@ -703,6 +716,60 @@ wait_for_inferior ()
          continue;
        }
 
+#ifdef HAVE_STEPPABLE_WATCHPOINT
+      /* It may not be necessary to disable the watchpoint to stop over
+        it.  For example, the PA can (with some kernel cooperation) 
+        single step over a watchpoint without disabling the watchpoint.  */
+      if (STOPPED_BY_WATCHPOINT (w))
+       {
+         resume (1, 0);
+         continue;
+       }
+#endif
+
+#ifdef HAVE_NONSTEPPABLE_WATCHPOINT
+      /* It is far more common to need to disable a watchpoint
+        to step the inferior over it.  FIXME.  What else might
+        a debug register or page protection watchpoint scheme need
+        here?  */
+      if (STOPPED_BY_WATCHPOINT (w))
+       {
+/* At this point, we are stopped at an instruction which has attempted to write
+   to a piece of memory under control of a watchpoint.  The instruction hasn't
+   actually executed yet.  If we were to evaluate the watchpoint expression
+   now, we would get the old value, and therefore no change would seem to have
+   occurred.
+
+   In order to make watchpoints work `right', we really need to complete the
+   memory write, and then evaluate the watchpoint expression.  The following
+   code does that by removing the watchpoint (actually, all watchpoints and
+   breakpoints), single-stepping the target, re-inserting watchpoints, and then
+   falling through to let normal single-step processing handle proceed.  Since
+   this includes evaluating watchpoints, things will come to a stop in the
+   correct manner.  */
+
+         write_pc (stop_pc - DECR_PC_AFTER_BREAK);
+
+         remove_breakpoints ();
+         target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */
+
+         if (target_wait_hook)
+           target_wait_hook (pid, &w);
+         else
+           target_wait (pid, &w);
+         insert_breakpoints ();
+         /* FIXME-maybe: is this cleaner than setting a flag?  Does it
+            handle things like signals arriving and other things happening
+            in combination correctly?  */
+         goto have_waited;
+       }
+#endif
+
+#ifdef HAVE_CONTINUABLE_WATCHPOINT
+      /* It may be possible to simply continue after a watchpoint.  */
+      STOPPED_BY_WATCHPOINT (w);
+#endif
+
       stop_func_start = 0;
       stop_func_name = 0;
       /* Don't care about return value; stop_func_start and stop_func_name
@@ -967,6 +1034,47 @@ wait_for_inferior ()
              another_trap = 1;
            break;
 
+#ifdef SOLIB_ADD
+         case BPSTAT_WHAT_CHECK_SHLIBS:
+           {
+             extern int auto_solib_add;
+
+             /* Check for any newly added shared libraries if we're
+                supposed to be adding them automatically.  */
+             if (auto_solib_add)
+               {
+                 /* Remove breakpoints, SOLIB_ADD might adjust breakpoint
+                    addresses via breakpoint_re_set.  */
+                 if (breakpoints_inserted)
+                   remove_breakpoints ();
+                 breakpoints_inserted = 0;
+
+                 /* Switch terminal for any messages produced by
+                    breakpoint_re_set.  */
+                 target_terminal_ours_for_output ();
+                 SOLIB_ADD (NULL, 0, NULL);
+                 target_terminal_inferior ();
+               }
+
+             /* If requested, stop when the dynamic linker notifies
+                gdb of events.  This allows the user to get control
+                and place breakpoints in initializer routines for
+                dynamically loaded objects (among other things).  */
+             if (stop_on_solib_events)
+               {
+                 stop_print_frame = 0;
+                 goto stop_stepping;
+               }
+             else
+               {
+                 /* We want to step over this breakpoint, then keep going.  */
+                 another_trap = 1;
+                 remove_breakpoints_on_following_step = 1;
+                 break;
+               }
+           }
+#endif
+
          case BPSTAT_WHAT_LAST:
            /* Not a real code, but listed here to shut up gcc -Wall.  */
 
@@ -1020,6 +1128,10 @@ wait_for_inferior ()
       /* If stepping through a line, keep going if still within it.  */
       if (stop_pc >= step_range_start
          && stop_pc < step_range_end
+#if 0
+/* I haven't a clue what might trigger this clause, and it seems wrong anyway,
+   so I've disabled it until someone complains.  -Stu 10/24/95 */
+
          /* The step range might include the start of the
             function, so if we are at the start of the
             step range and either the stack or frame pointers
@@ -1027,7 +1139,9 @@ wait_for_inferior ()
          && !(stop_pc == step_range_start
               && FRAME_FP (get_current_frame ())
               && (read_sp () INNER_THAN step_sp
-                  || FRAME_FP (get_current_frame ()) != step_frame_address)))
+                  || FRAME_FP (get_current_frame ()) != step_frame_address))
+#endif
+)
        {
          /* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal.
             So definately need to check for sigtramp here.  */
@@ -1083,7 +1197,13 @@ wait_for_inferior ()
          goto keep_going;
        }
 
-#if 1
+#if 0
+      /* I disabled this test because it was too complicated and slow.  The
+        SKIP_PROLOGUE was especially slow, because it caused unnecessary
+        prologue examination on various architectures.  The code in the #else
+        clause has been tested on the Sparc, Mips, PA, and Power
+        architectures, so it's pretty likely to be correct.  -Stu 10/24/95 */
+
       /* See if we left the step range due to a subroutine call that
         we should proceed to the end of.  */
 
@@ -1148,13 +1268,16 @@ wait_for_inferior ()
                 handling_longjmp stuff is working.  */
              ))
 #else
-/* This is experimental code which greatly simplifies the subroutine call
-   test.  I've actually tested on the Alpha, and it works great. -Stu */
-
-       if (in_prologue (stop_pc, NULL)
-           || (prev_func_start != 0
-               && stop_func_start == 0))
+       /* This test is a much more streamlined, (but hopefully correct)
+          replacement for the code above.  It's been tested on the Sparc,
+          Mips, PA, and Power architectures with good results.  */
+
+       if (stop_pc == stop_func_start /* Quick test */
+           || in_prologue (stop_pc, stop_func_start)
+           || IN_SOLIB_CALL_TRAMPOLINE (stop_pc, stop_func_name)
+           || stop_func_start == 0)
 #endif
+
        {
          /* It's a subroutine call.  */
 
@@ -1179,6 +1302,22 @@ wait_for_inferior ()
          tmp = SKIP_TRAMPOLINE_CODE (stop_pc);
          if (tmp != 0)
            stop_func_start = tmp;
+         else
+           {
+             tmp = DYNAMIC_TRAMPOLINE_NEXTPC (stop_pc);
+             if (tmp)
+               {
+                 struct symtab_and_line xxx;
+
+                 xxx.pc = tmp;
+                 xxx.symtab = NULL;
+                 xxx.line = 0;
+                 step_resume_breakpoint = 
+                   set_momentary_breakpoint (xxx, NULL, bp_step_resume);
+                 insert_breakpoints ();
+                 goto keep_going;
+               }
+           }
 
          /* If we have line number information for the function we
             are thinking of stepping into, step into it.
@@ -1531,6 +1670,11 @@ Further execution is probably impossible.\n");
 
   target_terminal_ours ();
 
+  if (stop_bpstat
+      && stop_bpstat->breakpoint_at
+      && stop_bpstat->breakpoint_at->type == bp_shlib_event)
+    printf_filtered ("Stopped due to shared library event\n");
+
   /* Look up the hook_stop and run it if it exists.  */
 
   if (stop_command->hook)
@@ -2059,4 +2203,16 @@ of the program stops.", &cmdlist);
   signal_print[TARGET_SIGNAL_POLL] = 0;
   signal_stop[TARGET_SIGNAL_URG] = 0;
   signal_print[TARGET_SIGNAL_URG] = 0;
+
+#ifdef SOLIB_ADD
+  add_show_from_set
+    (add_set_cmd ("stop-on-solib-events", class_support, var_zinteger,
+                  (char *) &stop_on_solib_events,
+                 "Set stopping for shared library events.\n\
+If nonzero, gdb will give control to the user when the dynamic linker\n\
+notifies gdb of shared library events.  The most common event of interest\n\
+to the user would be loading/unloading of a new library.\n",
+                  &setlist),
+     &showlist);
+#endif
 }
This page took 0.02965 seconds and 4 git commands to generate.