From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12752 invoked by alias); 7 Sep 2005 22:44:53 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 12736 invoked by uid 22791); 7 Sep 2005 22:44:47 -0000 Received: from mx1.redhat.com (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org (qpsmtpd/0.30-dev) with ESMTP; Wed, 07 Sep 2005 22:44:47 +0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.12.11/8.12.11) with ESMTP id j87MijaF015918 for ; Wed, 7 Sep 2005 18:44:46 -0400 Received: from potter.sfbay.redhat.com (potter.sfbay.redhat.com [172.16.27.15]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id j87MijV08971; Wed, 7 Sep 2005 18:44:45 -0400 Received: from [172.16.24.50] (bluegiant.sfbay.redhat.com [172.16.24.50]) by potter.sfbay.redhat.com (8.12.8/8.12.8) with ESMTP id j87MicGE029021; Wed, 7 Sep 2005 18:44:38 -0400 Message-ID: <431F6D55.5040501@redhat.com> Date: Wed, 07 Sep 2005 22:44:00 -0000 From: Michael Snyder User-Agent: Mozilla Thunderbird (X11/20050322) MIME-Version: 1.0 To: GDB Patches CC: jrydberg@virtutech.com Subject: [RFC] reverse-step, reverse-next Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-SW-Source: 2005-09/txt/msg00050.txt.bz2 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");