/* Branch trace support for GDB, the GNU debugger.
- Copyright (C) 2013-2021 Free Software Foundation, Inc.
+ Copyright (C) 2013-2023 Free Software Foundation, Inc.
Contributed by Intel Corp. <markus.t.metzger@intel.com>
#include "cli/cli-style.h"
#include "async-event.h"
#include <forward_list>
+#include "objfiles.h"
+#include "interps.h"
static const target_info record_btrace_target_info = {
"record-btrace",
strata stratum () const override { return record_stratum; }
void close () override;
- void async (int) override;
+ void async (bool) override;
void detach (inferior *inf, int from_tty) override
{ record_detach (this, inf, from_tty); }
do \
{ \
if (record_debug != 0) \
- fprintf_unfiltered (gdb_stdlog, \
- "[record-btrace] " msg "\n", ##args); \
+ gdb_printf (gdb_stdlog, \
+ "[record-btrace] " msg "\n", ##args); \
} \
while (0)
return &tp->btrace;
}
-/* Enable branch tracing for one thread. Warn on errors. */
+/* The new thread observer. */
static void
-record_btrace_enable_warn (struct thread_info *tp)
+record_btrace_on_new_thread (struct thread_info *tp)
{
/* Ignore this thread if its inferior is not recorded by us. */
target_ops *rec = tp->inf->target_at (record_stratum);
{
DEBUG ("attach thread observer");
- gdb::observers::new_thread.attach (record_btrace_enable_warn,
+ gdb::observers::new_thread.attach (record_btrace_on_new_thread,
record_btrace_thread_observer_token,
"record-btrace");
}
record_btrace_generating_corefile = 0;
format = btrace_format_short_string (record_btrace_conf.format);
- gdb::observers::record_changed.notify (current_inferior (), 1, "btrace", format);
+ interps_notify_record_changed (current_inferior (), 1, "btrace", format);
}
/* Disable btrace on a set of threads on scope exit. */
/* The async method of target record-btrace. */
void
-record_btrace_target::async (int enable)
+record_btrace_target::async (bool enable)
{
if (enable)
mark_async_event_handler (record_btrace_async_inferior_event_handler);
if (size > 0)
{
suffix = record_btrace_adjust_size (&size);
- printf_unfiltered (_("Buffer size: %u%s.\n"), size, suffix);
+ gdb_printf (_("Buffer size: %u%s.\n"), size, suffix);
}
}
if (size > 0)
{
suffix = record_btrace_adjust_size (&size);
- printf_unfiltered (_("Buffer size: %u%s.\n"), size, suffix);
+ gdb_printf (_("Buffer size: %u%s.\n"), size, suffix);
}
}
static void
record_btrace_print_conf (const struct btrace_config *conf)
{
- printf_unfiltered (_("Recording format: %s.\n"),
- btrace_format_string (conf->format));
+ gdb_printf (_("Recording format: %s.\n"),
+ btrace_format_string (conf->format));
switch (conf->format)
{
return;
}
- internal_error (__FILE__, __LINE__, _("Unknown branch trace format."));
+ internal_error (_("Unknown branch trace format."));
}
/* The info_record method of target record-btrace. */
gaps = btinfo->ngaps;
}
- printf_unfiltered (_("Recorded %u instructions in %u functions (%u gaps) "
- "for thread %s (%s).\n"), insns, calls, gaps,
- print_thread_id (tp),
- target_pid_to_str (tp->ptid).c_str ());
+ gdb_printf (_("Recorded %u instructions in %u functions (%u gaps) "
+ "for thread %s (%s).\n"), insns, calls, gaps,
+ print_thread_id (tp),
+ target_pid_to_str (tp->ptid).c_str ());
if (btrace_is_replaying (tp))
- printf_unfiltered (_("Replay in progress. At instruction %u.\n"),
- btrace_insn_number (btinfo->replay));
+ gdb_printf (_("Replay in progress. At instruction %u.\n"),
+ btrace_insn_number (btinfo->replay));
}
/* Print a decode error. */
btrace_find_line_range (CORE_ADDR pc)
{
struct btrace_line_range range;
- struct linetable_entry *lines;
- struct linetable *ltable;
+ const linetable_entry *lines;
+ const linetable *ltable;
struct symtab *symtab;
int nlines, i;
if (symtab == NULL)
return btrace_mk_line_range (NULL, 0, 0);
- ltable = SYMTAB_LINETABLE (symtab);
+ ltable = symtab->linetable ();
if (ltable == NULL)
return btrace_mk_line_range (symtab, 0, 0);
if (nlines <= 0)
return btrace_mk_line_range (symtab, 0, 0);
+ struct objfile *objfile = symtab->compunit ()->objfile ();
+ unrelocated_addr unrel_pc
+ = unrelocated_addr (pc - objfile->text_section_offset ());
+
range = btrace_mk_line_range (symtab, 0, 0);
for (i = 0; i < nlines - 1; i++)
{
possibly adding more line numbers to the range. At the time this
change was made I was unsure how to test this so chose to go with
maintaining the existing experience. */
- if ((lines[i].pc == pc) && (lines[i].line != 0)
- && (lines[i].is_stmt == 1))
+ if (lines[i].unrelocated_pc () == unrel_pc && lines[i].line != 0
+ && lines[i].is_stmt)
range = btrace_line_range_add (range, lines[i].line);
}
static void
btrace_print_lines (struct btrace_line_range lines, struct ui_out *uiout,
- gdb::optional<ui_out_emit_tuple> *src_and_asm_tuple,
- gdb::optional<ui_out_emit_list> *asm_list,
+ std::optional<ui_out_emit_tuple> *src_and_asm_tuple,
+ std::optional<ui_out_emit_list> *asm_list,
gdb_disassembly_flags flags)
{
print_source_lines_flags psl_flags;
flags |= DISASSEMBLY_SPECULATIVE;
- struct gdbarch *gdbarch = target_gdbarch ();
+ gdbarch *gdbarch = current_inferior ()->arch ();
btrace_line_range last_lines = btrace_mk_line_range (NULL, 0, 0);
ui_out_emit_list list_emitter (uiout, "asm_insns");
- gdb::optional<ui_out_emit_tuple> src_and_asm_tuple;
- gdb::optional<ui_out_emit_list> asm_list;
+ std::optional<ui_out_emit_tuple> src_and_asm_tuple;
+ std::optional<ui_out_emit_list> asm_list;
gdb_pretty_print_disassembler disasm (gdbarch, uiout);
else
{
if (size < 0)
- printf_unfiltered (_("At the start of the branch trace record.\n"));
+ gdb_printf (_("At the start of the branch trace record.\n"));
else
- printf_unfiltered (_("At the end of the branch trace record.\n"));
+ gdb_printf (_("At the end of the branch trace record.\n"));
}
btrace_set_insn_history (btinfo, &begin, &end);
if (sym == NULL)
goto out;
- symtab = symbol_symtab (sym);
+ symtab = sym->symtab ();
for (const btrace_insn &insn : bfun->insn)
{
return;
uiout->field_string ("file",
- symtab_to_filename_for_display (symbol_symtab (sym)),
+ symtab_to_filename_for_display (sym->symtab ()),
file_name_style.style ());
btrace_compute_src_line_range (bfun, &begin, &end);
else
{
if (size < 0)
- printf_unfiltered (_("At the start of the branch trace record.\n"));
+ gdb_printf (_("At the start of the branch trace record.\n"));
else
- printf_unfiltered (_("At the end of the branch trace record.\n"));
+ gdb_printf (_("At the end of the branch trace record.\n"));
}
btrace_set_call_history (btinfo, &begin, &end);
record_btrace_target::record_method (ptid_t ptid)
{
process_stratum_target *proc_target = current_inferior ()->process_target ();
- thread_info *const tp = find_thread_ptid (proc_target, ptid);
+ thread_info *const tp = proc_target->find_thread (ptid);
if (tp == NULL)
error (_("No thread."));
/* Thread-db may ask for a thread's registers before GDB knows about the
thread. We forward the request to the target beneath in this
case. */
- thread_info *tp = find_thread_ptid (regcache->target (), regcache->ptid ());
+ thread_info *tp
+ = current_inferior ()->process_target ()->find_thread (regcache->ptid ());
if (tp != nullptr)
replay = tp->btrace.replay;
struct thread_info *tp;
/* The frame info. */
- struct frame_info *frame;
+ frame_info *frame;
/* The branch trace function segment. */
const struct btrace_function *bfun;
/* Create a new btrace frame cache. */
static struct btrace_frame_cache *
-bfcache_new (struct frame_info *frame)
+bfcache_new (frame_info_ptr frame)
{
struct btrace_frame_cache *cache;
void **slot;
cache = FRAME_OBSTACK_ZALLOC (struct btrace_frame_cache);
- cache->frame = frame;
+ cache->frame = frame.get ();
slot = htab_find_slot (bfcache, cache, INSERT);
gdb_assert (*slot == NULL);
/* Extract the branch trace function from a branch trace frame. */
static const struct btrace_function *
-btrace_get_frame_function (struct frame_info *frame)
+btrace_get_frame_function (frame_info_ptr frame)
{
const struct btrace_frame_cache *cache;
struct btrace_frame_cache pattern;
void **slot;
- pattern.frame = frame;
+ pattern.frame = frame.get ();
slot = htab_find_slot (bfcache, &pattern, NO_INSERT);
if (slot == NULL)
/* Implement stop_reason method for record_btrace_frame_unwind. */
static enum unwind_stop_reason
-record_btrace_frame_unwind_stop_reason (struct frame_info *this_frame,
+record_btrace_frame_unwind_stop_reason (frame_info_ptr this_frame,
void **this_cache)
{
const struct btrace_frame_cache *cache;
/* Implement this_id method for record_btrace_frame_unwind. */
static void
-record_btrace_frame_this_id (struct frame_info *this_frame, void **this_cache,
+record_btrace_frame_this_id (frame_info_ptr this_frame, void **this_cache,
struct frame_id *this_id)
{
const struct btrace_frame_cache *cache;
/* Implement prev_register method for record_btrace_frame_unwind. */
static struct value *
-record_btrace_frame_prev_register (struct frame_info *this_frame,
+record_btrace_frame_prev_register (frame_info_ptr this_frame,
void **this_cache,
int regnum)
{
static int
record_btrace_frame_sniffer (const struct frame_unwind *self,
- struct frame_info *this_frame,
+ frame_info_ptr this_frame,
void **this_cache)
{
const struct btrace_function *bfun;
struct btrace_frame_cache *cache;
struct thread_info *tp;
- struct frame_info *next;
+ frame_info_ptr next;
/* THIS_FRAME does not contain a reference to its thread. */
tp = inferior_thread ();
static int
record_btrace_tailcall_frame_sniffer (const struct frame_unwind *self,
- struct frame_info *this_frame,
+ frame_info_ptr this_frame,
void **this_cache)
{
const struct btrace_function *bfun, *callee;
struct btrace_frame_cache *cache;
struct btrace_call_iterator it;
- struct frame_info *next;
+ frame_info_ptr next;
struct thread_info *tinfo;
next = get_next_frame (this_frame);
}
static void
-record_btrace_frame_dealloc_cache (struct frame_info *self, void *this_cache)
+record_btrace_frame_dealloc_cache (frame_info *self, void *this_cache)
{
struct btrace_frame_cache *cache;
void **slot;
struct btrace_thread_info *btinfo;
DEBUG ("resuming thread %s (%s): %x (%s)", print_thread_id (tp),
- target_pid_to_str (tp->ptid).c_str (), flag,
+ tp->ptid.to_string ().c_str (), flag,
btrace_thread_flag_to_str (flag));
btinfo = &tp->btrace;
static struct frame_id
get_thread_current_frame_id (struct thread_info *tp)
{
- struct frame_id id;
- bool executing;
-
/* Set current thread, which is implicitly used by
get_current_frame. */
scoped_restore_current_thread restore_thread;
For the former, EXECUTING is true and we're in wait, about to
move the thread. Since we need to recompute the stack, we temporarily
set EXECUTING to false. */
- executing = tp->executing;
+ bool executing = tp->executing ();
set_executing (proc_target, inferior_ptid, false);
-
- id = null_frame_id;
- try
+ SCOPE_EXIT
{
- id = get_frame_id (get_current_frame ());
- }
- catch (const gdb_exception &except)
- {
- /* Restore the previous execution state. */
set_executing (proc_target, inferior_ptid, executing);
-
- throw;
- }
-
- /* Restore the previous execution state. */
- set_executing (proc_target, inferior_ptid, executing);
-
- return id;
+ };
+ return get_frame_id (get_current_frame ());
}
/* Start replaying a thread. */
/* We can't start replaying without trace. */
if (btinfo->functions.empty ())
- return NULL;
+ error (_("No trace."));
/* GDB stores the current frame_id when stepping in order to detects steps
into subroutines.
frame_id = get_thread_current_frame_id (tp);
/* Check if we need to update any stepping-related frame id's. */
- upd_step_frame_id = frame_id_eq (frame_id,
- tp->control.step_frame_id);
- upd_step_stack_frame_id = frame_id_eq (frame_id,
- tp->control.step_stack_frame_id);
+ upd_step_frame_id = (frame_id == tp->control.step_frame_id);
+ upd_step_stack_frame_id = (frame_id == tp->control.step_stack_frame_id);
/* We start replaying at the end of the branch trace. This corresponds
to the current instruction. */
{
enum btrace_thread_flag flag, cflag;
- DEBUG ("resume %s: %s%s", target_pid_to_str (ptid).c_str (),
+ DEBUG ("resume %s: %s%s", ptid.to_string ().c_str (),
::execution_direction == EXEC_REVERSE ? "reverse-" : "",
step ? "step" : "cont");
/* Async support. */
if (target_can_async_p ())
{
- target_async (1);
+ target_async (true);
mark_async_event_handler (record_btrace_async_inferior_event_handler);
}
}
DEBUG ("cancel resume thread %s (%s): %x (%s)",
print_thread_id (tp),
- target_pid_to_str (tp->ptid).c_str (), flags.raw (),
+ tp->ptid.to_string ().c_str (), flags.raw (),
btrace_thread_flag_to_str (flags));
tp->btrace.flags &= ~(BTHR_MOVE | BTHR_STOP);
{
struct target_waitstatus status;
- status.kind = TARGET_WAITKIND_NO_HISTORY;
+ status.set_no_history ();
return status;
}
{
struct target_waitstatus status;
- status.kind = TARGET_WAITKIND_STOPPED;
- status.value.sig = GDB_SIGNAL_TRAP;
+ status.set_stopped (GDB_SIGNAL_TRAP);
return status;
}
{
struct target_waitstatus status;
- status.kind = TARGET_WAITKIND_STOPPED;
- status.value.sig = GDB_SIGNAL_0;
+ status.set_stopped (GDB_SIGNAL_0);
return status;
}
{
struct target_waitstatus status;
- status.kind = TARGET_WAITKIND_SPURIOUS;
+ status.set_spurious ();
return status;
}
{
struct target_waitstatus status;
- status.kind = TARGET_WAITKIND_NO_RESUMED;
+ status.set_no_resumed ();
return status;
}
{
struct target_waitstatus status;
- status.kind = TARGET_WAITKIND_IGNORE;
+ status.set_ignore ();
return status;
}
if (insn == NULL)
return 0;
- return record_check_stopped_by_breakpoint (tp->inf->aspace, insn->pc,
+ return record_check_stopped_by_breakpoint (tp->inf->aspace.get (), insn->pc,
&btinfo->stop_reason);
}
btinfo->flags &= ~(BTHR_MOVE | BTHR_STOP);
DEBUG ("stepping thread %s (%s): %x (%s)", print_thread_id (tp),
- target_pid_to_str (tp->ptid).c_str (), flags.raw (),
+ tp->ptid.to_string ().c_str (), flags.raw (),
btrace_thread_flag_to_str (flags));
/* We can't step without an execution history. */
switch (flags)
{
default:
- internal_error (__FILE__, __LINE__, _("invalid stepping type."));
+ internal_error (_("invalid stepping type."));
case BTHR_STOP:
return btrace_step_stopped_on_request ();
case BTHR_STEP:
status = record_btrace_single_step_forward (tp);
- if (status.kind != TARGET_WAITKIND_SPURIOUS)
+ if (status.kind () != TARGET_WAITKIND_SPURIOUS)
break;
return btrace_step_stopped ();
case BTHR_RSTEP:
status = record_btrace_single_step_backward (tp);
- if (status.kind != TARGET_WAITKIND_SPURIOUS)
+ if (status.kind () != TARGET_WAITKIND_SPURIOUS)
break;
return btrace_step_stopped ();
case BTHR_CONT:
status = record_btrace_single_step_forward (tp);
- if (status.kind != TARGET_WAITKIND_SPURIOUS)
+ if (status.kind () != TARGET_WAITKIND_SPURIOUS)
break;
btinfo->flags |= flags;
case BTHR_RCONT:
status = record_btrace_single_step_backward (tp);
- if (status.kind != TARGET_WAITKIND_SPURIOUS)
+ if (status.kind () != TARGET_WAITKIND_SPURIOUS)
break;
btinfo->flags |= flags;
/* We keep threads moving at the end of their execution history. The wait
method will stop the thread for whom the event is reported. */
- if (status.kind == TARGET_WAITKIND_NO_HISTORY)
+ if (status.kind () == TARGET_WAITKIND_NO_HISTORY)
btinfo->flags |= flags;
return status;
/* Clear this, if needed we'll re-mark it below. */
clear_async_event_handler (record_btrace_async_inferior_event_handler);
- DEBUG ("wait %s (0x%x)", target_pid_to_str (ptid).c_str (),
+ DEBUG ("wait %s (0x%x)", ptid.to_string ().c_str (),
(unsigned) options);
/* As long as we're not replaying, just forward the request. */
{
*status = btrace_step_no_resumed ();
- DEBUG ("wait ended by %s: %s", target_pid_to_str (null_ptid).c_str (),
- target_waitstatus_to_string (status).c_str ());
+ DEBUG ("wait ended by %s: %s", null_ptid.to_string ().c_str (),
+ status->to_string ().c_str ());
return null_ptid;
}
*status = record_btrace_step_thread (tp);
- switch (status->kind)
+ switch (status->kind ())
{
case TARGET_WAITKIND_IGNORE:
ix++;
DEBUG ("wait ended by thread %s (%s): %s",
print_thread_id (eventing),
- target_pid_to_str (eventing->ptid).c_str (),
- target_waitstatus_to_string (status).c_str ());
+ eventing->ptid.to_string ().c_str (),
+ status->to_string ().c_str ());
return eventing->ptid;
}
void
record_btrace_target::stop (ptid_t ptid)
{
- DEBUG ("stop %s", target_pid_to_str (ptid).c_str ());
+ DEBUG ("stop %s", ptid.to_string ().c_str ());
/* As long as we're not replaying, just forward the request. */
if ((::execution_direction != EXEC_REVERSE)
/* Start anew from the new replay position. */
record_btrace_clear_histories (btinfo);
- inferior_thread ()->set_stop_pc (regcache_read_pc (get_current_regcache ()));
+ tp->set_stop_pc (regcache_read_pc (get_thread_regcache (tp)));
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
}
{
execute_command ("target record-btrace", from_tty);
}
- catch (const gdb_exception &exception)
+ catch (const gdb_exception_error &exception)
{
record_btrace_conf.format = BTRACE_FORMAT_BTS;
cmd_show_replay_memory_access (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (gdb_stdout, _("Replay memory access is %s.\n"),
- replay_memory_access);
+ gdb_printf (file, _("Replay memory access is %s.\n"),
+ replay_memory_access);
}
/* The "set record btrace cpu none" command. */
switch (record_btrace_cpu_state)
{
case CS_AUTO:
- printf_unfiltered (_("btrace cpu is 'auto'.\n"));
+ gdb_printf (_("btrace cpu is 'auto'.\n"));
return;
case CS_NONE:
- printf_unfiltered (_("btrace cpu is 'none'.\n"));
+ gdb_printf (_("btrace cpu is 'none'.\n"));
return;
case CS_CPU:
{
case CV_INTEL:
if (record_btrace_cpu.stepping == 0)
- printf_unfiltered (_("btrace cpu is 'intel: %u/%u'.\n"),
- record_btrace_cpu.family,
- record_btrace_cpu.model);
+ gdb_printf (_("btrace cpu is 'intel: %u/%u'.\n"),
+ record_btrace_cpu.family,
+ record_btrace_cpu.model);
else
- printf_unfiltered (_("btrace cpu is 'intel: %u/%u/%u'.\n"),
- record_btrace_cpu.family,
- record_btrace_cpu.model,
- record_btrace_cpu.stepping);
+ gdb_printf (_("btrace cpu is 'intel: %u/%u/%u'.\n"),
+ record_btrace_cpu.family,
+ record_btrace_cpu.model,
+ record_btrace_cpu.stepping);
return;
}
}
struct cmd_list_element *c,
const char *value)
{
- fprintf_filtered (file, _("The record/replay bts buffer size is %s.\n"),
- value);
+ gdb_printf (file, _("The record/replay bts buffer size is %s.\n"),
+ value);
}
/* The "record pt buffer-size" show value function. */
struct cmd_list_element *c,
const char *value)
{
- fprintf_filtered (file, _("The record/replay pt buffer size is %s.\n"),
- value);
+ gdb_printf (file, _("The record/replay pt buffer size is %s.\n"),
+ value);
}
/* Initialize btrace commands. */
&record_btrace_cmdlist);
add_alias_cmd ("pt", record_btrace_pt_cmd, class_obscure, 1, &record_cmdlist);
- add_basic_prefix_cmd ("btrace", class_support,
- _("Set record options."), &set_record_btrace_cmdlist,
- 0, &set_record_cmdlist);
-
- add_show_prefix_cmd ("btrace", class_support,
- _("Show record options."), &show_record_btrace_cmdlist,
- 0, &show_record_cmdlist);
+ add_setshow_prefix_cmd ("btrace", class_support,
+ _("Set record options."),
+ _("Show record options."),
+ &set_record_btrace_cmdlist,
+ &show_record_btrace_cmdlist,
+ &set_record_cmdlist, &show_record_cmdlist);
add_setshow_enum_cmd ("replay-memory-access", no_class,
replay_memory_access_types, &replay_memory_access, _("\
Show the cpu to be used for trace decode."),
&show_record_btrace_cmdlist);
- add_basic_prefix_cmd ("bts", class_support,
- _("Set record btrace bts options."),
- &set_record_btrace_bts_cmdlist,
- 0,
- &set_record_btrace_cmdlist);
-
- add_show_prefix_cmd ("bts", class_support,
- _("Show record btrace bts options."),
- &show_record_btrace_bts_cmdlist,
- 0,
- &show_record_btrace_cmdlist);
+ add_setshow_prefix_cmd ("bts", class_support,
+ _("Set record btrace bts options."),
+ _("Show record btrace bts options."),
+ &set_record_btrace_bts_cmdlist,
+ &show_record_btrace_bts_cmdlist,
+ &set_record_btrace_cmdlist,
+ &show_record_btrace_cmdlist);
add_setshow_uinteger_cmd ("buffer-size", no_class,
&record_btrace_conf.bts.size,
&set_record_btrace_bts_cmdlist,
&show_record_btrace_bts_cmdlist);
- add_basic_prefix_cmd ("pt", class_support,
- _("Set record btrace pt options."),
- &set_record_btrace_pt_cmdlist,
- 0,
- &set_record_btrace_cmdlist);
-
- add_show_prefix_cmd ("pt", class_support,
- _("Show record btrace pt options."),
- &show_record_btrace_pt_cmdlist,
- 0,
- &show_record_btrace_cmdlist);
+ add_setshow_prefix_cmd ("pt", class_support,
+ _("Set record btrace pt options."),
+ _("Show record btrace pt options."),
+ &set_record_btrace_pt_cmdlist,
+ &show_record_btrace_pt_cmdlist,
+ &set_record_btrace_cmdlist,
+ &show_record_btrace_cmdlist);
add_setshow_uinteger_cmd ("buffer-size", no_class,
&record_btrace_conf.pt.size,