diff options
author | Markus Metzger <mmetzger@sourceware.org> | 2013-03-11 08:17:08 +0000 |
---|---|---|
committer | Markus Metzger <mmetzger@sourceware.org> | 2013-03-11 08:17:08 +0000 |
commit | 02d27625761a91b9ea78ab4048e1171a7b47a603 (patch) | |
tree | b2ccd263c72cb451d952aca550d8389ce488e6e7 | |
parent | 7bc0ae020fedff59d2acda93cb9e78b112b350ea (diff) | |
download | gdb-02d27625761a91b9ea78ab4048e1171a7b47a603.zip gdb-02d27625761a91b9ea78ab4048e1171a7b47a603.tar.gz gdb-02d27625761a91b9ea78ab4048e1171a7b47a603.tar.bz2 |
Add branch trace information to struct thread_info.
Add functions to enable, disable, clear, and fetch a thread's branch trace.
gdb/
* target.h: Include btrace.h.
(struct target_ops) <to_supports_btrace, to_enable_btrace,
to_disable_btrace, to_teardown_btrace, to_read_btrace>: New.
* target.c (target_supports_btrace): New function.
(target_enable_btrace): New function.
(target_disable_btrace): New function.
(target_teardown_btrace): New function.
(target_read_btrace): New function.
* btrace.h: New file.
* btrace.c: New file.
* Makefile.in: Add btrace.c.
* gdbthread.h: Include btrace.h.
(struct thread_info): Add btrace field.
* thread.c: Include btrace.h.
(clear_thread_inferior_resources): Call target_teardown_btrace.
* common/btrace-common.h: New file.
-rw-r--r-- | gdb/ChangeLog | 19 | ||||
-rw-r--r-- | gdb/Makefile.in | 4 | ||||
-rw-r--r-- | gdb/btrace.c | 449 | ||||
-rw-r--r-- | gdb/btrace.h | 139 | ||||
-rw-r--r-- | gdb/common/btrace-common.h | 73 | ||||
-rw-r--r-- | gdb/gdbthread.h | 4 | ||||
-rw-r--r-- | gdb/target.c | 73 | ||||
-rw-r--r-- | gdb/target.h | 40 | ||||
-rw-r--r-- | gdb/thread.c | 3 |
9 files changed, 801 insertions, 3 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5dbee6b..0b0192f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,22 @@ +2013-03-13 Markus Metzger <markus.t.metzger@intel.com> + + * target.h: Include btrace.h. + (struct target_ops) <to_supports_btrace, to_enable_btrace, + to_disable_btrace, to_teardown_btrace, to_read_btrace>: New. + * target.c (target_supports_btrace): New function. + (target_enable_btrace): New function. + (target_disable_btrace): New function. + (target_teardown_btrace): New function. + (target_read_btrace): New function. + * btrace.h: New file. + * btrace.c: New file. + * Makefile.in: Add btrace.c. + * gdbthread.h: Include btrace.h. + (struct thread_info): Add btrace field. + * thread.c: Include btrace.h. + (clear_thread_inferior_resources): Call target_teardown_btrace. + * common/btrace-common.h: New file. + 2013-03-10 Jan Kratochvil <jan.kratochvil@redhat.com> * common/linux-ptrace.c (linux_ptrace_test_ret_to_nx): Call also kill diff --git a/gdb/Makefile.in b/gdb/Makefile.in index ed30db5..1cf8134 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -759,7 +759,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ regset.c sol-thread.c windows-termcap.c \ common/gdb_vecs.c common/common-utils.c common/xml-utils.c \ common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c \ - common/format.c + common/format.c btrace.c LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c @@ -928,7 +928,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ inferior.o osdata.o gdb_usleep.o record.o gcore.o \ gdb_vecs.o jit.o progspace.o skip.o probe.o \ common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \ - format.o registry.o + format.o registry.o btrace.o TSOBS = inflow.o diff --git a/gdb/btrace.c b/gdb/btrace.c new file mode 100644 index 0000000..2acecbe --- /dev/null +++ b/gdb/btrace.c @@ -0,0 +1,449 @@ +/* Branch trace support for GDB, the GNU debugger. + + Copyright (C) 2013 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.h" +#include "gdbthread.h" +#include "exceptions.h" +#include "inferior.h" +#include "target.h" +#include "record.h" +#include "symtab.h" +#include "disasm.h" +#include "source.h" +#include "filenames.h" + +/* Print a record debug message. Use do ... while (0) to avoid ambiguities + when used in if statements. */ + +#define DEBUG(msg, args...) \ + do \ + { \ + if (record_debug != 0) \ + fprintf_unfiltered (gdb_stdlog, \ + "[btrace] " msg "\n", ##args); \ + } \ + while (0) + +#define DEBUG_FTRACE(msg, args...) DEBUG ("[ftrace] " msg, ##args) + +/* Initialize the instruction iterator. */ + +static void +btrace_init_insn_iterator (struct btrace_thread_info *btinfo) +{ + DEBUG ("init insn iterator"); + + btinfo->insn_iterator.begin = 1; + btinfo->insn_iterator.end = 0; +} + +/* Initialize the function iterator. */ + +static void +btrace_init_func_iterator (struct btrace_thread_info *btinfo) +{ + DEBUG ("init func iterator"); + + btinfo->func_iterator.begin = 1; + btinfo->func_iterator.end = 0; +} + +/* Compute the instruction trace from the block trace. */ + +static VEC (btrace_inst_s) * +compute_itrace (VEC (btrace_block_s) *btrace) +{ + VEC (btrace_inst_s) *itrace; + struct gdbarch *gdbarch; + unsigned int b; + + DEBUG ("compute itrace"); + + itrace = NULL; + gdbarch = target_gdbarch (); + b = VEC_length (btrace_block_s, btrace); + + while (b-- != 0) + { + btrace_block_s *block; + CORE_ADDR pc; + + block = VEC_index (btrace_block_s, btrace, b); + pc = block->begin; + + /* Add instructions for this block. */ + for (;;) + { + btrace_inst_s *inst; + int size; + + /* We should hit the end of the block. Warn if we went too far. */ + if (block->end < pc) + { + warning (_("Recorded trace may be corrupted.")); + break; + } + + inst = VEC_safe_push (btrace_inst_s, itrace, NULL); + inst->pc = pc; + + /* We're done once we pushed the instruction at the end. */ + if (block->end == pc) + break; + + size = gdb_insn_length (gdbarch, pc); + + /* Make sure we terminate if we fail to compute the size. */ + if (size <= 0) + { + warning (_("Recorded trace may be incomplete.")); + break; + } + + pc += size; + } + } + + return itrace; +} + +/* Return the function name of a recorded function segment for printing. + This function never returns NULL. */ + +static const char * +ftrace_print_function_name (struct btrace_func *bfun) +{ + struct minimal_symbol *msym; + struct symbol *sym; + + msym = bfun->msym; + sym = bfun->sym; + + if (sym != NULL) + return SYMBOL_PRINT_NAME (sym); + + if (msym != NULL) + return SYMBOL_PRINT_NAME (msym); + + return "<unknown>"; +} + +/* Return the file name of a recorded function segment for printing. + This function never returns NULL. */ + +static const char * +ftrace_print_filename (struct btrace_func *bfun) +{ + struct symbol *sym; + const char *filename; + + sym = bfun->sym; + + if (sym != NULL) + filename = symtab_to_filename_for_display (sym->symtab); + else + filename = "<unknown>"; + + return filename; +} + +/* Print an ftrace debug status message. */ + +static void +ftrace_debug (struct btrace_func *bfun, const char *prefix) +{ + DEBUG_FTRACE ("%s: fun = %s, file = %s, lines = [%d; %d], insn = [%u; %u]", + prefix, ftrace_print_function_name (bfun), + ftrace_print_filename (bfun), bfun->lbegin, bfun->lend, + bfun->ibegin, bfun->iend); +} + +/* Initialize a recorded function segment. */ + +static void +ftrace_init_func (struct btrace_func *bfun, struct minimal_symbol *mfun, + struct symbol *fun, unsigned int idx) +{ + bfun->msym = mfun; + bfun->sym = fun; + bfun->lbegin = INT_MAX; + bfun->lend = 0; + bfun->ibegin = idx; + bfun->iend = idx; +} + +/* Check whether the function has changed. */ + +static int +ftrace_function_switched (struct btrace_func *bfun, + struct minimal_symbol *mfun, struct symbol *fun) +{ + struct minimal_symbol *msym; + struct symbol *sym; + + /* The function changed if we did not have one before. */ + if (bfun == NULL) + return 1; + + msym = bfun->msym; + sym = bfun->sym; + + /* If the minimal symbol changed, we certainly switched functions. */ + if (mfun != NULL && msym != NULL + && strcmp (SYMBOL_LINKAGE_NAME (mfun), SYMBOL_LINKAGE_NAME (msym)) != 0) + return 1; + + /* If the symbol changed, we certainly switched functions. */ + if (fun != NULL && sym != NULL) + { + const char *bfname, *fname; + + /* Check the function name. */ + if (strcmp (SYMBOL_LINKAGE_NAME (fun), SYMBOL_LINKAGE_NAME (sym)) != 0) + return 1; + + /* Check the location of those functions, as well. */ + bfname = symtab_to_fullname (sym->symtab); + fname = symtab_to_fullname (fun->symtab); + if (filename_cmp (fname, bfname) != 0) + return 1; + } + + return 0; +} + +/* Check if we should skip this file when generating the function call + history. We would want to do that if, say, a macro that is defined + in another file is expanded in this function. */ + +static int +ftrace_skip_file (struct btrace_func *bfun, const char *filename) +{ + struct symbol *sym; + const char *bfile; + + sym = bfun->sym; + + if (sym != NULL) + bfile = symtab_to_fullname (sym->symtab); + else + bfile = ""; + + if (filename == NULL) + filename = ""; + + return (filename_cmp (bfile, filename) != 0); +} + +/* Compute the function trace from the instruction trace. */ + +static VEC (btrace_func_s) * +compute_ftrace (VEC (btrace_inst_s) *itrace) +{ + VEC (btrace_func_s) *ftrace; + struct btrace_inst *binst; + struct btrace_func *bfun; + unsigned int idx; + + DEBUG ("compute ftrace"); + + ftrace = NULL; + bfun = NULL; + + for (idx = 0; VEC_iterate (btrace_inst_s, itrace, idx, binst); ++idx) + { + struct symtab_and_line sal; + struct minimal_symbol *mfun; + struct symbol *fun; + const char *filename; + CORE_ADDR pc; + + pc = binst->pc; + + /* Try to determine the function we're in. We use both types of symbols + to avoid surprises when we sometimes get a full symbol and sometimes + only a minimal symbol. */ + fun = find_pc_function (pc); + mfun = lookup_minimal_symbol_by_pc (pc); + + if (fun == NULL && mfun == NULL) + { + DEBUG_FTRACE ("no symbol at %u, pc=%s", idx, + core_addr_to_string_nz (pc)); + continue; + } + + /* If we're switching functions, we start over. */ + if (ftrace_function_switched (bfun, mfun, fun)) + { + bfun = VEC_safe_push (btrace_func_s, ftrace, NULL); + + ftrace_init_func (bfun, mfun, fun, idx); + ftrace_debug (bfun, "init"); + } + + /* Update the instruction range. */ + bfun->iend = idx; + ftrace_debug (bfun, "update insns"); + + /* Let's see if we have source correlation, as well. */ + sal = find_pc_line (pc, 0); + if (sal.symtab == NULL || sal.line == 0) + { + DEBUG_FTRACE ("no lines at %u, pc=%s", idx, + core_addr_to_string_nz (pc)); + continue; + } + + /* Check if we switched files. This could happen if, say, a macro that + is defined in another file is expanded here. */ + filename = symtab_to_fullname (sal.symtab); + if (ftrace_skip_file (bfun, filename)) + { + DEBUG_FTRACE ("ignoring file at %u, pc=%s, file=%s", idx, + core_addr_to_string_nz (pc), filename); + continue; + } + + /* Update the line range. */ + bfun->lbegin = min (bfun->lbegin, sal.line); + bfun->lend = max (bfun->lend, sal.line); + ftrace_debug (bfun, "update lines"); + } + + return ftrace; +} + +/* See btrace.h. */ + +void +btrace_enable (struct thread_info *tp) +{ + if (tp->btrace.target != NULL) + return; + + if (!target_supports_btrace ()) + error (_("Target does not support branch tracing.")); + + DEBUG ("enable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); + + tp->btrace.target = target_enable_btrace (tp->ptid); +} + +/* See btrace.h. */ + +void +btrace_disable (struct thread_info *tp) +{ + struct btrace_thread_info *btp = &tp->btrace; + int errcode = 0; + + if (btp->target == NULL) + return; + + DEBUG ("disable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); + + target_disable_btrace (btp->target); + btp->target = NULL; + + btrace_clear (tp); +} + +/* See btrace.h. */ + +void +btrace_teardown (struct thread_info *tp) +{ + struct btrace_thread_info *btp = &tp->btrace; + int errcode = 0; + + if (btp->target == NULL) + return; + + DEBUG ("teardown thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); + + target_teardown_btrace (btp->target); + btp->target = NULL; + + btrace_clear (tp); +} + +/* See btrace.h. */ + +void +btrace_fetch (struct thread_info *tp) +{ + struct btrace_thread_info *btinfo; + VEC (btrace_block_s) *btrace; + + DEBUG ("fetch thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); + + btinfo = &tp->btrace; + if (btinfo->target == NULL) + return; + + btrace = target_read_btrace (btinfo->target, btrace_read_new); + if (VEC_empty (btrace_block_s, btrace)) + return; + + btrace_clear (tp); + + btinfo->btrace = btrace; + btinfo->itrace = compute_itrace (btinfo->btrace); + btinfo->ftrace = compute_ftrace (btinfo->itrace); + + /* Initialize branch trace iterators. */ + btrace_init_insn_iterator (btinfo); + btrace_init_func_iterator (btinfo); +} + +/* See btrace.h. */ + +void +btrace_clear (struct thread_info *tp) +{ + struct btrace_thread_info *btinfo; + + DEBUG ("clear thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); + + btinfo = &tp->btrace; + + VEC_free (btrace_block_s, btinfo->btrace); + VEC_free (btrace_inst_s, btinfo->itrace); + VEC_free (btrace_func_s, btinfo->ftrace); + + btinfo->btrace = NULL; + btinfo->itrace = NULL; + btinfo->ftrace = NULL; +} + +/* See btrace.h. */ + +void +btrace_free_objfile (struct objfile *objfile) +{ + struct thread_info *tp; + + DEBUG ("free objfile"); + + ALL_THREADS (tp) + btrace_clear (tp); +} diff --git a/gdb/btrace.h b/gdb/btrace.h new file mode 100644 index 0000000..26b1686 --- /dev/null +++ b/gdb/btrace.h @@ -0,0 +1,139 @@ +/* Branch trace support for GDB, the GNU debugger. + + Copyright (C) 2013 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/>. */ + +#ifndef BTRACE_H +#define BTRACE_H + +/* Branch tracing (btrace) is a per-thread control-flow execution trace of the + inferior. For presentation purposes, the branch trace is represented as a + list of sequential control-flow blocks, one such list per thread. */ + +#include "btrace-common.h" + +struct thread_info; + +/* A branch trace instruction. + + This represents a single instruction in a branch trace. */ +struct btrace_inst +{ + /* The address of this instruction. */ + CORE_ADDR pc; +}; + +/* A branch trace function. + + This represents a function segment in a branch trace, i.e. a consecutive + number of instructions belonging to the same function. */ +struct btrace_func +{ + /* The full and minimal symbol for the function. One of them may be NULL. */ + struct minimal_symbol *msym; + struct symbol *sym; + + /* The source line range of this function segment (both inclusive). */ + int lbegin, lend; + + /* The instruction number range in the instruction trace corresponding + to this function segment (both inclusive). */ + unsigned int ibegin, iend; +}; + +/* Branch trace may also be represented as a vector of: + + - branch trace instructions starting with the oldest instruction. + - branch trace functions starting with the oldest function. */ +typedef struct btrace_inst btrace_inst_s; +typedef struct btrace_func btrace_func_s; + +/* Define functions operating on branch trace vectors. */ +DEF_VEC_O (btrace_inst_s); +DEF_VEC_O (btrace_func_s); + +/* Branch trace iteration state for "record instruction-history". */ +struct btrace_insn_iterator +{ + /* The instruction index range from begin (inclusive) to end (exclusive) + that has been covered last time. + If end < begin, the branch trace has just been updated. */ + unsigned int begin; + unsigned int end; +}; + +/* Branch trace iteration state for "record function-call-history". */ +struct btrace_func_iterator +{ + /* The function index range from begin (inclusive) to end (exclusive) + that has been covered last time. + If end < begin, the branch trace has just been updated. */ + unsigned int begin; + unsigned int end; +}; + +/* Branch trace information per thread. + + This represents the branch trace configuration as well as the entry point + into the branch trace data. For the latter, it also contains the index into + an array of branch trace blocks used for iterating though the branch trace + blocks of a thread. */ +struct btrace_thread_info +{ + /* The target branch trace information for this thread. + + This contains the branch trace configuration as well as any + target-specific information necessary for implementing branch tracing on + the underlying architecture. */ + struct btrace_target_info *target; + + /* The current branch trace for this thread. */ + VEC (btrace_block_s) *btrace; + VEC (btrace_inst_s) *itrace; + VEC (btrace_func_s) *ftrace; + + /* The instruction history iterator. */ + struct btrace_insn_iterator insn_iterator; + + /* The function call history iterator. */ + struct btrace_func_iterator func_iterator; +}; + +/* Enable branch tracing for a thread. */ +extern void btrace_enable (struct thread_info *tp); + +/* Disable branch tracing for a thread. + This will also delete the current branch trace data. */ +extern void btrace_disable (struct thread_info *); + +/* Disable branch tracing for a thread during teardown. + This is similar to btrace_disable, except that it will use + target_teardown_btrace instead of target_disable_btrace. */ +extern void btrace_teardown (struct thread_info *); + +/* Fetch the branch trace for a single thread. */ +extern void btrace_fetch (struct thread_info *); + +/* Clear the branch trace for a single thread. */ +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 *); + +#endif /* BTRACE_H */ diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h new file mode 100644 index 0000000..b157c7c --- /dev/null +++ b/gdb/common/btrace-common.h @@ -0,0 +1,73 @@ +/* Branch trace support for GDB, the GNU debugger. + + Copyright (C) 2013 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/>. */ + +#ifndef BTRACE_COMMON_H +#define BTRACE_COMMON_H + +/* Branch tracing (btrace) is a per-thread control-flow execution trace of the + inferior. For presentation purposes, the branch trace is represented as a + list of sequential control-flow blocks, one such list per thread. */ + +#ifdef GDBSERVER +# include "server.h" +#else +# include "defs.h" +#endif + +#include "vec.h" + +/* A branch trace block. + + This represents a block of sequential control-flow. Adjacent blocks will be + connected via calls, returns, or jumps. The latter can be direct or + indirect, conditional or unconditional. Branches can further be + asynchronous, e.g. interrupts. */ +struct btrace_block +{ + /* The address of the first byte of the first instruction in the block. */ + CORE_ADDR begin; + + /* The address of the first byte of the last instruction in the 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. */ +DEF_VEC_O (btrace_block_s); + +/* Target specific branch trace information. */ +struct btrace_target_info; + +/* Enumeration of btrace read types. */ + +enum btrace_read_type +{ + /* Send all available trace. */ + btrace_read_all, + + /* Send all available trace, if it changed. */ + btrace_read_new +}; + +#endif /* BTRACE_COMMON_H */ diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index 824e4d0..0846322 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -27,6 +27,7 @@ struct symtab; #include "frame.h" #include "ui-out.h" #include "inferior.h" +#include "btrace.h" /* Frontend view of the thread state. Possible extensions: stepping, finishing, until(ling),... */ @@ -226,6 +227,9 @@ struct thread_info /* Function that is called to free PRIVATE. If this is NULL, then xfree will be called on PRIVATE. */ void (*private_dtor) (struct private_thread_info *); + + /* Branch trace information for this thread. */ + struct btrace_thread_info btrace; }; /* Create an empty thread list, or empty the existing one. */ diff --git a/gdb/target.c b/gdb/target.c index 0b4f39d..524caec 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -4153,6 +4153,79 @@ target_ranged_break_num_registers (void) return -1; } +/* See target.h. */ + +int +target_supports_btrace (void) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_supports_btrace != NULL) + return t->to_supports_btrace (); + + return 0; +} + +/* See target.h. */ + +struct btrace_target_info * +target_enable_btrace (ptid_t ptid) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_enable_btrace != NULL) + return t->to_enable_btrace (ptid); + + tcomplain (); + return NULL; +} + +/* See target.h. */ + +void +target_disable_btrace (struct btrace_target_info *btinfo) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_disable_btrace != NULL) + return t->to_disable_btrace (btinfo); + + tcomplain (); +} + +/* See target.h. */ + +void +target_teardown_btrace (struct btrace_target_info *btinfo) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_teardown_btrace != NULL) + return t->to_teardown_btrace (btinfo); + + tcomplain (); +} + +/* See target.h. */ + +VEC (btrace_block_s) * +target_read_btrace (struct btrace_target_info *btinfo, + enum btrace_read_type type) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_read_btrace != NULL) + return t->to_read_btrace (btinfo, type); + + tcomplain (); + return NULL; +} + static void debug_to_prepare_to_store (struct regcache *regcache) { diff --git a/gdb/target.h b/gdb/target.h index c99642d..05a3ad1 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -62,6 +62,7 @@ struct expression; #include "memattr.h" #include "vec.h" #include "gdb_signals.h" +#include "btrace.h" enum strata { @@ -286,7 +287,7 @@ enum target_object /* Darwin dynamic linker info data. */ TARGET_OBJECT_DARWIN_DYLD_INFO, /* OpenVMS Unwind Information Block. */ - TARGET_OBJECT_OPENVMS_UIB + TARGET_OBJECT_OPENVMS_UIB, /* Possible future objects: TARGET_OBJECT_FILE, ... */ }; @@ -859,6 +860,26 @@ struct target_ops /* Is the target able to use agent in current state? */ int (*to_can_use_agent) (void); + /* Check whether the target supports branch tracing. */ + int (*to_supports_btrace) (void); + + /* Enable branch tracing for PTID and allocate a branch trace target + information struct for reading and for disabling branch trace. */ + struct btrace_target_info *(*to_enable_btrace) (ptid_t ptid); + + /* Disable branch tracing and deallocate TINFO. */ + void (*to_disable_btrace) (struct btrace_target_info *tinfo); + + /* Disable branch tracing and deallocate TINFO. This function is similar + to to_disable_btrace, except that it is called during teardown and is + only allowed to perform actions that are safe. A counter-example would + be attempting to talk to a remote target. */ + void (*to_teardown_btrace) (struct btrace_target_info *tinfo); + + /* Read branch trace data. */ + VEC (btrace_block_s) *(*to_read_btrace) (struct btrace_target_info *, + enum btrace_read_type); + int to_magic; /* Need sub-structure for target machine related rather than comm related? */ @@ -1902,4 +1923,21 @@ extern void update_target_permissions (void); /* Blank target vector entries are initialized to target_ignore. */ void target_ignore (void); +/* See to_supports_btrace in struct target_ops. */ +extern int target_supports_btrace (void); + +/* See to_enable_btrace in struct target_ops. */ +extern struct btrace_target_info *target_enable_btrace (ptid_t ptid); + +/* See to_disable_btrace in struct target_ops. */ +extern void target_disable_btrace (struct btrace_target_info *btinfo); + +/* See to_teardown_btrace in struct target_ops. */ +extern void target_teardown_btrace (struct btrace_target_info *btinfo); + +/* See to_read_btrace in struct target_ops. */ +extern VEC (btrace_block_s) *target_read_btrace (struct btrace_target_info *, + enum btrace_read_type); + + #endif /* !defined (TARGET_H) */ diff --git a/gdb/thread.c b/gdb/thread.c index 24e6413..2a1d723 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -33,6 +33,7 @@ #include "regcache.h" #include "gdb.h" #include "gdb_string.h" +#include "btrace.h" #include <ctype.h> #include <sys/types.h> @@ -116,6 +117,8 @@ clear_thread_inferior_resources (struct thread_info *tp) bpstat_clear (&tp->control.stop_bpstat); + btrace_teardown (tp); + do_all_intermediate_continuations_thread (tp, 1); do_all_continuations_thread (tp, 1); } |