[PATCH v2 01/13] btrace: add struct btrace_data

Markus Metzger
2014-11-20T10:47:41Z

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.

2014-11-20 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.
* 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.
---
gdb/Makefile.in | 9 ++-
gdb/btrace.c | 154 ++++++++++++++++++++++++++++++++-------------
gdb/btrace.h | 6 +-
gdb/common/btrace-common.c | 82 ++++++++++++++++++++++++
gdb/common/btrace-common.h | 50 +++++++++++++--
gdb/gdbserver/Makefile.in | 8 ++-
gdb/gdbserver/linux-low.c | 37 ++++++++---
gdb/nat/linux-btrace.c | 36 ++++++++---
gdb/nat/linux-btrace.h | 2 +-
gdb/remote.c | 4 +-
gdb/target-debug.h | 2 +
gdb/target-delegates.c | 8 +--
gdb/target.c | 2 +-
gdb/target.h | 8 +--
gdb/x86-linux-nat.c | 2 +-
15 files changed, 325 insertions(+), 85 deletions(-)
create mode 100644 gdb/common/btrace-common.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 1da8af6..344ff94 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -852,7 +852,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.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/errors.c common/common-debug.c common/common-exceptions.c \
+ common/btrace-common.c

LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c

@@ -1039,7 +1040,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

TSOBS = inflow.o

@@ -2172,6 +2173,10 @@ common-exceptions.o: ${srcdir}/common/common-exceptions.c
$(COMPILE) $(srcdir)/common/common-exceptions.c
$(POSTCOMPILE)

+btrace-common.o: ${srcdir}/common/btrace-common.c
+ $(COMPILE) $(srcdir)/common/btrace-common.c
+ $(POSTCOMPILE)
+
#
# gdb/target/ dependencies
#
diff --git a/gdb/btrace.c b/gdb/btrace.c
index b8b5139..470a676 100644
--- a/gdb/btrace.c
+++ b/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);
+}
diff --git a/gdb/btrace.h b/gdb/btrace.h
index f83a80f..3954581 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -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 */
diff --git a/gdb/common/btrace-common.c b/gdb/common/btrace-common.c
new file mode 100644
index 0000000..869d0cb
--- /dev/null
+++ b/gdb/common/btrace-common.c
@@ -0,0 +1,82 @@
+/* Copyright (C) 2014 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 "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 _("Intel(R) 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."));
+}
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index 339e684..27e7a95 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -26,6 +26,7 @@
inferior. For presentation purposes, the branch trace is represented as a
list of sequential control-flow blocks, one such list per thread. */

+#include "common-defs.h"
#include "vec.h"

/* A branch trace block.
@@ -45,13 +46,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 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 +117,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 */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 8b0318a..98897d9 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -172,7 +172,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@

@@ -186,7 +187,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@
@@ -581,6 +582,9 @@ linux-waitpid.o: ../nat/linux-waitpid.c
mips-linux-watch.o: ../nat/mips-linux-watch.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
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 01f11b7..dcaa829 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -102,6 +102,7 @@

#ifdef HAVE_LINUX_BTRACE
# include "nat/linux-btrace.h"
+# include "btrace-common.h"
#endif

#ifndef HAVE_ELF32_AUXV_T
@@ -5968,12 +5969,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)
{
@@ -5982,20 +5984,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, " \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;
+
+ case BTRACE_FORMAT_BTS:
+ buffer_grow_str (buffer, " \n");
+ buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");

- 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));
+ 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));

- buffer_grow_str0 (buffer, "</btrace>\n");
+ buffer_grow_str0 (buffer, "</btrace>\n");
+ break;
+
+ default:
+ buffer_grow_str0 (buffer, "E.Unknown Trace Format.");

- VEC_free (btrace_block_s, btrace);
+ btrace_data_fini (&btrace);
+ return -1;
+ }

+ btrace_data_fini (&btrace);
return 0;
}
#endif /* HAVE_LINUX_BTRACE */
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 37c85c0..916f6b3 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -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)
{
diff --git a/gdb/nat/linux-btrace.h b/gdb/nat/linux-btrace.h
index e4b2604..2a08df7 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -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);

diff --git a/gdb/remote.c b/gdb/remote.c
index 4b9b099..249deaa 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -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;
diff --git a/gdb/target-debug.h b/gdb/target-debug.h
index 3dd705c..60da35c 100644
--- a/gdb/target-debug.h
+++ b/gdb/target-debug.h
@@ -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)
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index 9beb5ff..00956ba 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -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);
diff --git a/gdb/target.c b/gdb/target.c
index ab5f2b9..891183f 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3380,7 +3380,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)
{
diff --git a/gdb/target.h b/gdb/target.h
index d363b61..dee587f 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -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 ());
@@ -2226,7 +2224,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);

diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
index b2141eb..d9ba33e 100644
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -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)
{
--
1.8.3.1