]> Git Repo - binutils.git/blobdiff - gdb/infrun.c
* infrun.c (wait_for_inferior): Enable code which assumes that if
[binutils.git] / gdb / infrun.c
index b3484a157c024b9f28cf96ce551f71b2544fa017..f8720c3e14b297225093d97d435dc1d6ab44a6b1 100644 (file)
@@ -18,90 +18,6 @@ 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.  */
 
-/* Notes on the algorithm used in wait_for_inferior to determine if we
-   just did a subroutine call when stepping.  We have the following
-   information at that point:
-
-                  Current and previous (just before this step) pc.
-                 Current and previous sp.
-                 Current and previous start of current function.
-
-   If the starts of the functions don't match, then
-
-       a) We did a subroutine call.
-
-   In this case, the pc will be at the beginning of a function.
-
-       b) We did a subroutine return.
-
-   Otherwise.
-
-       c) We did a longjmp.
-
-   If we did a longjump, we were doing "nexti", since a next would
-   have attempted to skip over the assembly language routine in which
-   the longjmp is coded and would have simply been the equivalent of a
-   continue.  I consider this ok behaivior.  We'd like one of two
-   things to happen if we are doing a nexti through the longjmp()
-   routine: 1) It behaves as a stepi, or 2) It acts like a continue as
-   above.  Given that this is a special case, and that anybody who
-   thinks that the concept of sub calls is meaningful in the context
-   of a longjmp, I'll take either one.  Let's see what happens.  
-
-   Acts like a subroutine return.  I can handle that with no problem
-   at all.
-
-   -->So: If the current and previous beginnings of the current
-   function don't match, *and* the pc is at the start of a function,
-   we've done a subroutine call.  If the pc is not at the start of a
-   function, we *didn't* do a subroutine call.  
-
-   -->If the beginnings of the current and previous function do match,
-   either: 
-
-       a) We just did a recursive call.
-
-          In this case, we would be at the very beginning of a
-          function and 1) it will have a prologue (don't jump to
-          before prologue, or 2) (we assume here that it doesn't have
-          a prologue) there will have been a change in the stack
-          pointer over the last instruction.  (Ie. it's got to put
-          the saved pc somewhere.  The stack is the usual place.  In
-          a recursive call a register is only an option if there's a
-          prologue to do something with it.  This is even true on
-          register window machines; the prologue sets up the new
-          window.  It might not be true on a register window machine
-          where the call instruction moved the register window
-          itself.  Hmmm.  One would hope that the stack pointer would
-          also change.  If it doesn't, somebody send me a note, and
-          I'll work out a more general theory.
-          [email protected]).  This is true (albeit slipperly
-          so) on all machines I'm aware of:
-
-             m68k:     Call changes stack pointer.  Regular jumps don't.
-
-             sparc:    Recursive calls must have frames and therefor,
-                       prologues.
-
-             vax:      All calls have frames and hence change the
-                       stack pointer.
-
-       b) We did a return from a recursive call.  I don't see that we
-          have either the ability or the need to distinguish this
-          from an ordinary jump.  The stack frame will be printed
-          when and if the frame pointer changes; if we are in a
-          function without a frame pointer, it's the users own
-          lookout.
-
-       c) We did a jump within a function.  We assume that this is
-          true if we didn't do a recursive call.
-
-       d) We are in no-man's land ("I see no symbols here").  We
-          don't worry about this; it will make calls look like simple
-          jumps (and the stack frames will be printed when the frame
-          pointer moves), which is a reasonably non-violent response.
-*/
-
 #include "defs.h"
 #include <string.h>
 #include <ctype.h>
@@ -113,6 +29,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "gdbcore.h"
 #include "gdbcmd.h"
 #include "target.h"
+#include "thread.h"
 
 #include <signal.h>
 
@@ -158,6 +75,13 @@ hook_stop_stub PARAMS ((char *));
 #define        SKIP_TRAMPOLINE_CODE(pc)        0
 #endif
 
+/* On Irix 5, some function calls automatically skip the first few
+   instructions, so we need a more complicated test to see if we are
+   the start of a function.  */
+#ifndef AT_FUNCTION_START
+#define AT_FUNCTION_START(pc,func_name,func_addr)      0
+#endif
+
 /* For SVR4 shared libraries, each call goes through a small piece of
    trampoline code in the ".init" section.  IN_SOLIB_TRAMPOLINE evaluates
    to nonzero if we are current stopped in one of these. */
@@ -283,6 +207,14 @@ resume (step, sig)
   struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
   QUIT;
 
+#ifdef CANNOT_STEP_BREAKPOINT
+  /* Most targets can step a breakpoint instruction, thus executing it
+     normally.  But if this one cannot, just continue and we will hit
+     it anyway.  */
+  if (step && breakpoints_inserted && breakpoint_here_p (read_pc ()))
+    step = 0;
+#endif
+
 #ifdef NO_SINGLE_STEP
   if (step) {
     single_step(sig);  /* Do it the hard way, w/temp breakpoints */
@@ -295,7 +227,10 @@ resume (step, sig)
   DO_DEFERRED_STORES;
 #endif
 
-  target_resume (inferior_pid, step, sig);
+  /* Install inferior's terminal modes.  */
+  target_terminal_inferior ();
+
+  target_resume (-1, step, sig);
   discard_cleanups (old_cleanups);
 }
 
@@ -383,9 +318,6 @@ The same program may be running in another process.");
       breakpoints_inserted = 1;
     }
 
-  /* Install inferior's terminal modes.  */
-  target_terminal_inferior ();
-
   if (siggnal >= 0)
     stop_signal = siggnal;
   /* If this signal should not be seen by program,
@@ -439,7 +371,7 @@ init_wait_for_inferior ()
 
   trap_expected_after_continue = 0;
   breakpoints_inserted = 0;
-  mark_breakpoints_out ();
+  breakpoint_init_inferior ();
   stop_signal = 0;             /* Don't confuse first call to proceed(). */
 }
 
@@ -472,6 +404,7 @@ wait_for_inferior ()
   struct symtab_and_line sal;
   int remove_breakpoints_on_following_step = 0;
   int current_line;
+  struct symtab *current_symtab;
   int handling_longjmp = 0;    /* FIXME */
   struct breakpoint *step_resume_breakpoint = NULL;
   int pid;
@@ -480,6 +413,7 @@ wait_for_inferior ()
                               &step_resume_breakpoint);
   sal = find_pc_line(prev_pc, 0);
   current_line = sal.line;
+  current_symtab = sal.symtab;
 
   /* Are we stepping?  */
 #define CURRENTLY_STEPPING() ((step_resume_breakpoint == NULL \
@@ -494,7 +428,7 @@ wait_for_inferior ()
       flush_cached_frames ();
       registers_changed ();
 
-      pid = target_wait (&w);
+      pid = target_wait (-1, &w);
 
 #ifdef SIGTRAP_STOP_AFTER_LOAD
 
@@ -514,7 +448,7 @@ wait_for_inferior ()
          else
            if (!batch_mode())
              printf_filtered ("\nProgram exited normally.\n");
-         fflush (stdout);
+         gdb_flush (gdb_stdout);
          target_mourn_inferior ();
 #ifdef NO_SINGLE_STEP
          one_stepped = 0;
@@ -544,29 +478,78 @@ wait_for_inferior ()
          printf_filtered (", %s\n", safe_strsignal (stop_signal));
 #endif
          printf_filtered ("The program no longer exists.\n");
-         fflush (stdout);
+         gdb_flush (gdb_stdout);
 #ifdef NO_SINGLE_STEP
          one_stepped = 0;
 #endif
          break;
        }
-      
+
+      stop_signal = WSTOPSIG (w);
+
+      if (pid != inferior_pid)
+       {
+         int save_pid = inferior_pid;
+
+         inferior_pid = pid;   /* Setup for target memory/regs */
+         registers_changed ();
+         stop_pc = read_pc ();
+         inferior_pid = save_pid;
+         registers_changed ();
+       }
+      else
+       stop_pc = read_pc ();
+
+      if (stop_signal == SIGTRAP
+         && breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK))
+       {
+         if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, pid))
+           {
+             /* Saw a breakpoint, but it was hit by the wrong thread.  Just continue. */
+             if (breakpoints_inserted)
+               {
+                 if (pid != inferior_pid)
+                   {
+                     int save_pid = inferior_pid;
+
+                     inferior_pid = pid;
+                     registers_changed ();
+                     write_pc (stop_pc - DECR_PC_AFTER_BREAK);
+                     inferior_pid = save_pid;
+                     registers_changed ();
+                   }
+                 else
+                   write_pc (stop_pc - DECR_PC_AFTER_BREAK);
+
+                 remove_breakpoints ();
+                 target_resume (pid, 1, 0); /* Single step */
+                 /* FIXME: What if a signal arrives instead of the single-step
+                    happening?  */
+                 target_wait (pid, &w);
+                 insert_breakpoints ();
+               }
+             target_resume (-1, 0, 0);
+             continue;
+           }
+         else
+           if (pid != inferior_pid)
+             goto switch_thread;
+       }
+
       if (pid != inferior_pid)
        {
          int printed = 0;
 
          if (!in_thread_list (pid))
            {
-             fprintf (stderr, "[New %s]\n", target_pid_to_str (pid));
+             fprintf_unfiltered (gdb_stderr, "[New %s]\n", target_pid_to_str (pid));
              add_thread (pid);
 
-             target_resume (pid, 0, 0);
+             target_resume (-1, 0, 0);
              continue;
            }
          else
            {
-             stop_signal = WSTOPSIG (w);
-
              if (stop_signal >= NSIG || signal_print[stop_signal])
                {
                  char *signame;
@@ -581,11 +564,14 @@ wait_for_inferior ()
                    printf_filtered ("%s (%d)", signame, stop_signal);
                  printf_filtered (", %s\n", safe_strsignal (stop_signal));
 
-                 fflush (stdout);
+                 gdb_flush (gdb_stdout);
                }
 
-             if (stop_signal >= NSIG || signal_stop[stop_signal])
+             if (stop_signal == SIGTRAP
+                 || stop_signal >= NSIG
+                 || signal_stop[stop_signal])
                {
+switch_thread:
                  inferior_pid = pid;
                  printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid));
 
@@ -635,7 +621,6 @@ wait_for_inferior ()
          continue;
        }
 
-      stop_pc = read_pc ();
       set_current_frame ( create_new_frame (read_fp (), stop_pc));
 
       stop_frame_address = FRAME_FP (get_current_frame ());
@@ -645,7 +630,7 @@ wait_for_inferior ()
       /* Don't care about return value; stop_func_start and stop_func_name
         will both be 0 if it doesn't work.  */
       find_pc_partial_function (stop_pc, &stop_func_name, &stop_func_start,
-                               (CORE_ADDR *)NULL);
+                               NULL);
       stop_func_start += FUNCTION_START_OFFSET;
       another_trap = 0;
       bpstat_clear (&stop_bpstat);
@@ -664,8 +649,6 @@ wait_for_inferior ()
         3) set random_signal to 1, and the decision between 1 and 2
         will be made according to the signal handling tables.  */
       
-      stop_signal = WSTOPSIG (w);
-      
       /* First, distinguish signals caused by the debugger from signals
         that have to do with the program's own actions.
         Note that breakpoint insns may cause SIGTRAP or SIGILL
@@ -777,7 +760,7 @@ wait_for_inferior ()
                printf_filtered ("%s (%d)", signame, stop_signal);
              printf_filtered (", %s\n", safe_strsignal (stop_signal));
 #endif /* PRINT_RANDOM_SIGNAL */
-             fflush (stdout);
+             gdb_flush (gdb_stdout);
            }
          if (stop_signal >= NSIG
              || signal_stop[stop_signal])
@@ -883,6 +866,9 @@ wait_for_inferior ()
               cleanup chain, so no need to worry about it here.  */
            goto stop_stepping;
 
+         case BPSTAT_WHAT_LAST:
+           /* Not a real code, but listed here to shut up gcc -Wall.  */
+
          case BPSTAT_WHAT_KEEP_CHECKING:
            break;
          }
@@ -1005,13 +991,51 @@ wait_for_inferior ()
          SKIP_PROLOGUE (prologue_pc);
        }
 
-      /* ==> See comments at top of file on this algorithm.  <==*/
+      if ((/* Might be a non-recursive call.  If the symbols are missing
+             enough that stop_func_start == prev_func_start even though
+             they are really two functions, we will treat some calls as
+             jumps.  */
+          stop_func_start != prev_func_start
+
+          /* Might be a recursive call if either we have a prologue
+             or the call instruction itself saves the PC on the stack.  */
+          || prologue_pc != stop_func_start
+          || stop_sp != prev_sp)
+         && (/* PC is completely out of bounds of any known objfiles.  Treat
+                like a subroutine call. */
+             ! stop_func_start
+
+             /* If we do a call, we will be at the start of a function...  */
+             || stop_pc == stop_func_start
+#if 0
+             /* Should be taken care of by the stop_pc < prologue_pc check
+                below.  Also, on irix5 where this checks for stop_pc
+                equal to stop_func_start plus 12, it would seem to be
+                wrong for a function with a 4 byte prologue, and an 8 byte
+                call; a "return" could end up at stop_func_start+12.  */
+
+             || AT_FUNCTION_START (stop_pc, stop_func_name, stop_func_start)
+#endif
 
-      if ((stop_pc == stop_func_start
-          || IN_SOLIB_TRAMPOLINE (stop_pc, stop_func_name))
-         && (stop_func_start != prev_func_start
-             || prologue_pc != stop_func_start
-             || stop_sp != prev_sp))
+             /* ...except on the Alpha with -O (and also Irix 5 and
+                perhaps others), in which we might call the address
+                after the load of gp.  Since prologues don't contain
+                calls, we can't return to within one, and we don't
+                jump back into them, so this check is OK.  */
+
+             || stop_pc < prologue_pc
+
+             /* If we end up in certain places, it means we did a subroutine
+                call.  I'm not completely sure this is necessary now that we
+                have the above checks with stop_func_start (and now that
+                find_pc_partial_function is pickier).  */
+             || IN_SOLIB_TRAMPOLINE (stop_pc, stop_func_name)
+
+             /* If none of the above apply, it is a jump within a function,
+                or a return from a subroutine.  The other case is longjmp,
+                which can no longer happen here as long as the
+                handling_longjmp stuff is working.  */
+             ))
        {
          /* It's a subroutine call.  */
 
@@ -1116,9 +1140,7 @@ step_into_function:
          goto keep_going;
        }
 
-      /* We've wandered out of the step range (but haven't done a
-        subroutine call or return).  (Is that true?  I think we get
-        here if we did a return and maybe a longjmp).  */
+      /* We've wandered out of the step range.  */
 
       sal = find_pc_line(stop_pc, 0);
 
@@ -1140,7 +1162,8 @@ step_into_function:
          break;
        }
 
-      if (stop_pc == sal.pc && current_line != sal.line)
+      if (stop_pc == sal.pc
+         && (current_line != sal.line || current_symtab != sal.symtab))
        {
          /* We are at the start of a different line.  So stop.  Note that
             we don't stop if we step into the middle of a different line.
@@ -1255,19 +1278,13 @@ step_into_function:
          /* I'm not sure when this following segment applies.  I do know, now,
             that we shouldn't rewrite the regs when we were stopped by a
             random signal from the inferior process.  */
+         /* FIXME: Shouldn't this be based on the valid bit of the SXIP?
+            (this is only used on the 88k).  */
 
           if (!bpstat_explains_signal (stop_bpstat)
              && (stop_signal != SIGCLD) 
               && !stopped_by_random_signal)
-            {
-            CORE_ADDR pc_contents = read_register (PC_REGNUM);
-            CORE_ADDR npc_contents = read_register (NPC_REGNUM);
-            if (pc_contents != npc_contents)
-              {
-              write_register (NNPC_REGNUM, npc_contents);
-              write_register (NPC_REGNUM, pc_contents);
-             }
-            }
+            SHIFT_INST_REGS();
 #endif /* SHIFT_INST_REGS */
 
          resume (CURRENTLY_STEPPING (), stop_signal);
@@ -1302,7 +1319,7 @@ normal_stop ()
   /* Make sure that the current_frame's pc is correct.  This
      is a correction for setting up the frame info before doing
      DECR_PC_AFTER_BREAK */
-  if (target_has_execution)
+  if (target_has_execution && get_current_frame())
     (get_current_frame ())->pc = read_pc ();
   
   if (breakpoints_failed)
@@ -1578,8 +1595,8 @@ handle_command (args, from_tty)
                      }
                    else
                      {
-                       printf ("Not confirmed, unchanged.\n");
-                       fflush (stdout);
+                       printf_unfiltered ("Not confirmed, unchanged.\n");
+                       gdb_flush (gdb_stdout);
                      }
                  }
                break;
@@ -1592,7 +1609,7 @@ handle_command (args, from_tty)
       argv++;
     }
 
-  target_notice_signals();
+  target_notice_signals(inferior_pid);
 
   if (from_tty)
     {
This page took 0.041414 seconds and 4 git commands to generate.