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
3 changed files with 46 additions and 81 deletions
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);
|
||||
}
|
||||
|
||||
/* 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 zero otherwise. */
|
||||
|
||||
|
@ -216,8 +231,7 @@ ftrace_new_function (struct btrace_function *prev,
|
|||
prev->flow.next = bfun;
|
||||
|
||||
bfun->number = prev->number + 1;
|
||||
bfun->insn_offset = (prev->insn_offset
|
||||
+ VEC_length (btrace_insn_s, prev->insn));
|
||||
bfun->insn_offset = prev->insn_offset + ftrace_call_num_insn (prev);
|
||||
bfun->level = prev->level;
|
||||
}
|
||||
|
||||
|
@ -2178,18 +2192,18 @@ btrace_insn_get (const struct btrace_insn_iterator *it)
|
|||
|
||||
/* See btrace.h. */
|
||||
|
||||
int
|
||||
btrace_insn_get_error (const struct btrace_insn_iterator *it)
|
||||
{
|
||||
return it->function->errcode;
|
||||
}
|
||||
|
||||
/* See btrace.h. */
|
||||
|
||||
unsigned int
|
||||
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;
|
||||
return it->function->insn_offset + it->index;
|
||||
}
|
||||
|
||||
/* See btrace.h. */
|
||||
|
@ -2384,37 +2398,6 @@ 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);
|
||||
}
|
||||
|
||||
|
@ -2426,26 +2409,15 @@ btrace_find_insn_by_number (struct btrace_insn_iterator *it,
|
|||
unsigned int number)
|
||||
{
|
||||
const struct btrace_function *bfun;
|
||||
unsigned int end, length;
|
||||
|
||||
for (bfun = btinfo->end; bfun != NULL; bfun = bfun->flow.prev)
|
||||
{
|
||||
/* Skip gaps. */
|
||||
if (bfun->errcode != 0)
|
||||
continue;
|
||||
|
||||
if (bfun->insn_offset <= number)
|
||||
break;
|
||||
}
|
||||
if (bfun->insn_offset <= number)
|
||||
break;
|
||||
|
||||
if (bfun == NULL)
|
||||
return 0;
|
||||
|
||||
length = VEC_length (btrace_insn_s, bfun->insn);
|
||||
gdb_assert (length > 0);
|
||||
|
||||
end = bfun->insn_offset + length;
|
||||
if (end <= number)
|
||||
if (bfun->insn_offset + ftrace_call_num_insn (bfun) <= number)
|
||||
return 0;
|
||||
|
||||
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 *
|
||||
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.
|
||||
Returns one past the maximum instruction number for the end iterator.
|
||||
Returns zero if the iterator does not point to a valid instruction. */
|
||||
Returns one past the maximum instruction number for the end 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
|
||||
|
@ -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,
|
||||
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
|
||||
iterator to point to this instruction and return non-zero.
|
||||
Return zero otherwise. */
|
||||
|
|
|
@ -443,28 +443,12 @@ record_btrace_info (struct target_ops *self)
|
|||
calls = btrace_call_number (&call);
|
||||
|
||||
btrace_insn_end (&insn, btinfo);
|
||||
|
||||
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. */
|
||||
do
|
||||
{
|
||||
steps = btrace_insn_prev (&insn, 1);
|
||||
if (steps == 0)
|
||||
break;
|
||||
|
||||
insns = btrace_insn_number (&insn);
|
||||
}
|
||||
while (insns == 0);
|
||||
}
|
||||
/* If the last instruction is not a gap, it is the current instruction
|
||||
that is not actually part of the record. */
|
||||
if (btrace_insn_get (&insn) != NULL)
|
||||
insns -= 1;
|
||||
|
||||
gaps = btinfo->ngaps;
|
||||
}
|
||||
|
@ -737,7 +721,11 @@ btrace_insn_history (struct ui_out *uiout,
|
|||
/* We have trace so we must have a configuration. */
|
||||
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);
|
||||
}
|
||||
else
|
||||
|
@ -2828,7 +2816,9 @@ record_btrace_goto (struct target_ops *self, ULONGEST insn)
|
|||
tp = require_btrace_thread ();
|
||||
|
||||
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."));
|
||||
|
||||
record_btrace_set_replay (tp, &it);
|
||||
|
|
Loading…
Add table
Reference in a new issue