From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21245 invoked by alias); 20 Nov 2014 17:32:25 -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 21236 invoked by uid 89); 20 Nov 2014 17:32:25 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.8 required=5.0 tests=AWL,BAYES_00,SPF_PASS,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mga11.intel.com Received: from mga11.intel.com (HELO mga11.intel.com) (192.55.52.93) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 20 Nov 2014 17:32:21 +0000 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP; 20 Nov 2014 09:31:40 -0800 X-ExtLoop1: 1 Received: from irsmsx109.ger.corp.intel.com ([163.33.3.23]) by fmsmga001.fm.intel.com with ESMTP; 20 Nov 2014 09:30:15 -0800 Received: from irsmsx104.ger.corp.intel.com ([169.254.5.209]) by IRSMSX109.ger.corp.intel.com ([169.254.13.244]) with mapi id 14.03.0195.001; Thu, 20 Nov 2014 17:30:10 +0000 From: "Metzger, Markus T" To: "Eli Zaretskii (eliz@gnu.org)" CC: "gdb-patches@sourceware.org" , "palves@redhat.com" Subject: RE: [PATCH v2 11/13] record-btrace: indicate gaps Date: Thu, 20 Nov 2014 17:32:00 -0000 Message-ID: References: <1416480444-9943-1-git-send-email-markus.t.metzger@intel.com> <1416480444-9943-12-git-send-email-markus.t.metzger@intel.com> In-Reply-To: <1416480444-9943-12-git-send-email-markus.t.metzger@intel.com> Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes X-SW-Source: 2014-11/txt/msg00483.txt.bz2 Hello Eli, I forgot to CC you on this patch. It contains some user-visible strings. Thanks for your feedback on the other patch. Thanks, Markus. > -----Original Message----- > From: Metzger, Markus T > Sent: Thursday, November 20, 2014 11:47 AM > To: palves@redhat.com > Cc: gdb-patches@sourceware.org > Subject: [PATCH v2 11/13] record-btrace: indicate gaps >=20 > 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. >=20 > Show the gap when traversing the instruction or function call history. > Also indicate gaps in "info record". >=20 > It looks like this: >=20 > (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 : sub $0x1,%rax > [decode error (1): instruction overflow] > 21 0x0000000000400613 : add $0x1,%rax > 22 0x0000000000400617 : mov %rax,0x200a3a(%rip) > (gdb) >=20 > Gaps are ignored during reverse execution and replay. >=20 > 2014-11-20 Markus Metzger >=20 > * 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) : Update comment. > (btrace_function) : New. > (btrace_thread_info) : New. > (btrace_thread_info) : 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. >=20 > 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(-) >=20 > diff --git a/gdb/btrace.c b/gdb/btrace.c > index efd0572..91df7a0 100644 > --- a/gdb/btrace.c > +++ b/gdb/btrace.c > @@ -336,8 +336,9 @@ ftrace_find_call (struct btrace_function *bfun) > { > struct btrace_insn *last; >=20 > - /* We do not allow empty function segments. */ > - gdb_assert (!VEC_empty (btrace_insn_s, bfun->insn)); > + /* Skip gaps. */ > + if (bfun->errcode !=3D 0) > + continue; >=20 > last =3D VEC_last (btrace_insn_s, bfun->insn); >=20 > @@ -446,6 +447,32 @@ ftrace_new_switch (struct btrace_function *prev, > return bfun; > } >=20 > +/* Add a new function segment for a gap in the trace due to a decode err= or. > + 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 !=3D NULL && prev->errcode =3D=3D 0 > + && VEC_empty (btrace_insn_s, prev->insn)) > + bfun =3D prev; > + else > + bfun =3D 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 =3D prev !=3D NULL ? prev->level : 0; > + bfun->errcode =3D errcode; > + > + ftrace_debug (bfun, "new gap"); > + > + return bfun; > +} > + > /* Update BFUN with respect to the instruction at PC. This may create n= ew > 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 =3D=3D NULL && mfun =3D=3D NULL) > DEBUG_FTRACE ("no symbol at %s", core_addr_to_string_nz (pc)); >=20 > - /* If we didn't have a function before, we create one. */ > - if (bfun =3D=3D NULL) > + /* If we didn't have a function or if we had a gap before, we create o= ne. > */ > + if (bfun =3D=3D NULL || bfun->errcode !=3D 0) > return ftrace_new_function (bfun, mfun, fun); >=20 > /* Check the last instruction, if we have one. > @@ -597,13 +624,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; >=20 > gdbarch =3D target_gdbarch (); > btinfo =3D &tp->btrace; > begin =3D btinfo->begin; > end =3D btinfo->end; > + ngaps =3D btinfo->ngaps; > level =3D begin !=3D NULL ? -btinfo->level : INT_MAX; > blk =3D VEC_length (btrace_block_s, btrace->blocks); >=20 > @@ -628,6 +656,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 =3D ftrace_new_gap (end, BDE_BTS_OVERFLOW); > + ngaps +=3D 1; > + > break; > } >=20 > @@ -660,6 +693,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 =3D ftrace_new_gap (end, BDE_BTS_INSN_SIZE); > + ngaps +=3D 1; > + > break; > } >=20 > @@ -678,6 +716,7 @@ btrace_compute_ftrace_bts (struct thread_info *tp, >=20 > btinfo->begin =3D begin; > btinfo->end =3D end; > + btinfo->ngaps =3D ngaps; >=20 > /* LEVEL is the minimal function level of all btrace function segments. > Define the global level offset to -LEVEL so all function levels are > @@ -1009,6 +1048,7 @@ btrace_clear (struct thread_info *tp) >=20 > btinfo->begin =3D NULL; > btinfo->end =3D NULL; > + btinfo->ngaps =3D 0; >=20 > btrace_clear_history (btinfo); > } > @@ -1206,6 +1246,10 @@ btrace_insn_get (const struct btrace_insn_iterator > *it) > index =3D it->index; > bfun =3D it->function; >=20 > + /* Check if the iterator points to a gap in the trace. */ > + if (bfun->errcode !=3D 0) > + return NULL; > + > /* The index is within the bounds of this function's instruction vecto= r. */ > end =3D VEC_length (btrace_insn_s, bfun->insn); > gdb_assert (0 < end); > @@ -1222,6 +1266,11 @@ btrace_insn_number (const struct > btrace_insn_iterator *it) > const struct btrace_function *bfun; >=20 > bfun =3D it->function; > + > + /* Return zero if the iterator points to a gap in the trace. */ > + if (bfun->errcode !=3D 0) > + return 0; > + > return bfun->insn_offset + it->index; > } >=20 > @@ -1257,6 +1306,7 @@ btrace_insn_end (struct btrace_insn_iterator *it, > /* The last instruction in the last function is the current instructio= n. > We point to it - it is one past the end of the execution trace. */ > length =3D VEC_length (btrace_insn_s, bfun->insn); > + gdb_assert (length > 0); >=20 > it->function =3D bfun; > it->index =3D length - 1; > @@ -1280,6 +1330,23 @@ btrace_insn_next (struct btrace_insn_iterator *it, > unsigned int stride) >=20 > end =3D VEC_length (btrace_insn_s, bfun->insn); >=20 > + /* An empty function segment represents a gap in the trace. We co= unt > + it as one instruction. */ > + if (end =3D=3D 0) > + { > + stride -=3D 1; > + steps +=3D 1; > + > + bfun =3D bfun->flow.next; > + index =3D 0; > + > + /* There won't be a gap at the end since we will always add > + an entry for the current PC. */ > + gdb_assert (bfun !=3D NULL); > + > + continue; > + } > + > gdb_assert (0 < end); > gdb_assert (index < end); >=20 > @@ -1354,12 +1421,20 @@ btrace_insn_prev (struct btrace_insn_iterator > *it, unsigned int stride) > bfun =3D prev; > index =3D VEC_length (btrace_insn_s, bfun->insn); >=20 > - /* 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 =3D=3D 0) > + { > + stride -=3D 1; > + steps +=3D 1; > + > + continue; > + } > } >=20 > /* Advance the iterator as far as possible within this segment. */ > adv =3D min (index, stride); > + > stride -=3D adv; > index -=3D adv; > steps +=3D adv; > @@ -1386,6 +1461,37 @@ btrace_insn_cmp (const struct > btrace_insn_iterator *lhs, > lnum =3D btrace_insn_number (lhs); > rnum =3D btrace_insn_number (rhs); >=20 > + /* 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 =3D=3D 0 && rnum =3D=3D 0) > + { > + lnum =3D lhs->function->insn_offset; > + rnum =3D rhs->function->insn_offset; > + } > + else if (lnum =3D=3D 0) > + { > + lnum =3D lhs->function->insn_offset; > + > + if (lnum =3D=3D rnum) > + lnum -=3D 1; > + } > + else if (rnum =3D=3D 0) > + { > + rnum =3D rhs->function->insn_offset; > + > + if (rnum =3D=3D lnum) > + rnum -=3D 1; > + } > + > return (int) (lnum - rnum); > } >=20 > @@ -1397,7 +1503,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; >=20 > for (bfun =3D btinfo->end; bfun !=3D NULL; bfun =3D bfun->flow.prev) > if (bfun->insn_offset <=3D number) > @@ -1406,7 +1512,12 @@ btrace_find_insn_by_number (struct > btrace_insn_iterator *it, > if (bfun =3D=3D NULL) > return 0; >=20 > - end =3D bfun->insn_offset + VEC_length (btrace_insn_s, bfun->insn); > + /* Since we're searching backwards from the end, we will never find ga= ps; > + we will already stop at the function segment succeeding a gap. */ > + length =3D VEC_length (btrace_insn_s, bfun->insn); > + gdb_assert (length > 0); > + > + end =3D bfun->insn_offset + length; > if (end <=3D number) > return 0; >=20 > @@ -1508,6 +1619,9 @@ btrace_call_next (struct btrace_call_iterator *it, > unsigned int stride) > insns =3D VEC_length (btrace_insn_s, bfun->insn); > if (insns =3D=3D 1) > steps -=3D 1; > + > + /* We won't have gaps at the end. */ > + gdb_assert (insns > 0); > } >=20 > if (stride =3D=3D steps) > @@ -1548,6 +1662,9 @@ btrace_call_prev (struct btrace_call_iterator *it, > unsigned int stride) > if (insns =3D=3D 1) > bfun =3D bfun->flow.prev; >=20 > + /* We won't have gaps at the end. */ > + gdb_assert (insns > 0); > + > if (bfun =3D=3D NULL) > return 0; >=20 > diff --git a/gdb/btrace.h b/gdb/btrace.h > index 2082bc7..71be12e 100644 > --- a/gdb/btrace.h > +++ b/gdb/btrace.h > @@ -86,12 +86,25 @@ enum btrace_function_flag > BFUN_UP_LINKS_TO_TAILCALL =3D (1 << 1) > }; >=20 > +/* Decode errors for the BTS recording format. */ > +enum btrace_bts_error > +{ > + /* The instruction trace overflowed the end of the trace block. */ > + BDE_BTS_OVERFLOW =3D 1, > + > + /* The instruction size could not be determined. */ > + BDE_BTS_INSN_SIZE > +}; > + > /* A branch trace function segment. >=20 > This represents a function segment in a branch trace, i.e. a consecut= ive > number of instructions belonging to the same function. >=20 > - 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; >=20 > /* 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; >=20 > + /* 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; >=20 > - /* 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 erro= r, > + we still count the gap as a function. */ > unsigned int number; >=20 > /* The function level in a back trace across the entire branch trace. > @@ -223,6 +245,9 @@ struct btrace_thread_info > becomes zero. */ > int level; >=20 > + /* The number of gaps in the trace. */ > + unsigned int ngaps; > + > /* A bit-vector of btrace_thread_flag. */ > enum btrace_thread_flag flags; >=20 > @@ -232,7 +257,9 @@ struct btrace_thread_info > /* The function call history iterator. */ > struct btrace_call_history *call_history; >=20 > - /* 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; > }; >=20 > @@ -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); >=20 > /* 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 *); >=20 > diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c > index d9c1456..3075b8e 100644 > --- a/gdb/record-btrace.c > +++ b/gdb/record-btrace.c > @@ -350,7 +350,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; >=20 > DEBUG ("info"); >=20 > @@ -368,6 +368,7 @@ record_btrace_info (struct target_ops *self) >=20 > insns =3D 0; > calls =3D 0; > + gaps =3D 0; >=20 > if (!btrace_is_empty (tp)) > { > @@ -379,19 +380,67 @@ record_btrace_info (struct target_ops *self) > calls =3D btrace_call_number (&call); >=20 > btrace_insn_end (&insn, btinfo); > - btrace_insn_prev (&insn, 1); > insns =3D btrace_insn_number (&insn); > + /* The last instruction does not really belong to the trace. */ > + insns -=3D 1; > + > + gaps =3D btinfo->ngaps; > } >=20 > - printf_unfiltered (_("Recorded %u instructions in %u functions for thr= ead " > - "%d (%s).\n"), insns, calls, tp->num, > - target_pid_to_str (tp->ptid)); > + printf_unfiltered (_("Recorded %u instructions in %u functions (%u gap= s) " > + "for thread %d (%s).\n"), insns, calls, gaps, > + tp->num, target_pid_to_str (tp->ptid)); >=20 > if (btrace_is_replaying (tp)) > printf_unfiltered (_("Replay in progress. At instruction %u.\n"), > btrace_insn_number (btinfo->replay)); > } >=20 > +/* 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 =3D _("unknown"); > + is_error =3D 1; > + > + switch (format) > + { > + default: > + break; > + > + case BTRACE_FORMAT_BTS: > + switch (errcode) > + { > + default: > + break; > + > + case BDE_BTS_OVERFLOW: > + errstr =3D _("instruction overflow"); > + break; > + > + case BDE_BTS_INSN_SIZE: > + errstr =3D _("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. */ >=20 > static void > @@ -404,6 +453,7 @@ ui_out_field_uint (struct ui_out *uiout, const char > *fld, unsigned int val) >=20 > 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) > { > @@ -421,13 +471,30 @@ btrace_insn_history (struct ui_out *uiout, >=20 > insn =3D btrace_insn_get (&it); >=20 > - /* 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 =3D=3D NULL) > + { > + const struct btrace_config *conf; > + > + conf =3D btrace_conf (btinfo); >=20 > - /* Disassembly with '/m' flag may not produce the expected result. > - See PR gdb/11833. */ > - gdb_disassembly (gdbarch, uiout, NULL, flags, 1, insn->pc, insn->p= c + 1); > + /* We have trace so we must have a configuration. */ > + gdb_assert (conf !=3D 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); > + } > } > } >=20 > @@ -504,7 +571,7 @@ record_btrace_insn_history (struct target_ops *self, > int size, int flags) > } >=20 > if (covered > 0) > - btrace_insn_history (uiout, &begin, &end, flags); > + btrace_insn_history (uiout, btinfo, &begin, &end, flags); > else > { > if (size < 0) > @@ -564,7 +631,7 @@ record_btrace_insn_history_range (struct target_ops > *self, > btrace_insn_next (&end, 1); > } >=20 > - btrace_insn_history (uiout, &begin, &end, flags); > + btrace_insn_history (uiout, btinfo, &begin, &end, flags); > btrace_set_insn_history (btinfo, &begin, &end); >=20 > do_cleanups (uiout_cleanup); > @@ -705,6 +772,21 @@ btrace_call_history (struct ui_out *uiout, > ui_out_field_uint (uiout, "index", bfun->number); > ui_out_text (uiout, "\t"); >=20 > + /* Indicate gaps in the trace. */ > + if (bfun->errcode !=3D 0) > + { > + const struct btrace_config *conf; > + > + conf =3D btrace_conf (btinfo); > + > + /* We have trace so we must have a configuration. */ > + gdb_assert (conf !=3D NULL); > + > + btrace_ui_out_decode_error (uiout, bfun->errcode, conf->format); > + > + continue; > + } > + > if ((flags & RECORD_PRINT_INDENT_CALLS) !=3D 0) > { > int level =3D bfun->level + btinfo->level, i; > @@ -1713,9 +1795,13 @@ record_btrace_step_thread (struct thread_info > *tp) > if (replay =3D=3D NULL) > return btrace_step_no_history (); >=20 > - /* We are always able to step at least once. */ > - steps =3D btrace_insn_next (replay, 1); > - gdb_assert (steps =3D=3D 1); > + /* We are always able to step at least once - to the last instruct= ion. > + Skip gaps during replay. */ > + do > + { > + steps =3D btrace_insn_next (replay, 1); > + gdb_assert (steps =3D=3D 1); > + } while (btrace_insn_get (replay) =3D=3D NULL); >=20 > /* Determine the end of the instruction trace. */ > btrace_insn_end (&end, btinfo); > @@ -1731,10 +1817,14 @@ record_btrace_step_thread (struct thread_info > *tp) > if (replay =3D=3D NULL) > replay =3D record_btrace_start_replaying (tp); >=20 > - /* If we can't step any further, we reached the end of the history= . */ > - steps =3D btrace_insn_prev (replay, 1); > - if (steps =3D=3D 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 =3D btrace_insn_prev (replay, 1); > + if (steps =3D=3D 0) > + return btrace_step_no_history (); > + } while (btrace_insn_get (replay) =3D=3D NULL); >=20 > return btrace_step_stopped (); >=20 > @@ -1753,9 +1843,15 @@ record_btrace_step_thread (struct thread_info > *tp) > { > const struct btrace_insn *insn; >=20 > - /* We are always able to step at least once. */ > - steps =3D btrace_insn_next (replay, 1); > - gdb_assert (steps =3D=3D 1); > + /* We are always able to step at least once - to the last instruction. > + Skip gaps during replay. */ > + do > + { > + steps =3D btrace_insn_next (replay, 1); > + gdb_assert (steps =3D=3D 1); > + > + insn =3D btrace_insn_get (replay); > + } while (insn =3D=3D NULL); >=20 > /* We stop replaying if we reached the end of the trace. */ > if (btrace_insn_cmp (replay, &end) =3D=3D 0) > @@ -1764,9 +1860,6 @@ record_btrace_step_thread (struct thread_info > *tp) > return btrace_step_no_history (); > } >=20 > - insn =3D 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)); > @@ -1787,13 +1880,16 @@ record_btrace_step_thread (struct thread_info > *tp) > { > const struct btrace_insn *insn; >=20 > - /* If we can't step any further, we're done. */ > - steps =3D btrace_insn_prev (replay, 1); > - if (steps =3D=3D 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 =3D btrace_insn_prev (replay, 1); > + if (steps =3D=3D 0) > + return btrace_step_no_history (); >=20 > - insn =3D btrace_insn_get (replay); > - gdb_assert (insn); > + insn =3D btrace_insn_get (replay); > + } while (insn =3D=3D NULL); >=20 > 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 9d36361..51d861c 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"] "info record with small bts buffer" > gdb_test "record stop" ".*" "stop recording with small bts buffer" >=20 > @@ -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"] "info record with unlimited bts buffer" > gdb_test "record stop" ".*" "stop recording with unlimited bts buffer" > 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" >=20 > @@ -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 w= ithout > trace" > +Recorded 0 instructions in 0 functions \\\(0 gaps\\\) for thread 1.*\\."= "info > record without trace" >=20 > # 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" >=20 > # 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" >=20 > # 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"] > } >=20 > 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" >=20 > # let's step from a goto position somewhere in the middle > -- > 1.8.3.1 Intel GmbH Dornacher Strasse 1 85622 Feldkirchen/Muenchen, Deutschland Sitz der Gesellschaft: Feldkirchen bei Muenchen Geschaeftsfuehrer: Christian Lamprechter, Hannes Schwaderer, Douglas Lusk Registergericht: Muenchen HRB 47456 Ust.-IdNr./VAT Registration No.: DE129385895 Citibank Frankfurt a.M. (BLZ 502 109 00) 600119052