This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] reverse-step, reverse-next


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]