@@ -6,6 +6,13 @@
* 'info proc' now works on running processes on FreeBSD systems and core
files created on FreeBSD systems.
+* New options
+
+set record btrace cpu
+show record btrace cpu
+ Controls the processor to be used for enabling errata workarounds for branch
+ trace decode.
+
*** Changes in GDB 8.1
* GDB now supports dynamically creating arbitrary register groups specified
@@ -35,6 +35,9 @@
#include "gdbcmd.h"
#include "cli/cli-utils.h"
+/* For maintenance commands. */
+#include "record-btrace.h"
+
#include <inttypes.h>
#include <ctype.h>
#include <algorithm>
@@ -1428,15 +1431,19 @@ btrace_compute_ftrace_pt (struct thread_info *tp,
config.begin = btrace->data;
config.end = btrace->data + btrace->size;
- config.cpu.vendor = pt_translate_cpu_vendor (btrace->config.cpu.vendor);
- config.cpu.family = btrace->config.cpu.family;
- config.cpu.model = btrace->config.cpu.model;
- config.cpu.stepping = btrace->config.cpu.stepping;
+ /* We treat an unknown vendor as 'no errata'. */
+ if (btrace->config.cpu.vendor != CV_UNKNOWN)
+ {
+ config.cpu.vendor = pt_translate_cpu_vendor (btrace->config.cpu.vendor);
+ config.cpu.family = btrace->config.cpu.family;
+ config.cpu.model = btrace->config.cpu.model;
+ config.cpu.stepping = btrace->config.cpu.stepping;
- errcode = pt_cpu_errata (&config.errata, &config.cpu);
- if (errcode < 0)
- error (_("Failed to configure the Intel Processor Trace decoder: %s."),
- pt_errstr (pt_errcode (errcode)));
+ errcode = pt_cpu_errata (&config.errata, &config.cpu);
+ if (errcode < 0)
+ error (_("Failed to configure the Intel Processor Trace decoder: %s."),
+ pt_errstr (pt_errcode (errcode)));
+ }
decoder = pt_insn_alloc_decoder (&config);
if (decoder == NULL)
@@ -1484,11 +1491,13 @@ btrace_compute_ftrace_pt (struct thread_info *tp,
#endif /* defined (HAVE_LIBIPT) */
-/* Compute the function branch trace from a block branch trace BTRACE for
- a thread given by BTINFO. */
+/* Compute the function branch trace from a block branch trace BTRACE for a
+ thread given by BTINFO. If CPU is not NULL, overwrite the cpu in the branch
+ trace configuration. This is currently only used for the PT format. */
static void
btrace_compute_ftrace_1 (struct thread_info *tp, struct btrace_data *btrace,
+ const struct btrace_cpu *cpu,
std::vector<unsigned int> &gaps)
{
DEBUG ("compute ftrace");
@@ -1503,6 +1512,10 @@ btrace_compute_ftrace_1 (struct thread_info *tp, struct btrace_data *btrace,
return;
case BTRACE_FORMAT_PT:
+ /* Overwrite the cpu we use for enabling errata workarounds. */
+ if (cpu != nullptr)
+ btrace->variant.pt.config.cpu = *cpu;
+
btrace_compute_ftrace_pt (tp, &btrace->variant.pt, gaps);
return;
}
@@ -1521,13 +1534,14 @@ btrace_finalize_ftrace (struct thread_info *tp, std::vector<unsigned int> &gaps)
}
static void
-btrace_compute_ftrace (struct thread_info *tp, struct btrace_data *btrace)
+btrace_compute_ftrace (struct thread_info *tp, struct btrace_data *btrace,
+ const struct btrace_cpu *cpu)
{
std::vector<unsigned int> gaps;
TRY
{
- btrace_compute_ftrace_1 (tp, btrace, gaps);
+ btrace_compute_ftrace_1 (tp, btrace, cpu, gaps);
}
CATCH (error, RETURN_MASK_ALL)
{
@@ -1564,7 +1578,7 @@ btrace_add_pc (struct thread_info *tp)
block->begin = pc;
block->end = pc;
- btrace_compute_ftrace (tp, &btrace);
+ btrace_compute_ftrace (tp, &btrace, NULL);
do_cleanups (cleanup);
}
@@ -1872,7 +1886,7 @@ btrace_decode_error (enum btrace_format format, int errcode)
/* See btrace.h. */
void
-btrace_fetch (struct thread_info *tp)
+btrace_fetch (struct thread_info *tp, const struct btrace_cpu *cpu)
{
struct btrace_thread_info *btinfo;
struct btrace_target_info *tinfo;
@@ -1948,7 +1962,7 @@ btrace_fetch (struct thread_info *tp)
btrace_maint_clear (btinfo);
btrace_clear_history (btinfo);
- btrace_compute_ftrace (tp, &btrace);
+ btrace_compute_ftrace (tp, &btrace, cpu);
}
do_cleanups (cleanup);
@@ -3028,6 +3042,7 @@ static void
btrace_maint_update_pt_packets (struct btrace_thread_info *btinfo)
{
struct pt_packet_decoder *decoder;
+ const struct btrace_cpu *cpu;
struct btrace_data_pt *pt;
struct pt_config config;
int errcode;
@@ -3044,15 +3059,23 @@ btrace_maint_update_pt_packets (struct btrace_thread_info *btinfo)
config.begin = pt->data;
config.end = pt->data + pt->size;
- config.cpu.vendor = pt_translate_cpu_vendor (pt->config.cpu.vendor);
- config.cpu.family = pt->config.cpu.family;
- config.cpu.model = pt->config.cpu.model;
- config.cpu.stepping = pt->config.cpu.stepping;
+ cpu = record_btrace_get_cpu ();
+ if (cpu == nullptr)
+ cpu = &pt->config.cpu;
- errcode = pt_cpu_errata (&config.errata, &config.cpu);
- if (errcode < 0)
- error (_("Failed to configure the Intel Processor Trace decoder: %s."),
- pt_errstr (pt_errcode (errcode)));
+ /* We treat an unknown vendor as 'no errata'. */
+ if (cpu->vendor != CV_UNKNOWN)
+ {
+ config.cpu.vendor = pt_translate_cpu_vendor (cpu->vendor);
+ config.cpu.family = cpu->family;
+ config.cpu.model = cpu->model;
+ config.cpu.stepping = cpu->stepping;
+
+ errcode = pt_cpu_errata (&config.errata, &config.cpu);
+ if (errcode < 0)
+ error (_("Failed to configure the Intel Processor Trace decoder: %s."),
+ pt_errstr (pt_errcode (errcode)));
+ }
decoder = pt_pkt_alloc_decoder (&config);
if (decoder == NULL)
@@ -385,8 +385,9 @@ extern void btrace_teardown (struct thread_info *);
extern const char *btrace_decode_error (enum btrace_format format, int errcode);
-/* Fetch the branch trace for a single thread. */
-extern void btrace_fetch (struct thread_info *);
+/* Fetch the branch trace for a single thread. If CPU is not NULL, assume CPU
+ for trace decode. */
+extern void btrace_fetch (struct thread_info *, const struct btrace_cpu *cpu);
/* Clear the branch trace for a single thread. */
extern void btrace_clear (struct thread_info *);
@@ -6952,10 +6952,51 @@ and to read-write memory. Beware that the accessed memory corresponds
to the live target and not necessarily to the current replay
position.
+@item set record btrace cpu @var{identifier}
+Set the processor to be used for enabling trace decode errata
+workarounds. The general @var{identifier} format is a vendor
+identifier followed by a vendor-specific processor identifier. In
+addition, there are two special identifiers, @code{none} and
+@code{auto} (default).
+
+The following vendor identifiers and corresponding processor
+identifiers are currently supported:
+
+@multitable @columnfractions .1 .9
+
+@item @code{intel}
+@tab @var{family}/@var{model}[/@var{stepping}]
+
+@end multitable
+
+If @var{identifier} is @code{auto}, enable errata workarounds for the
+processor on which the trace was recorded. If @var{identifier} is
+@code{none}, errata workarounds are disabled.
+
+For example:
+
+@smallexample
+(gdb) info record
+Active record target: record-btrace
+Recording format: Intel Processor Trace.
+Buffer size: 16kB.
+Failed to configure the Intel Processor Trace decoder: unknown cpu.
+(gdb) set record btrace cpu intel:6/158
+(gdb) info record
+Active record target: record-btrace
+Recording format: Intel Processor Trace.
+Buffer size: 16kB.
+Recorded 84872 instructions in 3189 functions (0 gaps) for thread 1 (...).
+@end smallexample
+
@kindex show record btrace
@item show record btrace replay-memory-access
Show the current setting of @code{replay-memory-access}.
+@item show record btrace cpu
+Show the processor to be used for enabling trace decode errata
+workarounds.
+
@kindex set record btrace bts
@item set record btrace bts buffer-size @var{size}
@itemx set record btrace bts buffer-size unlimited
@@ -24,6 +24,7 @@
#include "btrace.h"
#include "py-record.h"
#include "py-record-btrace.h"
+#include "record-btrace.h"
#include "disasm.h"
#if defined (IS_PY3K)
@@ -678,7 +679,7 @@ recpy_bt_begin (PyObject *self, void *closure)
if (tinfo == NULL)
Py_RETURN_NONE;
- btrace_fetch (tinfo);
+ btrace_fetch (tinfo, record_btrace_get_cpu ());
if (btrace_is_empty (tinfo))
Py_RETURN_NONE;
@@ -700,7 +701,7 @@ recpy_bt_end (PyObject *self, void *closure)
if (tinfo == NULL)
Py_RETURN_NONE;
- btrace_fetch (tinfo);
+ btrace_fetch (tinfo, record_btrace_get_cpu ());
if (btrace_is_empty (tinfo))
Py_RETURN_NONE;
@@ -724,7 +725,7 @@ recpy_bt_instruction_history (PyObject *self, void *closure)
if (tinfo == NULL)
Py_RETURN_NONE;
- btrace_fetch (tinfo);
+ btrace_fetch (tinfo, record_btrace_get_cpu ());
if (btrace_is_empty (tinfo))
Py_RETURN_NONE;
@@ -753,7 +754,7 @@ recpy_bt_function_call_history (PyObject *self, void *closure)
if (tinfo == NULL)
Py_RETURN_NONE;
- btrace_fetch (tinfo);
+ btrace_fetch (tinfo, record_btrace_get_cpu ());
if (btrace_is_empty (tinfo))
Py_RETURN_NONE;
@@ -60,6 +60,20 @@ static const char *const replay_memory_access_types[] =
/* The currently allowed replay memory access type. */
static const char *replay_memory_access = replay_memory_access_read_only;
+/* The cpu state kinds. */
+enum record_btrace_cpu_state_kind
+{
+ CS_AUTO,
+ CS_NONE,
+ CS_CPU
+};
+
+/* The current cpu state. */
+static enum record_btrace_cpu_state_kind record_btrace_cpu_state = CS_AUTO;
+
+/* The current cpu for trace decode. */
+static struct btrace_cpu record_btrace_cpu;
+
/* 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;
@@ -87,6 +101,9 @@ static struct cmd_list_element *show_record_btrace_bts_cmdlist;
static struct cmd_list_element *set_record_btrace_pt_cmdlist;
static struct cmd_list_element *show_record_btrace_pt_cmdlist;
+/* Command list for "set record btrace cpu". */
+static struct cmd_list_element *set_record_btrace_cpu_cmdlist;
+
/* Print a record-btrace debug message. Use do ... while (0) to avoid
ambiguities when used in if statements. */
@@ -100,6 +117,26 @@ static struct cmd_list_element *show_record_btrace_pt_cmdlist;
while (0)
+/* Return the cpu configured by the user. Returns NULL if the cpu was
+ configured as auto. */
+const struct btrace_cpu *
+record_btrace_get_cpu (void)
+{
+ switch (record_btrace_cpu_state)
+ {
+ case CS_AUTO:
+ return nullptr;
+
+ case CS_NONE:
+ record_btrace_cpu.vendor = CV_UNKNOWN;
+ /* Fall through. */
+ case CS_CPU:
+ return &record_btrace_cpu;
+ }
+
+ error (_("Internal error: bad record btrace cpu state."));
+}
+
/* Update the branch trace for the current thread and return a pointer to its
thread_info.
@@ -119,7 +156,7 @@ require_btrace_thread (void)
validate_registers_access ();
- btrace_fetch (tp);
+ btrace_fetch (tp, record_btrace_get_cpu ());
if (btrace_is_empty (tp))
error (_("No trace."));
@@ -427,7 +464,7 @@ record_btrace_info (struct target_ops *self)
if (conf != NULL)
record_btrace_print_conf (conf);
- btrace_fetch (tp);
+ btrace_fetch (tp, record_btrace_get_cpu ());
insns = 0;
calls = 0;
@@ -1843,7 +1880,7 @@ record_btrace_resume_thread (struct thread_info *tp,
btinfo = &tp->btrace;
/* Fetch the latest branch trace. */
- btrace_fetch (tp);
+ btrace_fetch (tp, record_btrace_get_cpu ());
/* A resume request overwrites a preceding resume or stop request. */
btinfo->flags &= ~(BTHR_MOVE | BTHR_STOP);
@@ -2979,7 +3016,113 @@ cmd_show_replay_memory_access (struct ui_file *file, int from_tty,
replay_memory_access);
}
-/* The "set record btrace bts" command. */
+/* The "set record btrace cpu none" command. */
+
+static void
+cmd_set_record_btrace_cpu_none (const char *args, int from_tty)
+{
+ if (args != nullptr && *args != 0)
+ error (_("Trailing junk: '%s'."), args);
+
+ record_btrace_cpu_state = CS_NONE;
+}
+
+/* The "set record btrace cpu auto" command. */
+
+static void
+cmd_set_record_btrace_cpu_auto (const char *args, int from_tty)
+{
+ if (args != nullptr && *args != 0)
+ error (_("Trailing junk: '%s'."), args);
+
+ record_btrace_cpu_state = CS_AUTO;
+}
+
+/* The "set record btrace cpu" command. */
+
+static void
+cmd_set_record_btrace_cpu (const char *args, int from_tty)
+{
+ if (args == nullptr)
+ args = "";
+
+ /* We use a hard-coded vendor string for now. */
+ unsigned int family, model, stepping;
+ int l1, l2, matches = sscanf (args, "intel: %u/%u%n/%u%n", &family, &model,
+ &l1, &stepping, &l2);
+ if (matches == 3)
+ {
+ if (strlen (args) != l2)
+ error (_("Trailing junk: '%s'."), args + l2);
+ }
+ else if (matches == 2)
+ {
+ if (strlen (args) != l1)
+ error (_("Trailing junk: '%s'."), args + l1);
+
+ stepping = 0;
+ }
+ else
+ error (_("Bad format. See \"help set record btrace cpu\"."));
+
+ if (USHRT_MAX < family)
+ error (_("Cpu family too big."));
+
+ if (UCHAR_MAX < model)
+ error (_("Cpu model too big."));
+
+ if (UCHAR_MAX < stepping)
+ error (_("Cpu stepping too big."));
+
+ record_btrace_cpu.vendor = CV_INTEL;
+ record_btrace_cpu.family = family;
+ record_btrace_cpu.model = model;
+ record_btrace_cpu.stepping = stepping;
+
+ record_btrace_cpu_state = CS_CPU;
+}
+
+/* The "show record btrace cpu" command. */
+
+static void
+cmd_show_record_btrace_cpu (const char *args, int from_tty)
+{
+ const char *cpu;
+
+ if (args != nullptr && *args != 0)
+ error (_("Trailing junk: '%s'."), args);
+
+ switch (record_btrace_cpu_state)
+ {
+ case CS_AUTO:
+ printf_unfiltered (_("btrace cpu is 'auto'.\n"));
+ return;
+
+ case CS_NONE:
+ printf_unfiltered (_("btrace cpu is 'none'.\n"));
+ return;
+
+ case CS_CPU:
+ switch (record_btrace_cpu.vendor)
+ {
+ 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);
+ else
+ printf_unfiltered (_("btrace cpu is 'intel: %u/%u/%u'.\n"),
+ record_btrace_cpu.family,
+ record_btrace_cpu.model,
+ record_btrace_cpu.stepping);
+ return;
+ }
+ }
+
+ error (_("Internal error: bad cpu state."));
+}
+
+/* The "s record btrace bts" command. */
static void
cmd_set_record_btrace_bts (const char *args, int from_tty)
@@ -3087,6 +3230,31 @@ replay."),
&set_record_btrace_cmdlist,
&show_record_btrace_cmdlist);
+ add_prefix_cmd ("cpu", class_support, cmd_set_record_btrace_cpu,
+ _("\
+Set the cpu to be used for trace decode.\n\n\
+The format is \"<vendor>: <identifier>\" or \"none\" or \"auto\" (default).\n\
+For vendor \"intel\" the format is \"<family>/<model>[/<stepping>]\".\n\n\
+When decoding branch trace, enable errata workarounds for the specified cpu.\n\
+The default is AUTO, which uses the cpu on which the trace was recorded.\n\
+When GDB does not support that cpu, this option can be used to enable\n\
+workarounds for a similar cpu that GDB supports.\n\n\
+When set to NONE, errata workarounds are disabled."),
+ &set_record_btrace_cpu_cmdlist, _("set record btrace cpu "),
+ 1, &set_record_btrace_cmdlist);
+
+ add_cmd ("auto", class_support, cmd_set_record_btrace_cpu_auto, _("\
+Automatically determine the cpu to be used for trace decode."),
+ &set_record_btrace_cpu_cmdlist);
+
+ add_cmd ("none", class_support, cmd_set_record_btrace_cpu_none, _("\
+Do not enable errata workarounds for trace decode."),
+ &set_record_btrace_cpu_cmdlist);
+
+ add_cmd ("cpu", class_support, cmd_show_record_btrace_cpu, _("\
+Show the cpu to be used for trace decode."),
+ &show_record_btrace_cmdlist);
+
add_prefix_cmd ("bts", class_support, cmd_set_record_btrace_bts,
_("Set record btrace bts options"),
&set_record_btrace_bts_cmdlist,
@@ -25,4 +25,8 @@
/* Push the record_btrace target. */
extern void record_btrace_push_target (void);
+/* Return the cpu configured by the user via "set btrace cpu". Returns NULL if
+ the cpu was configured as auto. */
+extern const struct btrace_cpu *record_btrace_get_cpu (void);
+
#endif /* RECORD_BTRACE_H */
new file mode 100644
@@ -0,0 +1,74 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2018 Free Software Foundation, Inc.
+#
+# 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/>.
+
+gdb_start
+
+proc test_good { arg } {
+ gdb_test_no_output "set record btrace cpu $arg" "set cpu $arg"
+ gdb_test "show record btrace cpu" "btrace cpu is '$arg'\." "show cpu $arg"
+}
+
+proc test_bad { arg current } {
+ gdb_test "set record btrace cpu $arg" \
+ "Bad format\. See \"help set record btrace cpu\"\." \
+ "set cpu $arg"
+ gdb_test "show record btrace cpu" "btrace cpu is '$current'\." \
+ "show cpu $arg"
+}
+
+proc test_junk { arg junk current } {
+ gdb_test "set record btrace cpu $arg" \
+ "Trailing junk: '$junk'\." \
+ "set cpu $arg"
+ gdb_test "show record btrace cpu" "btrace cpu is '$current'\." \
+ "show cpu $arg"
+}
+
+gdb_test "show record btrace cpu" "btrace cpu is 'auto'\." "default cpu"
+
+gdb_test "set record" \
+ "\"set record\" must be followed by an apporpriate subcommand.*" \
+ "set record"
+gdb_test "set record btrace" \
+ "\"set record btrace\" must be followed by an apporpriate subcommand.*" \
+ "set record btrace"
+test_bad "" "auto"
+
+test_good "intel: 0/0"
+test_good "intel: 0/0/1"
+
+# We omit a zero stepping in the output.
+gdb_test_no_output "set record btrace cpu intel: 0/0/0" "set cpu intel: 0/0/0"
+gdb_test "show record btrace cpu" "btrace cpu is 'intel: 0/0'\." \
+ "show cpu intel: 0/0/0"
+
+test_good "auto"
+test_good "none"
+
+test_bad "intel: foo" "none"
+test_bad "intel: 0" "none"
+test_bad "intel: 0/" "none"
+test_bad "intel: 0/foo" "none"
+test_bad "intel: foo/bar" "none"
+test_bad "intel: foo/0" "none"
+test_bad "intel: 0x0/0" "none"
+
+test_junk "intel: 0/0 foo" " foo" "none"
+test_junk "intel: 0/0x0" "x0" "none"
+test_junk "intel: 0/0/foo" "/foo" "none"
+test_junk "intel: 0/0/0 foo" " foo" "none"
+test_junk "intel: 0/0/0x0" "x0" "none"