This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RE: [PATCH v2 11/13] record-btrace: indicate gaps


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
> 
> 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-11-20  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 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;
> 
> -      /* 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.
> @@ -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;
> 
>    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);
> 
> @@ -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 = ftrace_new_gap (end, BDE_BTS_OVERFLOW);
> +	      ngaps += 1;
> +
>  	      break;
>  	    }
> 
> @@ -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 = ftrace_new_gap (end, BDE_BTS_INSN_SIZE);
> +	      ngaps += 1;
> +
>  	      break;
>  	    }
> 
> @@ -678,6 +716,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
> @@ -1009,6 +1048,7 @@ btrace_clear (struct thread_info *tp)
> 
>    btinfo->begin = NULL;
>    btinfo->end = NULL;
> +  btinfo->ngaps = 0;
> 
>    btrace_clear_history (btinfo);
>  }
> @@ -1206,6 +1246,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);
> @@ -1222,6 +1266,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;
>  }
> 
> @@ -1257,6 +1306,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;
> @@ -1280,6 +1330,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);
> 
> @@ -1354,12 +1421,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;
> @@ -1386,6 +1461,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);
>  }
> 
> @@ -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;
> 
>    for (bfun = btinfo->end; bfun != NULL; bfun = bfun->flow.prev)
>      if (bfun->insn_offset <= number)
> @@ -1406,7 +1512,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;
> 
> @@ -1508,6 +1619,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)
> @@ -1548,6 +1662,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 2082bc7..71be12e 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 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;
> 
>    DEBUG ("info");
> 
> @@ -368,6 +368,7 @@ record_btrace_info (struct target_ops *self)
> 
>    insns = 0;
>    calls = 0;
> +  gaps = 0;
> 
>    if (!btrace_is_empty (tp))
>      {
> @@ -379,19 +380,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
> @@ -404,6 +453,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)
>  {
> @@ -421,13 +471,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);
> +	}
>      }
>  }
> 
> @@ -504,7 +571,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)
> @@ -564,7 +631,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);
> @@ -705,6 +772,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;
> @@ -1713,9 +1795,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);
> @@ -1731,10 +1817,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 ();
> 
> @@ -1753,9 +1843,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)
> @@ -1764,9 +1860,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));
> @@ -1787,13 +1880,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 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"
> 
> @@ -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"
> 
> @@ -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

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]