]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
2006-05-02 Michael Snyder <msnyder@redhat.com>
authorMichael Snyder <msnyder@vmware.com>
Wed, 3 May 2006 00:36:00 +0000 (00:36 +0000)
committerMichael Snyder <msnyder@vmware.com>
Wed, 3 May 2006 00:36:00 +0000 (00:36 +0000)
* breakpoint.h (breakpoint_silence): Export.
* breakpoint.c (breakpoint_silence): New function.
* infcmd.c (finish_command): Check for reverse exec direction.
(finish_backward): New function, handle finish cmd in reverse.
* infrun.c (enum inferior_stop_reason): Add NO_HISTORY reason.
(handle_inferior_event): Handle TARGET_WAITKIND_NO_HISTORY.
Handle stepping over a function call in reverse.
Handle stepping thru a line range in reverse.
Handle setting a step-resume breakpoint in reverse.
Handle stepping into a function in reverse.
Handle stepping between line ranges in reverse.
(print_stop_reason): Print reason for NO_HISTORY.

gdb/ChangeLog
gdb/breakpoint.c
gdb/breakpoint.h
gdb/infcmd.c
gdb/infrun.c

index 81fa9f7b8ab966fabec54d85f77c7b236dc61688..e81afd3f1decee51da4ec766b50eb299e9ec09ca 100644 (file)
        Also check for empty reply (target doesn't understand "bs" or "bc).
        (_initialize_remote): Add new methods to remote target vector.
 
+       * breakpoint.h (breakpoint_silence): Export.
+       * breakpoint.c (breakpoint_silence): New function.
+       * infcmd.c (finish_command): Check for reverse exec direction.
+       (finish_backward): New function, handle finish cmd in reverse.
+       * infrun.c (enum inferior_stop_reason): Add NO_HISTORY reason.
+       (handle_inferior_event): Handle TARGET_WAITKIND_NO_HISTORY.
+       Handle stepping over a function call in reverse.
+       Handle stepping thru a line range in reverse.
+       Handle setting a step-resume breakpoint in reverse.
+       Handle stepping into a function in reverse.
+       Handle stepping between line ranges in reverse.
+       (print_stop_reason): Print reason for NO_HISTORY.
+
 2006-04-30  Mark Kettenis  <kettenis@gnu.org>
 
        * breakpoint.c (insert_single_step_breakpoint): Make a failure to
index fd231dee498e3bb022cec819ca2707eee94a6459..cbd05545e06d72e35aba8320163bf508a06490aa 100644 (file)
@@ -7317,6 +7317,13 @@ breakpoint_clear_ignore_counts (void)
     b->ignore_count = 0;
 }
 
+void
+breakpoint_silence (struct breakpoint *b)
+{
+  /* Silence the breakpoint.  */
+  b->silent = 1;
+}
+
 /* Command to set ignore-count of breakpoint N to COUNT.  */
 
 static void
index 607fd7787c90e7d0073db85ce4eae42b7a4ffa2c..76ad84e0cbddab15adf26641e90ac91c7ccf910a 100644 (file)
@@ -1,6 +1,6 @@
 /* Data structures associated with breakpoints in GDB.
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2006
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -844,4 +844,7 @@ extern int deprecated_exception_catchpoints_are_fragile;
    reinitialized -- e.g. when program is re-run.  */
 extern int deprecated_exception_support_initialized;
 
+/* Tell a breakpoint to be quiet.  */
+extern void breakpoint_silence (struct breakpoint *);
+
 #endif /* !defined (BREAKPOINT_H) */
index 12a305de2c3380bbaac2ef35407a80fe9695c0b9..719cd84375577e7b6df1d758cc8a4f2d13aa9c38 100644 (file)
@@ -1251,6 +1251,8 @@ finish_command_continuation (struct continuation_arg *arg)
 /* "finish": Set a temporary breakpoint at the place the selected
    frame will return to, then continue.  */
 
+static void finish_backwards (struct symbol *);
+
 static void
 finish_command (char *arg, int from_tty)
 {
@@ -1293,16 +1295,6 @@ finish_command (char *arg, int from_tty)
 
   clear_proceed_status ();
 
-  sal = find_pc_line (get_frame_pc (frame), 0);
-  sal.pc = get_frame_pc (frame);
-
-  breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_finish);
-
-  if (!target_can_async_p ())
-    old_chain = make_cleanup_delete_breakpoint (breakpoint);
-  else
-    old_chain = make_exec_cleanup_delete_breakpoint (breakpoint);
-
   /* Find the function we will return from.  */
 
   function = find_pc_function (get_frame_pc (deprecated_selected_frame));
@@ -1311,10 +1303,33 @@ finish_command (char *arg, int from_tty)
      source.  */
   if (from_tty)
     {
-      printf_filtered (_("Run till exit from "));
+      if (target_get_execdir () == EXEC_REVERSE)
+       printf_filtered (_("Run backward to before call of "));
+      else
+       printf_filtered (_("Run till exit from "));
+
       print_stack_frame (get_selected_frame (NULL), 1, LOCATION);
     }
 
+  if (target_get_execdir () == EXEC_REVERSE)
+    {
+      /* Split off at this point.  */
+      if (async_exec)
+       error (_("Asynchronous finish not supported in reverse mode."));
+      finish_backwards (function);
+      return;
+    }
+
+  sal = find_pc_line (get_frame_pc (frame), 0);
+  sal.pc = get_frame_pc (frame);
+
+  breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_finish);
+
+  if (!target_can_async_p ())
+    old_chain = make_cleanup_delete_breakpoint (breakpoint);
+  else
+    old_chain = make_exec_cleanup_delete_breakpoint (breakpoint);
+
   /* If running asynchronously and the target support asynchronous
      execution, set things up for the rest of the finish command to be
      completed later on, when gdb has detected that the target has
@@ -1371,6 +1386,64 @@ finish_command (char *arg, int from_tty)
       do_cleanups (old_chain);
     }
 }
+
+static void
+finish_backwards (struct symbol *function)
+{
+  struct symtab_and_line sal;
+  struct breakpoint *breakpoint;
+  struct cleanup *old_chain;
+  CORE_ADDR func_addr;
+
+  if (find_pc_partial_function (get_frame_pc (get_selected_frame (NULL)),
+                               NULL, &func_addr, NULL) == 0)
+    internal_error (__FILE__, __LINE__, 
+                   "Finish: couldn't find function.");
+
+  sal = find_pc_line (func_addr, 0);
+
+  /* Let's cheat and not worry about async until later.  */
+
+  /* We don't need a return value.  */
+  proceed_to_finish = 0;
+  /* Special case: if we're sitting at the function entry point, 
+     then all we need to do is take a reverse singlestep.  We
+     don't need to set a breakpoint, and indeed it would do us
+     no good to do so.
+
+     Note that this can only happen at frame #0, since there's
+     no way that a function up the stack can have a return address
+     that's equal to its entry point.  */
+
+  if (sal.pc != get_frame_pc (get_selected_frame (NULL)))
+    {
+      /* Set breakpoint and continue.  */
+      breakpoint = 
+       set_momentary_breakpoint (sal, 
+                                 get_frame_id (get_selected_frame (NULL)),
+                                 bp_breakpoint);
+      /* Tell the breakpoint to keep quiet.  We won't be done 
+         until we've done another reverse single-step.  */
+      breakpoint_silence (breakpoint);
+      old_chain = make_cleanup_delete_breakpoint (breakpoint);
+      proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+      /* We will be stopped when proceed returns,
+         but we still need the breakpoint below.  */
+    }
+  if (breakpoint != NULL
+      && bpstat_find_breakpoint (stop_bpstat, breakpoint) != NULL)
+    {
+      /* If in fact we hit the step-resume breakpoint (and not
+        some other breakpoint), then we're almost there -- 
+        we just need to back up by one more single-step.  */
+      do_cleanups (old_chain);
+      /* (Kludgy way of letting wait_for_inferior know...) */
+      step_range_start = step_range_end = 1;
+      proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+    }
+  return;
+}
+
 \f
 
 static void
index bccca0d7dc901a8cc2e99999087b59d391c423c5..f8fe07eb77423e72b335d445d4f93a43a1cf5528 100644 (file)
@@ -2,8 +2,8 @@
    process.
 
    Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
-   1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free
-   Software Foundation, Inc.
+   1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -905,7 +905,9 @@ enum inferior_stop_reason
   /* Inferior exited. */
   EXITED,
   /* Inferior received signal, and user asked to be notified. */
-  SIGNAL_RECEIVED
+  SIGNAL_RECEIVED,
+  /* Reverse execution -- target ran out of history info.  */
+  NO_HISTORY
 };
 
 /* This structure contains what used to be local variables in
@@ -1504,6 +1506,12 @@ handle_inferior_event (struct execution_control_state *ecs)
       stop_signal = ecs->ws.value.sig;
       break;
 
+    case TARGET_WAITKIND_NO_HISTORY:
+      /* Reverse execution: target ran out of history info.  */
+      print_stop_reason (NO_HISTORY, 0);
+      stop_stepping (ecs);
+      return;
+
       /* 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.
@@ -2129,6 +2137,17 @@ process_event_stop_test:
            keep_going (ecs);
            return;
          }
+       if (stop_pc == ecs->stop_func_start
+           && target_get_execdir () == EXEC_REVERSE)
+         {
+           /* We are stepping over a function call in reverse, and
+              just hit the step-resume breakpoint at the start
+              address of the function.  Go back to single-stepping,
+              which should take us back to the function call.  */
+           ecs->another_trap = 1;
+           keep_going (ecs);
+           return;
+         }
        break;
 
       case BPSTAT_WHAT_THROUGH_SIGTRAMP:
@@ -2312,7 +2331,22 @@ process_event_stop_test:
         fprintf_unfiltered (gdb_stdlog, "infrun: stepping inside range [0x%s-0x%s]\n",
                            paddr_nz (step_range_start),
                            paddr_nz (step_range_end));
-      keep_going (ecs);
+
+      /* When stepping backward, stop at beginning of line range
+        (unles it's the function entry point, in which case 
+        keep going back to the call point).  */
+      if (stop_pc == step_range_start
+         && stop_pc != ecs->stop_func_start
+         && target_get_execdir () == EXEC_REVERSE)
+       {
+         stop_step = 1;
+         print_stop_reason (END_STEPPING_RANGE, 0);
+         stop_stepping (ecs);
+       }
+      else
+       {
+         keep_going (ecs);
+       }
       return;
     }
 
@@ -2393,10 +2427,59 @@ process_event_stop_test:
 
       if (step_over_calls == STEP_OVER_ALL)
        {
-         /* We're doing a "next", set a breakpoint at callee's return
-            address (the address at which the caller will
-            resume).  */
-         insert_step_resume_breakpoint_at_frame (get_prev_frame (get_current_frame ()));
+         /* We're doing a "next".
+
+            Normal (forward) execution: set a breakpoint at the
+            callee's return address (the address at which the caller
+            will resume).
+
+            Reverse (backward) execution.  Set the step-resume
+            breakpoint at the start of the function that we just
+            stepped into (backwards), and continue to there.  When we
+            get there, we'll need to single-step back to the
+            caller.  */
+
+         if (target_get_execdir () == EXEC_REVERSE)
+           {
+             /* FIXME: I'm not sure if we've handled the frame for
+                recursion.  */
+
+             struct symtab_and_line sr_sal;
+           mrhappy:
+             init_sal (&sr_sal);
+             sr_sal.pc = ecs->stop_func_start;
+#if 0
+             insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
+#else
+             /* Let's try to find the right frame id.  
+                First try curr_frame.  */
+#if 0
+             insert_step_resume_breakpoint_at_sal (sr_sal, frame_unwind_id
+                                                   (get_current_frame ()));
+#else
+#if 0
+             /* Fails to stop.  Try prev_frame.  */
+             insert_step_resume_breakpoint_at_sal (sr_sal, frame_unwind_id
+                                                   (get_prev_frame
+                                                   (get_current_frame ())));
+#else
+#if 0
+             /* One last try -- try step_frame_id.  */
+             insert_step_resume_breakpoint_at_sal (sr_sal, step_frame_id);
+#else
+             /* Ok, really the last try.  */
+             insert_step_resume_breakpoint_at_sal (sr_sal, get_frame_id
+                                                   (get_current_frame ()));
+#endif
+#endif
+#endif
+#endif
+           }
+         else
+           {
+             insert_step_resume_breakpoint_at_frame
+               (get_prev_frame (get_current_frame ()));
+           }
          keep_going (ecs);
          return;
        }
@@ -2457,9 +2540,23 @@ process_event_stop_test:
          return;
        }
 
-      /* Set a breakpoint at callee's return address (the address at
-         which the caller will resume).  */
-      insert_step_resume_breakpoint_at_frame (get_prev_frame (get_current_frame ()));
+      if (target_get_execdir () == EXEC_REVERSE)
+       {
+         /* Set a breakpoint at callee's start address.
+            From there we can step once and be back in the caller.  */
+         /* FIXME: I'm not sure we've handled the frame for recursion.  */
+         struct symtab_and_line sr_sal;
+         init_sal (&sr_sal);
+         sr_sal.pc = ecs->stop_func_start;
+         insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
+       }
+      else
+       {
+         /* Set a breakpoint at callee's return address (the address
+            at which the caller will resume).  */
+         insert_step_resume_breakpoint_at_frame
+           (get_prev_frame (get_current_frame ()));
+       }
       keep_going (ecs);
       return;
     }
@@ -2585,17 +2682,43 @@ process_event_stop_test:
 
   if (ecs->stop_func_end && ecs->sal.end >= ecs->stop_func_end)
     {
-      /* If this is the last line of the function, don't keep stepping
-         (it would probably step us out of the function).
-         This is particularly necessary for a one-line function,
-         in which after skipping the prologue we better stop even though
-         we will be in mid-line.  */
-      if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different function\n");
-      stop_step = 1;
-      print_stop_reason (END_STEPPING_RANGE, 0);
-      stop_stepping (ecs);
-      return;
+      if (target_get_execdir () != EXEC_REVERSE)
+       {
+         /* If this is the last line of the function, don't keep
+            stepping (it would probably step us out of the function).
+            This is particularly necessary for a one-line function,
+            in which after skipping the prologue we better stop even
+            though we will be in mid-line.  */
+         if (debug_infrun)
+           fprintf_unfiltered (gdb_stdlog, 
+                               "infrun: stepped to a different function\n");
+         stop_step = 1;
+         print_stop_reason (END_STEPPING_RANGE, 0);
+         stop_stepping (ecs);
+         return;
+       }
+      else
+       {
+         /* If we stepped backward into the last line of a function,
+            then we've presumably stepped thru a return.  We want to
+            keep stepping backward until we reach the beginning of
+            the new line.  */
+
+         /* KLUDGE have we missed detecting a reverse-next?  */
+         if (step_over_calls == STEP_OVER_ALL)
+           goto mrhappy;       /* AHHHH!  FIXME!  */
+
+         step_range_start = ecs->sal.pc;
+         step_range_end = ecs->sal.end;
+         step_frame_id = get_frame_id (get_current_frame ());
+         ecs->current_line = ecs->sal.line;
+         ecs->current_symtab = ecs->sal.symtab;
+         /* Adjust for prologue, in case of a one-line function.  */
+         if (in_prologue (step_range_start, ecs->stop_func_start))
+           step_range_start = SKIP_PROLOGUE (step_range_start);
+         keep_going (ecs);
+         return;
+       }
     }
   step_range_start = ecs->sal.pc;
   step_range_end = ecs->sal.end;
@@ -2658,6 +2781,28 @@ step_into_function (struct execution_control_state *ecs)
   if (s && s->language != language_asm)
     ecs->stop_func_start = SKIP_PROLOGUE (ecs->stop_func_start);
 
+  if (target_get_execdir () == EXEC_REVERSE)
+    {
+      ecs->sal = find_pc_line (stop_pc, 0);
+
+      /* OK, we're just gonna keep stepping here.  */
+      if (ecs->sal.pc == stop_pc)
+       {
+         /* We're there already.  Just stop stepping now.  */
+         stop_step = 1;
+         print_stop_reason (END_STEPPING_RANGE, 0);
+         stop_stepping (ecs);
+         return;
+       }
+      /* Else just reset the step range and keep going.
+        No step-resume breakpoint, they don't work for
+        epilogues, which can have multiple entry paths.  */
+      step_range_start = ecs->sal.pc;
+      step_range_end   = ecs->sal.end;
+      keep_going (ecs);
+      return;
+    }
+  /* else... */
   ecs->sal = find_pc_line (ecs->stop_func_start, 0);
   /* Use the step_resume_break to step until the end of the prologue,
      even if that involves jumps (as it seems to on the vax under
@@ -2960,6 +3105,10 @@ print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info)
       annotate_signal_string_end ();
       ui_out_text (uiout, ".\n");
       break;
+    case NO_HISTORY:
+      /* Reverse execution: target ran out of history info.  */
+      ui_out_text (uiout, _("\nNo more reverse-execution history.\n"));
+      break;
     default:
       internal_error (__FILE__, __LINE__,
                      _("print_stop_reason: unrecognized enum value"));