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:
Markus Metzger 2013-03-11 08:17:08 +00:00
parent 7bc0ae020f
commit 02d2762576
9 changed files with 801 additions and 3 deletions

View File

@ -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

View File

@ -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
View 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
View 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 */

View 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 */

View File

@ -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. */

View File

@ -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)
{

View File

@ -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) */

View File

@ -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);
}