This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 10/12] record-btrace: indicate gaps
- From: Markus Metzger <markus dot t dot metzger at intel dot com>
- To: palves at redhat dot com
- Cc: gdb-patches at sourceware dot org
- Date: Mon, 14 Jul 2014 15:56:34 +0200
- Subject: [PATCH 10/12] record-btrace: indicate gaps
- Authentication-results: sourceware.org; auth=none
- References: <1405346196-1804-1-git-send-email-markus dot t dot metzger at intel dot com>
Indicate gaps in the trace due to decode errors. Internally, a gap is
represented as a btrace function segment without instructions and with a
non-zero format-specific error code.
Show the gap when traversing the instruction or function call history.
Also indicate gaps in "info record".
It looks like this:
(gdb) info record
Active record target: record-btrace
Recording format: Intel(R) Branch Trace Store.
Buffer size: 64KB.
Recorded 32 instructions in 5 functions (1 gaps) for thread 1 (process 7182).
(gdb) record function-call-history /cli
1 fib inst 1,9 at src/fib.c:9,14
2 fib inst 10,20 at src/fib.c:6,14
3 [decode error (1): instruction overflow]
4 fib inst 21,28 at src/fib.c:11,14
5 fib inst 29,33 at src/fib.c:6,9
(gdb) record instruction-history 20,22
20 0x000000000040062f <fib+47>: sub $0x1,%rax
[decode error (1): instruction overflow]
21 0x0000000000400613 <fib+19>: add $0x1,%rax
22 0x0000000000400617 <fib+23>: mov %rax,0x200a3a(%rip)
(gdb)
Gaps are ignored during reverse execution and replay.
2014-07-14 Markus Metzger <markus.t.metzger@intel.com>
* btrace.c (ftrace_find_call): Skip gaps.
(ftrace_new_gap): New.
(ftrace_update_function): Create new function after gap.
(btrace_compute_ftrace_bts): Create gap on error.
(btrace_clear): Reset the number of gaps.
(btrace_insn_get): Return NULL if the iterator points to a gap.
(btrace_insn_number): Return zero if the iterator points to a gap.
(btrace_insn_end): Assert that the last function is not empty.
(btrace_insn_next, btrace_insn_prev, btrace_insn_cmp): Handle gaps.
(btrace_find_insn_by_number): Assert that the found iterator does
not point to a gap.
(btrace_call_next, btrace_call_prev): Assert that the last function
is not a gap.
* btrace.h (btrace_bts_error): New.
(btrace_function): Update comment.
(btrace_function) <insn, insn_offset, number>: Update comment.
(btrace_function) <errcode>: New.
(btrace_thread_info) <ngaps>: New.
(btrace_thread_info) <replay>: Update comment.
(btrace_insn_get): Update comment.
* record-btrace.c (btrace_ui_out_decode_error): New.
(record_btrace_info): Print number of gaps.
(btrace_insn_history, btrace_call_history): Call
btrace_ui_out_decode_error for gaps.
(record_btrace_step_thread): Skip gaps.
testsuite/
* gdb.btrace/buffer-size.exp: Update "info record" output.
* gdb.btrace/delta.exp: Update "info record" output.
* gdb.btrace/enable.exp: Update "info record" output.
* gdb.btrace/finish.exp: Update "info record" output.
* gdb.btrace/instruction_history.exp: Update "info record" output.
* gdb.btrace/next.exp: Update "info record" output.
* gdb.btrace/nexti.exp: Update "info record" output.
* gdb.btrace/step.exp: Update "info record" output.
* gdb.btrace/stepi.exp: Update "info record" output.
* gdb.btrace/nohist.exp: Update "info record" output.
---
gdb/btrace.c | 135 +++++++++++++++++--
gdb/btrace.h | 40 +++++-
gdb/record-btrace.c | 160 ++++++++++++++++++-----
gdb/testsuite/gdb.btrace/buffer-size.exp | 4 +-
gdb/testsuite/gdb.btrace/delta.exp | 8 +-
gdb/testsuite/gdb.btrace/enable.exp | 2 +-
gdb/testsuite/gdb.btrace/finish.exp | 2 +-
gdb/testsuite/gdb.btrace/instruction_history.exp | 2 +-
gdb/testsuite/gdb.btrace/next.exp | 4 +-
gdb/testsuite/gdb.btrace/nexti.exp | 4 +-
gdb/testsuite/gdb.btrace/nohist.exp | 2 +-
gdb/testsuite/gdb.btrace/step.exp | 4 +-
gdb/testsuite/gdb.btrace/stepi.exp | 4 +-
13 files changed, 306 insertions(+), 65 deletions(-)
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 0171352..517c73a 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -336,8 +336,9 @@ ftrace_find_call (struct btrace_function *bfun)
{
struct btrace_insn *last;
- /* We do not allow empty function segments. */
- gdb_assert (!VEC_empty (btrace_insn_s, bfun->insn));
+ /* Skip gaps. */
+ if (bfun->errcode != 0)
+ continue;
last = VEC_last (btrace_insn_s, bfun->insn);
@@ -446,6 +447,32 @@ ftrace_new_switch (struct btrace_function *prev,
return bfun;
}
+/* Add a new function segment for a gap in the trace due to a decode error.
+ PREV is the chronologically preceding function segment.
+ ERRCODE is the format-specific error code. */
+
+static struct btrace_function *
+ftrace_new_gap (struct btrace_function *prev, int errcode)
+{
+ struct btrace_function *bfun;
+
+ /* We hijack prev if it was empty. */
+ if (prev != NULL && prev->errcode == 0
+ && VEC_empty (btrace_insn_s, prev->insn))
+ bfun = prev;
+ else
+ bfun = ftrace_new_function (prev, NULL, NULL);
+
+ /* This is a gap in the trace. The call stack will likely be wrong at this
+ point. We keep the function level, though. */
+ bfun->level = prev != NULL ? prev->level : 0;
+ bfun->errcode = errcode;
+
+ ftrace_debug (bfun, "new gap");
+
+ return bfun;
+}
+
/* Update BFUN with respect to the instruction at PC. This may create new
function segments.
Return the chronologically latest function segment, never NULL. */
@@ -468,8 +495,8 @@ ftrace_update_function (struct btrace_function *bfun, CORE_ADDR pc)
if (fun == NULL && mfun == NULL)
DEBUG_FTRACE ("no symbol at %s", core_addr_to_string_nz (pc));
- /* If we didn't have a function before, we create one. */
- if (bfun == NULL)
+ /* If we didn't have a function or if we had a gap before, we create one. */
+ if (bfun == NULL || bfun->errcode != 0)
return ftrace_new_function (bfun, mfun, fun);
/* Check the last instruction, if we have one.
@@ -595,13 +622,14 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
struct btrace_thread_info *btinfo;
struct btrace_function *begin, *end;
struct gdbarch *gdbarch;
- unsigned int blk;
+ unsigned int blk, ngaps;
int level;
gdbarch = target_gdbarch ();
btinfo = &tp->btrace;
begin = btinfo->begin;
end = btinfo->end;
+ ngaps = btinfo->ngaps;
level = begin != NULL ? -btinfo->level : INT_MAX;
blk = VEC_length (btrace_block_s, btrace->blocks);
@@ -626,6 +654,11 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
{
warning (_("Recorded trace may be corrupted around %s."),
core_addr_to_string_nz (pc));
+
+ /* Indicate the gap in the trace. */
+ end = ftrace_new_gap (end, BDE_BTS_OVERFLOW);
+ ngaps += 1;
+
break;
}
@@ -658,6 +691,11 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
{
warning (_("Recorded trace may be incomplete around %s."),
core_addr_to_string_nz (pc));
+
+ /* Indicate the gap in the trace. */
+ end = ftrace_new_gap (end, BDE_BTS_INSN_SIZE);
+ ngaps += 1;
+
break;
}
@@ -676,6 +714,7 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
btinfo->begin = begin;
btinfo->end = end;
+ btinfo->ngaps = ngaps;
/* LEVEL is the minimal function level of all btrace function segments.
Define the global level offset to -LEVEL so all function levels are
@@ -1007,6 +1046,7 @@ btrace_clear (struct thread_info *tp)
btinfo->begin = NULL;
btinfo->end = NULL;
+ btinfo->ngaps = 0;
btrace_clear_history (btinfo);
}
@@ -1205,6 +1245,10 @@ btrace_insn_get (const struct btrace_insn_iterator *it)
index = it->index;
bfun = it->function;
+ /* Check if the iterator points to a gap in the trace. */
+ if (bfun->errcode != 0)
+ return NULL;
+
/* The index is within the bounds of this function's instruction vector. */
end = VEC_length (btrace_insn_s, bfun->insn);
gdb_assert (0 < end);
@@ -1221,6 +1265,11 @@ btrace_insn_number (const struct btrace_insn_iterator *it)
const struct btrace_function *bfun;
bfun = it->function;
+
+ /* Return zero if the iterator points to a gap in the trace. */
+ if (bfun->errcode != 0)
+ return 0;
+
return bfun->insn_offset + it->index;
}
@@ -1256,6 +1305,7 @@ btrace_insn_end (struct btrace_insn_iterator *it,
/* The last instruction in the last function is the current instruction.
We point to it - it is one past the end of the execution trace. */
length = VEC_length (btrace_insn_s, bfun->insn);
+ gdb_assert (length > 0);
it->function = bfun;
it->index = length - 1;
@@ -1279,6 +1329,23 @@ btrace_insn_next (struct btrace_insn_iterator *it, unsigned int stride)
end = VEC_length (btrace_insn_s, bfun->insn);
+ /* An empty function segment represents a gap in the trace. We count
+ it as one instruction. */
+ if (end == 0)
+ {
+ stride -= 1;
+ steps += 1;
+
+ bfun = bfun->flow.next;
+ index = 0;
+
+ /* There won't be a gap at the end since we will always add
+ an entry for the current PC. */
+ gdb_assert (bfun != NULL);
+
+ continue;
+ }
+
gdb_assert (0 < end);
gdb_assert (index < end);
@@ -1353,12 +1420,20 @@ btrace_insn_prev (struct btrace_insn_iterator *it, unsigned int stride)
bfun = prev;
index = VEC_length (btrace_insn_s, bfun->insn);
- /* There is at least one instruction in this function segment. */
- gdb_assert (index > 0);
+ /* An empty function segment represents a gap in the trace. We count
+ it as one instruction. */
+ if (index == 0)
+ {
+ stride -= 1;
+ steps += 1;
+
+ continue;
+ }
}
/* Advance the iterator as far as possible within this segment. */
adv = min (index, stride);
+
stride -= adv;
index -= adv;
steps += adv;
@@ -1385,6 +1460,37 @@ btrace_insn_cmp (const struct btrace_insn_iterator *lhs,
lnum = btrace_insn_number (lhs);
rnum = btrace_insn_number (rhs);
+ /* A gap has an instruction number of zero. Things are getting more
+ complicated if gaps are involved.
+
+ We take the instruction number offset from the iterator's function.
+ This is the number of the first instruction after the gap.
+
+ This is OK as long as both lhs and rhs point to gaps. If only one of
+ them does, we need to adjust the number based on the other's regular
+ instruction number. Otherwise, a gap might compare equal to an
+ instruction. */
+
+ if (lnum == 0 && rnum == 0)
+ {
+ lnum = lhs->function->insn_offset;
+ rnum = rhs->function->insn_offset;
+ }
+ else if (lnum == 0)
+ {
+ lnum = lhs->function->insn_offset;
+
+ if (lnum == rnum)
+ lnum -= 1;
+ }
+ else if (rnum == 0)
+ {
+ rnum = rhs->function->insn_offset;
+
+ if (rnum == lnum)
+ rnum -= 1;
+ }
+
return (int) (lnum - rnum);
}
@@ -1396,7 +1502,7 @@ btrace_find_insn_by_number (struct btrace_insn_iterator *it,
unsigned int number)
{
const struct btrace_function *bfun;
- unsigned int end;
+ unsigned int end, length;
for (bfun = btinfo->end; bfun != NULL; bfun = bfun->flow.prev)
if (bfun->insn_offset <= number)
@@ -1405,7 +1511,12 @@ btrace_find_insn_by_number (struct btrace_insn_iterator *it,
if (bfun == NULL)
return 0;
- end = bfun->insn_offset + VEC_length (btrace_insn_s, bfun->insn);
+ /* Since we're searching backwards from the end, we will never find gaps;
+ we will already stop at the function segment succeeding a gap. */
+ length = VEC_length (btrace_insn_s, bfun->insn);
+ gdb_assert (length > 0);
+
+ end = bfun->insn_offset + length;
if (end <= number)
return 0;
@@ -1507,6 +1618,9 @@ btrace_call_next (struct btrace_call_iterator *it, unsigned int stride)
insns = VEC_length (btrace_insn_s, bfun->insn);
if (insns == 1)
steps -= 1;
+
+ /* We won't have gaps at the end. */
+ gdb_assert (insns > 0);
}
if (stride == steps)
@@ -1547,6 +1661,9 @@ btrace_call_prev (struct btrace_call_iterator *it, unsigned int stride)
if (insns == 1)
bfun = bfun->flow.prev;
+ /* We won't have gaps at the end. */
+ gdb_assert (insns > 0);
+
if (bfun == NULL)
return 0;
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 3de7b73..7b524fa 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -86,12 +86,25 @@ enum btrace_function_flag
BFUN_UP_LINKS_TO_TAILCALL = (1 << 1)
};
+/* Decode errors for the BTS recording format. */
+enum btrace_bts_error
+{
+ /* The instruction trace overflowed the end of the trace block. */
+ BDE_BTS_OVERFLOW = 1,
+
+ /* The instruction size could not be determined. */
+ BDE_BTS_INSN_SIZE
+};
+
/* A branch trace function segment.
This represents a function segment in a branch trace, i.e. a consecutive
number of instructions belonging to the same function.
- We do not allow function segments without any instructions. */
+ In case of decode errors, we add an empty function segment to indicate
+ the gap in the trace.
+
+ We do not allow function segments without instructions otherwise. */
struct btrace_function
{
/* The full and minimal symbol for the function. Both may be NULL. */
@@ -110,14 +123,23 @@ struct btrace_function
struct btrace_function *up;
/* The instructions in this function segment.
- The instruction vector will never be empty. */
+ The instruction vector will be empty if the function segment
+ represents a decode error. */
VEC (btrace_insn_s) *insn;
+ /* The error code of a decode error that led to a gap.
+ Must be zero unless INSN is empty; non-zero otherwise. */
+ int errcode;
+
/* The instruction number offset for the first instruction in this
- function segment. */
+ function segment.
+ If INSN is empty this is the insn_offset of the succeding function
+ segment in control-flow order. */
unsigned int insn_offset;
- /* The function number in control-flow order. */
+ /* The function number in control-flow order.
+ If INSN is empty indicating a gap in the trace due to a decode error,
+ we still count the gap as a function. */
unsigned int number;
/* The function level in a back trace across the entire branch trace.
@@ -223,6 +245,9 @@ struct btrace_thread_info
becomes zero. */
int level;
+ /* The number of gaps in the trace. */
+ unsigned int ngaps;
+
/* A bit-vector of btrace_thread_flag. */
enum btrace_thread_flag flags;
@@ -232,7 +257,9 @@ struct btrace_thread_info
/* The function call history iterator. */
struct btrace_call_history *call_history;
- /* The current replay position. NULL if not replaying. */
+ /* The current replay position. NULL if not replaying.
+ Gaps are skipped during replay, so REPLAY always points to a valid
+ instruction. */
struct btrace_insn_iterator *replay;
};
@@ -270,7 +297,8 @@ extern void parse_xml_btrace (struct btrace_data *data, const char *xml);
extern void parse_xml_btrace_conf (struct btrace_config *conf, const char *xml);
/* Dereference a branch trace instruction iterator. Return a pointer to the
- instruction the iterator points to. */
+ instruction the iterator points to.
+ May return NULL if the iterator points to a gap in the trace. */
extern const struct btrace_insn *
btrace_insn_get (const struct btrace_insn_iterator *);
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index f653d6b..418bb92 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -351,7 +351,7 @@ record_btrace_info (struct target_ops *self)
struct btrace_thread_info *btinfo;
const struct btrace_config *conf;
struct thread_info *tp;
- unsigned int insns, calls;
+ unsigned int insns, calls, gaps;
DEBUG ("info");
@@ -369,6 +369,7 @@ record_btrace_info (struct target_ops *self)
insns = 0;
calls = 0;
+ gaps = 0;
if (!btrace_is_empty (tp))
{
@@ -380,19 +381,67 @@ record_btrace_info (struct target_ops *self)
calls = btrace_call_number (&call);
btrace_insn_end (&insn, btinfo);
- btrace_insn_prev (&insn, 1);
insns = btrace_insn_number (&insn);
+ /* The last instruction does not really belong to the trace. */
+ insns -= 1;
+
+ gaps = btinfo->ngaps;
}
- printf_unfiltered (_("Recorded %u instructions in %u functions for thread "
- "%d (%s).\n"), insns, calls, tp->num,
- target_pid_to_str (tp->ptid));
+ printf_unfiltered (_("Recorded %u instructions in %u functions (%u gaps) "
+ "for thread %d (%s).\n"), insns, calls, gaps,
+ tp->num, target_pid_to_str (tp->ptid));
if (btrace_is_replaying (tp))
printf_unfiltered (_("Replay in progress. At instruction %u.\n"),
btrace_insn_number (btinfo->replay));
}
+/* Print a decode error. */
+
+static void
+btrace_ui_out_decode_error (struct ui_out *uiout, int errcode,
+ enum btrace_format format)
+{
+ const char *errstr;
+ int is_error;
+
+ errstr = _("unknown");
+ is_error = 1;
+
+ switch (format)
+ {
+ default:
+ break;
+
+ case BTRACE_FORMAT_BTS:
+ switch (errcode)
+ {
+ default:
+ break;
+
+ case BDE_BTS_OVERFLOW:
+ errstr = _("instruction overflow");
+ break;
+
+ case BDE_BTS_INSN_SIZE:
+ errstr = _("unknown instruction");
+ break;
+ }
+ break;
+ }
+
+ ui_out_text (uiout, _("["));
+ if (is_error)
+ {
+ ui_out_text (uiout, _("decode error ("));
+ ui_out_field_int (uiout, "errcode", errcode);
+ ui_out_text (uiout, _("): "));
+ }
+ ui_out_text (uiout, errstr);
+ ui_out_text (uiout, _("]\n"));
+}
+
/* Print an unsigned int. */
static void
@@ -405,6 +454,7 @@ ui_out_field_uint (struct ui_out *uiout, const char *fld, unsigned int val)
static void
btrace_insn_history (struct ui_out *uiout,
+ const struct btrace_thread_info *btinfo,
const struct btrace_insn_iterator *begin,
const struct btrace_insn_iterator *end, int flags)
{
@@ -422,13 +472,30 @@ btrace_insn_history (struct ui_out *uiout,
insn = btrace_insn_get (&it);
- /* Print the instruction index. */
- ui_out_field_uint (uiout, "index", btrace_insn_number (&it));
- ui_out_text (uiout, "\t");
+ /* A NULL instruction indicates a gap in the trace. */
+ if (insn == NULL)
+ {
+ const struct btrace_config *conf;
+
+ conf = btrace_conf (btinfo);
- /* Disassembly with '/m' flag may not produce the expected result.
- See PR gdb/11833. */
- gdb_disassembly (gdbarch, uiout, NULL, flags, 1, insn->pc, insn->pc + 1);
+ /* We have trace so we must have a configuration. */
+ gdb_assert (conf != NULL);
+
+ btrace_ui_out_decode_error (uiout, it.function->errcode,
+ conf->format);
+ }
+ else
+ {
+ /* Print the instruction index. */
+ ui_out_field_uint (uiout, "index", btrace_insn_number (&it));
+ ui_out_text (uiout, "\t");
+
+ /* Disassembly with '/m' flag may not produce the expected result.
+ See PR gdb/11833. */
+ gdb_disassembly (gdbarch, uiout, NULL, flags, 1, insn->pc,
+ insn->pc + 1);
+ }
}
}
@@ -505,7 +572,7 @@ record_btrace_insn_history (struct target_ops *self, int size, int flags)
}
if (covered > 0)
- btrace_insn_history (uiout, &begin, &end, flags);
+ btrace_insn_history (uiout, btinfo, &begin, &end, flags);
else
{
if (size < 0)
@@ -565,7 +632,7 @@ record_btrace_insn_history_range (struct target_ops *self,
btrace_insn_next (&end, 1);
}
- btrace_insn_history (uiout, &begin, &end, flags);
+ btrace_insn_history (uiout, btinfo, &begin, &end, flags);
btrace_set_insn_history (btinfo, &begin, &end);
do_cleanups (uiout_cleanup);
@@ -706,6 +773,21 @@ btrace_call_history (struct ui_out *uiout,
ui_out_field_uint (uiout, "index", bfun->number);
ui_out_text (uiout, "\t");
+ /* Indicate gaps in the trace. */
+ if (bfun->errcode != 0)
+ {
+ const struct btrace_config *conf;
+
+ conf = btrace_conf (btinfo);
+
+ /* We have trace so we must have a configuration. */
+ gdb_assert (conf != NULL);
+
+ btrace_ui_out_decode_error (uiout, bfun->errcode, conf->format);
+
+ continue;
+ }
+
if ((flags & RECORD_PRINT_INDENT_CALLS) != 0)
{
int level = bfun->level + btinfo->level, i;
@@ -1736,9 +1818,13 @@ record_btrace_step_thread (struct thread_info *tp)
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);
+ /* We are always able to step at least once - to the last instruction.
+ Skip gaps during replay. */
+ do
+ {
+ steps = btrace_insn_next (replay, 1);
+ gdb_assert (steps == 1);
+ } while (btrace_insn_get (replay) == NULL);
/* Determine the end of the instruction trace. */
btrace_insn_end (&end, btinfo);
@@ -1754,10 +1840,14 @@ record_btrace_step_thread (struct thread_info *tp)
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 ();
+ /* If we can't step any further, we reached the end of the history.
+ Skip gaps during replay. */
+ do
+ {
+ steps = btrace_insn_prev (replay, 1);
+ if (steps == 0)
+ return btrace_step_no_history ();
+ } while (btrace_insn_get (replay) == NULL);
return btrace_step_stopped ();
@@ -1776,9 +1866,15 @@ record_btrace_step_thread (struct thread_info *tp)
{
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 are always able to step at least once - to the last instruction.
+ Skip gaps during replay. */
+ do
+ {
+ steps = btrace_insn_next (replay, 1);
+ gdb_assert (steps == 1);
+
+ insn = btrace_insn_get (replay);
+ } while (insn == NULL);
/* We stop replaying if we reached the end of the trace. */
if (btrace_insn_cmp (replay, &end) == 0)
@@ -1787,9 +1883,6 @@ record_btrace_step_thread (struct thread_info *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));
@@ -1810,13 +1903,16 @@ record_btrace_step_thread (struct thread_info *tp)
{
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 ();
+ /* If we can't step any further, we reached the end of the history.
+ Skip gaps during replay. */
+ do
+ {
+ steps = btrace_insn_prev (replay, 1);
+ if (steps == 0)
+ return btrace_step_no_history ();
- insn = btrace_insn_get (replay);
- gdb_assert (insn);
+ insn = btrace_insn_get (replay);
+ } while (insn == NULL);
DEBUG ("reverse-stepping %d (%s) ... %s", tp->num,
target_pid_to_str (tp->ptid),
diff --git a/gdb/testsuite/gdb.btrace/buffer-size.exp b/gdb/testsuite/gdb.btrace/buffer-size.exp
index a13b950..68a9563 100644
--- a/gdb/testsuite/gdb.btrace/buffer-size.exp
+++ b/gdb/testsuite/gdb.btrace/buffer-size.exp
@@ -39,7 +39,7 @@ gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: Intel\\\(R\\\) Branch Trace Store\." \
"Buffer size: 4KB\." \
- "Recorded 0 instructions in 0 functions for \[^\\\r\\\n\]*" \
+ "Recorded 0 instructions in 0 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
] "\r\n"]
gdb_test "record stop" ".*"
@@ -52,6 +52,6 @@ gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: Intel\\\(R\\\) Branch Trace Store\." \
"Buffer size: .*\." \
- "Recorded 0 instructions in 0 functions for \[^\\\r\\\n\]*" \
+ "Recorded 0 instructions in 0 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
] "\r\n"]
gdb_test "record stop" ".*"
diff --git a/gdb/testsuite/gdb.btrace/delta.exp b/gdb/testsuite/gdb.btrace/delta.exp
index 71ccf07..d594102 100644
--- a/gdb/testsuite/gdb.btrace/delta.exp
+++ b/gdb/testsuite/gdb.btrace/delta.exp
@@ -40,7 +40,7 @@ with_test_prefix "no trace" {
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 0 instructions in 0 functions for .*" \
+ "Recorded 0 instructions in 0 functions \\\(0 gaps\\\) for .*" \
] "\r\n"]
gdb_test "record instruction-history" "No trace\."
gdb_test "record function-call-history" "No trace\."
@@ -53,7 +53,7 @@ proc check_trace {} {
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 1 instructions in 1 functions for .*" \
+ "Recorded 1 instructions in 1 functions \\\(0 gaps\\\) for .*" \
] "\r\n"]
gdb_test "record instruction-history /f 1" \
"1\t 0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tmov *\\\$0x0,%eax\r"
@@ -74,7 +74,7 @@ gdb_test "reverse-stepi"
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 1 instructions in 1 functions for .*" \
+ "Recorded 1 instructions in 1 functions \\\(0 gaps\\\) for .*" \
"Replay in progress\. At instruction 1\." \
] "\r\n"] "reverse-stepi"
@@ -83,5 +83,5 @@ gdb_test "stepi"
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 1 instructions in 1 functions for .*" \
+ "Recorded 1 instructions in 1 functions \\\(0 gaps\\\) for .*" \
] "\r\n"] "and back"
diff --git a/gdb/testsuite/gdb.btrace/enable.exp b/gdb/testsuite/gdb.btrace/enable.exp
index 2926c0f..37203a3 100644
--- a/gdb/testsuite/gdb.btrace/enable.exp
+++ b/gdb/testsuite/gdb.btrace/enable.exp
@@ -58,7 +58,7 @@ gdb_test "record full" "The process is already being recorded\\. Use \"record s
# no trace recorded yet
gdb_test "info record" "Active record target: record-btrace\r
.*\r
-Recorded 0 instructions in 0 functions for thread 1.*\\." "info record without trace"
+Recorded 0 instructions in 0 functions \\\(0 gaps\\\) for thread 1.*\\." "info record without trace"
# stop btrace record
gdb_test "record stop" "Process record is stopped and all execution logs are deleted\\." "record stop"
diff --git a/gdb/testsuite/gdb.btrace/finish.exp b/gdb/testsuite/gdb.btrace/finish.exp
index 593055b..c55c9de 100644
--- a/gdb/testsuite/gdb.btrace/finish.exp
+++ b/gdb/testsuite/gdb.btrace/finish.exp
@@ -38,7 +38,7 @@ proc check_replay_at { insn } {
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 40 instructions in 16 functions for .*" \
+ "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for .*" \
"Replay in progress\. At instruction $insn\." \
] "\r\n"]
}
diff --git a/gdb/testsuite/gdb.btrace/instruction_history.exp b/gdb/testsuite/gdb.btrace/instruction_history.exp
index 5a77357..e61a297 100644
--- a/gdb/testsuite/gdb.btrace/instruction_history.exp
+++ b/gdb/testsuite/gdb.btrace/instruction_history.exp
@@ -50,7 +50,7 @@ gdb_continue_to_breakpoint "cont to $bp_location" ".*$srcfile2:$bp_location.*"
set traced {}
set testname "determine number of recorded instructions"
gdb_test_multiple "info record" $testname {
- -re "Active record target: record-btrace\r\n.*\r\nRecorded \(\[0-9\]*\) instructions in \(\[0-9\]*\) functions for thread 1 .*\\.\r\n$gdb_prompt $" {
+ -re "Active record target: record-btrace\r\n.*\r\nRecorded \(\[0-9\]*\) instructions in \(\[0-9\]*\) functions \\\(0 gaps\\\) for thread 1 .*\\.\r\n$gdb_prompt $" {
set traced $expect_out(1,string)
pass $testname
}
diff --git a/gdb/testsuite/gdb.btrace/next.exp b/gdb/testsuite/gdb.btrace/next.exp
index 1bc8125..7bf7cc9 100644
--- a/gdb/testsuite/gdb.btrace/next.exp
+++ b/gdb/testsuite/gdb.btrace/next.exp
@@ -38,7 +38,7 @@ proc check_replay_at { insn } {
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 40 instructions in 16 functions for .*" \
+ "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for .*" \
"Replay in progress\. At instruction $insn\." \
] "\r\n"]
}
@@ -57,7 +57,7 @@ gdb_test "next" ".*main\.3.*"
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
+ "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
] "\r\n"] "next back"
# let's go somewhere where we can step some more
diff --git a/gdb/testsuite/gdb.btrace/nexti.exp b/gdb/testsuite/gdb.btrace/nexti.exp
index a263607..2cdaf73 100644
--- a/gdb/testsuite/gdb.btrace/nexti.exp
+++ b/gdb/testsuite/gdb.btrace/nexti.exp
@@ -38,7 +38,7 @@ proc check_replay_at { insn } {
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 40 instructions in 16 functions for .*" \
+ "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for .*" \
"Replay in progress\. At instruction $insn\." \
] "\r\n"]
}
@@ -57,7 +57,7 @@ gdb_test "nexti" ".*main\.3.*" "next, 1.5"
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
+ "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
] "\r\n"] "nexti back"
# let's go somewhere where we can step some more
diff --git a/gdb/testsuite/gdb.btrace/nohist.exp b/gdb/testsuite/gdb.btrace/nohist.exp
index 4c1d875..6925193 100644
--- a/gdb/testsuite/gdb.btrace/nohist.exp
+++ b/gdb/testsuite/gdb.btrace/nohist.exp
@@ -34,7 +34,7 @@ proc check_not_replaying {} {
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 0 instructions in 0 functions for \[^\\\r\\\n\]*" \
+ "Recorded 0 instructions in 0 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
] "\r\n"]
}
diff --git a/gdb/testsuite/gdb.btrace/step.exp b/gdb/testsuite/gdb.btrace/step.exp
index 483166b..86ffa0a 100644
--- a/gdb/testsuite/gdb.btrace/step.exp
+++ b/gdb/testsuite/gdb.btrace/step.exp
@@ -38,7 +38,7 @@ proc check_replay_at { insn } {
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 40 instructions in 16 functions for .*" \
+ "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for .*" \
"Replay in progress\. At instruction $insn\." \
] "\r\n"]
}
@@ -87,5 +87,5 @@ gdb_test "step" ".*main\.3.*"
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
+ "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
] "\r\n"] "step to live"
diff --git a/gdb/testsuite/gdb.btrace/stepi.exp b/gdb/testsuite/gdb.btrace/stepi.exp
index cce41e6..5c9625c 100644
--- a/gdb/testsuite/gdb.btrace/stepi.exp
+++ b/gdb/testsuite/gdb.btrace/stepi.exp
@@ -36,7 +36,7 @@ proc check_replay_at { insn } {
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 40 instructions in 16 functions for .*" \
+ "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for .*" \
"Replay in progress\. At instruction $insn\." \
] "\r\n"]
}
@@ -61,7 +61,7 @@ gdb_test "stepi" ".*main\.3.*"
gdb_test "info record" [join [list \
"Active record target: record-btrace" \
"Recording format: .*" \
- "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
+ "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
] "\r\n"] "stepi to live"
# let's step from a goto position somewhere in the middle
--
1.8.3.1