mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 10:03:47 +08:00
btrace: add struct btrace_data
Add a structure to hold the branch trace data and an enum to describe the format of that data. So far, only BTS is supported. Also added a NONE format to indicate that no branch trace data is available. This will make it easier to support different branch trace formats in the future. 2015-02-09 Markus Metzger <markus.t.metzger@intel.com> * Makefile.in (SFILES): Add common/btrace-common.c. (COMMON_OBS): Add common/btrace-common.o. (btrace-common.o): Add build rules. * btrace.c (parse_xml_btrace): Update parameters. (parse_xml_btrace_block): Set format field. (btrace_add_pc, btrace_fetch): Use struct btrace_data. (do_btrace_data_cleanup, make_cleanup_btrace_data): New. (btrace_compute_ftrace): Split into this and... (btrace_compute_ftrace_bts): ...this. (btrace_stitch_trace): Split into this and... (btrace_stitch_bts): ...this. * btrace.h (parse_xml_btrace): Update parameters. (make_cleanup_btrace_data): New. * common/btrace-common.c: New. * common/btrace-common.h: Include common-defs.h. (btrace_block_s): Update comment. (btrace_format): New. (btrace_format_string): New. (btrace_data_bts): New. (btrace_data): New. (btrace_data_init, btrace_data_fini, btrace_data_empty): New. * remote.c (remote_read_btrace): Update parameters. * target.c (target_read_btrace): Update parameters. * target.h (target_read_btrace): Update parameters. (target_ops)<to_read_btrace>: Update parameters. * x86-linux-nat.c (x86_linux_read_btrace): Update parameters. * target-delegates.c: Regenerate. * target-debug (target_debug_print_struct_btrace_data_p): New. * nat/linux-btrace.c (linux_read_btrace): Split into this and... (linux_read_bts): ...this. * nat/linux-btrace.h (linux_read_btrace): Update parameters. gdbserver/ * Makefile.in (SFILES): Add common/btrace-common.c. (OBS): Add common/btrace-common.o. (btrace-common.o): Add build rules. * linux-low: Include btrace-common.h. (linux_low_read_btrace): Use struct btrace_data. Call btrace_data_init and btrace_data_fini.
This commit is contained in:
parent
989f98793c
commit
734b0e4bda
@ -1,3 +1,37 @@
|
||||
2015-02-09 Markus Metzger <markus.t.metzger@intel.com>
|
||||
|
||||
* Makefile.in (SFILES): Add common/btrace-common.c.
|
||||
(COMMON_OBS): Add common/btrace-common.o.
|
||||
(btrace-common.o): Add build rules.
|
||||
* btrace.c (parse_xml_btrace): Update parameters.
|
||||
(parse_xml_btrace_block): Set format field.
|
||||
(btrace_add_pc, btrace_fetch): Use struct btrace_data.
|
||||
(do_btrace_data_cleanup, make_cleanup_btrace_data): New.
|
||||
(btrace_compute_ftrace): Split into this and...
|
||||
(btrace_compute_ftrace_bts): ...this.
|
||||
(btrace_stitch_trace): Split into this and...
|
||||
(btrace_stitch_bts): ...this.
|
||||
* btrace.h (parse_xml_btrace): Update parameters.
|
||||
(make_cleanup_btrace_data): New.
|
||||
* common/btrace-common.c: New.
|
||||
* common/btrace-common.h: Include common-defs.h.
|
||||
(btrace_block_s): Update comment.
|
||||
(btrace_format): New.
|
||||
(btrace_format_string): New.
|
||||
(btrace_data_bts): New.
|
||||
(btrace_data): New.
|
||||
(btrace_data_init, btrace_data_fini, btrace_data_empty): New.
|
||||
* remote.c (remote_read_btrace): Update parameters.
|
||||
* target.c (target_read_btrace): Update parameters.
|
||||
* target.h (target_read_btrace): Update parameters.
|
||||
(target_ops)<to_read_btrace>: Update parameters.
|
||||
* x86-linux-nat.c (x86_linux_read_btrace): Update parameters.
|
||||
* target-delegates.c: Regenerate.
|
||||
* target-debug (target_debug_print_struct_btrace_data_p): New.
|
||||
* nat/linux-btrace.c (linux_read_btrace): Split into this and...
|
||||
(linux_read_bts): ...this.
|
||||
* nat/linux-btrace.h (linux_read_btrace): Update parameters.
|
||||
|
||||
2015-02-06 Doug Evans <dje@google.com>
|
||||
|
||||
* remote-m32r-sdi.c: Include symfile.h.
|
||||
|
@ -873,6 +873,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
|
||||
common/format.c common/filestuff.c btrace.c record-btrace.c ctf.c \
|
||||
target/waitstatus.c common/print-utils.c common/rsp-low.c \
|
||||
common/errors.c common/common-debug.c common/common-exceptions.c \
|
||||
common/btrace-common.c \
|
||||
$(SUBDIR_GCC_COMPILE_SRCS)
|
||||
|
||||
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
|
||||
@ -1060,7 +1061,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
|
||||
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
|
||||
format.o registry.o btrace.o record-btrace.o waitstatus.o \
|
||||
print-utils.o rsp-low.o errors.o common-debug.o debug.o \
|
||||
common-exceptions.o \
|
||||
common-exceptions.o btrace-common.o \
|
||||
$(SUBDIR_GCC_COMPILE_OBS)
|
||||
|
||||
TSOBS = inflow.o
|
||||
@ -2234,6 +2235,10 @@ mingw-strerror.o: ${srcdir}/common/mingw-strerror.c
|
||||
$(COMPILE) $(srcdir)/common/mingw-strerror.c
|
||||
$(POSTCOMPILE)
|
||||
|
||||
btrace-common.o: ${srcdir}/common/btrace-common.c
|
||||
$(COMPILE) $(srcdir)/common/btrace-common.c
|
||||
$(POSTCOMPILE)
|
||||
|
||||
#
|
||||
# gdb/target/ dependencies
|
||||
#
|
||||
|
154
gdb/btrace.c
154
gdb/btrace.c
@ -585,25 +585,22 @@ ftrace_update_insns (struct btrace_function *bfun, CORE_ADDR pc)
|
||||
ftrace_debug (bfun, "update insn");
|
||||
}
|
||||
|
||||
/* Compute the function branch trace from a block branch trace BTRACE for
|
||||
a thread given by BTINFO. */
|
||||
/* Compute the function branch trace from BTS trace. */
|
||||
|
||||
static void
|
||||
btrace_compute_ftrace (struct btrace_thread_info *btinfo,
|
||||
VEC (btrace_block_s) *btrace)
|
||||
btrace_compute_ftrace_bts (struct btrace_thread_info *btinfo,
|
||||
const struct btrace_data_bts *btrace)
|
||||
{
|
||||
struct btrace_function *begin, *end;
|
||||
struct gdbarch *gdbarch;
|
||||
unsigned int blk;
|
||||
int level;
|
||||
|
||||
DEBUG ("compute ftrace");
|
||||
|
||||
gdbarch = target_gdbarch ();
|
||||
begin = btinfo->begin;
|
||||
end = btinfo->end;
|
||||
level = begin != NULL ? -btinfo->level : INT_MAX;
|
||||
blk = VEC_length (btrace_block_s, btrace);
|
||||
blk = VEC_length (btrace_block_s, btrace->blocks);
|
||||
|
||||
while (blk != 0)
|
||||
{
|
||||
@ -612,7 +609,7 @@ btrace_compute_ftrace (struct btrace_thread_info *btinfo,
|
||||
|
||||
blk -= 1;
|
||||
|
||||
block = VEC_index (btrace_block_s, btrace, blk);
|
||||
block = VEC_index (btrace_block_s, btrace->blocks, blk);
|
||||
pc = block->begin;
|
||||
|
||||
for (;;)
|
||||
@ -675,12 +672,34 @@ btrace_compute_ftrace (struct btrace_thread_info *btinfo,
|
||||
btinfo->level = -level;
|
||||
}
|
||||
|
||||
/* Compute the function branch trace from a block branch trace BTRACE for
|
||||
a thread given by BTINFO. */
|
||||
|
||||
static void
|
||||
btrace_compute_ftrace (struct btrace_thread_info *btinfo,
|
||||
struct btrace_data *btrace)
|
||||
{
|
||||
DEBUG ("compute ftrace");
|
||||
|
||||
switch (btrace->format)
|
||||
{
|
||||
case BTRACE_FORMAT_NONE:
|
||||
return;
|
||||
|
||||
case BTRACE_FORMAT_BTS:
|
||||
btrace_compute_ftrace_bts (btinfo, &btrace->variant.bts);
|
||||
return;
|
||||
}
|
||||
|
||||
internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
|
||||
}
|
||||
|
||||
/* Add an entry for the current PC. */
|
||||
|
||||
static void
|
||||
btrace_add_pc (struct thread_info *tp)
|
||||
{
|
||||
VEC (btrace_block_s) *btrace;
|
||||
struct btrace_data btrace;
|
||||
struct btrace_block *block;
|
||||
struct regcache *regcache;
|
||||
struct cleanup *cleanup;
|
||||
@ -689,14 +708,17 @@ btrace_add_pc (struct thread_info *tp)
|
||||
regcache = get_thread_regcache (tp->ptid);
|
||||
pc = regcache_read_pc (regcache);
|
||||
|
||||
btrace = NULL;
|
||||
cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace);
|
||||
btrace_data_init (&btrace);
|
||||
btrace.format = BTRACE_FORMAT_BTS;
|
||||
btrace.variant.bts.blocks = NULL;
|
||||
|
||||
block = VEC_safe_push (btrace_block_s, btrace, NULL);
|
||||
cleanup = make_cleanup_btrace_data (&btrace);
|
||||
|
||||
block = VEC_safe_push (btrace_block_s, btrace.variant.bts.blocks, NULL);
|
||||
block->begin = pc;
|
||||
block->end = pc;
|
||||
|
||||
btrace_compute_ftrace (&tp->btrace, btrace);
|
||||
btrace_compute_ftrace (&tp->btrace, &btrace);
|
||||
|
||||
do_cleanups (cleanup);
|
||||
}
|
||||
@ -760,31 +782,24 @@ btrace_teardown (struct thread_info *tp)
|
||||
btrace_clear (tp);
|
||||
}
|
||||
|
||||
/* Adjust the block trace in order to stitch old and new trace together.
|
||||
BTRACE is the new delta trace between the last and the current stop.
|
||||
BTINFO is the old branch trace until the last stop.
|
||||
May modify BTRACE as well as the existing trace in BTINFO.
|
||||
Return 0 on success, -1 otherwise. */
|
||||
/* Stitch branch trace in BTS format. */
|
||||
|
||||
static int
|
||||
btrace_stitch_trace (VEC (btrace_block_s) **btrace,
|
||||
const struct btrace_thread_info *btinfo)
|
||||
btrace_stitch_bts (struct btrace_data_bts *btrace,
|
||||
const struct btrace_thread_info *btinfo)
|
||||
{
|
||||
struct btrace_function *last_bfun;
|
||||
struct btrace_insn *last_insn;
|
||||
btrace_block_s *first_new_block;
|
||||
|
||||
/* If we don't have trace, there's nothing to do. */
|
||||
if (VEC_empty (btrace_block_s, *btrace))
|
||||
return 0;
|
||||
|
||||
last_bfun = btinfo->end;
|
||||
gdb_assert (last_bfun != NULL);
|
||||
|
||||
/* Beware that block trace starts with the most recent block, so the
|
||||
chronologically first block in the new trace is the last block in
|
||||
the new trace's block vector. */
|
||||
first_new_block = VEC_last (btrace_block_s, *btrace);
|
||||
gdb_assert (!VEC_empty (btrace_block_s, btrace->blocks));
|
||||
first_new_block = VEC_last (btrace_block_s, btrace->blocks);
|
||||
last_insn = VEC_last (btrace_insn_s, last_bfun->insn);
|
||||
|
||||
/* If the current PC at the end of the block is the same as in our current
|
||||
@ -796,9 +811,9 @@ btrace_stitch_trace (VEC (btrace_block_s) **btrace,
|
||||
In the second case, the delta trace vector should contain exactly one
|
||||
entry for the partial block containing the current PC. Remove it. */
|
||||
if (first_new_block->end == last_insn->pc
|
||||
&& VEC_length (btrace_block_s, *btrace) == 1)
|
||||
&& VEC_length (btrace_block_s, btrace->blocks) == 1)
|
||||
{
|
||||
VEC_pop (btrace_block_s, *btrace);
|
||||
VEC_pop (btrace_block_s, btrace->blocks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -834,6 +849,32 @@ btrace_stitch_trace (VEC (btrace_block_s) **btrace,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Adjust the block trace in order to stitch old and new trace together.
|
||||
BTRACE is the new delta trace between the last and the current stop.
|
||||
BTINFO is the old branch trace until the last stop.
|
||||
May modifx BTRACE as well as the existing trace in BTINFO.
|
||||
Return 0 on success, -1 otherwise. */
|
||||
|
||||
static int
|
||||
btrace_stitch_trace (struct btrace_data *btrace,
|
||||
const struct btrace_thread_info *btinfo)
|
||||
{
|
||||
/* If we don't have trace, there's nothing to do. */
|
||||
if (btrace_data_empty (btrace))
|
||||
return 0;
|
||||
|
||||
switch (btrace->format)
|
||||
{
|
||||
case BTRACE_FORMAT_NONE:
|
||||
return 0;
|
||||
|
||||
case BTRACE_FORMAT_BTS:
|
||||
return btrace_stitch_bts (&btrace->variant.bts, btinfo);
|
||||
}
|
||||
|
||||
internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
|
||||
}
|
||||
|
||||
/* Clear the branch trace histories in BTINFO. */
|
||||
|
||||
static void
|
||||
@ -855,13 +896,12 @@ btrace_fetch (struct thread_info *tp)
|
||||
{
|
||||
struct btrace_thread_info *btinfo;
|
||||
struct btrace_target_info *tinfo;
|
||||
VEC (btrace_block_s) *btrace;
|
||||
struct btrace_data btrace;
|
||||
struct cleanup *cleanup;
|
||||
int errcode;
|
||||
|
||||
DEBUG ("fetch thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
|
||||
|
||||
btrace = NULL;
|
||||
btinfo = &tp->btrace;
|
||||
tinfo = btinfo->target;
|
||||
if (tinfo == NULL)
|
||||
@ -873,7 +913,8 @@ btrace_fetch (struct thread_info *tp)
|
||||
if (btinfo->replay != NULL)
|
||||
return;
|
||||
|
||||
cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace);
|
||||
btrace_data_init (&btrace);
|
||||
cleanup = make_cleanup_btrace_data (&btrace);
|
||||
|
||||
/* Let's first try to extend the trace we already have. */
|
||||
if (btinfo->end != NULL)
|
||||
@ -890,7 +931,7 @@ btrace_fetch (struct thread_info *tp)
|
||||
errcode = target_read_btrace (&btrace, tinfo, BTRACE_READ_NEW);
|
||||
|
||||
/* If we got any new trace, discard what we have. */
|
||||
if (errcode == 0 && !VEC_empty (btrace_block_s, btrace))
|
||||
if (errcode == 0 && !btrace_data_empty (&btrace))
|
||||
btrace_clear (tp);
|
||||
}
|
||||
|
||||
@ -909,10 +950,10 @@ btrace_fetch (struct thread_info *tp)
|
||||
error (_("Failed to read branch trace."));
|
||||
|
||||
/* Compute the trace, provided we have any. */
|
||||
if (!VEC_empty (btrace_block_s, btrace))
|
||||
if (!btrace_data_empty (&btrace))
|
||||
{
|
||||
btrace_clear_history (btinfo);
|
||||
btrace_compute_ftrace (btinfo, btrace);
|
||||
btrace_compute_ftrace (btinfo, &btrace);
|
||||
}
|
||||
|
||||
do_cleanups (cleanup);
|
||||
@ -984,16 +1025,30 @@ parse_xml_btrace_block (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC (gdb_xml_value_s) *attributes)
|
||||
{
|
||||
VEC (btrace_block_s) **btrace;
|
||||
struct btrace_data *btrace;
|
||||
struct btrace_block *block;
|
||||
ULONGEST *begin, *end;
|
||||
|
||||
btrace = user_data;
|
||||
block = VEC_safe_push (btrace_block_s, *btrace, NULL);
|
||||
|
||||
switch (btrace->format)
|
||||
{
|
||||
case BTRACE_FORMAT_BTS:
|
||||
break;
|
||||
|
||||
case BTRACE_FORMAT_NONE:
|
||||
btrace->format = BTRACE_FORMAT_BTS;
|
||||
btrace->variant.bts.blocks = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
gdb_xml_error (parser, _("Btrace format error."));
|
||||
}
|
||||
|
||||
begin = xml_find_attribute (attributes, "begin")->value;
|
||||
end = xml_find_attribute (attributes, "end")->value;
|
||||
|
||||
block = VEC_safe_push (btrace_block_s, btrace->variant.bts.blocks, NULL);
|
||||
block->begin = *begin;
|
||||
block->end = *end;
|
||||
}
|
||||
@ -1025,18 +1080,19 @@ static const struct gdb_xml_element btrace_elements[] = {
|
||||
|
||||
/* See btrace.h. */
|
||||
|
||||
VEC (btrace_block_s) *
|
||||
parse_xml_btrace (const char *buffer)
|
||||
void
|
||||
parse_xml_btrace (struct btrace_data *btrace, const char *buffer)
|
||||
{
|
||||
VEC (btrace_block_s) *btrace = NULL;
|
||||
struct cleanup *cleanup;
|
||||
int errcode;
|
||||
|
||||
#if defined (HAVE_LIBEXPAT)
|
||||
|
||||
cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace);
|
||||
btrace->format = BTRACE_FORMAT_NONE;
|
||||
|
||||
cleanup = make_cleanup_btrace_data (btrace);
|
||||
errcode = gdb_xml_parse_quick (_("btrace"), "btrace.dtd", btrace_elements,
|
||||
buffer, &btrace);
|
||||
buffer, btrace);
|
||||
if (errcode != 0)
|
||||
error (_("Error parsing branch trace."));
|
||||
|
||||
@ -1048,8 +1104,6 @@ parse_xml_btrace (const char *buffer)
|
||||
error (_("Cannot process branch trace. XML parsing is not supported."));
|
||||
|
||||
#endif /* !defined (HAVE_LIBEXPAT) */
|
||||
|
||||
return btrace;
|
||||
}
|
||||
|
||||
/* See btrace.h. */
|
||||
@ -1526,3 +1580,19 @@ btrace_is_empty (struct thread_info *tp)
|
||||
|
||||
return btrace_insn_cmp (&begin, &end) == 0;
|
||||
}
|
||||
|
||||
/* Forward the cleanup request. */
|
||||
|
||||
static void
|
||||
do_btrace_data_cleanup (void *arg)
|
||||
{
|
||||
btrace_data_fini (arg);
|
||||
}
|
||||
|
||||
/* See btrace.h. */
|
||||
|
||||
struct cleanup *
|
||||
make_cleanup_btrace_data (struct btrace_data *data)
|
||||
{
|
||||
return make_cleanup (do_btrace_data_cleanup, data);
|
||||
}
|
||||
|
@ -235,8 +235,8 @@ extern void btrace_clear (struct thread_info *);
|
||||
/* Clear the branch trace for all threads when an object file goes away. */
|
||||
extern void btrace_free_objfile (struct objfile *);
|
||||
|
||||
/* Parse a branch trace xml document into a block vector. */
|
||||
extern VEC (btrace_block_s) *parse_xml_btrace (const char*);
|
||||
/* Parse a branch trace xml document XML into DATA. */
|
||||
extern void parse_xml_btrace (struct btrace_data *data, const char *xml);
|
||||
|
||||
/* Dereference a branch trace instruction iterator. Return a pointer to the
|
||||
instruction the iterator points to. */
|
||||
@ -339,5 +339,7 @@ extern int btrace_is_replaying (struct thread_info *tp);
|
||||
/* Return non-zero if the branch trace for TP is empty; zero otherwise. */
|
||||
extern int btrace_is_empty (struct thread_info *tp);
|
||||
|
||||
/* Create a cleanup for DATA. */
|
||||
extern struct cleanup *make_cleanup_btrace_data (struct btrace_data *data);
|
||||
|
||||
#endif /* BTRACE_H */
|
||||
|
83
gdb/common/btrace-common.c
Normal file
83
gdb/common/btrace-common.c
Normal file
@ -0,0 +1,83 @@
|
||||
/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
|
||||
|
||||
Contributed by Intel Corp. <markus.t.metzger@intel.com>
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "common-defs.h"
|
||||
#include "btrace-common.h"
|
||||
|
||||
|
||||
/* See btrace-common.h. */
|
||||
|
||||
const char *
|
||||
btrace_format_string (enum btrace_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case BTRACE_FORMAT_NONE:
|
||||
return _("No or unknown format");
|
||||
|
||||
case BTRACE_FORMAT_BTS:
|
||||
return _("Branch Trace Store");
|
||||
}
|
||||
|
||||
internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
|
||||
}
|
||||
|
||||
/* See btrace-common.h. */
|
||||
|
||||
void
|
||||
btrace_data_init (struct btrace_data *data)
|
||||
{
|
||||
data->format = BTRACE_FORMAT_NONE;
|
||||
}
|
||||
|
||||
/* See btrace-common.h. */
|
||||
|
||||
void
|
||||
btrace_data_fini (struct btrace_data *data)
|
||||
{
|
||||
switch (data->format)
|
||||
{
|
||||
case BTRACE_FORMAT_NONE:
|
||||
/* Nothing to do. */
|
||||
return;
|
||||
|
||||
case BTRACE_FORMAT_BTS:
|
||||
VEC_free (btrace_block_s, data->variant.bts.blocks);
|
||||
return;
|
||||
}
|
||||
|
||||
internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
|
||||
}
|
||||
|
||||
/* See btrace-common.h. */
|
||||
|
||||
int
|
||||
btrace_data_empty (struct btrace_data *data)
|
||||
{
|
||||
switch (data->format)
|
||||
{
|
||||
case BTRACE_FORMAT_NONE:
|
||||
return 1;
|
||||
|
||||
case BTRACE_FORMAT_BTS:
|
||||
return VEC_empty (btrace_block_s, data->variant.bts.blocks);
|
||||
}
|
||||
|
||||
internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
|
||||
}
|
@ -45,13 +45,42 @@ struct btrace_block
|
||||
CORE_ADDR end;
|
||||
};
|
||||
|
||||
/* Branch trace is represented as a vector of branch trace blocks starting with
|
||||
the most recent block. */
|
||||
typedef struct btrace_block btrace_block_s;
|
||||
|
||||
/* Define functions operating on a vector of branch trace blocks. */
|
||||
typedef struct btrace_block btrace_block_s;
|
||||
DEF_VEC_O (btrace_block_s);
|
||||
|
||||
/* Enumeration of btrace formats. */
|
||||
|
||||
enum btrace_format
|
||||
{
|
||||
/* No branch trace format. */
|
||||
BTRACE_FORMAT_NONE,
|
||||
|
||||
/* Branch trace is in Branch Trace Store (BTS) format.
|
||||
Actually, the format is a sequence of blocks derived from BTS. */
|
||||
BTRACE_FORMAT_BTS
|
||||
};
|
||||
|
||||
/* Branch trace in BTS format. */
|
||||
struct btrace_data_bts
|
||||
{
|
||||
/* Branch trace is represented as a vector of branch trace blocks starting
|
||||
with the most recent block. */
|
||||
VEC (btrace_block_s) *blocks;
|
||||
};
|
||||
|
||||
/* The branch trace data. */
|
||||
struct btrace_data
|
||||
{
|
||||
enum btrace_format format;
|
||||
|
||||
union
|
||||
{
|
||||
/* Format == BTRACE_FORMAT_BTS. */
|
||||
struct btrace_data_bts bts;
|
||||
} variant;
|
||||
};
|
||||
|
||||
/* Target specific branch trace information. */
|
||||
struct btrace_target_info;
|
||||
|
||||
@ -87,4 +116,16 @@ enum btrace_error
|
||||
BTRACE_ERR_OVERFLOW
|
||||
};
|
||||
|
||||
/* Return a string representation of FORMAT. */
|
||||
extern const char *btrace_format_string (enum btrace_format format);
|
||||
|
||||
/* Initialize DATA. */
|
||||
extern void btrace_data_init (struct btrace_data *data);
|
||||
|
||||
/* Cleanup DATA. */
|
||||
extern void btrace_data_fini (struct btrace_data *data);
|
||||
|
||||
/* Return non-zero if DATA is empty; zero otherwise. */
|
||||
extern int btrace_data_empty (struct btrace_data *data);
|
||||
|
||||
#endif /* BTRACE_COMMON_H */
|
||||
|
@ -1,3 +1,12 @@
|
||||
2015-02-09 Markus Metzger <markus.t.metzger@intel.com>
|
||||
|
||||
* Makefile.in (SFILES): Add common/btrace-common.c.
|
||||
(OBS): Add common/btrace-common.o.
|
||||
(btrace-common.o): Add build rules.
|
||||
* linux-low: Include btrace-common.h.
|
||||
(linux_low_read_btrace): Use struct btrace_data. Call
|
||||
btrace_data_init and btrace_data_fini.
|
||||
|
||||
2015-02-06 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* thread-db.c (find_new_threads_callback): Add debug output.
|
||||
|
@ -173,7 +173,8 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
|
||||
$(srcdir)/nat/mips-linux-watch.c $(srcdir)/common/print-utils.c \
|
||||
$(srcdir)/common/rsp-low.c $(srcdir)/common/errors.c \
|
||||
$(srcdir)/common/common-debug.c $(srcdir)/common/cleanups.c \
|
||||
$(srcdir)/common/common-exceptions.c $(srcdir)/symbol.c
|
||||
$(srcdir)/common/common-exceptions.c $(srcdir)/symbol.c \
|
||||
$(srcdir)/common/btrace-common.c
|
||||
|
||||
DEPFILES = @GDBSERVER_DEPFILES@
|
||||
|
||||
@ -187,7 +188,7 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o \
|
||||
mem-break.o hostio.o event-loop.o tracepoint.o xml-utils.o \
|
||||
common-utils.o ptid.o buffer.o format.o filestuff.o dll.o notif.o \
|
||||
tdesc.o print-utils.o rsp-low.o errors.o common-debug.o cleanups.o \
|
||||
common-exceptions.o symbol.o \
|
||||
common-exceptions.o symbol.o btrace-common.o \
|
||||
$(XML_BUILTIN) $(DEPFILES) $(LIBOBJS)
|
||||
GDBREPLAY_OBS = gdbreplay.o version.o
|
||||
GDBSERVER_LIBS = @GDBSERVER_LIBS@
|
||||
@ -594,6 +595,9 @@ ppc-linux.o: ../nat/ppc-linux.c
|
||||
linux-personality.o: ../nat/linux-personality.c
|
||||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
btrace-common.o: ../common/btrace-common.c
|
||||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
aarch64.c : $(srcdir)/../regformats/aarch64.dat $(regdat_sh)
|
||||
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/aarch64.dat aarch64.c
|
||||
|
@ -103,6 +103,7 @@
|
||||
|
||||
#ifdef HAVE_LINUX_BTRACE
|
||||
# include "nat/linux-btrace.h"
|
||||
# include "btrace-common.h"
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ELF32_AUXV_T
|
||||
@ -5971,12 +5972,13 @@ static int
|
||||
linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
|
||||
int type)
|
||||
{
|
||||
VEC (btrace_block_s) *btrace;
|
||||
struct btrace_data btrace;
|
||||
struct btrace_block *block;
|
||||
enum btrace_error err;
|
||||
int i;
|
||||
|
||||
btrace = NULL;
|
||||
btrace_data_init (&btrace);
|
||||
|
||||
err = linux_read_btrace (&btrace, tinfo, type);
|
||||
if (err != BTRACE_ERR_NONE)
|
||||
{
|
||||
@ -5985,20 +5987,37 @@ linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
|
||||
else
|
||||
buffer_grow_str0 (buffer, "E.Generic Error.");
|
||||
|
||||
btrace_data_fini (&btrace);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
|
||||
buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
|
||||
switch (btrace.format)
|
||||
{
|
||||
case BTRACE_FORMAT_NONE:
|
||||
buffer_grow_str0 (buffer, "E.No Trace.");
|
||||
break;
|
||||
|
||||
for (i = 0; VEC_iterate (btrace_block_s, btrace, i, block); i++)
|
||||
buffer_xml_printf (buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
|
||||
paddress (block->begin), paddress (block->end));
|
||||
case BTRACE_FORMAT_BTS:
|
||||
buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
|
||||
buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
|
||||
|
||||
buffer_grow_str0 (buffer, "</btrace>\n");
|
||||
for (i = 0;
|
||||
VEC_iterate (btrace_block_s, btrace.variant.bts.blocks, i, block);
|
||||
i++)
|
||||
buffer_xml_printf (buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
|
||||
paddress (block->begin), paddress (block->end));
|
||||
|
||||
VEC_free (btrace_block_s, btrace);
|
||||
buffer_grow_str0 (buffer, "</btrace>\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
buffer_grow_str0 (buffer, "E.Unknown Trace Format.");
|
||||
|
||||
btrace_data_fini (&btrace);
|
||||
return -1;
|
||||
}
|
||||
|
||||
btrace_data_fini (&btrace);
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_LINUX_BTRACE */
|
||||
|
@ -495,12 +495,13 @@ linux_btrace_has_changed (struct btrace_target_info *tinfo)
|
||||
return header->data_head != tinfo->data_head;
|
||||
}
|
||||
|
||||
/* See linux-btrace.h. */
|
||||
/* Read branch trace data in BTS format for the thread given by TINFO into
|
||||
BTRACE using the TYPE reading method. */
|
||||
|
||||
enum btrace_error
|
||||
linux_read_btrace (VEC (btrace_block_s) **btrace,
|
||||
struct btrace_target_info *tinfo,
|
||||
enum btrace_read_type type)
|
||||
static enum btrace_error
|
||||
linux_read_bts (struct btrace_data_bts *btrace,
|
||||
struct btrace_target_info *tinfo,
|
||||
enum btrace_read_type type)
|
||||
{
|
||||
volatile struct perf_event_mmap_page *header;
|
||||
const uint8_t *begin, *end, *start;
|
||||
@ -522,7 +523,7 @@ linux_read_btrace (VEC (btrace_block_s) **btrace,
|
||||
data_head = header->data_head;
|
||||
|
||||
/* Delete any leftover trace from the previous iteration. */
|
||||
VEC_free (btrace_block_s, *btrace);
|
||||
VEC_free (btrace_block_s, btrace->blocks);
|
||||
|
||||
if (type == BTRACE_READ_DELTA)
|
||||
{
|
||||
@ -559,7 +560,7 @@ linux_read_btrace (VEC (btrace_block_s) **btrace,
|
||||
else
|
||||
end = perf_event_buffer_end (tinfo);
|
||||
|
||||
*btrace = perf_event_read_bts (tinfo, begin, end, start, size);
|
||||
btrace->blocks = perf_event_read_bts (tinfo, begin, end, start, size);
|
||||
|
||||
/* The stopping thread notifies its ptracer before it is scheduled out.
|
||||
On multi-core systems, the debugger might therefore run while the
|
||||
@ -575,12 +576,27 @@ linux_read_btrace (VEC (btrace_block_s) **btrace,
|
||||
/* Prune the incomplete last block (i.e. the first one of inferior execution)
|
||||
if we're not doing a delta read. There is no way of filling in its zeroed
|
||||
BEGIN element. */
|
||||
if (!VEC_empty (btrace_block_s, *btrace) && type != BTRACE_READ_DELTA)
|
||||
VEC_pop (btrace_block_s, *btrace);
|
||||
if (!VEC_empty (btrace_block_s, btrace->blocks)
|
||||
&& type != BTRACE_READ_DELTA)
|
||||
VEC_pop (btrace_block_s, btrace->blocks);
|
||||
|
||||
return BTRACE_ERR_NONE;
|
||||
}
|
||||
|
||||
/* See linux-btrace.h. */
|
||||
|
||||
enum btrace_error
|
||||
linux_read_btrace (struct btrace_data *btrace,
|
||||
struct btrace_target_info *tinfo,
|
||||
enum btrace_read_type type)
|
||||
{
|
||||
/* We read btrace in BTS format. */
|
||||
btrace->format = BTRACE_FORMAT_BTS;
|
||||
btrace->variant.bts.blocks = NULL;
|
||||
|
||||
return linux_read_bts (&btrace->variant.bts, tinfo, type);
|
||||
}
|
||||
|
||||
#else /* !HAVE_LINUX_PERF_EVENT_H */
|
||||
|
||||
/* See linux-btrace.h. */
|
||||
@ -610,7 +626,7 @@ linux_disable_btrace (struct btrace_target_info *tinfo)
|
||||
/* See linux-btrace.h. */
|
||||
|
||||
enum btrace_error
|
||||
linux_read_btrace (VEC (btrace_block_s) **btrace,
|
||||
linux_read_btrace (struct btrace_data *btrace,
|
||||
struct btrace_target_info *tinfo,
|
||||
enum btrace_read_type type)
|
||||
{
|
||||
|
@ -70,7 +70,7 @@ extern struct btrace_target_info *linux_enable_btrace (ptid_t ptid);
|
||||
extern enum btrace_error linux_disable_btrace (struct btrace_target_info *ti);
|
||||
|
||||
/* See to_read_btrace in target.h. */
|
||||
extern enum btrace_error linux_read_btrace (VEC (btrace_block_s) **btrace,
|
||||
extern enum btrace_error linux_read_btrace (struct btrace_data *btrace,
|
||||
struct btrace_target_info *btinfo,
|
||||
enum btrace_read_type type);
|
||||
|
||||
|
@ -11419,7 +11419,7 @@ remote_teardown_btrace (struct target_ops *self,
|
||||
|
||||
static enum btrace_error
|
||||
remote_read_btrace (struct target_ops *self,
|
||||
VEC (btrace_block_s) **btrace,
|
||||
struct btrace_data *btrace,
|
||||
struct btrace_target_info *tinfo,
|
||||
enum btrace_read_type type)
|
||||
{
|
||||
@ -11459,7 +11459,7 @@ remote_read_btrace (struct target_ops *self,
|
||||
return BTRACE_ERR_UNKNOWN;
|
||||
|
||||
cleanup = make_cleanup (xfree, xml);
|
||||
*btrace = parse_xml_btrace (xml);
|
||||
parse_xml_btrace (btrace, xml);
|
||||
do_cleanups (cleanup);
|
||||
|
||||
return BTRACE_ERR_NONE;
|
||||
|
@ -144,6 +144,8 @@
|
||||
target_debug_do_print (host_address_to_string (X))
|
||||
#define target_debug_print_const_struct_frame_unwind_p(X) \
|
||||
target_debug_do_print (host_address_to_string (X))
|
||||
#define target_debug_print_struct_btrace_data_p(X) \
|
||||
target_debug_do_print (host_address_to_string (X))
|
||||
|
||||
static void
|
||||
target_debug_print_struct_target_waitstatus_p (struct target_waitstatus *status)
|
||||
|
@ -3191,20 +3191,20 @@ debug_teardown_btrace (struct target_ops *self, struct btrace_target_info *arg1)
|
||||
}
|
||||
|
||||
static enum btrace_error
|
||||
delegate_read_btrace (struct target_ops *self, VEC (btrace_block_s) **arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
|
||||
delegate_read_btrace (struct target_ops *self, struct btrace_data *arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
|
||||
{
|
||||
self = self->beneath;
|
||||
return self->to_read_btrace (self, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
static enum btrace_error
|
||||
tdefault_read_btrace (struct target_ops *self, VEC (btrace_block_s) **arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
|
||||
tdefault_read_btrace (struct target_ops *self, struct btrace_data *arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
|
||||
{
|
||||
tcomplain ();
|
||||
}
|
||||
|
||||
static enum btrace_error
|
||||
debug_read_btrace (struct target_ops *self, VEC (btrace_block_s) **arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
|
||||
debug_read_btrace (struct target_ops *self, struct btrace_data *arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
|
||||
{
|
||||
enum btrace_error result;
|
||||
fprintf_unfiltered (gdb_stdlog, "-> %s->to_read_btrace (...)\n", debug_target.to_shortname);
|
||||
@ -3212,7 +3212,7 @@ debug_read_btrace (struct target_ops *self, VEC (btrace_block_s) **arg1, struct
|
||||
fprintf_unfiltered (gdb_stdlog, "<- %s->to_read_btrace (", debug_target.to_shortname);
|
||||
target_debug_print_struct_target_ops_p (&debug_target);
|
||||
fputs_unfiltered (", ", gdb_stdlog);
|
||||
target_debug_print_VEC__btrace_block_s__pp (arg1);
|
||||
target_debug_print_struct_btrace_data_p (arg1);
|
||||
fputs_unfiltered (", ", gdb_stdlog);
|
||||
target_debug_print_struct_btrace_target_info_p (arg2);
|
||||
fputs_unfiltered (", ", gdb_stdlog);
|
||||
|
@ -3414,7 +3414,7 @@ target_teardown_btrace (struct btrace_target_info *btinfo)
|
||||
/* See target.h. */
|
||||
|
||||
enum btrace_error
|
||||
target_read_btrace (VEC (btrace_block_s) **btrace,
|
||||
target_read_btrace (struct btrace_data *btrace,
|
||||
struct btrace_target_info *btinfo,
|
||||
enum btrace_read_type type)
|
||||
{
|
||||
|
@ -1022,11 +1022,9 @@ struct target_ops
|
||||
TARGET_DEFAULT_NORETURN (tcomplain ());
|
||||
|
||||
/* Read branch trace data for the thread indicated by BTINFO into DATA.
|
||||
DATA is cleared before new trace is added.
|
||||
The branch trace will start with the most recent block and continue
|
||||
towards older blocks. */
|
||||
DATA is cleared before new trace is added. */
|
||||
enum btrace_error (*to_read_btrace) (struct target_ops *self,
|
||||
VEC (btrace_block_s) **data,
|
||||
struct btrace_data *data,
|
||||
struct btrace_target_info *btinfo,
|
||||
enum btrace_read_type type)
|
||||
TARGET_DEFAULT_NORETURN (tcomplain ());
|
||||
@ -2230,7 +2228,7 @@ extern void target_disable_btrace (struct btrace_target_info *btinfo);
|
||||
extern void target_teardown_btrace (struct btrace_target_info *btinfo);
|
||||
|
||||
/* See to_read_btrace in struct target_ops. */
|
||||
extern enum btrace_error target_read_btrace (VEC (btrace_block_s) **,
|
||||
extern enum btrace_error target_read_btrace (struct btrace_data *,
|
||||
struct btrace_target_info *,
|
||||
enum btrace_read_type);
|
||||
|
||||
|
@ -470,7 +470,7 @@ x86_linux_teardown_btrace (struct target_ops *self,
|
||||
|
||||
static enum btrace_error
|
||||
x86_linux_read_btrace (struct target_ops *self,
|
||||
VEC (btrace_block_s) **data,
|
||||
struct btrace_data *data,
|
||||
struct btrace_target_info *btinfo,
|
||||
enum btrace_read_type type)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user