btrace: Store function segments as objects.

This commit is contained in:
Tim Wiederhake 2017-05-30 12:47:37 +02:00
parent 8ffd39f2e4
commit 08c3f6d234
4 changed files with 82 additions and 57 deletions

View File

@ -1,3 +1,21 @@
2017-05-30 Tim Wiederhake <tim.wiederhake@intel.com>
* btrace.c (ftrace_find_call_by_number): New function.
(ftrace_new_function): Store objects, not pointers.
(ftrace_find_call_by_number, ftrace_new_return, ftrace_new_switch,
ftrace_new_gap, ftrace_update_function,
ftrace_compute_global_level_offset, btrace_stich_bts, btrace_clear,
btrace_insn_get, btrace_insn_get_error, btrace_insn_end,
btrace_insn_next, btrace_insn_prev, ptrace_find_insn_by_number,
btrace_ends_with_single_insn, btrace_call_get): Account for
btrace_thread_info::functions now storing objects.
* btrace.h (struct btrace_thread_info): Add constructor.
(struct btrace_thread_info) <functions>: Make std::vector.
(struct btrace_thread_info) <prev, next, up, insn, errcode, flags):
Initialize with default values.
* record-btrace.c (record_btrace_frame_sniffer): Account for
btrace_thread_info::functions now storing objects.
2017-05-30 Tim Wiederhake <tim.wiederhake@intel.com>
* btrace.c: Remove typedef bfun_s.

View File

@ -156,13 +156,25 @@ ftrace_call_num_insn (const struct btrace_function* bfun)
exists. BTINFO is the branch trace information for the current thread. */
static struct btrace_function *
ftrace_find_call_by_number (struct btrace_thread_info *btinfo,
unsigned int number)
{
if (number == 0 || number > btinfo->functions.size ())
return NULL;
return &btinfo->functions[number - 1];
}
/* A const version of the function above. */
static const struct btrace_function *
ftrace_find_call_by_number (const struct btrace_thread_info *btinfo,
unsigned int number)
{
if (number == 0 || number > btinfo->functions.size ())
return NULL;
return btinfo->functions[number - 1];
return &btinfo->functions[number - 1];
}
/* Return non-zero if BFUN does not match MFUN and FUN,
@ -214,37 +226,34 @@ ftrace_function_switched (const struct btrace_function *bfun,
/* Allocate and initialize a new branch trace function segment at the end of
the trace.
BTINFO is the branch trace information for the current thread.
MFUN and FUN are the symbol information we have for this function. */
MFUN and FUN are the symbol information we have for this function.
This invalidates all struct btrace_function pointer currently held. */
static struct btrace_function *
ftrace_new_function (struct btrace_thread_info *btinfo,
struct minimal_symbol *mfun,
struct symbol *fun)
{
struct btrace_function *bfun;
bfun = XCNEW (struct btrace_function);
bfun->msym = mfun;
bfun->sym = fun;
int level;
unsigned int number, insn_offset;
if (btinfo->functions.empty ())
{
/* Start counting at one. */
bfun->number = 1;
bfun->insn_offset = 1;
/* Start counting NUMBER and INSN_OFFSET at one. */
level = 0;
number = 1;
insn_offset = 1;
}
else
{
struct btrace_function *prev = btinfo->functions.back ();
bfun->number = prev->number + 1;
bfun->insn_offset = prev->insn_offset + ftrace_call_num_insn (prev);
bfun->level = prev->level;
const struct btrace_function *prev = &btinfo->functions.back ();
level = prev->level;
number = prev->number + 1;
insn_offset = prev->insn_offset + ftrace_call_num_insn (prev);
}
btinfo->functions.push_back (bfun);
return bfun;
btinfo->functions.emplace_back (mfun, fun, number, insn_offset, level);
return &btinfo->functions.back ();
}
/* Update the UP field of a function segment. */
@ -406,10 +415,10 @@ ftrace_new_return (struct btrace_thread_info *btinfo,
struct minimal_symbol *mfun,
struct symbol *fun)
{
struct btrace_function *prev = btinfo->functions.back ();
struct btrace_function *bfun, *caller;
struct btrace_function *prev, *bfun, *caller;
bfun = ftrace_new_function (btinfo, mfun, fun);
prev = ftrace_find_call_by_number (btinfo, bfun->number - 1);
/* It is important to start at PREV's caller. Otherwise, we might find
PREV itself, if PREV is a recursive function. */
@ -488,12 +497,12 @@ ftrace_new_switch (struct btrace_thread_info *btinfo,
struct minimal_symbol *mfun,
struct symbol *fun)
{
struct btrace_function *prev = btinfo->functions.back ();
struct btrace_function *bfun;
struct btrace_function *prev, *bfun;
/* This is an unexplained function switch. We can't really be sure about the
call stack, yet the best I can think of right now is to preserve it. */
bfun = ftrace_new_function (btinfo, mfun, fun);
prev = ftrace_find_call_by_number (btinfo, bfun->number - 1);
bfun->up = prev->up;
bfun->flags = prev->flags;
@ -518,7 +527,7 @@ ftrace_new_gap (struct btrace_thread_info *btinfo, int errcode,
else
{
/* We hijack the previous function segment if it was empty. */
bfun = btinfo->functions.back ();
bfun = &btinfo->functions.back ();
if (bfun->errcode != 0 || !VEC_empty (btrace_insn_s, bfun->insn))
bfun = ftrace_new_function (btinfo, NULL, NULL);
}
@ -559,7 +568,7 @@ ftrace_update_function (struct btrace_thread_info *btinfo, CORE_ADDR pc)
return ftrace_new_function (btinfo, mfun, fun);
/* If we had a gap before, we create a function. */
bfun = btinfo->functions.back ();
bfun = &btinfo->functions.back ();
if (bfun->errcode != 0)
return ftrace_new_function (btinfo, mfun, fun);
@ -732,12 +741,12 @@ ftrace_compute_global_level_offset (struct btrace_thread_info *btinfo)
unsigned int length = btinfo->functions.size() - 1;
for (unsigned int i = 0; i < length; ++i)
level = std::min (level, btinfo->functions[i]->level);
level = std::min (level, btinfo->functions[i].level);
/* The last function segment contains the current instruction, which is not
really part of the trace. If it contains just this one instruction, we
ignore the segment. */
struct btrace_function *last = btinfo->functions.back();
struct btrace_function *last = &btinfo->functions.back();
if (VEC_length (btrace_insn_s, last->insn) != 1)
level = std::min (level, last->level);
@ -1607,7 +1616,7 @@ btrace_stitch_bts (struct btrace_data_bts *btrace, struct thread_info *tp)
gdb_assert (!btinfo->functions.empty ());
gdb_assert (!VEC_empty (btrace_block_s, btrace->blocks));
last_bfun = btinfo->functions.back ();
last_bfun = &btinfo->functions.back ();
/* If the existing trace ends with a gap, we just glue the traces
together. We need to drop the last (i.e. chronologically first) block
@ -1899,10 +1908,7 @@ btrace_clear (struct thread_info *tp)
btinfo = &tp->btrace;
for (auto &bfun : btinfo->functions)
{
VEC_free (btrace_insn_s, bfun->insn);
xfree (bfun);
}
VEC_free (btrace_insn_s, bfun.insn);
btinfo->functions.clear ();
btinfo->ngaps = 0;
@ -2251,7 +2257,7 @@ btrace_insn_get (const struct btrace_insn_iterator *it)
unsigned int index, end;
index = it->insn_index;
bfun = it->btinfo->functions[it->call_index];
bfun = &it->btinfo->functions[it->call_index];
/* Check if the iterator points to a gap in the trace. */
if (bfun->errcode != 0)
@ -2270,10 +2276,7 @@ btrace_insn_get (const struct btrace_insn_iterator *it)
int
btrace_insn_get_error (const struct btrace_insn_iterator *it)
{
const struct btrace_function *bfun;
bfun = it->btinfo->functions[it->call_index];
return bfun->errcode;
return it->btinfo->functions[it->call_index].errcode;
}
/* See btrace.h. */
@ -2281,10 +2284,7 @@ btrace_insn_get_error (const struct btrace_insn_iterator *it)
unsigned int
btrace_insn_number (const struct btrace_insn_iterator *it)
{
const struct btrace_function *bfun;
bfun = it->btinfo->functions[it->call_index];
return bfun->insn_offset + it->insn_index;
return it->btinfo->functions[it->call_index].insn_offset + it->insn_index;
}
/* See btrace.h. */
@ -2313,7 +2313,7 @@ btrace_insn_end (struct btrace_insn_iterator *it,
if (btinfo->functions.empty ())
error (_("No trace."));
bfun = btinfo->functions.back ();
bfun = &btinfo->functions.back ();
length = VEC_length (btrace_insn_s, bfun->insn);
/* The last function may either be a gap or it contains the current
@ -2335,7 +2335,7 @@ btrace_insn_next (struct btrace_insn_iterator *it, unsigned int stride)
const struct btrace_function *bfun;
unsigned int index, steps;
bfun = it->btinfo->functions[it->call_index];
bfun = &it->btinfo->functions[it->call_index];
steps = 0;
index = it->insn_index;
@ -2417,7 +2417,7 @@ btrace_insn_prev (struct btrace_insn_iterator *it, unsigned int stride)
const struct btrace_function *bfun;
unsigned int index, steps;
bfun = it->btinfo->functions[it->call_index];
bfun = &it->btinfo->functions[it->call_index];
steps = 0;
index = it->insn_index;
@ -2495,12 +2495,12 @@ btrace_find_insn_by_number (struct btrace_insn_iterator *it,
return 0;
lower = 0;
bfun = btinfo->functions[lower];
bfun = &btinfo->functions[lower];
if (number < bfun->insn_offset)
return 0;
upper = btinfo->functions.size () - 1;
bfun = btinfo->functions[upper];
bfun = &btinfo->functions[upper];
if (number >= bfun->insn_offset + ftrace_call_num_insn (bfun))
return 0;
@ -2509,7 +2509,7 @@ btrace_find_insn_by_number (struct btrace_insn_iterator *it,
{
const unsigned int average = lower + (upper - lower) / 2;
bfun = btinfo->functions[average];
bfun = &btinfo->functions[average];
if (number < bfun->insn_offset)
{
@ -2543,7 +2543,7 @@ btrace_ends_with_single_insn (const struct btrace_thread_info *btinfo)
if (btinfo->functions.empty ())
return false;
bfun = btinfo->functions.back ();
bfun = &btinfo->functions.back ();
if (bfun->errcode != 0)
return false;
@ -2558,7 +2558,7 @@ btrace_call_get (const struct btrace_call_iterator *it)
if (it->index >= it->btinfo->functions.size ())
return NULL;
return it->btinfo->functions[it->index];
return &it->btinfo->functions[it->index];
}
/* See btrace.h. */

View File

@ -135,6 +135,13 @@ enum btrace_pt_error
We do not allow function segments without instructions otherwise. */
struct btrace_function
{
btrace_function (struct minimal_symbol *msym_, struct symbol *sym_,
unsigned int number_, unsigned int insn_offset_, int level_)
: msym (msym_), sym (sym_), insn_offset (insn_offset_), number (number_),
level (level_)
{
}
/* The full and minimal symbol for the function. Both may be NULL. */
struct minimal_symbol *msym;
struct symbol *sym;
@ -143,22 +150,22 @@ struct btrace_function
the same function. If a function calls another function, the former will
have at least two segments: one before the call and another after the
return. Will be zero if there is no such function segment. */
unsigned int prev;
unsigned int next;
unsigned int prev = 0;
unsigned int next = 0;
/* The function segment number of the directly preceding function segment in
a (fake) call stack. Will be zero if there is no such function segment in
the record. */
unsigned int up;
unsigned int up = 0;
/* The instructions in this function segment.
The instruction vector will be empty if the function segment
represents a decode error. */
VEC (btrace_insn_s) *insn;
VEC (btrace_insn_s) *insn = NULL;
/* The error code of a decode error that led to a gap.
Must be zero unless INSN is empty; non-zero otherwise. */
int errcode;
int errcode = 0;
/* The instruction number offset for the first instruction in this
function segment.
@ -180,7 +187,7 @@ struct btrace_function
int level;
/* A bit-vector of btrace_function_flag. */
btrace_function_flags flags;
btrace_function_flags flags = 0;
};
/* A branch trace instruction iterator. */
@ -325,10 +332,10 @@ struct btrace_thread_info
/* The raw branch trace data for the below branch trace. */
struct btrace_data data;
/* Vector of pointer to decoded function segments in execution flow order.
/* Vector of decoded function segments in execution flow order.
Note that the numbering for btrace function segments starts with 1, so
function segment i will be at index (i - 1). */
std::vector<btrace_function *> functions;
std::vector<btrace_function> functions;
/* The function level offset. When added to each function's LEVEL,
this normalizes the function levels such that the smallest level

View File

@ -1681,7 +1681,7 @@ record_btrace_frame_sniffer (const struct frame_unwind *self,
replay = tp->btrace.replay;
if (replay != NULL)
bfun = replay->btinfo->functions[replay->call_index];
bfun = &replay->btinfo->functions[replay->call_index];
}
else
{