From: Markus Metzger Date: Wed, 13 Nov 2013 14:31:07 +0000 (+0100) Subject: btrace: add struct btrace_data X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=734b0e4bda4c56d0003182cdc3f5137d4bea00d4;p=binutils-gdb.git 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 * 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): 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. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a0c7668c3e2..12b8e9f61f3 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,37 @@ +2015-02-09 Markus Metzger + + * 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): 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 * remote-m32r-sdi.c: Include symfile.h. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 8addef470e6..bfebf613a2e 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -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 # diff --git a/gdb/btrace.c b/gdb/btrace.c index b6e6bf7503d..3b20981a6db 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 e3a241940a2..730cb5f80fa 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 00000000000..0ea50f039f3 --- /dev/null +++ b/gdb/common/btrace-common.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2014-2015 Free Software Foundation, Inc. + + Contributed by Intel Corp. + + 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 . */ + +#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.")); +} diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h index 6118c0da678..f230dbc9222 100644 --- a/gdb/common/btrace-common.h +++ b/gdb/common/btrace-common.h @@ -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 */ diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 866e2d66a23..fd8402e0b50 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,12 @@ +2015-02-09 Markus Metzger + + * 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 * thread-db.c (find_new_threads_callback): Add debug output. diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index b455c5b3458..e479c7c2593 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -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 diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 1682679f810..8bc73a473a5 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.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, "\n"); - buffer_grow_str (buffer, "\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, "\n"); - for (i = 0; VEC_iterate (btrace_block_s, btrace, i, block); i++) - buffer_xml_printf (buffer, "\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, "\n", + paddress (block->begin), paddress (block->end)); - buffer_grow_str0 (buffer, "\n"); + buffer_grow_str0 (buffer, "\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 1181a4c8e5d..6cec5d04c10 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 3bfb798000c..1b11abaf74a 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 e971a29d51a..e7557d77fdf 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 65db5d915b9..8a32810be83 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 9beb5ff2172..00956ba3109 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 5f0ed6f0ffb..763ddcba87e 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -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) { diff --git a/gdb/target.h b/gdb/target.h index 2a40cd126e7..36fa3c6a945 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 ()); @@ -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); diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c index f7e9037d605..78b547b7b15 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) {