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.
This commit is contained in:
parent
7bc0ae020f
commit
02d2762576
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
449
gdb/btrace.c
Normal file
449
gdb/btrace.c
Normal file
@ -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);
|
||||
}
|
139
gdb/btrace.h
Normal file
139
gdb/btrace.h
Normal file
@ -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 */
|
73
gdb/common/btrace-common.h
Normal file
73
gdb/common/btrace-common.h
Normal file
@ -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 */
|
@ -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. */
|
||||
|
73
gdb/target.c
73
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)
|
||||
{
|
||||
|
40
gdb/target.h
40
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) */
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user