btrace: Count gaps as one instruction explicitly.
This gives all instructions, including gaps, a unique number. Add a function to retrieve the error code if a btrace instruction iterator points to an invalid instruction. Signed-off-by: Tim Wiederhake <tim.wiederhake@intel.com> gdb/ChangeLog: * btrace.c (ftrace_call_num_insn, btrace_insn_get_error): New function. (ftrace_new_function, btrace_insn_number, btrace_insn_cmp, btrace_find_insn_by_number): Remove special case for gaps. * btrace.h (btrace_insn_get_error): New export. (btrace_insn_number, btrace_find_insn_by_number): Adjust comment. * record-btrace.c (btrace_insn_history): Print number for gaps. (record_btrace_info, record_btrace_goto): Handle gaps. Change-Id: I8eb0e48a95f4278522fea74ea13526bfe6898ecc
This commit is contained in:
parent
4c2c7ac69d
commit
69090ceead
84
gdb/btrace.c
84
gdb/btrace.c
|
@ -141,6 +141,21 @@ ftrace_debug (const struct btrace_function *bfun, const char *prefix)
|
||||||
prefix, fun, file, level, ibegin, iend);
|
prefix, fun, file, level, ibegin, iend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the number of instructions in a given function call segment. */
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
ftrace_call_num_insn (const struct btrace_function* bfun)
|
||||||
|
{
|
||||||
|
if (bfun == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* A gap is always counted as one instruction. */
|
||||||
|
if (bfun->errcode != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return VEC_length (btrace_insn_s, bfun->insn);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return non-zero if BFUN does not match MFUN and FUN,
|
/* Return non-zero if BFUN does not match MFUN and FUN,
|
||||||
return zero otherwise. */
|
return zero otherwise. */
|
||||||
|
|
||||||
|
@ -216,8 +231,7 @@ ftrace_new_function (struct btrace_function *prev,
|
||||||
prev->flow.next = bfun;
|
prev->flow.next = bfun;
|
||||||
|
|
||||||
bfun->number = prev->number + 1;
|
bfun->number = prev->number + 1;
|
||||||
bfun->insn_offset = (prev->insn_offset
|
bfun->insn_offset = prev->insn_offset + ftrace_call_num_insn (prev);
|
||||||
+ VEC_length (btrace_insn_s, prev->insn));
|
|
||||||
bfun->level = prev->level;
|
bfun->level = prev->level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2178,18 +2192,18 @@ btrace_insn_get (const struct btrace_insn_iterator *it)
|
||||||
|
|
||||||
/* See btrace.h. */
|
/* See btrace.h. */
|
||||||
|
|
||||||
|
int
|
||||||
|
btrace_insn_get_error (const struct btrace_insn_iterator *it)
|
||||||
|
{
|
||||||
|
return it->function->errcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See btrace.h. */
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
btrace_insn_number (const struct btrace_insn_iterator *it)
|
btrace_insn_number (const struct btrace_insn_iterator *it)
|
||||||
{
|
{
|
||||||
const struct btrace_function *bfun;
|
return it->function->insn_offset + it->index;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See btrace.h. */
|
/* See btrace.h. */
|
||||||
|
@ -2384,37 +2398,6 @@ btrace_insn_cmp (const struct btrace_insn_iterator *lhs,
|
||||||
lnum = btrace_insn_number (lhs);
|
lnum = btrace_insn_number (lhs);
|
||||||
rnum = btrace_insn_number (rhs);
|
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);
|
return (int) (lnum - rnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2426,26 +2409,15 @@ btrace_find_insn_by_number (struct btrace_insn_iterator *it,
|
||||||
unsigned int number)
|
unsigned int number)
|
||||||
{
|
{
|
||||||
const struct btrace_function *bfun;
|
const struct btrace_function *bfun;
|
||||||
unsigned int end, length;
|
|
||||||
|
|
||||||
for (bfun = btinfo->end; bfun != NULL; bfun = bfun->flow.prev)
|
for (bfun = btinfo->end; bfun != NULL; bfun = bfun->flow.prev)
|
||||||
{
|
if (bfun->insn_offset <= number)
|
||||||
/* Skip gaps. */
|
break;
|
||||||
if (bfun->errcode != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (bfun->insn_offset <= number)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bfun == NULL)
|
if (bfun == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
length = VEC_length (btrace_insn_s, bfun->insn);
|
if (bfun->insn_offset + ftrace_call_num_insn (bfun) <= number)
|
||||||
gdb_assert (length > 0);
|
|
||||||
|
|
||||||
end = bfun->insn_offset + length;
|
|
||||||
if (end <= number)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
it->function = bfun;
|
it->function = bfun;
|
||||||
|
|
|
@ -405,9 +405,12 @@ extern void parse_xml_btrace_conf (struct btrace_config *conf, const char *xml);
|
||||||
extern const struct btrace_insn *
|
extern const struct btrace_insn *
|
||||||
btrace_insn_get (const struct btrace_insn_iterator *);
|
btrace_insn_get (const struct btrace_insn_iterator *);
|
||||||
|
|
||||||
|
/* Return the error code for a branch trace instruction iterator. Returns zero
|
||||||
|
if there is no error, i.e. the instruction is valid. */
|
||||||
|
extern int btrace_insn_get_error (const struct btrace_insn_iterator *);
|
||||||
|
|
||||||
/* Return the instruction number for a branch trace iterator.
|
/* Return the instruction number for a branch trace iterator.
|
||||||
Returns one past the maximum instruction number for the end iterator.
|
Returns one past the maximum instruction number for the end iterator. */
|
||||||
Returns zero if the iterator does not point to a valid instruction. */
|
|
||||||
extern unsigned int btrace_insn_number (const struct btrace_insn_iterator *);
|
extern unsigned int btrace_insn_number (const struct btrace_insn_iterator *);
|
||||||
|
|
||||||
/* Initialize a branch trace instruction iterator to point to the begin/end of
|
/* Initialize a branch trace instruction iterator to point to the begin/end of
|
||||||
|
@ -433,7 +436,7 @@ extern unsigned int btrace_insn_prev (struct btrace_insn_iterator *,
|
||||||
extern int btrace_insn_cmp (const struct btrace_insn_iterator *lhs,
|
extern int btrace_insn_cmp (const struct btrace_insn_iterator *lhs,
|
||||||
const struct btrace_insn_iterator *rhs);
|
const struct btrace_insn_iterator *rhs);
|
||||||
|
|
||||||
/* Find an instruction in the function branch trace by its number.
|
/* Find an instruction or gap in the function branch trace by its number.
|
||||||
If the instruction is found, initialize the branch trace instruction
|
If the instruction is found, initialize the branch trace instruction
|
||||||
iterator to point to this instruction and return non-zero.
|
iterator to point to this instruction and return non-zero.
|
||||||
Return zero otherwise. */
|
Return zero otherwise. */
|
||||||
|
|
|
@ -443,28 +443,12 @@ record_btrace_info (struct target_ops *self)
|
||||||
calls = btrace_call_number (&call);
|
calls = btrace_call_number (&call);
|
||||||
|
|
||||||
btrace_insn_end (&insn, btinfo);
|
btrace_insn_end (&insn, btinfo);
|
||||||
|
|
||||||
insns = btrace_insn_number (&insn);
|
insns = btrace_insn_number (&insn);
|
||||||
if (insns != 0)
|
|
||||||
{
|
|
||||||
/* The last instruction does not really belong to the trace. */
|
|
||||||
insns -= 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unsigned int steps;
|
|
||||||
|
|
||||||
/* Skip gaps at the end. */
|
/* If the last instruction is not a gap, it is the current instruction
|
||||||
do
|
that is not actually part of the record. */
|
||||||
{
|
if (btrace_insn_get (&insn) != NULL)
|
||||||
steps = btrace_insn_prev (&insn, 1);
|
insns -= 1;
|
||||||
if (steps == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
insns = btrace_insn_number (&insn);
|
|
||||||
}
|
|
||||||
while (insns == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
gaps = btinfo->ngaps;
|
gaps = btinfo->ngaps;
|
||||||
}
|
}
|
||||||
|
@ -737,7 +721,11 @@ btrace_insn_history (struct ui_out *uiout,
|
||||||
/* We have trace so we must have a configuration. */
|
/* We have trace so we must have a configuration. */
|
||||||
gdb_assert (conf != NULL);
|
gdb_assert (conf != NULL);
|
||||||
|
|
||||||
btrace_ui_out_decode_error (uiout, it.function->errcode,
|
uiout->field_fmt ("insn-number", "%u",
|
||||||
|
btrace_insn_number (&it));
|
||||||
|
uiout->text ("\t");
|
||||||
|
|
||||||
|
btrace_ui_out_decode_error (uiout, btrace_insn_get_error (&it),
|
||||||
conf->format);
|
conf->format);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2828,7 +2816,9 @@ record_btrace_goto (struct target_ops *self, ULONGEST insn)
|
||||||
tp = require_btrace_thread ();
|
tp = require_btrace_thread ();
|
||||||
|
|
||||||
found = btrace_find_insn_by_number (&it, &tp->btrace, number);
|
found = btrace_find_insn_by_number (&it, &tp->btrace, number);
|
||||||
if (found == 0)
|
|
||||||
|
/* Check if the instruction could not be found or is a gap. */
|
||||||
|
if (found == 0 || btrace_insn_get (&it) == NULL)
|
||||||
error (_("No such instruction."));
|
error (_("No such instruction."));
|
||||||
|
|
||||||
record_btrace_set_replay (tp, &it);
|
record_btrace_set_replay (tp, &it);
|
||||||
|
|
Loading…
Reference in New Issue