/* Command list for "record btrace". */
static struct cmd_list_element *record_btrace_cmdlist;
-/* Command lists for "set/show record btrace". */
-static struct cmd_list_element *set_record_btrace_cmdlist;
-static struct cmd_list_element *show_record_btrace_cmdlist;
-
/* Command lists for "set/show record btrace bts". */
static struct cmd_list_element *set_record_btrace_bts_cmdlist;
static struct cmd_list_element *show_record_btrace_bts_cmdlist;
+/* Command lists for "set/show record btrace pt". */
+static struct cmd_list_element *set_record_btrace_pt_cmdlist;
+static struct cmd_list_element *show_record_btrace_pt_cmdlist;
+
/* Print a record-btrace debug message. Use do ... while (0) to avoid
ambiguities when used in if statements. */
static void
record_btrace_enable_warn (struct thread_info *tp)
{
- volatile struct gdb_exception error;
-
- TRY_CATCH (error, RETURN_MASK_ERROR)
- btrace_enable (tp, &record_btrace_conf);
-
- if (error.message != NULL)
- warning ("%s", error.message);
+ TRY
+ {
+ btrace_enable (tp, &record_btrace_conf);
+ }
+ CATCH (error, RETURN_MASK_ERROR)
+ {
+ warning ("%s", error.message);
+ }
+ END_CATCH
}
/* Callback function to disable branch tracing for one thread. */
/* The to_async method of target record-btrace. */
static void
-record_btrace_async (struct target_ops *ops,
- void (*callback) (enum inferior_event_type event_type,
- void *context),
- void *context)
+record_btrace_async (struct target_ops *ops, int enable)
{
- if (callback != NULL)
+ if (enable)
mark_async_event_handler (record_btrace_async_inferior_event_handler);
else
clear_async_event_handler (record_btrace_async_inferior_event_handler);
- ops->beneath->to_async (ops->beneath, callback, context);
+ ops->beneath->to_async (ops->beneath, enable);
}
/* Adjusts the size and returns a human readable size suffix. */
}
}
+/* Print an Intel(R) Processor Trace configuration. */
+
+static void
+record_btrace_print_pt_conf (const struct btrace_config_pt *conf)
+{
+ const char *suffix;
+ unsigned int size;
+
+ size = conf->size;
+ if (size > 0)
+ {
+ suffix = record_btrace_adjust_size (&size);
+ printf_unfiltered (_("Buffer size: %u%s.\n"), size, suffix);
+ }
+}
+
/* Print a branch tracing configuration. */
static void
case BTRACE_FORMAT_BTS:
record_btrace_print_bts_conf (&conf->bts);
return;
+
+ case BTRACE_FORMAT_PT:
+ record_btrace_print_pt_conf (&conf->pt);
+ return;
}
internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
break;
}
break;
+
+#if defined (HAVE_LIBIPT)
+ case BTRACE_FORMAT_PT:
+ switch (errcode)
+ {
+ case BDE_PT_USER_QUIT:
+ is_error = 0;
+ errstr = _("trace decode cancelled");
+ break;
+
+ case BDE_PT_DISABLED:
+ is_error = 0;
+ errstr = _("disabled");
+ break;
+
+ case BDE_PT_OVERFLOW:
+ is_error = 0;
+ errstr = _("overflow");
+ break;
+
+ default:
+ if (errcode < 0)
+ errstr = pt_errstr (pt_errcode (errcode));
+ break;
+ }
+ break;
+#endif /* defined (HAVE_LIBIPT) */
}
ui_out_text (uiout, _("["));
ui_out_field_uint (uiout, "insn end", end);
}
+/* Compute the lowest and highest source line for the instructions in BFUN
+ and return them in PBEGIN and PEND.
+ Ignore instructions that can't be mapped to BFUN, e.g. instructions that
+ result from inlining or macro expansion. */
+
+static void
+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;
+ end = INT_MIN;
+
+ sym = bfun->sym;
+ if (sym == NULL)
+ goto out;
+
+ symtab = symbol_symtab (sym);
+
+ for (idx = 0; VEC_iterate (btrace_insn_s, bfun->insn, idx, insn); ++idx)
+ {
+ struct symtab_and_line sal;
+
+ sal = find_pc_line (insn->pc, 0);
+ if (sal.symtab != symtab || sal.line == 0)
+ continue;
+
+ begin = min (begin, sal.line);
+ end = max (end, sal.line);
+ }
+
+ out:
+ *pbegin = begin;
+ *pend = end;
+}
+
/* Print the source line information for a function call history line. */
static void
ui_out_field_string (uiout, "file",
symtab_to_filename_for_display (symbol_symtab (sym)));
- begin = bfun->lbegin;
- end = bfun->lend;
-
+ btrace_compute_src_line_range (bfun, &begin, &end);
if (end < begin)
return;
struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- volatile struct gdb_exception except;
const char *old;
int ret;
replay_memory_access = replay_memory_access_read_write;
ret = 0;
- TRY_CATCH (except, RETURN_MASK_ALL)
- ret = ops->beneath->to_insert_breakpoint (ops->beneath, gdbarch, bp_tgt);
-
+ TRY
+ {
+ ret = ops->beneath->to_insert_breakpoint (ops->beneath, gdbarch, bp_tgt);
+ }
+ CATCH (except, RETURN_MASK_ALL)
+ {
+ replay_memory_access = old;
+ throw_exception (except);
+ }
+ END_CATCH
replay_memory_access = old;
- if (except.reason < 0)
- throw_exception (except);
-
return ret;
}
struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- volatile struct gdb_exception except;
const char *old;
int ret;
replay_memory_access = replay_memory_access_read_write;
ret = 0;
- TRY_CATCH (except, RETURN_MASK_ALL)
- ret = ops->beneath->to_remove_breakpoint (ops->beneath, gdbarch, bp_tgt);
-
+ TRY
+ {
+ ret = ops->beneath->to_remove_breakpoint (ops->beneath, gdbarch, bp_tgt);
+ }
+ CATCH (except, RETURN_MASK_ALL)
+ {
+ replay_memory_access = old;
+ throw_exception (except);
+ }
+ END_CATCH
replay_memory_access = old;
- if (except.reason < 0)
- throw_exception (except);
-
return ret;
}
static struct btrace_insn_iterator *
record_btrace_start_replaying (struct thread_info *tp)
{
- volatile struct gdb_exception except;
struct btrace_insn_iterator *replay;
struct btrace_thread_info *btinfo;
int executing;
Since frames are computed differently when we're replaying, we need to
recompute those stored frames and fix them up so we can still detect
subroutines after we started replaying. */
- TRY_CATCH (except, RETURN_MASK_ALL)
+ TRY
{
struct frame_info *frame;
struct frame_id frame_id;
if (upd_step_stack_frame_id)
tp->control.step_stack_frame_id = frame_id;
}
-
- /* Restore the previous execution state. */
- set_executing (tp->ptid, executing);
-
- if (except.reason < 0)
+ CATCH (except, RETURN_MASK_ALL)
{
+ /* Restore the previous execution state. */
+ set_executing (tp->ptid, executing);
+
xfree (btinfo->replay);
btinfo->replay = NULL;
throw_exception (except);
}
+ END_CATCH
+
+ /* Restore the previous execution state. */
+ set_executing (tp->ptid, executing);
return replay;
}
/* Async support. */
if (target_can_async_p ())
{
- target_async (inferior_event_handler, 0);
+ target_async (1);
mark_async_event_handler (record_btrace_async_inferior_event_handler);
}
}
target_pid_to_str (tp->ptid),
core_addr_to_string_nz (insn->pc));
- if (breakpoint_here_p (aspace, insn->pc))
+ if (record_check_stopped_by_breakpoint (aspace, insn->pc,
+ &btinfo->stop_reason))
return btrace_step_stopped ();
}
target_pid_to_str (tp->ptid),
core_addr_to_string_nz (insn->pc));
- if (breakpoint_here_p (aspace, insn->pc))
+ if (record_check_stopped_by_breakpoint (aspace, insn->pc,
+ &btinfo->stop_reason))
return btrace_step_stopped ();
}
}
return 1;
}
-/* The to_decr_pc_after_break method of target record-btrace. */
+/* The to_stopped_by_sw_breakpoint method of target record-btrace. */
-static CORE_ADDR
-record_btrace_decr_pc_after_break (struct target_ops *ops,
- struct gdbarch *gdbarch)
+static int
+record_btrace_stopped_by_sw_breakpoint (struct target_ops *ops)
{
- /* When replaying, we do not actually execute the breakpoint instruction
- so there is no need to adjust the PC after hitting a breakpoint. */
if (record_btrace_is_replaying (ops))
- return 0;
+ {
+ struct thread_info *tp = inferior_thread ();
- return ops->beneath->to_decr_pc_after_break (ops->beneath, gdbarch);
+ return tp->btrace.stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT;
+ }
+
+ return ops->beneath->to_stopped_by_sw_breakpoint (ops->beneath);
+}
+
+/* The to_supports_stopped_by_sw_breakpoint method of target
+ record-btrace. */
+
+static int
+record_btrace_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
+{
+ if (record_btrace_is_replaying (ops))
+ return 1;
+
+ return ops->beneath->to_supports_stopped_by_sw_breakpoint (ops->beneath);
+}
+
+/* The to_stopped_by_sw_breakpoint method of target record-btrace. */
+
+static int
+record_btrace_stopped_by_hw_breakpoint (struct target_ops *ops)
+{
+ if (record_btrace_is_replaying (ops))
+ {
+ struct thread_info *tp = inferior_thread ();
+
+ return tp->btrace.stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT;
+ }
+
+ return ops->beneath->to_stopped_by_hw_breakpoint (ops->beneath);
+}
+
+/* The to_supports_stopped_by_hw_breakpoint method of target
+ record-btrace. */
+
+static int
+record_btrace_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
+{
+ if (record_btrace_is_replaying (ops))
+ return 1;
+
+ return ops->beneath->to_supports_stopped_by_hw_breakpoint (ops->beneath);
}
/* The to_update_thread_list method of target record-btrace. */
/* Start anew from the new replay position. */
record_btrace_clear_histories (btinfo);
+
+ stop_pc = regcache_read_pc (get_current_regcache ());
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
}
/* The to_goto_record_begin method of target record-btrace. */
btrace_insn_begin (&begin, &tp->btrace);
record_btrace_set_replay (tp, &begin);
-
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
}
/* The to_goto_record_end method of target record-btrace. */
tp = require_btrace_thread ();
record_btrace_set_replay (tp, NULL);
-
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
}
/* The to_goto_record method of target record-btrace. */
error (_("No such instruction."));
record_btrace_set_replay (tp, &it);
-
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
}
/* The to_execution_direction target method. */
ops->to_goto_record_end = record_btrace_goto_end;
ops->to_goto_record = record_btrace_goto;
ops->to_can_execute_reverse = record_btrace_can_execute_reverse;
- ops->to_decr_pc_after_break = record_btrace_decr_pc_after_break;
+ ops->to_stopped_by_sw_breakpoint = record_btrace_stopped_by_sw_breakpoint;
+ ops->to_supports_stopped_by_sw_breakpoint
+ = record_btrace_supports_stopped_by_sw_breakpoint;
+ ops->to_stopped_by_hw_breakpoint = record_btrace_stopped_by_hw_breakpoint;
+ ops->to_supports_stopped_by_hw_breakpoint
+ = record_btrace_supports_stopped_by_hw_breakpoint;
ops->to_execution_direction = record_btrace_execution_direction;
ops->to_prepare_to_generate_core = record_btrace_prepare_to_generate_core;
ops->to_done_generating_core = record_btrace_done_generating_core;
static void
cmd_record_btrace_bts_start (char *args, int from_tty)
{
- volatile struct gdb_exception exception;
-
if (args != NULL && *args != 0)
error (_("Invalid argument."));
record_btrace_conf.format = BTRACE_FORMAT_BTS;
- TRY_CATCH (exception, RETURN_MASK_ALL)
- execute_command ("target record-btrace", from_tty);
+ TRY
+ {
+ execute_command ("target record-btrace", from_tty);
+ }
+ CATCH (exception, RETURN_MASK_ALL)
+ {
+ record_btrace_conf.format = BTRACE_FORMAT_NONE;
+ throw_exception (exception);
+ }
+ END_CATCH
+}
+
+/* Start recording Intel(R) Processor Trace. */
+
+static void
+cmd_record_btrace_pt_start (char *args, int from_tty)
+{
+ if (args != NULL && *args != 0)
+ error (_("Invalid argument."));
+
+ record_btrace_conf.format = BTRACE_FORMAT_PT;
- if (exception.error != 0)
+ TRY
+ {
+ execute_command ("target record-btrace", from_tty);
+ }
+ CATCH (exception, RETURN_MASK_ALL)
{
record_btrace_conf.format = BTRACE_FORMAT_NONE;
throw_exception (exception);
}
+ END_CATCH
}
/* Alias for "target record". */
static void
cmd_record_btrace_start (char *args, int from_tty)
{
- volatile struct gdb_exception exception;
-
if (args != NULL && *args != 0)
error (_("Invalid argument."));
- record_btrace_conf.format = BTRACE_FORMAT_BTS;
-
- TRY_CATCH (exception, RETURN_MASK_ALL)
- execute_command ("target record-btrace", from_tty);
+ record_btrace_conf.format = BTRACE_FORMAT_PT;
- if (exception.error == 0)
- return;
+ TRY
+ {
+ execute_command ("target record-btrace", from_tty);
+ }
+ CATCH (exception, RETURN_MASK_ALL)
+ {
+ record_btrace_conf.format = BTRACE_FORMAT_BTS;
- record_btrace_conf.format = BTRACE_FORMAT_NONE;
- throw_exception (exception);
+ TRY
+ {
+ execute_command ("target record-btrace", from_tty);
+ }
+ CATCH (exception, RETURN_MASK_ALL)
+ {
+ record_btrace_conf.format = BTRACE_FORMAT_NONE;
+ throw_exception (exception);
+ }
+ END_CATCH
+ }
+ END_CATCH
}
/* The "set record btrace" command. */
cmd_set_record_btrace_bts (char *args, int from_tty)
{
printf_unfiltered (_("\"set record btrace bts\" must be followed "
- "by an apporpriate subcommand.\n"));
+ "by an appropriate subcommand.\n"));
help_list (set_record_btrace_bts_cmdlist, "set record btrace bts ",
all_commands, gdb_stdout);
}
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)
+{
+ printf_unfiltered (_("\"set record btrace pt\" must be followed "
+ "by an appropriate subcommand.\n"));
+ help_list (set_record_btrace_pt_cmdlist, "set record btrace pt ",
+ all_commands, gdb_stdout);
+}
+
+/* The "show record btrace pt" command. */
+
+static void
+cmd_show_record_btrace_pt (char *args, int from_tty)
+{
+ cmd_show_list (show_record_btrace_pt_cmdlist, from_tty, "");
+}
+
+/* The "record bts buffer-size" show value function. */
+
+static void
+show_record_bts_buffer_size_value (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ fprintf_filtered (file, _("The record/replay bts buffer size is %s.\n"),
+ value);
+}
+
+/* The "record pt buffer-size" show value function. */
+
+static void
+show_record_pt_buffer_size_value (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ fprintf_filtered (file, _("The record/replay pt buffer size is %s.\n"),
+ value);
+}
+
void _initialize_record_btrace (void);
/* Initialize btrace commands. */
&record_btrace_cmdlist);
add_alias_cmd ("bts", "btrace bts", class_obscure, 1, &record_cmdlist);
+ add_cmd ("pt", class_obscure, cmd_record_btrace_pt_start,
+ _("\
+Start branch trace recording in Intel(R) Processor Trace format.\n\n\
+This format may not be available on all processors."),
+ &record_btrace_cmdlist);
+ add_alias_cmd ("pt", "btrace pt", class_obscure, 1, &record_cmdlist);
+
add_prefix_cmd ("btrace", class_support, cmd_set_record_btrace,
_("Set record options"), &set_record_btrace_cmdlist,
"set record btrace ", 0, &set_record_cmdlist);
Use \"info record\" to see the actual buffer size.\n\n\
Bigger buffers allow longer recording but also take more time to process \
the recorded execution trace.\n\n\
-The trace buffer size may not be changed while recording."), NULL, NULL,
+The trace buffer size may not be changed while recording."), NULL,
+ show_record_bts_buffer_size_value,
&set_record_btrace_bts_cmdlist,
&show_record_btrace_bts_cmdlist);
+ add_prefix_cmd ("pt", class_support, cmd_set_record_btrace_pt,
+ _("Set record btrace pt options"),
+ &set_record_btrace_pt_cmdlist,
+ "set record btrace pt ", 0, &set_record_btrace_cmdlist);
+
+ add_prefix_cmd ("pt", class_support, cmd_show_record_btrace_pt,
+ _("Show record btrace pt options"),
+ &show_record_btrace_pt_cmdlist,
+ "show record btrace pt ", 0, &show_record_btrace_cmdlist);
+
+ add_setshow_uinteger_cmd ("buffer-size", no_class,
+ &record_btrace_conf.pt.size,
+ _("Set the record/replay pt buffer size."),
+ _("Show the record/replay pt buffer size."), _("\
+Bigger buffers allow longer recording but also take more time to process \
+the recorded execution.\n\
+The actual buffer size may differ from the requested size. Use \"info record\" \
+to see the actual buffer size."), NULL, show_record_pt_buffer_size_value,
+ &set_record_btrace_pt_cmdlist,
+ &show_record_btrace_pt_cmdlist);
+
init_record_btrace_ops ();
add_target (&record_btrace_ops);
xcalloc, xfree);
record_btrace_conf.bts.size = 64 * 1024;
+ record_btrace_conf.pt.size = 16 * 1024;
}