From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31747 invoked by alias); 3 Jul 2013 09:15:00 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 30783 invoked by uid 89); 3 Jul 2013 09:14:54 -0000 X-Spam-SWARE-Status: No, score=-5.2 required=5.0 tests=AWL,BAYES_50,KHOP_RCVD_UNTRUST,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,RP_MATCHES_RCVD,TW_XZ autolearn=ham version=3.3.1 Received: from mga09.intel.com (HELO mga09.intel.com) (134.134.136.24) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Wed, 03 Jul 2013 09:14:45 +0000 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP; 03 Jul 2013 02:12:18 -0700 X-ExtLoop1: 1 Received: from irvmail001.ir.intel.com ([163.33.26.43]) by fmsmga001.fm.intel.com with ESMTP; 03 Jul 2013 02:15:35 -0700 Received: from ulslx001.iul.intel.com (ulslx001.iul.intel.com [172.28.207.63]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id r639Ee7K009851; Wed, 3 Jul 2013 10:14:40 +0100 Received: from ulslx001.iul.intel.com (localhost [127.0.0.1]) by ulslx001.iul.intel.com with ESMTP id r639Eehu029370; Wed, 3 Jul 2013 11:14:40 +0200 Received: (from mmetzger@localhost) by ulslx001.iul.intel.com with id r639EeJL029366; Wed, 3 Jul 2013 11:14:40 +0200 From: Markus Metzger To: jan.kratochvil@redhat.com Cc: gdb-patches@sourceware.org Subject: [patch v4 23/24] record-btrace: add (reverse-)stepping support Date: Wed, 03 Jul 2013 09:15:00 -0000 Message-Id: <1372842874-28951-24-git-send-email-markus.t.metzger@intel.com> In-Reply-To: <1372842874-28951-1-git-send-email-markus.t.metzger@intel.com> References: <1372842874-28951-1-git-send-email-markus.t.metzger@intel.com> X-SW-Source: 2013-07/txt/msg00134.txt.bz2 There's an open regarding frame unwinding. When I start stepping, the frame cache will still be based on normal unwinding as will the frame cached in the thread's stepping context. This will prevent me from detecting that i stepped into a subroutine. To overcome that, I'm resetting the frame cache and setting the thread's stepping cache based on the current frame - which is now computed using branch tracing unwind. I had to split get_current_frame to avoid checks that would prevent me from doing this. I also need to call registers_changed when I return from to_wait. Otherwise, the PC is not updated and the current location is shown incorrectly. Not sure whether this is intended or whether I'm unintentionally working around something, here. It looks like I don't need any special support for breakpoints. Is there a scenario where normal breakpoints won't work? Non-stop mode is not working. Do not allow record-btrace in non-stop mode. Reviewed-by: Eli Zaretskii 2013-07-03 Markus Metzger * btrace.h (btrace_thread_flag): New. (struct btrace_thread_info): New. * frame.c (get_current_frame_nocheck): New. (get_current_frame): Call get_current_frame_nocheck. * frame.h (get_current_frame_nocheck): New. * record-btrace.c (record_btrace_resume_thread, record_btrace_find_thread_to_move, btrace_step_no_history, btrace_step_stopped, record_btrace_start_replaying, record_btrace_step_thread, record_btrace_find_resume_thread): New. (record_btrace_resume, record_btrace_wait): Extend. (record_btrace_can_execute_reverse): New. (record_btrace_open): Fail in non-stop mode. (record_btrace_set_replay): Split into this, ... (record_btrace_stop_replaying): ... this, ... (record_btrace_clear_histories): ... and this. (init_record_btrace_ops): Init to_can_execute_reverse. * NEWS: Announce it. testsuite/ * gdb.btrace/delta.exp: Check reverse stepi. * gdb.btrace/finish.exp: New. * gdb.btrace/next.exp: New. * gdb.btrace/nexti.exp: New. * gdb.btrace/record_goto.c: Add comments. * gdb.btrace/step.exp: New. * gdb.btrace/stepi.exp: New. * gdb.btrace/multi-thread-step.c: New. * gdb.btrace/multi-thread-step.exp: New. doc/ * gdb.texinfo: Document limited reverse/replay support for target record-btrace. --- gdb/NEWS | 4 + gdb/btrace.h | 22 ++ gdb/doc/gdb.texinfo | 4 +- gdb/frame.c | 38 ++- gdb/frame.h | 4 + gdb/record-btrace.c | 366 ++++++++++++++++++++++-- gdb/testsuite/gdb.btrace/delta.exp | 13 + gdb/testsuite/gdb.btrace/finish.exp | 70 +++++ gdb/testsuite/gdb.btrace/multi-thread-step.c | 53 ++++ gdb/testsuite/gdb.btrace/multi-thread-step.exp | 84 ++++++ gdb/testsuite/gdb.btrace/next.exp | 89 ++++++ gdb/testsuite/gdb.btrace/nexti.exp | 89 ++++++ gdb/testsuite/gdb.btrace/record_goto.c | 36 ++-- gdb/testsuite/gdb.btrace/step.exp | 113 ++++++++ gdb/testsuite/gdb.btrace/stepi.exp | 114 ++++++++ 15 files changed, 1047 insertions(+), 52 deletions(-) create mode 100644 gdb/testsuite/gdb.btrace/finish.exp create mode 100644 gdb/testsuite/gdb.btrace/multi-thread-step.c create mode 100644 gdb/testsuite/gdb.btrace/multi-thread-step.exp create mode 100644 gdb/testsuite/gdb.btrace/next.exp create mode 100644 gdb/testsuite/gdb.btrace/nexti.exp create mode 100644 gdb/testsuite/gdb.btrace/step.exp create mode 100644 gdb/testsuite/gdb.btrace/stepi.exp diff --git a/gdb/NEWS b/gdb/NEWS index 433a968..b53033a 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -13,6 +13,10 @@ Nios II ELF nios2*-*-elf Nios II GNU/Linux nios2*-*-linux Texas Instruments MSP430 msp430*-*-elf +* The btrace record target supports limited replay and reverse + execution. The target does not record data and does therefore + not allow reading memory or registers. + * The btrace record target supports the 'record goto' command. For locations inside the execution trace, the back trace is computed based on the information stored in the execution trace. diff --git a/gdb/btrace.h b/gdb/btrace.h index 04466d3..22fabb5 100644 --- a/gdb/btrace.h +++ b/gdb/btrace.h @@ -149,6 +149,25 @@ struct btrace_call_history struct btrace_call_iterator end; }; +/* Branch trace thread flags. */ +enum btrace_thread_flag + { + /* The thread is to be stepped forwards. */ + BTHR_STEP = (1 << 0), + + /* The thread is to be stepped backwards. */ + BTHR_RSTEP = (1 << 1), + + /* The thread is to be continued forwards. */ + BTHR_CONT = (1 << 2), + + /* The thread is to be continued backwards. */ + BTHR_RCONT = (1 << 3), + + /* The thread is to be moved. */ + BTHR_MOVE = (BTHR_STEP | BTHR_RSTEP | BTHR_CONT | BTHR_RCONT) + }; + /* Branch trace information per thread. This represents the branch trace configuration as well as the entry point @@ -176,6 +195,9 @@ struct btrace_thread_info becomes zero. */ int level; + /* A bit-vector of btrace_thread_flag. */ + unsigned int flags; + /* The instruction history iterator. */ struct btrace_insn_history *insn_history; diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 2dc45bc..9ad5391 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -6192,8 +6192,8 @@ replay implementation. This method allows replaying and reverse execution. @item btrace -Hardware-supported instruction recording. This method does not allow -replaying and reverse execution. +Hardware-supported instruction recording. This method does not record +data. It allows limited replay and reverse execution. This recording method may not be available on all processors. @end table diff --git a/gdb/frame.c b/gdb/frame.c index 5c080eb..f2dbdb4 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1367,6 +1367,29 @@ unwind_to_current_frame (struct ui_out *ui_out, void *args) return 0; } +/* See frame.h. */ + +struct frame_info *get_current_frame_nocheck (void) +{ + if (current_frame == NULL) + { + struct frame_info *sentinel_frame = + create_sentinel_frame (current_program_space, get_current_regcache ()); + + if (catch_exceptions (current_uiout, unwind_to_current_frame, + sentinel_frame, RETURN_MASK_ERROR) != 0) + { + /* Oops! Fake a current frame? Is this useful? It has a PC + of zero, for instance. */ + current_frame = sentinel_frame; + } + } + + return current_frame; +} + +/* See frame.h. */ + struct frame_info * get_current_frame (void) { @@ -1381,6 +1404,7 @@ get_current_frame (void) error (_("No stack.")); if (!target_has_memory) error (_("No memory.")); + /* Traceframes are effectively a substitute for the live inferior. */ if (get_traceframe_number () < 0) { @@ -1392,19 +1416,7 @@ get_current_frame (void) error (_("Target is executing.")); } - if (current_frame == NULL) - { - struct frame_info *sentinel_frame = - create_sentinel_frame (current_program_space, get_current_regcache ()); - if (catch_exceptions (current_uiout, unwind_to_current_frame, - sentinel_frame, RETURN_MASK_ERROR) != 0) - { - /* Oops! Fake a current frame? Is this useful? It has a PC - of zero, for instance. */ - current_frame = sentinel_frame; - } - } - return current_frame; + return get_current_frame_nocheck (); } /* The "selected" stack frame is used by default for local and arg diff --git a/gdb/frame.h b/gdb/frame.h index db4cc52..e3f004b 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -240,6 +240,10 @@ enum frame_type error. */ extern struct frame_info *get_current_frame (void); +/* Similar to get_current_frame except that we omit all checks. May + return NULL if unwinding fails. */ +extern struct frame_info *get_current_frame_nocheck (void); + /* Does the current target interface have enough state to be able to query the current inferior for frame info, and is the inferior in a state where that is possible? */ diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c index 14dbcd2..b45a5fb 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -151,6 +151,10 @@ record_btrace_open (char *args, int from_tty) if (!target_supports_btrace ()) error (_("Target does not support branch tracing.")); + if (non_stop) + error (_("Record btrace can't debug inferior in non-stop mode " + "(non-stop).")); + gdb_assert (record_btrace_thread_observer == NULL); disable_chain = make_cleanup (null_cleanup, NULL); @@ -1183,14 +1187,107 @@ static const struct frame_unwind record_btrace_frame_unwind = record_btrace_frame_dealloc_cache }; +/* Indicate that TP should be resumed according to FLAG. */ + +static void +record_btrace_resume_thread (struct thread_info *tp, + enum btrace_thread_flag flag) +{ + struct btrace_thread_info *btinfo; + + DEBUG ("resuming %d (%s): %u", tp->num, target_pid_to_str (tp->ptid), flag); + + btinfo = &tp->btrace; + + if ((btinfo->flags & BTHR_MOVE) != 0) + error (_("Thread already moving.")); + + /* Fetch the latest branch trace. */ + btrace_fetch (tp); + + btinfo->flags |= flag; +} + +/* Find the thread to resume given a PTID. */ + +static struct thread_info * +record_btrace_find_resume_thread (ptid_t ptid) +{ + struct thread_info *tp; + + /* When asked to resume everything, we pick the current thread. */ + if (ptid_equal (minus_one_ptid, ptid) || ptid_is_pid (ptid)) + ptid = inferior_ptid; + + return find_thread_ptid (ptid); +} + +/* Stop replaying a thread. */ + +static struct btrace_insn_iterator * +record_btrace_start_replaying (struct btrace_thread_info *btinfo) +{ + struct btrace_insn_iterator *replay; + const struct btrace_insn *insn; + struct symtab_and_line sal; + struct frame_info *frame; + + /* We can't start replaying without trace. */ + if (btinfo->begin == NULL) + return NULL; + + /* We start replaying at the end of the branch trace. This corresponds to the + current instruction. */ + replay = xzalloc (sizeof (*replay)); + btrace_insn_end (replay, btinfo); + + /* We're not replaying, yet. */ + gdb_assert (btinfo->replay == NULL); + btinfo->replay = replay; + + /* Make sure we're not using any stale registers or frames. */ + registers_changed (); + reinit_frame_cache (); + + /* We just started replaying. The frame id cached for stepping is based + on unwinding, not on branch tracing. Recompute it. */ + frame = get_current_frame_nocheck (); + insn = btrace_insn_get (replay); + sal = find_pc_line (insn->pc, 0); + set_step_info (frame, sal); + + return replay; +} + +/* Stop replaying a thread. */ + +static void +record_btrace_stop_replaying (struct btrace_thread_info *btinfo) +{ + xfree (btinfo->replay); + btinfo->replay = NULL; +} + /* The to_resume method of target record-btrace. */ static void record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step, enum gdb_signal signal) { + struct thread_info *tp, *other; + enum btrace_thread_flag flag; + + DEBUG ("resume %s: %s", target_pid_to_str (ptid), step ? "step" : "cont"); + + tp = record_btrace_find_resume_thread (ptid); + + /* Stop replaying other threads if the thread to resume is not replaying. */ + if (tp != NULL && !btrace_is_replaying (tp)) + ALL_THREADS (other) + record_btrace_stop_replaying (&other->btrace); + /* As long as we're not replaying, just forward the request. */ - if (!record_btrace_is_replaying ()) + if (!record_btrace_is_replaying () && execution_direction != EXEC_REVERSE) { for (ops = ops->beneath; ops != NULL; ops = ops->beneath) if (ops->to_resume != NULL) @@ -1199,7 +1296,211 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step, error (_("Cannot find target for stepping.")); } - error (_("You can't do this from here. Do 'record goto end', first.")); + /* We can't pass signals when replaying. */ + if (signal != GDB_SIGNAL_0) + error (_("You can't resume with signal from here.")); + + /* Compute the btrace thread flag for the requested move. */ + if (step == 0) + flag = execution_direction == EXEC_REVERSE ? BTHR_RCONT : BTHR_CONT; + else + flag = execution_direction == EXEC_REVERSE ? BTHR_RSTEP : BTHR_STEP; + + /* Find the thread to move. */ + if (ptid_equal (minus_one_ptid, ptid) || ptid_is_pid (ptid)) + { + ALL_THREADS (tp) + record_btrace_resume_thread (tp, flag); + } + else if (tp == NULL) + error (_("Cannot find thread to resume.")); + else + record_btrace_resume_thread (tp, flag); + + /* We just indicate the resume intent here. The actual stepping happens in + record_btrace_wait below. */ +} + +/* Find a thread to move. */ + +static struct thread_info * +record_btrace_find_thread_to_move (ptid_t ptid) +{ + struct thread_info *tp; + + /* First check the parameter thread. */ + tp = find_thread_ptid (ptid); + if (tp != NULL && (tp->btrace.flags & BTHR_MOVE) != 0) + return tp; + + /* Next check the current thread. */ + tp = find_thread_ptid (inferior_ptid); + if (tp != NULL && (tp->btrace.flags & BTHR_MOVE) != 0) + return tp; + + /* Otherwise, find one other thread that has been resumed. */ + ALL_THREADS (tp) + if ((tp->btrace.flags & BTHR_MOVE) != 0) + return tp; + + return NULL; +} + +/* Return a targetwait status indicating that we ran out of history. */ + +static struct target_waitstatus +btrace_step_no_history (void) +{ + struct target_waitstatus status; + + status.kind = TARGET_WAITKIND_NO_HISTORY; + + return status; +} + +/* Return a targetwait status indicating that we stopped. */ + +static struct target_waitstatus +btrace_step_stopped (void) +{ + struct target_waitstatus status; + + status.kind = TARGET_WAITKIND_STOPPED; + status.value.sig = GDB_SIGNAL_TRAP; + + return status; +} + +/* Clear the record histories. */ + +static void +record_btrace_clear_histories (struct btrace_thread_info *btinfo) +{ + xfree (btinfo->insn_history); + xfree (btinfo->call_history); + + btinfo->insn_history = NULL; + btinfo->call_history = NULL; +} + +/* Step a single thread. */ + +static struct target_waitstatus +record_btrace_step_thread (struct thread_info *tp) +{ + struct btrace_insn_iterator *replay, end; + struct btrace_thread_info *btinfo; + struct address_space *aspace; + unsigned int steps, flag; + + btinfo = &tp->btrace; + replay = btinfo->replay; + + flag = btinfo->flags & BTHR_MOVE; + btinfo->flags &= ~BTHR_MOVE; + + DEBUG ("stepping %d (%s): %u", tp->num, target_pid_to_str (tp->ptid), flag); + + switch (flag) + { + default: + internal_error (__FILE__, __LINE__, _("invalid stepping type.")); + + case BTHR_STEP: + /* We're done if we're not replaying. */ + if (replay == NULL) + return btrace_step_no_history (); + + /* We are always able to step at least once. */ + steps = btrace_insn_next (replay, 1); + gdb_assert (steps == 1); + + /* Determine the end of the instruction trace. */ + btrace_insn_end (&end, btinfo); + + /* We stop replaying if we reached the end of the trace. */ + if (btrace_insn_cmp (replay, &end) == 0) + record_btrace_stop_replaying (btinfo); + + return btrace_step_stopped (); + + case BTHR_RSTEP: + /* Start replaying if we're not already doing so. */ + if (replay == NULL) + replay = record_btrace_start_replaying (btinfo); + + /* If we can't step any further, we reached the end of the history. */ + steps = btrace_insn_prev (replay, 1); + if (steps == 0) + return btrace_step_no_history (); + + return btrace_step_stopped (); + + case BTHR_CONT: + /* We're done if we're not replaying. */ + if (replay == NULL) + return btrace_step_no_history (); + + /* I'd much rather go from TP to its inferior, but how? */ + aspace = current_inferior ()->aspace; + + /* Determine the end of the instruction trace. */ + btrace_insn_end (&end, btinfo); + + for (;;) + { + const struct btrace_insn *insn; + + /* We are always able to step at least once. */ + steps = btrace_insn_next (replay, 1); + gdb_assert (steps == 1); + + /* We stop replaying if we reached the end of the trace. */ + if (btrace_insn_cmp (replay, &end) == 0) + { + record_btrace_stop_replaying (btinfo); + return btrace_step_no_history (); + } + + insn = btrace_insn_get (replay); + gdb_assert (insn); + + DEBUG ("stepping %d (%s) ... %s", tp->num, + target_pid_to_str (tp->ptid), + core_addr_to_string_nz (insn->pc)); + + if (breakpoint_here_p (aspace, insn->pc)) + return btrace_step_stopped (); + } + + case BTHR_RCONT: + /* Start replaying if we're not already doing so. */ + if (replay == NULL) + replay = record_btrace_start_replaying (btinfo); + + /* I'd much rather go from TP to its inferior, but how? */ + aspace = current_inferior ()->aspace; + + for (;;) + { + const struct btrace_insn *insn; + + /* If we can't step any further, we're done. */ + steps = btrace_insn_prev (replay, 1); + if (steps == 0) + return btrace_step_no_history (); + + insn = btrace_insn_get (replay); + gdb_assert (insn); + + DEBUG ("stepping %d (%s): reverse~ ... %s", tp->num, + target_pid_to_str (tp->ptid), + core_addr_to_string_nz (insn->pc)); + + if (breakpoint_here_p (aspace, insn->pc)) + return btrace_step_stopped (); + } + } } /* The to_wait method of target record-btrace. */ @@ -1208,8 +1509,12 @@ static ptid_t record_btrace_wait (struct target_ops *ops, ptid_t ptid, struct target_waitstatus *status, int options) { + struct thread_info *tp, *other; + + DEBUG ("wait %s (0x%x)", target_pid_to_str (ptid), options); + /* As long as we're not replaying, just forward the request. */ - if (!record_btrace_is_replaying ()) + if (!record_btrace_is_replaying () && execution_direction != EXEC_REVERSE) { for (ops = ops->beneath; ops != NULL; ops = ops->beneath) if (ops->to_wait != NULL) @@ -1218,7 +1523,40 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid, error (_("Cannot find target for stepping.")); } - error (_("You can't do this from here. Do 'record goto end', first.")); + /* Let's find a thread to move. */ + tp = record_btrace_find_thread_to_move (ptid); + if (tp == NULL) + { + DEBUG ("wait %s: no thread", target_pid_to_str (ptid)); + + status->kind = TARGET_WAITKIND_IGNORE; + return minus_one_ptid; + } + + /* We only move a single thread. We're not able to correlate threads. */ + *status = record_btrace_step_thread (tp); + + /* Stop all other threads. */ + if (!non_stop) + ALL_THREADS (other) + other->btrace.flags &= ~BTHR_MOVE; + + /* Start record histories anew from the current position. */ + record_btrace_clear_histories (&tp->btrace); + + /* GDB seems to need this. Without, a stale PC seems to be used resulting in + the current location to be displayed incorrectly. */ + registers_changed (); + + return tp->ptid; +} + +/* The to_can_execute_reverse method of target record-btrace. */ + +static int +record_btrace_can_execute_reverse (void) +{ + return 1; } /* The to_find_new_threads method of target record-btrace. */ @@ -1246,30 +1584,19 @@ record_btrace_set_replay (struct btrace_thread_info *btinfo, const struct btrace_insn_iterator *it) { if (it == NULL || it->function == NULL) - { - if (btinfo->replay == NULL) - return; - - xfree (btinfo->replay); - btinfo->replay = NULL; - } + record_btrace_stop_replaying (btinfo); else { if (btinfo->replay == NULL) - btinfo->replay = xzalloc (sizeof (*btinfo->replay)); + record_btrace_start_replaying (btinfo); else if (btrace_insn_cmp (btinfo->replay, it) == 0) return; *btinfo->replay = *it; } - /* Clear the function call and instruction histories so we start anew - from the new replay position. */ - xfree (btinfo->insn_history); - xfree (btinfo->call_history); - - btinfo->insn_history = NULL; - btinfo->call_history = NULL; + /* Start anew from the new replay position. */ + record_btrace_clear_histories (btinfo); registers_changed (); reinit_frame_cache (); @@ -1365,6 +1692,7 @@ init_record_btrace_ops (void) ops->to_goto_record_begin = record_btrace_goto_begin; ops->to_goto_record_end = record_btrace_goto_end; ops->to_goto_record = record_btrace_goto; + ops->to_can_execute_reverse = record_btrace_can_execute_reverse; ops->to_stratum = record_stratum; ops->to_magic = OPS_MAGIC; } diff --git a/gdb/testsuite/gdb.btrace/delta.exp b/gdb/testsuite/gdb.btrace/delta.exp index 9ee2629..49d151e 100644 --- a/gdb/testsuite/gdb.btrace/delta.exp +++ b/gdb/testsuite/gdb.btrace/delta.exp @@ -61,3 +61,16 @@ gdb_test "record instruction-history /f 1" " 1\t 0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tmov *\\\$0x0,%eax\r" "delta, 4.2" gdb_test "record function-call-history /c 1" " 1\tmain\r" "delta, 4.3" + +# check that we can reverse-stepi that instruction +gdb_test "reverse-stepi" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 1 instructions in 1 functions for .*\r +Replay in progress\. At instruction 1\." "delta, 5.1" + +# and back +gdb_test "stepi" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 1 instructions in 1 functions for .*" "delta, 5.2" diff --git a/gdb/testsuite/gdb.btrace/finish.exp b/gdb/testsuite/gdb.btrace/finish.exp new file mode 100644 index 0000000..87ebfe1 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/finish.exp @@ -0,0 +1,70 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# check for btrace support +if { [skip_btrace_tests] } { return -1 } + +# start inferior +standard_testfile x86-record_goto.S +if [prepare_for_testing finish.exp $testfile $srcfile] { + return -1 +} + +if ![runto_main] { + return -1 +} + +# trace the call to the test function +gdb_test_no_output "record btrace" +gdb_test "next" + +# let's go somewhere where we can finish +gdb_test "record goto 32" ".*fun1\.1.*" "finish, 1.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 32\." "finish, 1.2" + +# let's finish into fun2 +gdb_test "finish" ".*fun2\.3.*" "finish, 2.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 35\." "finish, 2.2" + +# now let's reverse-finish into fun3 +gdb_test "reverse-finish" ".*fun3\.3.*" "finish, 3.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 27\." "finish, 3.2" + +# finish again - into fun4 +gdb_test "finish" ".*fun4\.5.*" "finish, 4.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 39\." "finish, 4.2" + +# and reverse-finish again - into main +gdb_test "reverse-finish" ".*main\.2.*" "finish, 5.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 1\." "finish, 5.2" diff --git a/gdb/testsuite/gdb.btrace/multi-thread-step.c b/gdb/testsuite/gdb.btrace/multi-thread-step.c new file mode 100644 index 0000000..487565b --- /dev/null +++ b/gdb/testsuite/gdb.btrace/multi-thread-step.c @@ -0,0 +1,53 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 Free Software Foundation, Inc. + + Contributed by Intel Corp. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +static pthread_barrier_t barrier; +static int global; + +static void * +test (void *arg) +{ + pthread_barrier_wait (&barrier); + + global = 42; /* bp.1 */ + + pthread_barrier_wait (&barrier); + + global = 42; /* bp.2 */ + + return arg; +} + +int +main (void) +{ + pthread_t th; + + pthread_barrier_init (&barrier, NULL, 2); + pthread_create (&th, NULL, test, NULL); + + test (NULL); + + pthread_join (th, NULL); + pthread_barrier_destroy (&barrier); + + return 0; /* bp.3 */ +} diff --git a/gdb/testsuite/gdb.btrace/multi-thread-step.exp b/gdb/testsuite/gdb.btrace/multi-thread-step.exp new file mode 100644 index 0000000..bb88e13 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/multi-thread-step.exp @@ -0,0 +1,84 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# check for btrace support +if { [skip_btrace_tests] } { return -1 } + +# start inferior +standard_testfile +if {[gdb_compile_pthreads "$srcdir/$subdir/$srcfile" "$binfile" executable {debug}] != "" } { + return -1 +} +clean_restart $testfile + +if ![runto_main] { + return -1 +} + +# set up breakpoints +set bp_1 [gdb_get_line_number "bp.1" $srcfile] +set bp_2 [gdb_get_line_number "bp.2" $srcfile] +set bp_3 [gdb_get_line_number "bp.3" $srcfile] + +proc gdb_cont_to_line { line test } { + gdb_breakpoint $line + gdb_continue_to_breakpoint "$test - $line" ".*$line.*" + delete_breakpoints +} + +# trace the code between the two breakpoints +delete_breakpoints +gdb_cont_to_line $srcfile:$bp_1 "mts, 0.1" +# make sure GDB knows about the new thread +gdb_test "info threads" ".*" "mts, 0.2" +gdb_test_no_output "record btrace" "mts, 0.3" +gdb_cont_to_line $srcfile:$bp_2 "mts, 0.4" + +# navigate in the trace history for both threads +gdb_test "thread 1" ".*" "mts, 1.1" +gdb_test "record goto begin" ".*" "mts, 1.2" +gdb_test "info record" ".*Replay in progress\. At instruction 1\." "mts, 1.3" +gdb_test "thread 2" ".*" "mts, 1.4" +gdb_test "record goto begin" ".*" "mts, 1.5" +gdb_test "info record" ".*Replay in progress\. At instruction 1\." "mts, 1.6" + +# step both threads +gdb_test "thread 1" ".*" "mts, 2.1" +gdb_test "info record" ".*Replay in progress\. At instruction 1\." "mts, 2.2" +gdb_test "stepi" ".*" "mts, 2.3" +gdb_test "info record" ".*Replay in progress\. At instruction 2\." "mts, 2.4" +gdb_test "thread 2" ".*" "mts, 2.5" +gdb_test "info record" ".*Replay in progress\. At instruction 1\." "mts, 2.6" +gdb_test "stepi" ".*" "mts, 2.7" +gdb_test "info record" ".*Replay in progress\. At instruction 2\." "mts, 2.8" + +# run to the end of the history for both threads +gdb_test "thread 1" ".*" "mts, 3.1" +gdb_test "info record" ".*Replay in progress\. At instruction 2\." "mts, 3.2" +gdb_test "continue" "No more reverse-execution history.*" "mts, 3.3" +gdb_test "thread 2" ".*" "mts, 3.4" +gdb_test "info record" ".*Replay in progress\. At instruction 2\." "mts, 3.5" +gdb_test "continue" "No more reverse-execution history.*" "mts, 3.6" + +# navigate back into the history for thread 1 and continue thread 2 +gdb_test "thread 1" ".*" "mts, 4.1" +gdb_test "record goto begin" ".*" "mts, 4.2" +gdb_test "info record" ".*Replay in progress\. At instruction 1\." "mts, 4.3" +gdb_test "thread 2" ".*" "mts, 4.4" +gdb_cont_to_line $srcfile:$bp_3 "mts, 4.5" diff --git a/gdb/testsuite/gdb.btrace/next.exp b/gdb/testsuite/gdb.btrace/next.exp new file mode 100644 index 0000000..12a5e8e --- /dev/null +++ b/gdb/testsuite/gdb.btrace/next.exp @@ -0,0 +1,89 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# check for btrace support +if { [skip_btrace_tests] } { return -1 } + +# start inferior +standard_testfile x86-record_goto.S +if [prepare_for_testing next.exp $testfile $srcfile] { + return -1 +} + +if ![runto_main] { + return -1 +} + +# trace the call to the test function +gdb_test_no_output "record btrace" +gdb_test "next" + +# we start with stepping to make sure that the trace is fetched automatically +# the call is outside of our trace +gdb_test "reverse-next" ".*main\.2.*" "next, 1.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 1\." "next, 1.2" + +# we can't reverse-step any further +gdb_test "reverse-next" "No more reverse-execution history\.\r +.*main\.2.*" "next, 1.3" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 1\." "next, 1.4" + +# but we can step back again +gdb_test "next" ".*main\.3.*" "next, 1.5" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r" "next, 1.6" + +# let's go somewhere where we can step some more +gdb_test "record goto 22" ".*fun3\.2.*" "next, 2.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 22\." "next, 2.2" + +gdb_test "next" ".*fun3\.3.*" "next, 2.3" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 27\." "next, 2.4" + +gdb_test "next" ".*fun3\.4.*" "next, 2.5" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 37\." "next, 2.6" + +# and back again +gdb_test "reverse-next" ".*fun3\.3.*" "next, 3.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 27\." "next, 3.2" + +gdb_test "reverse-next" ".*fun3\.2.*" "next, 3.3" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 22\." "next, 3.4" diff --git a/gdb/testsuite/gdb.btrace/nexti.exp b/gdb/testsuite/gdb.btrace/nexti.exp new file mode 100644 index 0000000..559a9b7 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/nexti.exp @@ -0,0 +1,89 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# check for btrace support +if { [skip_btrace_tests] } { return -1 } + +# start inferior +standard_testfile x86-record_goto.S +if [prepare_for_testing nexti.exp $testfile $srcfile] { + return -1 +} + +if ![runto_main] { + return -1 +} + +# trace the call to the test function +gdb_test_no_output "record btrace" +gdb_test "next" + +# we start with stepping to make sure that the trace is fetched automatically +# the call is outside of our trace +gdb_test "reverse-nexti" ".*main\.2.*" "nexti, 1.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 1\." "nexti, 1.2" + +# we can't reverse-step any further +gdb_test "reverse-nexti" "No more reverse-execution history\.\r +.*main\.2.*" "nexti, 1.3" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 1\." "nexti, 1.4" + +# but we can step back again +gdb_test "nexti" ".*main\.3.*" "next, 1.5" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r" "next, 1.6" + +# let's go somewhere where we can step some more +gdb_test "record goto 22" ".*fun3\.2.*" "nexti, 2.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 22\." "nexti, 2.2" + +gdb_test "nexti" ".*fun3\.3.*" "nexti, 2.3" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 27\." "nexti, 2.4" + +gdb_test "nexti" ".*fun3\.4.*" "nexti, 2.5" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 37\." "nexti, 2.6" + +# and back again +gdb_test "reverse-nexti" ".*fun3\.3.*" "nexti, 3.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 27\." "nexti, 3.2" + +gdb_test "reverse-nexti" ".*fun3\.2.*" "nexti, 3.3" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 22\." "nexti, 3.4" diff --git a/gdb/testsuite/gdb.btrace/record_goto.c b/gdb/testsuite/gdb.btrace/record_goto.c index 1250708..90537f9 100644 --- a/gdb/testsuite/gdb.btrace/record_goto.c +++ b/gdb/testsuite/gdb.btrace/record_goto.c @@ -19,33 +19,33 @@ void fun1 (void) -{ -} +{ /* fun1.1 */ +} /* fun1.2 */ void fun2 (void) -{ - fun1 (); -} +{ /* fun2.1 */ + fun1 (); /* fun2.2 */ +} /* fun2.3 */ void fun3 (void) -{ - fun1 (); - fun2 (); -} +{ /* fun3.1 */ + fun1 (); /* fun3.2 */ + fun2 (); /* fun3.3 */ +} /* fun3.4 */ void fun4 (void) -{ - fun1 (); - fun2 (); - fun3 (); -} +{ /* fun4.1 */ + fun1 (); /* fun4.2 */ + fun2 (); /* fun4.3 */ + fun3 (); /* fun4.4 */ +} /* fun4.5 */ int main (void) -{ - fun4 (); - return 0; -} +{ /* main.1 */ + fun4 (); /* main.2 */ + return 0; /* main.3 */ +} /* main.4 */ diff --git a/gdb/testsuite/gdb.btrace/step.exp b/gdb/testsuite/gdb.btrace/step.exp new file mode 100644 index 0000000..bb8942e --- /dev/null +++ b/gdb/testsuite/gdb.btrace/step.exp @@ -0,0 +1,113 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# check for btrace support +if { [skip_btrace_tests] } { return -1 } + +# start inferior +standard_testfile x86-record_goto.S +if [prepare_for_testing step.exp $testfile $srcfile] { + return -1 +} + +if ![runto_main] { + return -1 +} + +# trace the call to the test function +gdb_test_no_output "record btrace" +gdb_test "next" + +# let's start by stepping back into the function we just returned from +gdb_test "reverse-step" ".*fun4\.5.*" "step, 1.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 39\." "step, 1.2" + +# again +gdb_test "reverse-step" ".*fun3\.4.*" "step, 2.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 37\." "step, 2.2" + +# and again +gdb_test "reverse-step" ".*fun2\.3.*" "step, 3.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 35\." "step, 3.2" + +# once more +gdb_test "reverse-step" ".*fun1\.2.*" "step, 4.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 33\." "step, 4.2" + +# and out again the other side +gdb_test "reverse-step" ".*fun2\.2.*" "step, 5.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 30\." "step, 5.2" + +# once again +gdb_test "reverse-step" ".*fun3\.3.*" "step, 6.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 27\." "step, 6.2" + +# and back the way we came +gdb_test "step" ".*fun2\.2.*" "step, 7.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 30\." "step, 7.2" + +gdb_test "step" ".*fun1\.2.*" "step, 8.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 33\." "step, 8.2" + +gdb_test "step" ".*fun2\.3.*" "step, 9.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 35\." "step, 9.2" + +gdb_test "step" ".*fun3\.4.*" "step, 10.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 37\." "step, 10.2" + +gdb_test "step" ".*fun4\.5.*" "step, 11.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 39\." "step, 11.2" + +gdb_test "step" ".*main\.3.*" "step, 12.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r" "step, 12.2" diff --git a/gdb/testsuite/gdb.btrace/stepi.exp b/gdb/testsuite/gdb.btrace/stepi.exp new file mode 100644 index 0000000..22f1574 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/stepi.exp @@ -0,0 +1,114 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# check for btrace support +if { [skip_btrace_tests] } { return -1 } + +# start inferior +standard_testfile x86-record_goto.S +if [prepare_for_testing stepi.exp $testfile $srcfile] { + return -1 +} + +global gdb_prompt + +if ![runto_main] { + return -1 +} + +# trace the call to the test function +gdb_test_no_output "record btrace" +gdb_test "next" + +# we start with stepping to make sure that the trace is fetched automatically +gdb_test "reverse-stepi" ".*fun4\.5.*" "stepi, 1.1" +gdb_test "reverse-stepi" ".*fun4\.5.*" "stepi, 1.2" + +# let's check where we are in the trace +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 39\." "stepi, 1.3" + +# let's step forward and check again +gdb_test "stepi" ".*fun4\.5.*" "stepi, 2.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 40\." "stepi, 2.2" + +# with the next step, we stop replaying +gdb_test "stepi" ".*main\.3.*" "stepi, 2.3" +gdb_test_multiple "info record" "stepi, 2.4" { + -re "Replay in progress.*$gdb_prompt $" { fail "stepi, 2.4" } + -re ".*$gdb_prompt $" { pass "stepi, 2.4" } +} + +# let's step from a goto position somewhere in the middle +gdb_test "record goto 22" ".*fun3\.2.*" "stepi, 3.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 22\." "stepi, 3.2" +gdb_test "stepi" ".*fun1\.1.*" "stepi, 3.3" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 23\." "stepi, 3.4" + +# and back again +gdb_test "reverse-stepi" ".*fun3\.2.*" "stepi, 4.1" +gdb_test "reverse-stepi" ".*fun3\.1.*" "stepi, 4.2" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 21\." "stepi, 4.3" + +# let's try to step off the left end +gdb_test "record goto begin" ".*main\.2.*" "stepi, 5.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 1\." "stepi, 5.2" +gdb_test "reverse-stepi" "No more reverse-execution history\.\r +.*main\.2.*" "stepi, 5.3" +gdb_test "reverse-stepi" "No more reverse-execution history\.\r +.*main\.2.*" "stepi, 5.4" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 1\." "stepi, 5.5" + +# we can step forward, though +gdb_test "stepi" ".*fun4\.1.*" "stepi, 6.1" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 2\." "stepi, 6.2" + +# let's try to step off the left end again +gdb_test "reverse-stepi" ".*main\.2.*" "stepi, 7.1" +gdb_test "reverse-stepi" "No more reverse-execution history\.\r +.*main\.2.*" "stepi, 7.2" +gdb_test "reverse-stepi" "No more reverse-execution history\.\r +.*main\.2.*" "stepi, 7.3" +gdb_test "info record" " +Active record target: record-btrace\r +Recorded 40 instructions in 16 functions for .*\r +Replay in progress\. At instruction 1\." "stepi, 7.4" -- 1.7.1