Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Michael Snyder <msnyder@redhat.com>
To: GDB Patches <gdb-patches@sources.redhat.com>
Cc: jrydberg@virtutech.com
Subject: [RFC] reverse-step, reverse-next
Date: Wed, 07 Sep 2005 22:44:00 -0000	[thread overview]
Message-ID: <431F6D55.5040501@redhat.com> (raw)

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");


             reply	other threads:[~2005-09-07 22:44 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-09-07 22:44 Michael Snyder [this message]
2005-09-08 21:41 ` Stan Shebs
2005-09-09 22:39   ` Michael Snyder
2005-09-17 22:19 ` Daniel Jacobowitz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=431F6D55.5040501@redhat.com \
    --to=msnyder@redhat.com \
    --cc=gdb-patches@sources.redhat.com \
    --cc=jrydberg@virtutech.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox