[PATCH v2 1/3] btrace: control memory access during replay

Markus Metzger
2014-05-20T12:01:22Z

The btrace record target does not trace data. We therefore do not allow
accessing read-write memory during replay.

In some cases, this might be useful to advanced users, though, who we assume
to know what they are doing.

Add a set|show command pair to turn this memory access restriction off.

CC: Eli Zaretskii <eliz@gnu.org>

2014-05-20 Markus Metzger <markus.t.metzger@intel.com>

* record-btrace.c (record_btrace_allow_memory_access): Remove.
(replay_memory_access_read_only, replay_memory_access_read_write)
(replay_memory_access_types, replay_memory_access)
(set_record_btrace_cmdlist, show_record_btrace_cmdlist)
(cmd_set_record_btrace, cmd_show_record_btrace)
(cmd_show_replay_memory_access): New.
(record_btrace_xfer_partial, record_btrace_insert_breakpoint)
(record_btrace_remove_breakpoint): Replace
record_btrace_allow_memory_access with replay_memory_access.
(_initialize_record_btrace): Add commands.
* NEWS: Announce it.

testsuite/
* gdb.btrace/data.exp: Test it.

doc/
* gdb.texinfo: Document it.

---
gdb/NEWS | 4 ++
gdb/doc/gdb.texinfo | 22 ++++++++++
gdb/record-btrace.c | 89 ++++++++++++++++++++++++++++++++++-----
gdb/testsuite/gdb.btrace/data.exp | 10 ++++-
4 files changed, 113 insertions(+), 12 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 00ec8b9..be8abc0 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -61,6 +61,10 @@ maint ada show ignore-descriptive-types
the user manual for more details on descriptive types and the intended
usage of this option.

+set record btrace replay-memory-access (read-only|read-write)
+show record btrace replay-memory-access
+ Control what memory accesses are allowed during replay.
+
* New features in the GDB remote stub, GDBserver

** New option --debug-format=option1[,option2,...] allows one to add
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a6bde12..3f1f5c8 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6400,6 +6400,28 @@ results.
@item show record full memory-query
Show the current setting of @code{memory-query}.

+@kindex set record btrace
+The btrace record target does not trace data. As a convenience,
+when replaying, GDB reads read-only memory off the live program
+directly, assuming that the addresses of the read-only areas
+don't change. This for example makes it possible to disassemble
+code while replaying, but not to print variables.
+In some cases, being able to inspect variables might be useful.
+You can use the following command for that:
+
+@item set record btrace replay-memory-access
+Control the behavior of the @code{btrace} recording method when
+accessing memory during replay. If READ-ONLY (the default),
+@value{GDBN} will only allow accesses to read-only memory.
+If READ-WRITE, @value{GDBN} will allow accesses to read-only and to
+read-write memory. Beware that the accessed memory corresponds
+to the live target and not necessarily to the current replay
+position.
+
+@kindex show record btrace
+@item show record btrace replay-memory-access
+Show the current setting of @code{replay-memory-access}.
+
@kindex info record
@item info record
Show various statistics about the recording depending on the recording
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index bcac165..f8f9942 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -42,8 +42,22 @@ static struct target_ops record_btrace_ops;
/* A new thread observer enabling branch tracing for the new thread. */
static struct observer *record_btrace_thread_observer;

-/* Temporarily allow memory accesses. */
-static int record_btrace_allow_memory_access;
+/* Memory access types used in set/show record btrace replay-memory-access. */
+static const char replay_memory_access_read_only[] = "read-only";
+static const char replay_memory_access_read_write[] = "read-write";
+static const char *const replay_memory_access_types[] =
+{
+ replay_memory_access_read_only,
+ replay_memory_access_read_write,
+ NULL
+};
+
+/* The currently allowed replay memory access type. */
+static const char *replay_memory_access = replay_memory_access_read_only;
+
+/* 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;

/* Print a record-btrace debug message. Use do ... while (0) to avoid
ambiguities when used in if statements. */
@@ -815,7 +829,8 @@ record_btrace_xfer_partial (struct target_ops *ops, enum target_object object,
struct target_ops *t;

/* Filter out requests that don't make sense during replay. */
- if (!record_btrace_allow_memory_access && record_btrace_is_replaying (ops))
+ if (replay_memory_access == replay_memory_access_read_only
+ && record_btrace_is_replaying (ops))
{
switch (object)
{
@@ -869,18 +884,19 @@ record_btrace_insert_breakpoint (struct target_ops *ops,
struct bp_target_info *bp_tgt)
{
volatile struct gdb_exception except;
- int old, ret;
+ const char *old;
+ int ret;

/* Inserting breakpoints requires accessing memory. Allow it for the
duration of this function. */
- old = record_btrace_allow_memory_access;
- record_btrace_allow_memory_access = 1;
+ old = replay_memory_access;
+ 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);

- record_btrace_allow_memory_access = old;
+ replay_memory_access = old;

if (except.reason < 0)
throw_exception (except);
@@ -896,18 +912,19 @@ record_btrace_remove_breakpoint (struct target_ops *ops,
struct bp_target_info *bp_tgt)
{
volatile struct gdb_exception except;
- int old, ret;
+ const char *old;
+ int ret;

/* Removing breakpoints requires accessing memory. Allow it for the
duration of this function. */
- old = record_btrace_allow_memory_access;
- record_btrace_allow_memory_access = 1;
+ old = replay_memory_access;
+ 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);

- record_btrace_allow_memory_access = old;
+ replay_memory_access = old;

if (except.reason < 0)
throw_exception (except);
@@ -1934,6 +1951,32 @@ cmd_record_btrace_start (char *args, int from_tty)
execute_command ("target record-btrace", from_tty);
}

+/* The "set record btrace" command. */
+
+static void
+cmd_set_record_btrace (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_list (show_record_btrace_cmdlist, from_tty, "");
+}
+
+/* The "show record btrace replay-memory-access" command. */
+
+static void
+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);
+}
+
void _initialize_record_btrace (void);

/* Initialize btrace commands. */
@@ -1946,6 +1989,30 @@ _initialize_record_btrace (void)
&record_cmdlist);
add_alias_cmd ("b", "btrace", 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);
+
+ add_prefix_cmd ("btrace", class_support, cmd_show_record_btrace,
+ _("Show record options"), &show_record_btrace_cmdlist,
+ "show record btrace ", 0, &show_record_cmdlist);
+
+ /* Record instructions number limit command. */
+ add_setshow_enum_cmd ("replay-memory-access", no_class,
+ replay_memory_access_types, &replay_memory_access, _("\
+Set what memory accesses are allowed during replay."), _("\
+Show what memory accesses are allowed during replay."),
+ _("Default is READ-ONLY.\n\n\
+The btrace record target does not trace data.\n\
+The memory therefore corresponds to the live target and not \
+to the current replay position.\n\n\
+When READ-ONLY, allow accesses to read-only memory during replay.\n\
+When READ-WRITE, allow accesses to read-only and read-write memory during \
+replay."),
+ NULL, cmd_show_replay_memory_access,
+ &set_record_btrace_cmdlist,
+ &show_record_btrace_cmdlist);
+
init_record_btrace_ops ();
add_target (&record_btrace_ops);

diff --git a/gdb/testsuite/gdb.btrace/data.exp b/gdb/testsuite/gdb.btrace/data.exp
index 64c5443..91d8d8b 100644
--- a/gdb/testsuite/gdb.btrace/data.exp
+++ b/gdb/testsuite/gdb.btrace/data.exp
@@ -40,6 +40,14 @@ gdb_test "reverse-step" ".*test\.4.*"
gdb_test "print glob" "unavailable\[^\\\r\\\n\]*"
gdb_test "print loc" "unavailable\[^\\\r\\\n\]*"

+# we can read memory if we explicitly allow it.
+gdb_test_no_output "set record btrace replay-memory-access read-write"
+gdb_test "print glob" "1"
+
+# we can't if we don't explicitly allow it.
+gdb_test_no_output "set record btrace replay-memory-access read-only"
+gdb_test "print glob" "unavailable\[^\\\r\\\n\]*"
+
# stop replaying and try again
-gdb_test "record goto end"
+gdb_test "record goto end" ".*main\.3.*"
gdb_test "print glob" "1"
--
1.8.3.1