/* Return the btrace instruction flags for INSN. */
static btrace_insn_flags
-pt_btrace_insn_flags (const struct pt_insn *insn)
+pt_btrace_insn_flags (const struct pt_insn &insn)
{
btrace_insn_flags flags = 0;
- if (insn->speculative)
+ if (insn.speculative)
flags |= BTRACE_INSN_FLAG_SPECULATIVE;
return flags;
}
+/* Return the btrace instruction for INSN. */
+
+static btrace_insn
+pt_btrace_insn (const struct pt_insn &insn)
+{
+ return {(CORE_ADDR) insn.ip, (gdb_byte) insn.size,
+ pt_reclassify_insn (insn.iclass),
+ pt_btrace_insn_flags (insn)};
+}
+
+
/* Add function branch trace using DECODER. */
static void
end = *pend;
for (;;)
{
- struct btrace_insn btinsn;
struct pt_insn insn;
errcode = pt_insn_sync_forward (decoder);
break;
}
- memset (&btinsn, 0, sizeof (btinsn));
for (;;)
{
errcode = pt_insn_next (decoder, &insn, sizeof(insn));
/* Maintain the function level offset. */
*plevel = std::min (*plevel, end->level);
- btinsn.pc = (CORE_ADDR) insn.ip;
- btinsn.size = (gdb_byte) insn.size;
- btinsn.iclass = pt_reclassify_insn (insn.iclass);
- btinsn.flags = pt_btrace_insn_flags (&insn);
-
+ btrace_insn btinsn = pt_btrace_insn (insn);
ftrace_update_insns (end, &btinsn);
}
/* See btrace.h. */
+const char *
+btrace_decode_error (enum btrace_format format, int errcode)
+{
+ switch (format)
+ {
+ case BTRACE_FORMAT_BTS:
+ switch (errcode)
+ {
+ case BDE_BTS_OVERFLOW:
+ return _("instruction overflow");
+
+ case BDE_BTS_INSN_SIZE:
+ return _("unknown instruction");
+
+ default:
+ break;
+ }
+ break;
+
+#if defined (HAVE_LIBIPT)
+ case BTRACE_FORMAT_PT:
+ switch (errcode)
+ {
+ case BDE_PT_USER_QUIT:
+ return _("trace decode cancelled");
+
+ case BDE_PT_DISABLED:
+ return _("disabled");
+
+ case BDE_PT_OVERFLOW:
+ return _("overflow");
+
+ default:
+ if (errcode < 0)
+ return pt_errstr (pt_errcode (errcode));
+ break;
+ }
+ break;
+#endif /* defined (HAVE_LIBIPT) */
+
+ default:
+ break;
+ }
+
+ return _("unknown");
+}
+
+/* See btrace.h. */
+
void
btrace_fetch (struct thread_info *tp)
{
/* Compute the trace, provided we have any. */
if (!btrace_data_empty (&btrace))
{
+ struct btrace_function *bfun;
+
/* Store the raw trace data. The stored data will be cleared in
btrace_clear, so we always append the new trace. */
btrace_data_append (&btinfo->data, &btrace);
btrace_maint_clear (btinfo);
+ VEC_truncate (btrace_fun_p, btinfo->functions, 0);
btrace_clear_history (btinfo);
btrace_compute_ftrace (tp, &btrace);
+
+ for (bfun = btinfo->begin; bfun != NULL; bfun = bfun->flow.next)
+ VEC_safe_push (btrace_fun_p, btinfo->functions, bfun);
}
do_cleanups (cleanup);
btinfo = &tp->btrace;
+ VEC_free (btrace_fun_p, btinfo->functions);
+
it = btinfo->begin;
while (it != NULL)
{
unsigned int number)
{
const struct btrace_function *bfun;
+ unsigned int upper, lower;
- for (bfun = btinfo->end; bfun != NULL; bfun = bfun->flow.prev)
- if (bfun->insn_offset <= number)
- break;
+ if (VEC_empty (btrace_fun_p, btinfo->functions))
+ return 0;
- if (bfun == NULL)
+ lower = 0;
+ bfun = VEC_index (btrace_fun_p, btinfo->functions, lower);
+ if (number < bfun->insn_offset)
return 0;
- if (bfun->insn_offset + ftrace_call_num_insn (bfun) <= number)
+ upper = VEC_length (btrace_fun_p, btinfo->functions) - 1;
+ bfun = VEC_index (btrace_fun_p, btinfo->functions, upper);
+ if (number >= bfun->insn_offset + ftrace_call_num_insn (bfun))
return 0;
+ /* We assume that there are no holes in the numbering. */
+ for (;;)
+ {
+ const unsigned int average = lower + (upper - lower) / 2;
+
+ bfun = VEC_index (btrace_fun_p, btinfo->functions, average);
+
+ if (number < bfun->insn_offset)
+ {
+ upper = average - 1;
+ continue;
+ }
+
+ if (number >= bfun->insn_offset + ftrace_call_num_insn (bfun))
+ {
+ lower = average + 1;
+ continue;
+ }
+
+ break;
+ }
+
it->function = bfun;
it->index = number - bfun->insn_offset;
-
return 1;
}