+2018-04-13 Markus Metzger <markus.t.metzger@intel.com>
+
+ * NEWS (New options): announce set/show record btrace cpu.
+ * btrace.c: Include record-btrace.h.
+ (btrace_compute_ftrace_pt): Skip enabling errata workarounds if
+ the vendor is unknown.
+ (btrace_compute_ftrace_1): Add cpu parameter. Update callers.
+ Maybe overwrite the btrace configuration's cpu.
+ (btrace_compute_ftrace): Add cpu parameter. Update callers.
+ (btrace_fetch): Add cpu parameter. Update callers.
+ (btrace_maint_update_pt_packets): Call record_btrace_get_cpu.
+ Maybe overwrite the btrace configuration's cpu. Skip enabling
+ errata workarounds if the vendor is unknown.
+ * python/py-record-btrace.c: Include record-btrace.h.
+ (recpy_bt_begin, recpy_bt_end, recpy_bt_instruction_history)
+ (recpy_bt_function_call_history): Call record_btrace_get_cpu.
+ * record-btrace.c (record_btrace_cpu_state_kind): New.
+ (record_btrace_cpu): New.
+ (set_record_btrace_cpu_cmdlist): New.
+ (record_btrace_get_cpu): New.
+ (require_btrace_thread, record_btrace_info)
+ (record_btrace_resume_thread): Call record_btrace_get_cpu.
+ (cmd_set_record_btrace_cpu_none): New.
+ (cmd_set_record_btrace_cpu_auto): New.
+ (cmd_set_record_btrace_cpu): New.
+ (cmd_show_record_btrace_cpu): New.
+ (_initialize_record_btrace): Initialize set/show record btrace cpu
+ commands.
+ * record-btrace.h (record_btrace_get_cpu): New.
+
2018-04-13 Markus Metzger <markus.t.metzger@intel.com>
* record.c (set_record_command): Fix typo in message.
objects being printed when those objects have a variable type,
instead of that maximum size being hardcoded to 65536 bytes.
+set|show record btrace cpu
+ Controls the processor to be used for enabling errata workarounds for
+ branch trace decode.
+
* New targets
RiscV ELF riscv*-*-elf
#include "gdbcmd.h"
#include "cli/cli-utils.h"
+/* For maintenance commands. */
+#include "record-btrace.h"
+
#include <inttypes.h>
#include <ctype.h>
#include <algorithm>
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)
#endif /* defined (HAVE_LIBIPT) */
/* Compute the function branch trace from a block branch trace BTRACE for
- a thread given by BTINFO. */
+ 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,
+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");
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;
}
}
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)
{
block->begin = pc;
block->end = pc;
- btrace_compute_ftrace (tp, &btrace);
+ btrace_compute_ftrace (tp, &btrace, NULL);
do_cleanups (cleanup);
}
/* 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;
btrace_maint_clear (btinfo);
btrace_clear_history (btinfo);
- btrace_compute_ftrace (tp, &btrace);
+ btrace_compute_ftrace (tp, &btrace, cpu);
}
do_cleanups (cleanup);
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;
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;
+
+ /* 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)));
+ 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)
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 *);
+2018-04-13 Markus Metzger <markus.t.metzger@intel.com>
+
+ * gdb.texinfo: Document set/show record btrace cpu.
+
2018-03-27 Joel Brobecker <brobecker@adacore.com>
* gdb.texinfo (Ada Settings): New subsubsection.
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 workarounds for processor
+errata when decoding the trace.
+
+Processor errata are defects in processor operation, caused by its
+design or manufacture. They can cause a trace not to match the
+specification. This, in turn, may cause trace decode to fail.
+@value{GDBN} can detect erroneous trace packets and correct them, thus
+avoiding the decoding failures. These corrections are known as
+@dfn{errata workarounds}, and are enabled based on the processor on
+which the trace was recorded.
+
+By default, @value{GDBN} attempts to detect the processor
+automatically, and apply the necessary workarounds for it. However,
+you may need to specify the processor if @value{GDBN} does not yet
+support it. This command allows you to do that, and also allows to
+disable the workarounds.
+
+The argument @var{identifier} identifies the @sc{cpu} and is of the
+form: @code{@var{vendor}:@var{procesor 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
+
+On GNU/Linux systems, the processor @var{family}, @var{model}, and
+@var{stepping} can be obtained from @code{/proc/cpuinfo}.
+
+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, when using an old @value{GDBN} on a new system, decode
+may fail because @value{GDBN} does not support the new processor. It
+often suffices to specify an older processor that @value{GDBN}
+supports.
+
+@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
#include "btrace.h"
#include "py-record.h"
#include "py-record-btrace.h"
+#include "record-btrace.h"
#include "disasm.h"
#if defined (IS_PY3K)
if (tinfo == NULL)
Py_RETURN_NONE;
- btrace_fetch (tinfo);
+ btrace_fetch (tinfo, record_btrace_get_cpu ());
if (btrace_is_empty (tinfo))
Py_RETURN_NONE;
if (tinfo == NULL)
Py_RETURN_NONE;
- btrace_fetch (tinfo);
+ btrace_fetch (tinfo, record_btrace_get_cpu ());
if (btrace_is_empty (tinfo))
Py_RETURN_NONE;
if (tinfo == NULL)
Py_RETURN_NONE;
- btrace_fetch (tinfo);
+ btrace_fetch (tinfo, record_btrace_get_cpu ());
if (btrace_is_empty (tinfo))
Py_RETURN_NONE;
if (tinfo == NULL)
Py_RETURN_NONE;
- btrace_fetch (tinfo);
+ btrace_fetch (tinfo, record_btrace_get_cpu ());
if (btrace_is_empty (tinfo))
Py_RETURN_NONE;
/* 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;
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. */
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.
validate_registers_access ();
- btrace_fetch (tp);
+ btrace_fetch (tp, record_btrace_get_cpu ());
if (btrace_is_empty (tp))
error (_("No trace."));
if (conf != NULL)
record_btrace_print_conf (conf);
- btrace_fetch (tp);
+ btrace_fetch (tp, record_btrace_get_cpu ());
insns = 0;
calls = 0;
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);
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)
&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,
/* 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 */
+2018-04-13 Markus Metzger <markus.t.metzger@intel.com>
+
+ * gdb.btrace/cpu.exp: New.
+
2018-04-13 Markus Metzger <markus.t.metzger@intel.com>
* gdb.base/step-indirect-call-thunk.exp: New.
--- /dev/null
+# 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 appropriate subcommand.*" \
+ "set record"
+gdb_test "set record btrace" \
+ "\"set record btrace\" must be followed by an appropriate 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"