diff options
-rw-r--r-- | gdb/ChangeLog | 18 | ||||
-rw-r--r-- | gdb/NEWS | 4 | ||||
-rw-r--r-- | gdb/btrace.h | 22 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 6 | ||||
-rw-r--r-- | gdb/record-btrace.c | 430 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 18 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/Makefile.in | 3 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/data.c | 36 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/data.exp | 45 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/delta.exp | 15 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/finish.exp | 59 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/multi-thread-step.c | 53 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/multi-thread-step.exp | 135 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/next.exp | 76 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/nexti.exp | 76 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/record_goto.c | 36 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/rn-dl-bind.c | 37 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/rn-dl-bind.exp | 52 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/step.exp | 89 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/stepi.exp | 93 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/tailcall.exp | 13 |
22 files changed, 1279 insertions, 42 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ad768a1..3e7f149 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,23 @@ 2014-01-16 Markus Metzger <markus.t.metzger@intel.com> + * btrace.h (btrace_thread_flag): New. + (struct btrace_thread_info) <flags>: 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_decr_pc_after_break) + (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. + +2014-01-16 Markus Metzger <markus.t.metzger@intel.com> + * target.h (struct target_ops) <to_decr_pc_after_break>: New. (forward_target_decr_pc_after_break) (target_decr_pc_after_break): New. @@ -22,6 +22,10 @@ For locations inside the execution trace, the back trace is computed based on the information stored in the execution trace. +* The btrace record target supports limited reverse execution and replay. + The target does not record data and therefore does not allow reading + memory or registers. + * New remote packets qXfer:btrace:read's annex diff --git a/gdb/btrace.h b/gdb/btrace.h index 193f916..f83a80f 100644 --- a/gdb/btrace.h +++ b/gdb/btrace.h @@ -153,6 +153,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 @@ -182,6 +201,9 @@ struct btrace_thread_info becomes zero. */ int level; + /* A bit-vector of btrace_thread_flag. */ + enum btrace_thread_flag flags; + /* The instruction history iterator. */ struct btrace_insn_history *insn_history; diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index b873f51..74a2763 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,5 +1,10 @@ 2014-01-16 Markus Metzger <markus.t.metzger@intel.com> + * gdb.texinfo: Document limited reverse/replay support + for target record-btrace. + +2014-01-16 Markus Metzger <markus.t.metzger@intel.com> + * gdb.texinfo (Process Record and Replay): Update documentation. 2014-01-16 Markus Metzger <markus.t.metzger@intel.com> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 57071d1..e77ca2a 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -6263,8 +6263,10 @@ 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. Further, the data is collected in a ring buffer so old data will +be overwritten when the buffer is full. It allows limited replay and +reverse execution. This recording method may not be available on all processors. @end table diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c index 8c8620c..3a93fdb 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -169,6 +169,9 @@ 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.")); + gdb_assert (record_btrace_thread_observer == NULL); disable_chain = make_cleanup (null_cleanup, NULL); @@ -1290,14 +1293,166 @@ const struct frame_unwind record_btrace_tailcall_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); +} + +/* Start replaying a thread. */ + +static struct btrace_insn_iterator * +record_btrace_start_replaying (struct thread_info *tp) +{ + volatile struct gdb_exception except; + struct btrace_insn_iterator *replay; + struct btrace_thread_info *btinfo; + int executing; + + btinfo = &tp->btrace; + replay = NULL; + + /* We can't start replaying without trace. */ + if (btinfo->begin == NULL) + return NULL; + + /* Clear the executing flag to allow changes to the current frame. + We are not actually running, yet. We just started a reverse execution + command or a record goto command. + For the latter, EXECUTING is false and this has no effect. + For the former, EXECUTING is true and we're in to_wait, about to + move the thread. Since we need to recompute the stack, we temporarily + set EXECUTING to flase. */ + executing = is_executing (tp->ptid); + set_executing (tp->ptid, 0); + + /* GDB stores the current frame_id when stepping in order to detects steps + into subroutines. + Since frames are computed differently when we're replaying, we need to + recompute those stored frames and fix them up so we can still detect + subroutines after we started replaying. */ + TRY_CATCH (except, RETURN_MASK_ALL) + { + struct frame_info *frame; + struct frame_id frame_id; + int upd_step_frame_id, upd_step_stack_frame_id; + + /* The current frame without replaying - computed via normal unwind. */ + frame = get_current_frame (); + frame_id = get_frame_id (frame); + + /* Check if we need to update any stepping-related frame id's. */ + upd_step_frame_id = frame_id_eq (frame_id, + tp->control.step_frame_id); + upd_step_stack_frame_id = frame_id_eq (frame_id, + tp->control.step_stack_frame_id); + + /* We start replaying at the end of the branch trace. This corresponds + to the current instruction. */ + replay = xmalloc (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. */ + registers_changed_ptid (tp->ptid); + + /* The current frame with replaying - computed via btrace unwind. */ + frame = get_current_frame (); + frame_id = get_frame_id (frame); + + /* Replace stepping related frames where necessary. */ + if (upd_step_frame_id) + tp->control.step_frame_id = frame_id; + if (upd_step_stack_frame_id) + tp->control.step_stack_frame_id = frame_id; + } + + /* Restore the previous execution state. */ + set_executing (tp->ptid, executing); + + if (except.reason < 0) + { + xfree (btinfo->replay); + btinfo->replay = NULL; + + registers_changed_ptid (tp->ptid); + + throw_exception (except); + } + + return replay; +} + +/* Stop replaying a thread. */ + +static void +record_btrace_stop_replaying (struct thread_info *tp) +{ + struct btrace_thread_info *btinfo; + + btinfo = &tp->btrace; + + xfree (btinfo->replay); + btinfo->replay = NULL; + + /* Make sure we're not leaving any stale registers. */ + registers_changed_ptid (tp->ptid); +} + /* 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); + if (tp == NULL) + error (_("Cannot find thread to resume.")); + + /* Stop replaying other threads if the thread to resume is not replaying. */ + if (!btrace_is_replaying (tp) && execution_direction != EXEC_REVERSE) + ALL_THREADS (other) + record_btrace_stop_replaying (other); + /* 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) @@ -1306,7 +1461,200 @@ 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.")); + /* 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; + + /* At the moment, we only move a single thread. We could also move + all threads in parallel by single-stepping each resumed thread + until the first runs into an event. + When we do that, we would want to continue all other threads. + For now, just resume one thread to not confuse to_wait. */ + 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; + + /* 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 target_waitstatus 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 target_waitstatus indicating that a step finished. */ + +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; + struct inferior *inf; + enum btrace_thread_flag flags; + unsigned int steps; + + btinfo = &tp->btrace; + replay = btinfo->replay; + + flags = btinfo->flags & BTHR_MOVE; + btinfo->flags &= ~BTHR_MOVE; + + DEBUG ("stepping %d (%s): %u", tp->num, target_pid_to_str (tp->ptid), flags); + + switch (flags) + { + 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 (tp); + + return btrace_step_stopped (); + + case BTHR_RSTEP: + /* Start replaying if we're not already doing so. */ + if (replay == NULL) + replay = record_btrace_start_replaying (tp); + + /* 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 (); + + inf = find_inferior_pid (ptid_get_pid (tp->ptid)); + aspace = inf->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 (tp); + 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 (tp); + + inf = find_inferior_pid (ptid_get_pid (tp->ptid)); + aspace = inf->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 ("reverse-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 (); + } + } } /* The to_wait method of target record-btrace. */ @@ -1315,8 +1663,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) @@ -1325,7 +1677,53 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid, error (_("Cannot find target for waiting.")); } - 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); + + /* We moved the replay position but did not update registers. */ + registers_changed_ptid (tp->ptid); + + 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_decr_pc_after_break method of target record-btrace. */ + +static CORE_ADDR +record_btrace_decr_pc_after_break (struct target_ops *ops, + struct gdbarch *gdbarch) +{ + /* When replaying, we do not actually execute the breakpoint instruction + so there is no need to adjust the PC after hitting a breakpoint. */ + if (record_btrace_is_replaying ()) + return 0; + + return forward_target_decr_pc_after_break (ops->beneath, gdbarch); } /* The to_find_new_threads method of target record-btrace. */ @@ -1375,32 +1773,20 @@ record_btrace_set_replay (struct thread_info *tp, btinfo = &tp->btrace; if (it == NULL || it->function == NULL) - { - if (btinfo->replay == NULL) - return; - - xfree (btinfo->replay); - btinfo->replay = NULL; - } + record_btrace_stop_replaying (tp); else { if (btinfo->replay == NULL) - btinfo->replay = xmalloc (sizeof (*btinfo->replay)); + record_btrace_start_replaying (tp); else if (btrace_insn_cmp (btinfo->replay, it) == 0) return; *btinfo->replay = *it; + registers_changed_ptid (tp->ptid); } - /* 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; - - registers_changed_ptid (tp->ptid); + /* Start anew from the new replay position. */ + record_btrace_clear_histories (btinfo); } /* The to_goto_record_begin method of target record-btrace. */ @@ -1502,6 +1888,8 @@ 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_decr_pc_after_break = record_btrace_decr_pc_after_break; ops->to_stratum = record_stratum; ops->to_magic = OPS_MAGIC; } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 9637566..6a9d8c0 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,23 @@ 2014-01-16 Markus Metzger <markus.t.metzger@intel.com> + * gdb.btrace/delta.exp: Check reverse stepi. + * gdb.btrace/tailcall.exp: Update. Add stepping tests. + * 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. + * gdb.btrace/rn-dl-bind.c: New. + * gdb.btrace/rn-dl-bind.exp: New. + * gdb.btrace/data.c: New. + * gdb.btrace/data.exp: New. + * gdb.btrace/Makefile.in (EXECUTABLES): Add new. + +2014-01-16 Markus Metzger <markus.t.metzger@intel.com> + * gdb.btrace/Makefile.in (EXECUTABLES): Add delta. * gdb.btrace/exception.exp: Update. * gdb.btrace/instruction_history.exp: Update. diff --git a/gdb/testsuite/gdb.btrace/Makefile.in b/gdb/testsuite/gdb.btrace/Makefile.in index 2ae673a..ec00b59 100644 --- a/gdb/testsuite/gdb.btrace/Makefile.in +++ b/gdb/testsuite/gdb.btrace/Makefile.in @@ -2,7 +2,8 @@ VPATH = @srcdir@ srcdir = @srcdir@ EXECUTABLES = enable function_call_history instruction_history tailcall \ - exception unknown_functions record_goto delta + exception unknown_functions record_goto delta finish next nexti step \ + stepi multi-thread-step rn-dl-bind data MISCELLANEOUS = diff --git a/gdb/testsuite/gdb.btrace/data.c b/gdb/testsuite/gdb.btrace/data.c new file mode 100644 index 0000000..7368394 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/data.c @@ -0,0 +1,36 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 Free Software Foundation, Inc. + + Contributed by Intel Corp. <markus.t.metzger@intel.com> + + 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 <http://www.gnu.org/licenses/>. */ + +volatile static int glob; + +void +test (void) +{ /* test.1 */ + volatile static int loc; + + loc += 1; /* test.2 */ + glob += loc; /* test.3 */ +} /* test.4 */ + +int +main (void) +{ /* main.1 */ + test (); /* main.2 */ + return 0; /* main.3 */ +} /* main.4 */ diff --git a/gdb/testsuite/gdb.btrace/data.exp b/gdb/testsuite/gdb.btrace/data.exp new file mode 100644 index 0000000..d6bc854 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/data.exp @@ -0,0 +1,45 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. <markus.t.metzger@intel.com> +# +# 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 <http://www.gnu.org/licenses/>. + +# check for btrace support +if { [skip_btrace_tests] } { return -1 } + +# start inferior +standard_testfile +if [prepare_for_testing $testfile.exp $testfile $srcfile] { + return -1 +} +if ![runto_main] { + return -1 +} + +# trace the test code +gdb_test_no_output "record btrace" +gdb_test "next" ".*main\.3.*" + +# reverse step into test +gdb_test "reverse-step" ".*test\.4.*" + +# we can't read memory while we're replaying +gdb_test "print glob" "Memory at .* unavailable\." +gdb_test "print loc" "Memory at .* unavailable\." + +# stop replaying and try again +gdb_test "record goto end" +gdb_test "print glob" "1" diff --git a/gdb/testsuite/gdb.btrace/delta.exp b/gdb/testsuite/gdb.btrace/delta.exp index e606751..5c3505c 100644 --- a/gdb/testsuite/gdb.btrace/delta.exp +++ b/gdb/testsuite/gdb.btrace/delta.exp @@ -66,3 +66,18 @@ with_test_prefix "once" { with_test_prefix "twice" { check_trace } + +# check that we can reverse-stepi that instruction +gdb_test "reverse-stepi" +gdb_test "info record" [join [list \ + "Active record target: record-btrace" \ + "Recorded 1 instructions in 1 functions for .*" \ + "Replay in progress\. At instruction 1\." \ + ] "\r\n"] "reverse-stepi" + +# and back +gdb_test "stepi" +gdb_test "info record" [join [list \ + "Active record target: record-btrace" \ + "Recorded 1 instructions in 1 functions for .*" \ + ] "\r\n"] "and back" diff --git a/gdb/testsuite/gdb.btrace/finish.exp b/gdb/testsuite/gdb.btrace/finish.exp new file mode 100644 index 0000000..a27082e --- /dev/null +++ b/gdb/testsuite/gdb.btrace/finish.exp @@ -0,0 +1,59 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. <markus.t.metzger@intel.com> +# +# 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 <http://www.gnu.org/licenses/>. + +# 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" + +proc check_replay_at { insn } { + gdb_test "info record" [join [list \ + "Active record target: record-btrace" \ + "Recorded 40 instructions in 16 functions for .*" \ + "Replay in progress\. At instruction $insn\." \ + ] "\r\n"] +} + +# let's go somewhere where we can finish +gdb_test "record goto 32" ".*fun1\.1.*" +with_test_prefix "at 32" { check_replay_at 32 } + +gdb_test "finish" ".*fun2\.3.*" +with_test_prefix "finish into fun2" { check_replay_at 35 } + +gdb_test "reverse-finish" ".*fun3\.3.*" +with_test_prefix "reverse-finish into fun3" { check_replay_at 27 } + +gdb_test "finish" ".*fun4\.5.*" +with_test_prefix "finish into fun4" { check_replay_at 39 } + +gdb_test "reverse-finish" ".*main\.2.*" +with_test_prefix "reverse-finish into main" { check_replay_at 1 } 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. <markus.t.metzger@intel.com> + + 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 <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> + +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..2c108b2 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/multi-thread-step.exp @@ -0,0 +1,135 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. <markus.t.metzger@intel.com> +# +# 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 <http://www.gnu.org/licenses/>. + +# 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 } { + gdb_breakpoint $line + gdb_continue_to_breakpoint "cont to $line" ".*$line\r\n.*" + delete_breakpoints +} + +# trace the code between the two breakpoints +delete_breakpoints +gdb_cont_to_line $srcfile:$bp_1 +# make sure GDB knows about the new thread +gdb_test "info threads" ".*" +gdb_test_no_output "record btrace" +gdb_cont_to_line $srcfile:$bp_2 + +# navigate in the trace history for both threads +with_test_prefix "navigate" { + gdb_test "thread 1" ".*" + with_test_prefix "thread 1" { + gdb_test "record goto begin" ".*" + gdb_test "info record" ".*Replay in progress\. At instruction 1\." + } + gdb_test "thread 2" ".*" + with_test_prefix "thread 2" { + gdb_test "record goto begin" ".*" + gdb_test "info record" ".*Replay in progress\. At instruction 1\." + } +} + +# step both threads +with_test_prefix "step" { + gdb_test "thread 1" ".*" + with_test_prefix "thread 1" { + gdb_test "info record" ".*Replay in progress\. At instruction 1\." + gdb_test "stepi" ".*" + gdb_test "info record" ".*Replay in progress\. At instruction 2\." + } + gdb_test "thread 2" ".*" + with_test_prefix "thread 2" { + gdb_test "info record" ".*Replay in progress\. At instruction 1\." + gdb_test "stepi" ".*" + gdb_test "info record" ".*Replay in progress\. At instruction 2\." + } +} + +# run to the end of the history for both threads +with_test_prefix "cont" { + gdb_test "thread 1" ".*" + with_test_prefix "thread 1" { + gdb_test "info record" ".*Replay in progress\. At instruction 2\." + gdb_test "continue" "No more reverse-execution history.*" + } + gdb_test "thread 2" ".*" + with_test_prefix "thread 2" { + gdb_test "info record" ".*Replay in progress\. At instruction 2\." + gdb_test "continue" "No more reverse-execution history.*" + } +} + +# reverse-step both threads +with_test_prefix "reverse-step" { + gdb_test "thread 1" ".*" + with_test_prefix "thread 1" { + gdb_test "reverse-stepi" ".*" + gdb_test "info record" ".*Replay in progress\..*" + } + gdb_test "thread 2" ".*" + with_test_prefix "thread 2" { + gdb_test "reverse-stepi" ".*" + gdb_test "info record" ".*Replay in progress\..*" + } +} + +# both threads are still replaying +with_test_prefix "check" { + gdb_test "thread 1" ".*" + with_test_prefix "thread 1" { + gdb_test "info record" ".*Replay in progress\..*" + } + gdb_test "thread 2" ".*" + with_test_prefix "thread 2" { + gdb_test "info record" ".*Replay in progress\..*" + } +} + +# navigate back into the history for thread 1 and continue thread 2 +with_test_prefix "cont" { + gdb_test "thread 1" ".*" + with_test_prefix "thread 1" { + gdb_test "record goto begin" ".*" + gdb_test "info record" ".*Replay in progress\. At instruction 1\." + } + gdb_test "thread 2" ".*" + with_test_prefix "thread 2" { + gdb_test "record goto end" ".*" + gdb_cont_to_line $srcfile:$bp_3 + } +} diff --git a/gdb/testsuite/gdb.btrace/next.exp b/gdb/testsuite/gdb.btrace/next.exp new file mode 100644 index 0000000..b39eb79 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/next.exp @@ -0,0 +1,76 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. <markus.t.metzger@intel.com> +# +# 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 <http://www.gnu.org/licenses/>. + +# 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" + +proc check_replay_at { insn } { + gdb_test "info record" [join [list \ + "Active record target: record-btrace" \ + "Recorded 40 instructions in 16 functions for .*" \ + "Replay in progress\. At instruction $insn\." \ + ] "\r\n"] +} + +# 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.*" +with_test_prefix "reverse-next - 1" { check_replay_at 1 } + +# we can't reverse-step any further +gdb_test "reverse-next" "No more reverse-execution history\.\r\n.*main\.2.*" +with_test_prefix "reverse-next - 2" { check_replay_at 1 } + +# but we can step back again +gdb_test "next" ".*main\.3.*" +gdb_test "info record" [join [list \ + "Active record target: record-btrace" \ + "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \ + ] "\r\n"] "next back" + +# let's go somewhere where we can step some more +gdb_test "record goto 22" ".*fun3\.2.*" +with_test_prefix "goto 22" { check_replay_at 22 } + +gdb_test "next" ".*fun3\.3.*" +with_test_prefix "next to 27" { check_replay_at 27 } + +gdb_test "next" ".*fun3\.4.*" +with_test_prefix "next to 37" { check_replay_at 37 } + +# and back again +gdb_test "reverse-next" ".*fun3\.3.*" +with_test_prefix "reverse-next to 27" { check_replay_at 27 } + +gdb_test "reverse-next" ".*fun3\.2.*" +with_test_prefix "reverse-next to 22" { check_replay_at 22 } diff --git a/gdb/testsuite/gdb.btrace/nexti.exp b/gdb/testsuite/gdb.btrace/nexti.exp new file mode 100644 index 0000000..fd94df6 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/nexti.exp @@ -0,0 +1,76 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. <markus.t.metzger@intel.com> +# +# 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 <http://www.gnu.org/licenses/>. + +# 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" + +proc check_replay_at { insn } { + gdb_test "info record" [join [list \ + "Active record target: record-btrace" \ + "Recorded 40 instructions in 16 functions for .*" \ + "Replay in progress\. At instruction $insn\." \ + ] "\r\n"] +} + +# 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.*" +with_test_prefix "reverse-nexti - 1" { check_replay_at 1 } + +# we can't reverse-step any further +gdb_test "reverse-nexti" "No more reverse-execution history\.\r\n.*main\.2.*" +with_test_prefix "reverse-nexti - 1" { check_replay_at 1 } + +# but we can step back again +gdb_test "nexti" ".*main\.3.*" "next, 1.5" +gdb_test "info record" [join [list \ + "Active record target: record-btrace" \ + "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \ + ] "\r\n"] "nexti back" + +# let's go somewhere where we can step some more +gdb_test "record goto 22" ".*fun3\.2.*" +with_test_prefix "goto 22" { check_replay_at 22 } + +gdb_test "nexti" ".*fun3\.3.*" +with_test_prefix "nexti to 27" { check_replay_at 27 } + +gdb_test "nexti" ".*fun3\.4.*" +with_test_prefix "nexti to 37" { check_replay_at 37 } + +# and back again +gdb_test "reverse-nexti" ".*fun3\.3.*" +with_test_prefix "reverse-nexti to 27" { check_replay_at 27 } + +gdb_test "reverse-nexti" ".*fun3\.2.*" +with_test_prefix "reverse-nexti to 22" { check_replay_at 22 } 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/rn-dl-bind.c b/gdb/testsuite/gdb.btrace/rn-dl-bind.c new file mode 100644 index 0000000..4930297 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/rn-dl-bind.c @@ -0,0 +1,37 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2013 Free Software Foundation, Inc. + + Contributed by Intel Corp. <markus.t.metzger@intel.com> + + 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 <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> + +int test (void) +{ + int ret; + + ret = strtoul ("42", NULL, 10); /* test.1 */ + return ret; /* test.2 */ +} /* test.3 */ + +int +main (void) +{ + int ret; + + ret = test (); /* main.1 */ + return ret; /* main.2 */ +} /* main.3 */ diff --git a/gdb/testsuite/gdb.btrace/rn-dl-bind.exp b/gdb/testsuite/gdb.btrace/rn-dl-bind.exp new file mode 100644 index 0000000..2f2250a --- /dev/null +++ b/gdb/testsuite/gdb.btrace/rn-dl-bind.exp @@ -0,0 +1,52 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. <markus.t.metzger@intel.com> +# +# 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 <http://www.gnu.org/licenses/>. +# +# +# Test that we can reverse-next over the dynamic linker's symbol +# lookup code. + +# check for btrace support +if { [skip_btrace_tests] } { return -1 } + +# start inferior +standard_testfile +if [prepare_for_testing $testfile.exp $testfile $srcfile {c++ debug}] { + return -1 +} +if ![runto_main] { + return -1 +} + +# trace the code for the call to test +gdb_test_no_output "record btrace" +gdb_test "next" ".*main\.2.*" + +# just dump the function-call-history to help debugging +gdb_test_no_output "set record function-call-history-size 0" +gdb_test "record function-call-history /cli 1" ".*" + +# check that we can reverse-next and next +gdb_test "reverse-next" ".*main\.1.*" +gdb_test "next" ".*main\.2.*" + +# now go into test and try to reverse-next and next over the library call +gdb_test "reverse-step" ".*test\.3.*" +gdb_test "reverse-step" ".*test\.2.*" +gdb_test "reverse-next" ".*test\.1.*" +gdb_test "next" ".*test\.2.*" diff --git a/gdb/testsuite/gdb.btrace/step.exp b/gdb/testsuite/gdb.btrace/step.exp new file mode 100644 index 0000000..7c34d25 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/step.exp @@ -0,0 +1,89 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. <markus.t.metzger@intel.com> +# +# 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 <http://www.gnu.org/licenses/>. + +# 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" + +proc check_replay_at { insn } { + gdb_test "info record" [join [list \ + "Active record target: record-btrace" \ + "Recorded 40 instructions in 16 functions for .*" \ + "Replay in progress\. At instruction $insn\." \ + ] "\r\n"] +} + +# let's start by stepping back into the function we just returned from +gdb_test "reverse-step" ".*fun4\.5.*" +with_test_prefix "reverse-step to 39" { check_replay_at 39 } + +# again +gdb_test "reverse-step" ".*fun3\.4.*" +with_test_prefix "reverse-step to 37" { check_replay_at 37 } + +# and again +gdb_test "reverse-step" ".*fun2\.3.*" +with_test_prefix "reverse-step to 35" { check_replay_at 35 } + +# once more +gdb_test "reverse-step" ".*fun1\.2.*" +with_test_prefix "reverse-step to 33" { check_replay_at 33 } + +# and out again the other side +gdb_test "reverse-step" ".*fun2\.2.*" +with_test_prefix "reverse-step to 30" { check_replay_at 30 } + +# once again +gdb_test "reverse-step" ".*fun3\.3.*" +with_test_prefix "reverse-step to 27" { check_replay_at 27 } + +# and back the way we came +gdb_test "step" ".*fun2\.2.*" +with_test_prefix "step to 30" { check_replay_at 30 } + +gdb_test "step" ".*fun1\.2.*" +with_test_prefix "step to 33" { check_replay_at 33 } + +gdb_test "step" ".*fun2\.3.*" +with_test_prefix "step to 35" { check_replay_at 35 } + +gdb_test "step" ".*fun3\.4.*" +with_test_prefix "step to 37" { check_replay_at 37 } + +gdb_test "step" ".*fun4\.5.*" +with_test_prefix "step to 39" { check_replay_at 39 } + +gdb_test "step" ".*main\.3.*" +gdb_test "info record" [join [list \ + "Active record target: record-btrace" \ + "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \ + ] "\r\n"] "step to live" diff --git a/gdb/testsuite/gdb.btrace/stepi.exp b/gdb/testsuite/gdb.btrace/stepi.exp new file mode 100644 index 0000000..fb12e28 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/stepi.exp @@ -0,0 +1,93 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2013 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. <markus.t.metzger@intel.com> +# +# 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 <http://www.gnu.org/licenses/>. + +# 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 +} + +proc check_replay_at { insn } { + gdb_test "info record" [join [list \ + "Active record target: record-btrace" \ + "Recorded 40 instructions in 16 functions for .*" \ + "Replay in progress\. At instruction $insn\." \ + ] "\r\n"] +} + +# 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.*" +gdb_test "reverse-stepi" ".*fun4\.5.*" + +# let's check where we are in the trace +with_test_prefix "reverse-stepi to 39" { check_replay_at 39 } + +# let's step forward and check again +gdb_test "stepi" ".*fun4\.5.*" +with_test_prefix "stepi to 40" { check_replay_at 40 } + +# with the next step, we stop replaying +gdb_test "stepi" ".*main\.3.*" +gdb_test "info record" [join [list \ + "Active record target: record-btrace" \ + "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \ + ] "\r\n"] "stepi to live" + +# let's step from a goto position somewhere in the middle +gdb_test "record goto 22" ".*fun3\.2.*" +with_test_prefix "goto 22" { check_replay_at 22 } + +gdb_test "stepi" ".*fun1\.1.*" +with_test_prefix "stepi to 23" { check_replay_at 23 } + +# and back again +gdb_test "reverse-stepi" ".*fun3\.2.*" +gdb_test "reverse-stepi" ".*fun3\.1.*" +with_test_prefix "reverse-stepi to 21" { check_replay_at 21 } + +# let's try to step off the left end +gdb_test "record goto begin" ".*main\.2.*" +with_test_prefix "goto begin" { check_replay_at 1 } + +gdb_test "reverse-stepi" "No more reverse-execution history\.\r\n.*main\.2.*" +gdb_test "reverse-stepi" "No more reverse-execution history\.\r\n.*main\.2.*" +with_test_prefix "reverse-stepi at begin" { check_replay_at 1 } + +# we can step forward, though +gdb_test "stepi" ".*fun4\.1.*" +with_test_prefix "stepi to 2" { check_replay_at 2 } + +# let's try to step off the left end again +gdb_test "reverse-stepi" ".*main\.2.*" +gdb_test "reverse-stepi" "No more reverse-execution history\.\r\n.*main\.2.*" +gdb_test "reverse-stepi" "No more reverse-execution history\.\r\n.*main\.2.*" +with_test_prefix "reverse-stepi at begin" { check_replay_at 1 } diff --git a/gdb/testsuite/gdb.btrace/tailcall.exp b/gdb/testsuite/gdb.btrace/tailcall.exp index 23988f2..ce1f053 100644 --- a/gdb/testsuite/gdb.btrace/tailcall.exp +++ b/gdb/testsuite/gdb.btrace/tailcall.exp @@ -77,3 +77,16 @@ gdb_test "backtrace" [join [list \ # walk the backtrace gdb_test "up" "#1\[^\r\n\]*foo \\(\\) at x86-tailcall.c:29\r\n.*" "up to foo" gdb_test "up" "#2\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" "up to main" +gdb_test "down" "#1\[^\r\n\]*foo \\(\\) at x86-tailcall.c:29\r\n.*" "down to foo" + +# test stepping into and out of tailcalls. +gdb_test "finish" "\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" +gdb_test "reverse-step" "\[^\r\n\]*bar \\(\\) at x86-tailcall.c:24\r\n.*" +gdb_test "reverse-finish" "\[^\r\n\]*foo \\(\\) at x86-tailcall.c:29\r\n.*" +gdb_test "reverse-step" "\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" +gdb_test "next" "\[^\r\n\]*main \\(\\) at x86-tailcall.c:39\r\n.*" +gdb_test "reverse-next" "\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" +gdb_test "step" "\[^\r\n\]*foo \\(\\) at x86-tailcall.c:29\r\n.*" +gdb_test "finish" "\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" +gdb_test "reverse-step" "\[^\r\n\]*bar \\(\\) at x86-tailcall.c:24\r\n.*" +gdb_test "finish" "\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" |