btrace: Remove struct btrace_thread_info::{begin,end}.
These are no longer needed and might hold invalid addresses once we change the vector of function segment pointers into a vector of function segment objects where a reallocation of the vector changes the address of its elements.
This commit is contained in:
parent
8286623c11
commit
b54b03bd87
@ -1,3 +1,17 @@
|
|||||||
|
2017-05-30 Tim Wiederhake <tim.wiederhake@intel.com>
|
||||||
|
|
||||||
|
* btrace.c (ftrace_new_function, ftrace_new_call, ftrace_new_tailcall,
|
||||||
|
ftrace_new_return, ftrace_new_switch, ftrace_new_gap,
|
||||||
|
ftrace_update_function, ftrace_compute_global_level_offset,
|
||||||
|
btrace_compute_ftrace_bts, ftrace_add_pt, btrace_compute_ftrace_pt,
|
||||||
|
btrace_stitch_bts, btrace_fetch, btrace_clear, btrace_insn_number,
|
||||||
|
btrace_insn_end, btrace_is_empty): Remove references to
|
||||||
|
btrace_thread_info::begin and btrace_thread_info::end.
|
||||||
|
* btrace.h (struct btrace_thread_info): Remove BEGIN and END.
|
||||||
|
(struct btrace_thread_info) <functions>: Adjust comment.
|
||||||
|
* record-btrace.c (record_btrace_start_replaying): Remove reference to
|
||||||
|
btrace_thread_info::begin.
|
||||||
|
|
||||||
2017-05-30 Tim Wiederhake <tim.wiederhake@intel.com>
|
2017-05-30 Tim Wiederhake <tim.wiederhake@intel.com>
|
||||||
|
|
||||||
* btrace.c (ftrace_new_function, ftrace_new_call, ftrace_new_tailcall,
|
* btrace.c (ftrace_new_function, ftrace_new_call, ftrace_new_tailcall,
|
||||||
|
190
gdb/btrace.c
190
gdb/btrace.c
@ -212,16 +212,14 @@ ftrace_new_function (struct btrace_thread_info *btinfo,
|
|||||||
struct minimal_symbol *mfun,
|
struct minimal_symbol *mfun,
|
||||||
struct symbol *fun)
|
struct symbol *fun)
|
||||||
{
|
{
|
||||||
struct btrace_function *bfun, *prev;
|
struct btrace_function *bfun;
|
||||||
|
|
||||||
prev = btinfo->end;
|
|
||||||
bfun = XCNEW (struct btrace_function);
|
bfun = XCNEW (struct btrace_function);
|
||||||
|
|
||||||
bfun->msym = mfun;
|
bfun->msym = mfun;
|
||||||
bfun->sym = fun;
|
bfun->sym = fun;
|
||||||
bfun->flow.prev = prev;
|
|
||||||
|
|
||||||
if (prev == NULL)
|
if (btinfo->functions.empty ())
|
||||||
{
|
{
|
||||||
/* Start counting at one. */
|
/* Start counting at one. */
|
||||||
bfun->number = 1;
|
bfun->number = 1;
|
||||||
@ -229,8 +227,11 @@ ftrace_new_function (struct btrace_thread_info *btinfo,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
struct btrace_function *prev = btinfo->functions.back ();
|
||||||
|
|
||||||
gdb_assert (prev->flow.next == NULL);
|
gdb_assert (prev->flow.next == NULL);
|
||||||
prev->flow.next = bfun;
|
prev->flow.next = bfun;
|
||||||
|
bfun->flow.prev = prev;
|
||||||
|
|
||||||
bfun->number = prev->number + 1;
|
bfun->number = prev->number + 1;
|
||||||
bfun->insn_offset = prev->insn_offset + ftrace_call_num_insn (prev);
|
bfun->insn_offset = prev->insn_offset + ftrace_call_num_insn (prev);
|
||||||
@ -238,7 +239,6 @@ ftrace_new_function (struct btrace_thread_info *btinfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
btinfo->functions.push_back (bfun);
|
btinfo->functions.push_back (bfun);
|
||||||
btinfo->end = bfun;
|
|
||||||
return bfun;
|
return bfun;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,10 +287,11 @@ ftrace_new_call (struct btrace_thread_info *btinfo,
|
|||||||
struct minimal_symbol *mfun,
|
struct minimal_symbol *mfun,
|
||||||
struct symbol *fun)
|
struct symbol *fun)
|
||||||
{
|
{
|
||||||
struct btrace_function *caller = btinfo->end;
|
const unsigned int length = btinfo->functions.size ();
|
||||||
struct btrace_function *bfun = ftrace_new_function (btinfo, mfun, fun);
|
struct btrace_function *bfun = ftrace_new_function (btinfo, mfun, fun);
|
||||||
|
|
||||||
bfun->up = caller;
|
if (length != 0)
|
||||||
|
bfun->up = btinfo->functions[length - 1];
|
||||||
bfun->level += 1;
|
bfun->level += 1;
|
||||||
|
|
||||||
ftrace_debug (bfun, "new call");
|
ftrace_debug (bfun, "new call");
|
||||||
@ -307,10 +308,11 @@ ftrace_new_tailcall (struct btrace_thread_info *btinfo,
|
|||||||
struct minimal_symbol *mfun,
|
struct minimal_symbol *mfun,
|
||||||
struct symbol *fun)
|
struct symbol *fun)
|
||||||
{
|
{
|
||||||
struct btrace_function *caller = btinfo->end;
|
const unsigned int length = btinfo->functions.size ();
|
||||||
struct btrace_function *bfun = ftrace_new_function (btinfo, mfun, fun);
|
struct btrace_function *bfun = ftrace_new_function (btinfo, mfun, fun);
|
||||||
|
|
||||||
bfun->up = caller;
|
if (length != 0)
|
||||||
|
bfun->up = btinfo->functions[length - 1];
|
||||||
bfun->level += 1;
|
bfun->level += 1;
|
||||||
bfun->flags |= BFUN_UP_LINKS_TO_TAILCALL;
|
bfun->flags |= BFUN_UP_LINKS_TO_TAILCALL;
|
||||||
|
|
||||||
@ -386,7 +388,7 @@ ftrace_new_return (struct btrace_thread_info *btinfo,
|
|||||||
struct minimal_symbol *mfun,
|
struct minimal_symbol *mfun,
|
||||||
struct symbol *fun)
|
struct symbol *fun)
|
||||||
{
|
{
|
||||||
struct btrace_function *prev = btinfo->end;
|
struct btrace_function *prev = btinfo->functions.back ();
|
||||||
struct btrace_function *bfun, *caller;
|
struct btrace_function *bfun, *caller;
|
||||||
|
|
||||||
bfun = ftrace_new_function (btinfo, mfun, fun);
|
bfun = ftrace_new_function (btinfo, mfun, fun);
|
||||||
@ -466,7 +468,7 @@ ftrace_new_switch (struct btrace_thread_info *btinfo,
|
|||||||
struct minimal_symbol *mfun,
|
struct minimal_symbol *mfun,
|
||||||
struct symbol *fun)
|
struct symbol *fun)
|
||||||
{
|
{
|
||||||
struct btrace_function *prev = btinfo->end;
|
struct btrace_function *prev = btinfo->functions.back ();
|
||||||
struct btrace_function *bfun;
|
struct btrace_function *bfun;
|
||||||
|
|
||||||
/* This is an unexplained function switch. We can't really be sure about the
|
/* This is an unexplained function switch. We can't really be sure about the
|
||||||
@ -488,15 +490,17 @@ ftrace_new_switch (struct btrace_thread_info *btinfo,
|
|||||||
static struct btrace_function *
|
static struct btrace_function *
|
||||||
ftrace_new_gap (struct btrace_thread_info *btinfo, int errcode)
|
ftrace_new_gap (struct btrace_thread_info *btinfo, int errcode)
|
||||||
{
|
{
|
||||||
struct btrace_function *prev = btinfo->end;
|
|
||||||
struct btrace_function *bfun;
|
struct btrace_function *bfun;
|
||||||
|
|
||||||
/* We hijack prev if it was empty. */
|
if (btinfo->functions.empty ())
|
||||||
if (prev != NULL && prev->errcode == 0
|
|
||||||
&& VEC_empty (btrace_insn_s, prev->insn))
|
|
||||||
bfun = prev;
|
|
||||||
else
|
|
||||||
bfun = ftrace_new_function (btinfo, NULL, NULL);
|
bfun = ftrace_new_function (btinfo, NULL, NULL);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We hijack the previous function segment if it was empty. */
|
||||||
|
bfun = btinfo->functions.back ();
|
||||||
|
if (bfun->errcode != 0 || !VEC_empty (btrace_insn_s, bfun->insn))
|
||||||
|
bfun = ftrace_new_function (btinfo, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
bfun->errcode = errcode;
|
bfun->errcode = errcode;
|
||||||
|
|
||||||
@ -516,7 +520,7 @@ ftrace_update_function (struct btrace_thread_info *btinfo, CORE_ADDR pc)
|
|||||||
struct minimal_symbol *mfun;
|
struct minimal_symbol *mfun;
|
||||||
struct symbol *fun;
|
struct symbol *fun;
|
||||||
struct btrace_insn *last;
|
struct btrace_insn *last;
|
||||||
struct btrace_function *bfun = btinfo->end;
|
struct btrace_function *bfun;
|
||||||
|
|
||||||
/* Try to determine the function we're in. We use both types of symbols
|
/* Try to determine the function we're in. We use both types of symbols
|
||||||
to avoid surprises when we sometimes get a full symbol and sometimes
|
to avoid surprises when we sometimes get a full symbol and sometimes
|
||||||
@ -528,8 +532,13 @@ ftrace_update_function (struct btrace_thread_info *btinfo, CORE_ADDR pc)
|
|||||||
if (fun == NULL && mfun == NULL)
|
if (fun == NULL && mfun == NULL)
|
||||||
DEBUG_FTRACE ("no symbol at %s", core_addr_to_string_nz (pc));
|
DEBUG_FTRACE ("no symbol at %s", core_addr_to_string_nz (pc));
|
||||||
|
|
||||||
/* If we didn't have a function or if we had a gap before, we create one. */
|
/* If we didn't have a function, we create one. */
|
||||||
if (bfun == NULL || bfun->errcode != 0)
|
if (btinfo->functions.empty ())
|
||||||
|
return ftrace_new_function (btinfo, mfun, fun);
|
||||||
|
|
||||||
|
/* If we had a gap before, we create a function. */
|
||||||
|
bfun = btinfo->functions.back ();
|
||||||
|
if (bfun->errcode != 0)
|
||||||
return ftrace_new_function (btinfo, mfun, fun);
|
return ftrace_new_function (btinfo, mfun, fun);
|
||||||
|
|
||||||
/* Check the last instruction, if we have one.
|
/* Check the last instruction, if we have one.
|
||||||
@ -685,26 +694,24 @@ ftrace_fixup_level (struct btrace_function *bfun, int adjustment)
|
|||||||
static void
|
static void
|
||||||
ftrace_compute_global_level_offset (struct btrace_thread_info *btinfo)
|
ftrace_compute_global_level_offset (struct btrace_thread_info *btinfo)
|
||||||
{
|
{
|
||||||
struct btrace_function *bfun, *end;
|
int level = INT_MAX;
|
||||||
int level;
|
|
||||||
|
|
||||||
if (btinfo == NULL)
|
if (btinfo == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bfun = btinfo->begin;
|
if (btinfo->functions.empty ())
|
||||||
if (bfun == NULL)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
unsigned int length = btinfo->functions.size() - 1;
|
||||||
|
for (unsigned int i = 0; i < length; ++i)
|
||||||
|
level = std::min (level, btinfo->functions[i]->level);
|
||||||
|
|
||||||
/* The last function segment contains the current instruction, which is not
|
/* The last function segment contains the current instruction, which is not
|
||||||
really part of the trace. If it contains just this one instruction, we
|
really part of the trace. If it contains just this one instruction, we
|
||||||
stop when we reach it; otherwise, we let the below loop run to the end. */
|
ignore the segment. */
|
||||||
end = btinfo->end;
|
struct btrace_function *last = btinfo->functions.back();
|
||||||
if (VEC_length (btrace_insn_s, end->insn) > 1)
|
if (VEC_length (btrace_insn_s, last->insn) != 1)
|
||||||
end = NULL;
|
level = std::min (level, last->level);
|
||||||
|
|
||||||
level = INT_MAX;
|
|
||||||
for (; bfun != end; bfun = bfun->flow.next)
|
|
||||||
level = std::min (level, bfun->level);
|
|
||||||
|
|
||||||
DEBUG_FTRACE ("setting global level offset: %d", -level);
|
DEBUG_FTRACE ("setting global level offset: %d", -level);
|
||||||
btinfo->level = -level;
|
btinfo->level = -level;
|
||||||
@ -986,18 +993,19 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
|
|||||||
VEC (bfun_s) **gaps)
|
VEC (bfun_s) **gaps)
|
||||||
{
|
{
|
||||||
struct btrace_thread_info *btinfo;
|
struct btrace_thread_info *btinfo;
|
||||||
struct btrace_function *begin, *end;
|
|
||||||
struct gdbarch *gdbarch;
|
struct gdbarch *gdbarch;
|
||||||
unsigned int blk;
|
unsigned int blk;
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
gdbarch = target_gdbarch ();
|
gdbarch = target_gdbarch ();
|
||||||
btinfo = &tp->btrace;
|
btinfo = &tp->btrace;
|
||||||
begin = btinfo->begin;
|
|
||||||
end = btinfo->end;
|
|
||||||
level = begin != NULL ? -btinfo->level : INT_MAX;
|
|
||||||
blk = VEC_length (btrace_block_s, btrace->blocks);
|
blk = VEC_length (btrace_block_s, btrace->blocks);
|
||||||
|
|
||||||
|
if (btinfo->functions.empty ())
|
||||||
|
level = INT_MAX;
|
||||||
|
else
|
||||||
|
level = -btinfo->level;
|
||||||
|
|
||||||
while (blk != 0)
|
while (blk != 0)
|
||||||
{
|
{
|
||||||
btrace_block_s *block;
|
btrace_block_s *block;
|
||||||
@ -1010,6 +1018,7 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
struct btrace_function *bfun;
|
||||||
struct btrace_insn insn;
|
struct btrace_insn insn;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
@ -1017,27 +1026,23 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
|
|||||||
if (block->end < pc)
|
if (block->end < pc)
|
||||||
{
|
{
|
||||||
/* Indicate the gap in the trace. */
|
/* Indicate the gap in the trace. */
|
||||||
end = ftrace_new_gap (btinfo, BDE_BTS_OVERFLOW);
|
bfun = ftrace_new_gap (btinfo, BDE_BTS_OVERFLOW);
|
||||||
if (begin == NULL)
|
|
||||||
begin = end;
|
|
||||||
|
|
||||||
VEC_safe_push (bfun_s, *gaps, end);
|
VEC_safe_push (bfun_s, *gaps, bfun);
|
||||||
|
|
||||||
warning (_("Recorded trace may be corrupted at instruction "
|
warning (_("Recorded trace may be corrupted at instruction "
|
||||||
"%u (pc = %s)."), end->insn_offset - 1,
|
"%u (pc = %s)."), bfun->insn_offset - 1,
|
||||||
core_addr_to_string_nz (pc));
|
core_addr_to_string_nz (pc));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
end = ftrace_update_function (btinfo, pc);
|
bfun = ftrace_update_function (btinfo, pc);
|
||||||
if (begin == NULL)
|
|
||||||
begin = end;
|
|
||||||
|
|
||||||
/* Maintain the function level offset.
|
/* Maintain the function level offset.
|
||||||
For all but the last block, we do it here. */
|
For all but the last block, we do it here. */
|
||||||
if (blk != 0)
|
if (blk != 0)
|
||||||
level = std::min (level, end->level);
|
level = std::min (level, bfun->level);
|
||||||
|
|
||||||
size = 0;
|
size = 0;
|
||||||
TRY
|
TRY
|
||||||
@ -1054,7 +1059,7 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
|
|||||||
insn.iclass = ftrace_classify_insn (gdbarch, pc);
|
insn.iclass = ftrace_classify_insn (gdbarch, pc);
|
||||||
insn.flags = 0;
|
insn.flags = 0;
|
||||||
|
|
||||||
ftrace_update_insns (end, &insn);
|
ftrace_update_insns (bfun, &insn);
|
||||||
|
|
||||||
/* We're done once we pushed the instruction at the end. */
|
/* We're done once we pushed the instruction at the end. */
|
||||||
if (block->end == pc)
|
if (block->end == pc)
|
||||||
@ -1065,12 +1070,12 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
|
|||||||
{
|
{
|
||||||
/* Indicate the gap in the trace. We just added INSN so we're
|
/* Indicate the gap in the trace. We just added INSN so we're
|
||||||
not at the beginning. */
|
not at the beginning. */
|
||||||
end = ftrace_new_gap (btinfo, BDE_BTS_INSN_SIZE);
|
bfun = ftrace_new_gap (btinfo, BDE_BTS_INSN_SIZE);
|
||||||
|
|
||||||
VEC_safe_push (bfun_s, *gaps, end);
|
VEC_safe_push (bfun_s, *gaps, bfun);
|
||||||
|
|
||||||
warning (_("Recorded trace may be incomplete at instruction %u "
|
warning (_("Recorded trace may be incomplete at instruction %u "
|
||||||
"(pc = %s)."), end->insn_offset - 1,
|
"(pc = %s)."), bfun->insn_offset - 1,
|
||||||
core_addr_to_string_nz (pc));
|
core_addr_to_string_nz (pc));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -1085,13 +1090,10 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
|
|||||||
and is not really part of the execution history, it shouldn't
|
and is not really part of the execution history, it shouldn't
|
||||||
affect the level. */
|
affect the level. */
|
||||||
if (blk == 0)
|
if (blk == 0)
|
||||||
level = std::min (level, end->level);
|
level = std::min (level, bfun->level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
btinfo->begin = begin;
|
|
||||||
btinfo->end = end;
|
|
||||||
|
|
||||||
/* LEVEL is the minimal function level of all btrace function segments.
|
/* LEVEL is the minimal function level of all btrace function segments.
|
||||||
Define the global level offset to -LEVEL so all function levels are
|
Define the global level offset to -LEVEL so all function levels are
|
||||||
normalized to start at zero. */
|
normalized to start at zero. */
|
||||||
@ -1148,16 +1150,13 @@ pt_btrace_insn (const struct pt_insn &insn)
|
|||||||
static void
|
static void
|
||||||
ftrace_add_pt (struct btrace_thread_info *btinfo,
|
ftrace_add_pt (struct btrace_thread_info *btinfo,
|
||||||
struct pt_insn_decoder *decoder,
|
struct pt_insn_decoder *decoder,
|
||||||
struct btrace_function **pbegin,
|
int *plevel,
|
||||||
struct btrace_function **pend, int *plevel,
|
|
||||||
VEC (bfun_s) **gaps)
|
VEC (bfun_s) **gaps)
|
||||||
{
|
{
|
||||||
struct btrace_function *begin, *end, *upd;
|
struct btrace_function *bfun;
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
int errcode;
|
int errcode;
|
||||||
|
|
||||||
begin = *pbegin;
|
|
||||||
end = *pend;
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
struct pt_insn insn;
|
struct pt_insn insn;
|
||||||
@ -1178,7 +1177,7 @@ ftrace_add_pt (struct btrace_thread_info *btinfo,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* Look for gaps in the trace - unless we're at the beginning. */
|
/* Look for gaps in the trace - unless we're at the beginning. */
|
||||||
if (begin != NULL)
|
if (!btinfo->functions.empty ())
|
||||||
{
|
{
|
||||||
/* Tracing is disabled and re-enabled each time we enter the
|
/* Tracing is disabled and re-enabled each time we enter the
|
||||||
kernel. Most times, we continue from the same instruction we
|
kernel. Most times, we continue from the same instruction we
|
||||||
@ -1187,64 +1186,53 @@ ftrace_add_pt (struct btrace_thread_info *btinfo,
|
|||||||
from some other instruction. Indicate this as a trace gap. */
|
from some other instruction. Indicate this as a trace gap. */
|
||||||
if (insn.enabled)
|
if (insn.enabled)
|
||||||
{
|
{
|
||||||
*pend = end = ftrace_new_gap (btinfo, BDE_PT_DISABLED);
|
bfun = ftrace_new_gap (btinfo, BDE_PT_DISABLED);
|
||||||
|
|
||||||
VEC_safe_push (bfun_s, *gaps, end);
|
VEC_safe_push (bfun_s, *gaps, bfun);
|
||||||
|
|
||||||
pt_insn_get_offset (decoder, &offset);
|
pt_insn_get_offset (decoder, &offset);
|
||||||
|
|
||||||
warning (_("Non-contiguous trace at instruction %u (offset "
|
warning (_("Non-contiguous trace at instruction %u (offset "
|
||||||
"= 0x%" PRIx64 ", pc = 0x%" PRIx64 ")."),
|
"= 0x%" PRIx64 ", pc = 0x%" PRIx64 ")."),
|
||||||
end->insn_offset - 1, offset, insn.ip);
|
bfun->insn_offset - 1, offset, insn.ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Indicate trace overflows. */
|
/* Indicate trace overflows. */
|
||||||
if (insn.resynced)
|
if (insn.resynced)
|
||||||
{
|
{
|
||||||
*pend = end = ftrace_new_gap (btinfo, BDE_PT_OVERFLOW);
|
bfun = ftrace_new_gap (btinfo, BDE_PT_OVERFLOW);
|
||||||
if (begin == NULL)
|
|
||||||
*pbegin = begin = end;
|
|
||||||
|
|
||||||
VEC_safe_push (bfun_s, *gaps, end);
|
VEC_safe_push (bfun_s, *gaps, bfun);
|
||||||
|
|
||||||
pt_insn_get_offset (decoder, &offset);
|
pt_insn_get_offset (decoder, &offset);
|
||||||
|
|
||||||
warning (_("Overflow at instruction %u (offset = 0x%" PRIx64
|
warning (_("Overflow at instruction %u (offset = 0x%" PRIx64
|
||||||
", pc = 0x%" PRIx64 ")."), end->insn_offset - 1,
|
", pc = 0x%" PRIx64 ")."), bfun->insn_offset - 1,
|
||||||
offset, insn.ip);
|
offset, insn.ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
upd = ftrace_update_function (btinfo, insn.ip);
|
bfun = ftrace_update_function (btinfo, insn.ip);
|
||||||
if (upd != end)
|
|
||||||
{
|
|
||||||
*pend = end = upd;
|
|
||||||
|
|
||||||
if (begin == NULL)
|
|
||||||
*pbegin = begin = upd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Maintain the function level offset. */
|
/* Maintain the function level offset. */
|
||||||
*plevel = std::min (*plevel, end->level);
|
*plevel = std::min (*plevel, bfun->level);
|
||||||
|
|
||||||
btrace_insn btinsn = pt_btrace_insn (insn);
|
btrace_insn btinsn = pt_btrace_insn (insn);
|
||||||
ftrace_update_insns (end, &btinsn);
|
ftrace_update_insns (bfun, &btinsn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errcode == -pte_eos)
|
if (errcode == -pte_eos)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Indicate the gap in the trace. */
|
/* Indicate the gap in the trace. */
|
||||||
*pend = end = ftrace_new_gap (btinfo, errcode);
|
bfun = ftrace_new_gap (btinfo, errcode);
|
||||||
if (begin == NULL)
|
|
||||||
*pbegin = begin = end;
|
|
||||||
|
|
||||||
VEC_safe_push (bfun_s, *gaps, end);
|
VEC_safe_push (bfun_s, *gaps, bfun);
|
||||||
|
|
||||||
pt_insn_get_offset (decoder, &offset);
|
pt_insn_get_offset (decoder, &offset);
|
||||||
|
|
||||||
warning (_("Decode error (%d) at instruction %u (offset = 0x%" PRIx64
|
warning (_("Decode error (%d) at instruction %u (offset = 0x%" PRIx64
|
||||||
", pc = 0x%" PRIx64 "): %s."), errcode, end->insn_offset - 1,
|
", pc = 0x%" PRIx64 "): %s."), errcode, bfun->insn_offset - 1,
|
||||||
offset, insn.ip, pt_errstr (pt_errcode (errcode)));
|
offset, insn.ip, pt_errstr (pt_errcode (errcode)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1326,7 +1314,10 @@ btrace_compute_ftrace_pt (struct thread_info *tp,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
btinfo = &tp->btrace;
|
btinfo = &tp->btrace;
|
||||||
level = btinfo->begin != NULL ? -btinfo->level : INT_MAX;
|
if (btinfo->functions.empty ())
|
||||||
|
level = INT_MAX;
|
||||||
|
else
|
||||||
|
level = -btinfo->level;
|
||||||
|
|
||||||
pt_config_init(&config);
|
pt_config_init(&config);
|
||||||
config.begin = btrace->data;
|
config.begin = btrace->data;
|
||||||
@ -1359,17 +1350,18 @@ btrace_compute_ftrace_pt (struct thread_info *tp,
|
|||||||
error (_("Failed to configure the Intel Processor Trace decoder: "
|
error (_("Failed to configure the Intel Processor Trace decoder: "
|
||||||
"%s."), pt_errstr (pt_errcode (errcode)));
|
"%s."), pt_errstr (pt_errcode (errcode)));
|
||||||
|
|
||||||
ftrace_add_pt (btinfo, decoder, &btinfo->begin, &btinfo->end, &level,
|
ftrace_add_pt (btinfo, decoder, &level, gaps);
|
||||||
gaps);
|
|
||||||
}
|
}
|
||||||
CATCH (error, RETURN_MASK_ALL)
|
CATCH (error, RETURN_MASK_ALL)
|
||||||
{
|
{
|
||||||
/* Indicate a gap in the trace if we quit trace processing. */
|
/* Indicate a gap in the trace if we quit trace processing. */
|
||||||
if (error.reason == RETURN_QUIT && btinfo->end != NULL)
|
if (error.reason == RETURN_QUIT && !btinfo->functions.empty ())
|
||||||
{
|
{
|
||||||
btinfo->end = ftrace_new_gap (btinfo, BDE_PT_USER_QUIT);
|
struct btrace_function *bfun;
|
||||||
|
|
||||||
VEC_safe_push (bfun_s, *gaps, btinfo->end);
|
bfun = ftrace_new_gap (btinfo, BDE_PT_USER_QUIT);
|
||||||
|
|
||||||
|
VEC_safe_push (bfun_s, *gaps, bfun);
|
||||||
}
|
}
|
||||||
|
|
||||||
btrace_finalize_ftrace_pt (decoder, tp, level);
|
btrace_finalize_ftrace_pt (decoder, tp, level);
|
||||||
@ -1596,10 +1588,11 @@ btrace_stitch_bts (struct btrace_data_bts *btrace, struct thread_info *tp)
|
|||||||
btrace_block_s *first_new_block;
|
btrace_block_s *first_new_block;
|
||||||
|
|
||||||
btinfo = &tp->btrace;
|
btinfo = &tp->btrace;
|
||||||
last_bfun = btinfo->end;
|
gdb_assert (!btinfo->functions.empty ());
|
||||||
gdb_assert (last_bfun != NULL);
|
|
||||||
gdb_assert (!VEC_empty (btrace_block_s, btrace->blocks));
|
gdb_assert (!VEC_empty (btrace_block_s, btrace->blocks));
|
||||||
|
|
||||||
|
last_bfun = btinfo->functions.back ();
|
||||||
|
|
||||||
/* If the existing trace ends with a gap, we just glue the traces
|
/* 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
|
together. We need to drop the last (i.e. chronologically first) block
|
||||||
of the new trace, though, since we can't fill in the start address.*/
|
of the new trace, though, since we can't fill in the start address.*/
|
||||||
@ -1664,7 +1657,7 @@ btrace_stitch_bts (struct btrace_data_bts *btrace, struct thread_info *tp)
|
|||||||
of just that one instruction. If we remove it, we might turn the now
|
of just that one instruction. If we remove it, we might turn the now
|
||||||
empty btrace function segment into a gap. But we don't want gaps at
|
empty btrace function segment into a gap. But we don't want gaps at
|
||||||
the beginning. To avoid this, we remove the entire old trace. */
|
the beginning. To avoid this, we remove the entire old trace. */
|
||||||
if (last_bfun == btinfo->begin && VEC_empty (btrace_insn_s, last_bfun->insn))
|
if (last_bfun->number == 1 && VEC_empty (btrace_insn_s, last_bfun->insn))
|
||||||
btrace_clear (tp);
|
btrace_clear (tp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1827,7 +1820,7 @@ btrace_fetch (struct thread_info *tp)
|
|||||||
make_cleanup_btrace_data (&btrace);
|
make_cleanup_btrace_data (&btrace);
|
||||||
|
|
||||||
/* Let's first try to extend the trace we already have. */
|
/* Let's first try to extend the trace we already have. */
|
||||||
if (btinfo->end != NULL)
|
if (!btinfo->functions.empty ())
|
||||||
{
|
{
|
||||||
errcode = target_read_btrace (&btrace, tinfo, BTRACE_READ_DELTA);
|
errcode = target_read_btrace (&btrace, tinfo, BTRACE_READ_DELTA);
|
||||||
if (errcode == 0)
|
if (errcode == 0)
|
||||||
@ -1896,8 +1889,6 @@ btrace_clear (struct thread_info *tp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
btinfo->functions.clear ();
|
btinfo->functions.clear ();
|
||||||
btinfo->begin = NULL;
|
|
||||||
btinfo->end = NULL;
|
|
||||||
btinfo->ngaps = 0;
|
btinfo->ngaps = 0;
|
||||||
|
|
||||||
/* Must clear the maint data before - it depends on BTINFO->DATA. */
|
/* Must clear the maint data before - it depends on BTINFO->DATA. */
|
||||||
@ -2286,10 +2277,7 @@ void
|
|||||||
btrace_insn_begin (struct btrace_insn_iterator *it,
|
btrace_insn_begin (struct btrace_insn_iterator *it,
|
||||||
const struct btrace_thread_info *btinfo)
|
const struct btrace_thread_info *btinfo)
|
||||||
{
|
{
|
||||||
const struct btrace_function *bfun;
|
if (btinfo->functions.empty ())
|
||||||
|
|
||||||
bfun = btinfo->begin;
|
|
||||||
if (bfun == NULL)
|
|
||||||
error (_("No trace."));
|
error (_("No trace."));
|
||||||
|
|
||||||
it->btinfo = btinfo;
|
it->btinfo = btinfo;
|
||||||
@ -2306,10 +2294,10 @@ btrace_insn_end (struct btrace_insn_iterator *it,
|
|||||||
const struct btrace_function *bfun;
|
const struct btrace_function *bfun;
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
|
|
||||||
bfun = btinfo->end;
|
if (btinfo->functions.empty ())
|
||||||
if (bfun == NULL)
|
|
||||||
error (_("No trace."));
|
error (_("No trace."));
|
||||||
|
|
||||||
|
bfun = btinfo->functions.back ();
|
||||||
length = VEC_length (btrace_insn_s, bfun->insn);
|
length = VEC_length (btrace_insn_s, bfun->insn);
|
||||||
|
|
||||||
/* The last function may either be a gap or it contains the current
|
/* The last function may either be a gap or it contains the current
|
||||||
@ -2743,7 +2731,7 @@ btrace_is_empty (struct thread_info *tp)
|
|||||||
|
|
||||||
btinfo = &tp->btrace;
|
btinfo = &tp->btrace;
|
||||||
|
|
||||||
if (btinfo->begin == NULL)
|
if (btinfo->functions.empty ())
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
btrace_insn_begin (&begin, btinfo);
|
btrace_insn_begin (&begin, btinfo);
|
||||||
|
14
gdb/btrace.h
14
gdb/btrace.h
@ -331,17 +331,9 @@ struct btrace_thread_info
|
|||||||
/* The raw branch trace data for the below branch trace. */
|
/* The raw branch trace data for the below branch trace. */
|
||||||
struct btrace_data data;
|
struct btrace_data data;
|
||||||
|
|
||||||
/* The current branch trace for this thread (both inclusive).
|
/* Vector of pointer to decoded function segments in execution flow order.
|
||||||
|
Note that the numbering for btrace function segments starts with 1, so
|
||||||
The last instruction of END is the current instruction, which is not
|
function segment i will be at index (i - 1). */
|
||||||
part of the execution history.
|
|
||||||
Both will be NULL if there is no branch trace available. If there is
|
|
||||||
branch trace available, both will be non-NULL. */
|
|
||||||
struct btrace_function *begin;
|
|
||||||
struct btrace_function *end;
|
|
||||||
|
|
||||||
/* Vector of pointer to decoded function segments. These are in execution
|
|
||||||
order with the first element == BEGIN and the last element == END. */
|
|
||||||
std::vector<btrace_function *> functions;
|
std::vector<btrace_function *> functions;
|
||||||
|
|
||||||
/* The function level offset. When added to each function's LEVEL,
|
/* The function level offset. When added to each function's LEVEL,
|
||||||
|
@ -1908,7 +1908,7 @@ record_btrace_start_replaying (struct thread_info *tp)
|
|||||||
replay = NULL;
|
replay = NULL;
|
||||||
|
|
||||||
/* We can't start replaying without trace. */
|
/* We can't start replaying without trace. */
|
||||||
if (btinfo->begin == NULL)
|
if (btinfo->functions.empty ())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* GDB stores the current frame_id when stepping in order to detects steps
|
/* GDB stores the current frame_id when stepping in order to detects steps
|
||||||
|
Loading…
Reference in New Issue
Block a user