/* Branch trace support for GDB, the GNU debugger.
- Copyright (C) 2013-2017 Free Software Foundation, Inc.
+ Copyright (C) 2013-2018 Free Software Foundation, Inc.
Contributed by Intel Corp. <markus.t.metzger@intel.com>
END_CATCH
}
-/* Callback function to disable branch tracing for one thread. */
-
-static void
-record_btrace_disable_callback (void *arg)
-{
- struct thread_info *tp = (struct thread_info *) arg;
-
- btrace_disable (tp);
-}
-
/* Enable automatic tracing of new threads. */
static void
observer_notify_record_changed (current_inferior (), 1, "btrace", format);
}
+/* Disable btrace on a set of threads on scope exit. */
+
+struct scoped_btrace_disable
+{
+ scoped_btrace_disable () = default;
+
+ DISABLE_COPY_AND_ASSIGN (scoped_btrace_disable);
+
+ ~scoped_btrace_disable ()
+ {
+ for (thread_info *tp : m_threads)
+ btrace_disable (tp);
+ }
+
+ void add_thread (thread_info *thread)
+ {
+ m_threads.push_front (thread);
+ }
+
+ void discard ()
+ {
+ m_threads.clear ();
+ }
+
+private:
+ std::forward_list<thread_info *> m_threads;
+};
+
/* The to_open method of target record-btrace. */
static void
record_btrace_open (const char *args, int from_tty)
{
- struct cleanup *disable_chain;
+ /* If we fail to enable btrace for one thread, disable it for the threads for
+ which it was successfully enabled. */
+ scoped_btrace_disable btrace_disable;
struct thread_info *tp;
DEBUG ("open");
gdb_assert (record_btrace_thread_observer == NULL);
- disable_chain = make_cleanup (null_cleanup, NULL);
ALL_NON_EXITED_THREADS (tp)
if (args == NULL || *args == 0 || number_is_in_list (args, tp->global_num))
{
btrace_enable (tp, &record_btrace_conf);
- make_cleanup (record_btrace_disable_callback, tp);
+ btrace_disable.add_thread (tp);
}
record_btrace_push_target ();
- discard_cleanups (disable_chain);
+ btrace_disable.discard ();
}
/* The to_stop_recording method of target record-btrace. */
static void
btrace_print_lines (struct btrace_line_range lines, struct ui_out *uiout,
- struct cleanup **ui_item_chain, int flags)
+ struct cleanup **ui_item_chain, gdb_disassembly_flags flags)
{
print_source_lines_flags psl_flags;
int line;
btrace_insn_history (struct ui_out *uiout,
const struct btrace_thread_info *btinfo,
const struct btrace_insn_iterator *begin,
- const struct btrace_insn_iterator *end, int flags)
+ const struct btrace_insn_iterator *end,
+ gdb_disassembly_flags flags)
{
struct cleanup *cleanups, *ui_item_chain;
struct gdbarch *gdbarch;
struct btrace_insn_iterator it;
struct btrace_line_range last_lines;
- DEBUG ("itrace (0x%x): [%u; %u)", flags, btrace_insn_number (begin),
- btrace_insn_number (end));
+ DEBUG ("itrace (0x%x): [%u; %u)", (unsigned) flags,
+ btrace_insn_number (begin), btrace_insn_number (end));
flags |= DISASSEMBLY_SPECULATIVE;
/* The to_insn_history method of target record-btrace. */
static void
-record_btrace_insn_history (struct target_ops *self, int size, int flags)
+record_btrace_insn_history (struct target_ops *self, int size,
+ gdb_disassembly_flags flags)
{
struct btrace_thread_info *btinfo;
struct btrace_insn_history *history;
struct btrace_insn_iterator begin, end;
- struct cleanup *uiout_cleanup;
struct ui_out *uiout;
unsigned int context, covered;
uiout = current_uiout;
- uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
- "insn history");
+ ui_out_emit_tuple tuple_emitter (uiout, "insn history");
context = abs (size);
if (context == 0)
error (_("Bad record instruction-history-size."));
{
struct btrace_insn_iterator *replay;
- DEBUG ("insn-history (0x%x): %d", flags, size);
+ DEBUG ("insn-history (0x%x): %d", (unsigned) flags, size);
/* If we're replaying, we start at the replay position. Otherwise, we
start at the tail of the trace. */
begin = history->begin;
end = history->end;
- DEBUG ("insn-history (0x%x): %d, prev: [%u; %u)", flags, size,
+ DEBUG ("insn-history (0x%x): %d, prev: [%u; %u)", (unsigned) flags, size,
btrace_insn_number (&begin), btrace_insn_number (&end));
if (size < 0)
}
btrace_set_insn_history (btinfo, &begin, &end);
- do_cleanups (uiout_cleanup);
}
/* The to_insn_history_range method of target record-btrace. */
static void
record_btrace_insn_history_range (struct target_ops *self,
- ULONGEST from, ULONGEST to, int flags)
+ ULONGEST from, ULONGEST to,
+ gdb_disassembly_flags flags)
{
struct btrace_thread_info *btinfo;
- struct btrace_insn_history *history;
struct btrace_insn_iterator begin, end;
- struct cleanup *uiout_cleanup;
struct ui_out *uiout;
unsigned int low, high;
int found;
uiout = current_uiout;
- uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
- "insn history");
+ ui_out_emit_tuple tuple_emitter (uiout, "insn history");
low = from;
high = to;
- DEBUG ("insn-history (0x%x): [%u; %u)", flags, low, high);
+ DEBUG ("insn-history (0x%x): [%u; %u)", (unsigned) flags, low, high);
/* Check for wrap-arounds. */
if (low != from || high != to)
btrace_insn_history (uiout, btinfo, &begin, &end, flags);
btrace_set_insn_history (btinfo, &begin, &end);
-
- do_cleanups (uiout_cleanup);
}
/* The to_insn_history_from method of target record-btrace. */
static void
record_btrace_insn_history_from (struct target_ops *self,
- ULONGEST from, int size, int flags)
+ ULONGEST from, int size,
+ gdb_disassembly_flags flags)
{
ULONGEST begin, end, context;
{
unsigned int begin, end, size;
- size = VEC_length (btrace_insn_s, bfun->insn);
+ size = bfun->insn.size ();
gdb_assert (size > 0);
begin = bfun->insn_offset;
btrace_compute_src_line_range (const struct btrace_function *bfun,
int *pbegin, int *pend)
{
- struct btrace_insn *insn;
struct symtab *symtab;
struct symbol *sym;
- unsigned int idx;
int begin, end;
begin = INT_MAX;
symtab = symbol_symtab (sym);
- for (idx = 0; VEC_iterate (btrace_insn_s, bfun->insn, idx, insn); ++idx)
+ for (const btrace_insn &insn : bfun->insn)
{
struct symtab_and_line sal;
- sal = find_pc_line (insn->pc, 0);
+ sal = find_pc_line (insn.pc, 0);
if (sal.symtab != symtab || sal.line == 0)
continue;
/* The to_call_history method of target record-btrace. */
static void
-record_btrace_call_history (struct target_ops *self, int size, int int_flags)
+record_btrace_call_history (struct target_ops *self, int size,
+ record_print_flags flags)
{
struct btrace_thread_info *btinfo;
struct btrace_call_history *history;
struct btrace_call_iterator begin, end;
- struct cleanup *uiout_cleanup;
struct ui_out *uiout;
unsigned int context, covered;
- record_print_flags flags = (enum record_print_flag) int_flags;
uiout = current_uiout;
- uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
- "insn history");
+ ui_out_emit_tuple tuple_emitter (uiout, "insn history");
context = abs (size);
if (context == 0)
error (_("Bad record function-call-history-size."));
{
struct btrace_insn_iterator *replay;
- DEBUG ("call-history (0x%x): %d", int_flags, size);
+ DEBUG ("call-history (0x%x): %d", (int) flags, size);
/* If we're replaying, we start at the replay position. Otherwise, we
start at the tail of the trace. */
replay = btinfo->replay;
if (replay != NULL)
{
- begin.function = replay->function;
begin.btinfo = btinfo;
+ begin.index = replay->call_index;
}
else
btrace_call_end (&begin, btinfo);
begin = history->begin;
end = history->end;
- DEBUG ("call-history (0x%x): %d, prev: [%u; %u)", int_flags, size,
+ DEBUG ("call-history (0x%x): %d, prev: [%u; %u)", (int) flags, size,
btrace_call_number (&begin), btrace_call_number (&end));
if (size < 0)
}
btrace_set_call_history (btinfo, &begin, &end);
- do_cleanups (uiout_cleanup);
}
/* The to_call_history_range method of target record-btrace. */
static void
record_btrace_call_history_range (struct target_ops *self,
ULONGEST from, ULONGEST to,
- int int_flags)
+ record_print_flags flags)
{
struct btrace_thread_info *btinfo;
- struct btrace_call_history *history;
struct btrace_call_iterator begin, end;
- struct cleanup *uiout_cleanup;
struct ui_out *uiout;
unsigned int low, high;
int found;
- record_print_flags flags = (enum record_print_flag) int_flags;
uiout = current_uiout;
- uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
- "func history");
+ ui_out_emit_tuple tuple_emitter (uiout, "func history");
low = from;
high = to;
- DEBUG ("call-history (0x%x): [%u; %u)", int_flags, low, high);
+ DEBUG ("call-history (0x%x): [%u; %u)", (int) flags, low, high);
/* Check for wrap-arounds. */
if (low != from || high != to)
btrace_call_history (uiout, btinfo, &begin, &end, flags);
btrace_set_call_history (btinfo, &begin, &end);
-
- do_cleanups (uiout_cleanup);
}
/* The to_call_history_from method of target record-btrace. */
static void
record_btrace_call_history_from (struct target_ops *self,
ULONGEST from, int size,
- int int_flags)
+ record_print_flags flags)
{
ULONGEST begin, end, context;
- record_print_flags flags = (enum record_print_flag) int_flags;
context = abs (size);
if (context == 0)
static enum record_method
record_btrace_record_method (struct target_ops *self, ptid_t ptid)
{
- const struct btrace_config *config;
struct thread_info * const tp = find_thread_ptid (ptid);
if (tp == NULL)
const gdb_byte *writebuf, ULONGEST offset,
ULONGEST len, ULONGEST *xfered_len)
{
- struct target_ops *t;
-
/* Filter out requests that don't make sense during replay. */
if (replay_memory_access == replay_memory_access_read_only
&& !record_btrace_generating_corefile
struct gdbarch *gdbarch;
int pcreg;
- gdbarch = get_regcache_arch (regcache);
+ gdbarch = regcache->arch ();
pcreg = gdbarch_pc_regnum (gdbarch);
if (pcreg < 0)
return;
btrace_get_frame_function (struct frame_info *frame)
{
const struct btrace_frame_cache *cache;
- const struct btrace_function *bfun;
struct btrace_frame_cache pattern;
void **slot;
bfun = cache->bfun;
gdb_assert (bfun != NULL);
- if (bfun->up == NULL)
+ if (bfun->up == 0)
return UNWIND_UNAVAILABLE;
return UNWIND_NO_REASON;
{
const struct btrace_frame_cache *cache;
const struct btrace_function *bfun;
+ struct btrace_call_iterator it;
CORE_ADDR code, special;
cache = (const struct btrace_frame_cache *) *this_cache;
bfun = cache->bfun;
gdb_assert (bfun != NULL);
- while (bfun->segment.prev != NULL)
- bfun = bfun->segment.prev;
+ while (btrace_find_call_by_number (&it, &cache->tp->btrace, bfun->prev) != 0)
+ bfun = btrace_call_get (&it);
code = get_frame_func (this_frame);
special = bfun->number;
{
const struct btrace_frame_cache *cache;
const struct btrace_function *bfun, *caller;
- const struct btrace_insn *insn;
+ struct btrace_call_iterator it;
struct gdbarch *gdbarch;
CORE_ADDR pc;
int pcreg;
bfun = cache->bfun;
gdb_assert (bfun != NULL);
- caller = bfun->up;
- if (caller == NULL)
+ if (btrace_find_call_by_number (&it, &cache->tp->btrace, bfun->up) == 0)
throw_error (NOT_AVAILABLE_ERROR,
_("No caller in btrace record history"));
+ caller = btrace_call_get (&it);
+
if ((bfun->flags & BFUN_UP_LINKS_TO_RET) != 0)
- {
- insn = VEC_index (btrace_insn_s, caller->insn, 0);
- pc = insn->pc;
- }
+ pc = caller->insn.front ().pc;
else
{
- insn = VEC_last (btrace_insn_s, caller->insn);
- pc = insn->pc;
-
+ pc = caller->insn.back ().pc;
pc += gdb_insn_length (gdbarch, pc);
}
replay = tp->btrace.replay;
if (replay != NULL)
- bfun = replay->function;
+ bfun = &replay->btinfo->functions[replay->call_index];
}
else
{
const struct btrace_function *callee;
+ struct btrace_call_iterator it;
callee = btrace_get_frame_function (next);
- if (callee != NULL && (callee->flags & BFUN_UP_LINKS_TO_TAILCALL) == 0)
- bfun = callee->up;
+ if (callee == NULL || (callee->flags & BFUN_UP_LINKS_TO_TAILCALL) != 0)
+ return 0;
+
+ if (btrace_find_call_by_number (&it, &tp->btrace, callee->up) == 0)
+ return 0;
+
+ bfun = btrace_call_get (&it);
}
if (bfun == NULL)
{
const struct btrace_function *bfun, *callee;
struct btrace_frame_cache *cache;
+ struct btrace_call_iterator it;
struct frame_info *next;
+ struct thread_info *tinfo;
next = get_next_frame (this_frame);
if (next == NULL)
if ((callee->flags & BFUN_UP_LINKS_TO_TAILCALL) == 0)
return 0;
- bfun = callee->up;
- if (bfun == NULL)
+ tinfo = find_thread_ptid (inferior_ptid);
+ if (btrace_find_call_by_number (&it, &tinfo->btrace, callee->up) == 0)
return 0;
+ bfun = btrace_call_get (&it);
+
DEBUG ("[frame] sniffed tailcall frame for %s on level %d",
btrace_get_bfun_name (bfun), bfun->level);
/* This is our frame. Initialize the frame cache. */
cache = bfcache_new (this_frame);
- cache->tp = find_thread_ptid (inferior_ptid);
+ cache->tp = tinfo;
cache->bfun = bfun;
*this_cache = cache;
replay = NULL;
/* We can't start replaying without trace. */
- if (btinfo->begin == NULL)
+ if (btinfo->functions.empty ())
return NULL;
/* GDB stores the current frame_id when stepping in order to detects steps
*status = btrace_step_no_resumed ();
DEBUG ("wait ended by %s: %s", target_pid_to_str (null_ptid),
- target_waitstatus_to_string (status));
+ target_waitstatus_to_string (status).c_str ());
do_cleanups (cleanups);
return null_ptid;
DEBUG ("wait ended by thread %s (%s): %s",
print_thread_id (eventing),
target_pid_to_str (eventing->ptid),
- target_waitstatus_to_string (status));
+ target_waitstatus_to_string (status).c_str ());
do_cleanups (cleanups);
return eventing->ptid;
btinfo = &tp->btrace;
- if (it == NULL || it->function == NULL)
+ if (it == NULL)
record_btrace_stop_replaying (tp);
else
{
/* Start recording in BTS format. */
static void
-cmd_record_btrace_bts_start (char *args, int from_tty)
+cmd_record_btrace_bts_start (const char *args, int from_tty)
{
if (args != NULL && *args != 0)
error (_("Invalid argument."));
/* Start recording in Intel Processor Trace format. */
static void
-cmd_record_btrace_pt_start (char *args, int from_tty)
+cmd_record_btrace_pt_start (const char *args, int from_tty)
{
if (args != NULL && *args != 0)
error (_("Invalid argument."));
/* Alias for "target record". */
static void
-cmd_record_btrace_start (char *args, int from_tty)
+cmd_record_btrace_start (const char *args, int from_tty)
{
if (args != NULL && *args != 0)
error (_("Invalid argument."));
/* The "set record btrace" command. */
static void
-cmd_set_record_btrace (char *args, int from_tty)
+cmd_set_record_btrace (const char *args, int from_tty)
{
cmd_show_list (set_record_btrace_cmdlist, from_tty, "");
}
/* The "show record btrace" command. */
static void
-cmd_show_record_btrace (char *args, int from_tty)
+cmd_show_record_btrace (const char *args, int from_tty)
{
cmd_show_list (show_record_btrace_cmdlist, from_tty, "");
}
/* The "set record btrace bts" command. */
static void
-cmd_set_record_btrace_bts (char *args, int from_tty)
+cmd_set_record_btrace_bts (const char *args, int from_tty)
{
printf_unfiltered (_("\"set record btrace bts\" must be followed "
"by an appropriate subcommand.\n"));
/* The "show record btrace bts" command. */
static void
-cmd_show_record_btrace_bts (char *args, int from_tty)
+cmd_show_record_btrace_bts (const char *args, int from_tty)
{
cmd_show_list (show_record_btrace_bts_cmdlist, from_tty, "");
}
/* The "set record btrace pt" command. */
static void
-cmd_set_record_btrace_pt (char *args, int from_tty)
+cmd_set_record_btrace_pt (const char *args, int from_tty)
{
printf_unfiltered (_("\"set record btrace pt\" must be followed "
"by an appropriate subcommand.\n"));
/* The "show record btrace pt" command. */
static void
-cmd_show_record_btrace_pt (char *args, int from_tty)
+cmd_show_record_btrace_pt (const char *args, int from_tty)
{
cmd_show_list (show_record_btrace_pt_cmdlist, from_tty, "");
}
value);
}
-void _initialize_record_btrace (void);
-
/* Initialize btrace commands. */
void