Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFC] reverse-step, reverse-next
@ 2005-09-07 22:44 Michael Snyder
  2005-09-08 21:41 ` Stan Shebs
  2005-09-17 22:19 ` Daniel Jacobowitz
  0 siblings, 2 replies; 4+ messages in thread
From: Michael Snyder @ 2005-09-07 22:44 UTC (permalink / raw)
  To: GDB Patches; +Cc: jrydberg

This isn't for submission, just for discussion.  This is something
that Johan Rydberg (of Virtutech) and I have been working on.

I'd like to hear what everybody thinks about this
bit of infrun implementation for the reverse debugging
that we discussed a few months ago.

This part is enough to get step and next to work in reverse,
based solely on the assumption that the backend (or someone)
provides an interface "get_exec_direction ()", which returns
forward or reverse.  It's also assumed that the backend will
know which direction to go (leaving user-interface issues
out of the picture).  One can imagine either a "set direction"
interface, or a "reverse-step/reverse-continue".

This is actually tested and working with the Simics simulator.
It steps and nexts backwards like a champ.

The only other bit of explanation that might be required
is that "NO_HISTORY" means you were going backward and
the target ran out of state data (you reached the beginning
of time).


Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.178
diff -p -r1.178 infrun.c
*** infrun.c    27 Sep 2004 17:58:08 -0000      1.178
--- infrun.c    5 Sep 2005 00:38:53 -0000
*************** enum inferior_stop_reason
*** 897,903 ****
     /* Inferior exited. */
     EXITED,
     /* Inferior received signal, and user asked to be notified. */
!   SIGNAL_RECEIVED
   };

   /* This structure contains what used to be local variables in
--- 897,905 ----
     /* Inferior exited. */
     EXITED,
     /* Inferior received signal, and user asked to be notified. */
!   SIGNAL_RECEIVED,
!   /* Reverse execution -- target ran out of history (FIXME: general?)  */
!   NO_HISTORY
   };

   /* This structure contains what used to be local variables in
*************** handle_inferior_event (struct execution_
*** 1516,1521 ****
--- 1518,1528 ----
         stop_signal = ecs->ws.value.sig;
         break;

+     case TARGET_WAITKIND_NO_HISTORY:
+       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.
*************** process_event_stop_test:
*** 2073,2078 ****
--- 2080,2096 ----
             keep_going (ecs);
             return;
           }
+       if (stop_pc == ecs->stop_func_start &&
+           get_exec_direction () == 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:
*************** process_event_stop_test:
*** 2237,2243 ****
        within it! */
     if (stop_pc >= step_range_start && stop_pc < step_range_end)
       {
!       keep_going (ecs);
         return;
       }

--- 2255,2272 ----
        within it! */
     if (stop_pc >= step_range_start && stop_pc < step_range_end)
       {
!       if (stop_pc == step_range_start &&
!         get_exec_direction () == EXEC_REVERSE)
!       {
!         /* When stepping backward, stop at beginning of line range.  */
!         stop_step = 1;
!         print_stop_reason (END_STEPPING_RANGE, 0);
!         stop_stepping (ecs);
!       }
!       else
!       {
!         keep_going (ecs);
!       }
         return;
       }

*************** process_event_stop_test:
*** 2319,2335 ****
           /* 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_f\rame ()));
           keep_going (ecs);
           return;
         }
   #endif
         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_f\rame ()));
           keep_going (ecs);
           return;
         }
--- 2348,2388 ----
           /* 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 ()));
           keep_going (ecs);
           return;
         }
   #endif
         if (step_over_calls == STEP_OVER_ALL)
         {
!         /* 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 (get_exec_direction () == EXEC_FORWARD)
!           {
!             insert_step_resume_breakpoint_at_frame
!               (get_prev_frame (get_current_frame ()));
!           }
!         else
!           {
!             /* FIXME: I'm not sure if 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);
!           }
           keep_going (ecs);
           return;
         }
*************** process_event_stop_test:
*** 2384,2392 ****
           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_fra\me ()));
         keep_going (ecs);
         return;
       }
--- 2437,2459 ----
           return;
         }

!       if (get_exec_direction () == EXEC_FORWARD)
!       {
!         /* 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 ()));
!       }
!       else
!       {
!         /* 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);
!       }
         keep_going (ecs);
         return;
       }
*************** step_into_function (struct execution_con
*** 2568,2574 ****
--- 2635,2668 ----
     if (s && s->language != language_asm)
       ecs->stop_func_start = SKIP_PROLOGUE (ecs->stop_func_start);

+   /* If we're going backward, we just stepped into the
+      return of a function.  Instead of continuing thru
+      the prologue, we want to continue back thru the epilogue.  */
+   /* FIXME: Should we just split this out into a separate fn?   */
+   if (get_exec_direction () == 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
        4.2).  */
*************** step_into_function (struct execution_con
*** 2615,2620 ****
--- 2709,2715 ----
       {
         /* Put the step-breakpoint there and go until there.  */
         init_sal (&sr_sal);     /* initialize to zeroes */
+
         sr_sal.pc = ecs->stop_func_start;
         sr_sal.section = find_pc_overlay (ecs->stop_func_start);

*************** print_stop_reason (enum inferior_stop_re
*** 2855,2860 ****
         annotate_signal_string_end ();
         ui_out_text (uiout, ".\n");
         break;
+     case NO_HISTORY:
+       /* Reverse execution: target ran out of history data.  */
+       ui_out_text (uiout, "\nNo more reverse-execution history.\n");
+       break;
       default:
         internal_error (__FILE__, __LINE__,
                       "print_stop_reason: unrecognized enum value");


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-09-17 22:19 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-09-07 22:44 [RFC] reverse-step, reverse-next Michael Snyder
2005-09-08 21:41 ` Stan Shebs
2005-09-09 22:39   ` Michael Snyder
2005-09-17 22:19 ` Daniel Jacobowitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox