* [patch v10 07/21] btrace, doc: document remote serial protocol
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
@ 2013-03-08 9:16 ` Markus Metzger
2013-03-08 9:17 ` [patch v10 06/21] remote, gdbserver: add btrace support Markus Metzger
` (21 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:16 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Document the branch tracing extensions to the remote serial protocol.
Approved by Eli Zaretskii.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
doc/
* gdb.texinfo (Requirements): List qXfer:btrace:read requiring expat.
(General Query Packets): Describe Qbtrace:bts, Qbtrace:off, and
qXfer:btrace:read.
---
gdb/doc/gdb.texinfo | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 119 insertions(+), 0 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5f39d2e..5c6859f 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -34764,6 +34764,8 @@ or alternatively @pxref{Library List Format for SVR4 Targets})
MS-Windows shared libraries (@pxref{Shared Libraries})
@item
Traceframe info (@pxref{Traceframe Info Format})
+@item
+Branch trace (@pxref{Branch Trace Format})
@end itemize
@item zlib
@@ -35625,6 +35627,7 @@ Show the current setting of the target wait timeout.
* Memory Map Format::
* Thread List Format::
* Traceframe Info Format::
+* Branch Trace Format::
@end menu
@node Overview
@@ -37248,6 +37251,11 @@ These are the currently defined stub features and their properties:
@tab @samp{-}
@tab Yes
+@item @samp{qXfer:btrace:read}
+@tab No
+@tab @samp{-}
+@tab Yes
+
@item @samp{qXfer:features:read}
@tab No
@tab @samp{-}
@@ -37308,6 +37316,16 @@ These are the currently defined stub features and their properties:
@tab @samp{-}
@tab Yes
+@item @samp{Qbtrace:off}
+@tab Yes
+@tab @samp{-}
+@tab Yes
+
+@item @samp{Qbtrace:bts}
+@tab Yes
+@tab @samp{-}
+@tab Yes
+
@item @samp{QNonStop}
@tab No
@tab @samp{-}
@@ -37403,6 +37421,10 @@ byte in its buffer for the NUL. If this stub feature is not supported,
The remote stub understands the @samp{qXfer:auxv:read} packet
(@pxref{qXfer auxiliary vector read}).
+@item qXfer:btrace:read
+The remote stub understands the @samp{qXfer:btrace:read}
+packet (@pxref{qXfer btrace read}).
+
@item qXfer:features:read
The remote stub understands the @samp{qXfer:features:read} packet
(@pxref{qXfer target description read}).
@@ -37537,6 +37559,12 @@ See @ref{Bytecode Descriptions} for details about the bytecode.
The remote stub supports running a breakpoint's command list itself,
rather than reporting the hit to @value{GDBN}.
+@item Qbtrace:off
+The remote stub understands the @samp{Qbtrace:off} packet.
+
+@item Qbtrace:bts
+The remote stub understands the @samp{Qbtrace:bts} packet.
+
@end table
@item qSymbol::
@@ -37655,6 +37683,25 @@ auxiliary vector}. Note @var{annex} must be empty.
This packet is not probed by default; the remote stub must request it,
by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
+@item qXfer:btrace:read:@var{annex}:@var{offset},@var{length}
+@anchor{qXfer btrace read}
+
+Return a description of the current branch trace.
+@xref{Branch Trace Format}. The annex part of the generic @samp{qXfer}
+packet may have one of the following values:
+
+@table @code
+@item all
+Returns all available branch trace.
+
+@item new
+Returns all available branch trace if the branch trace changed since
+the last read request.
+@end table
+
+This packet is not probed by default; the remote stub must request it
+by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
+
@item qXfer:features:read:@var{annex}:@var{offset},@var{length}
@anchor{qXfer target description read}
Access the @dfn{target description}. @xref{Target Descriptions}. The
@@ -37891,6 +37938,28 @@ The remote server created a new process.
A badly formed request or an error was encountered.
@end table
+@item Qbtrace:bts
+Enable branch tracing for the current thread using bts tracing.
+
+Reply:
+@table @samp
+@item OK
+Branch tracing has been enabled.
+@item E.errtext
+A badly formed request or an error was encountered.
+@end table
+
+@item Qbtrace:off
+Disable branch tracing for the current thread.
+
+Reply:
+@table @samp
+@item OK
+Branch tracing has been disabled.
+@item E.errtext
+A badly formed request or an error was encountered.
+@end table
+
@end table
@node Architecture-Specific Protocol Details
@@ -40342,6 +40411,56 @@ The formal DTD for the traceframe info format is given below:
length CDATA #REQUIRED>
@end smallexample
+@node Branch Trace Format
+@section Branch Trace Format
+@cindex branch trace format
+
+In order to display the branch trace of an inferior thread,
+@value{GDBN} needs to obtain the list of branches. This list is
+represented as list of sequential code blocks that are connected via
+branches. The code in each block has been executed sequentially.
+
+This list is obtained using the @samp{qXfer:btrace:read}
+(@pxref{qXfer btrace read}) packet and is an XML document.
+
+@value{GDBN} must be linked with the Expat library to support XML
+traceframe info discovery. @xref{Expat}.
+
+The top-level structure of the document is shown below:
+
+@smallexample
+<?xml version="1.0"?>
+<!DOCTYPE btrace
+ PUBLIC "+//IDN gnu.org//DTD GDB Branch Trace V1.0//EN"
+ "http://sourceware.org/gdb/gdb-btrace.dtd">
+<btrace>
+ block...
+</btrace>
+@end smallexample
+
+@itemize
+
+@item
+A block of sequentially executed instructions starting at @var{begin}
+and ending at @var{end}:
+
+@smallexample
+<block begin="@var{begin}" end="@var{end}"/>
+@end smallexample
+
+@end itemize
+
+The formal DTD for the branch trace format is given below:
+
+@smallexample
+<!ELEMENT btrace (block)* >
+<!ATTLIST btrace version CDATA #FIXED "1.0">
+
+<!ELEMENT block EMPTY>
+<!ATTLIST block begin CDATA #REQUIRED
+ end CDATA #REQUIRED>
+@end smallexample
+
@include agentexpr.texi
@node Target Descriptions
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 06/21] remote, gdbserver: add btrace support
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
2013-03-08 9:16 ` [patch v10 07/21] btrace, doc: document remote serial protocol Markus Metzger
@ 2013-03-08 9:17 ` Markus Metzger
2013-03-08 9:17 ` [patch v10 14/21] record: default target methods Markus Metzger
` (20 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:17 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger, Pedro Alves
Add the gdb remote target operations for branch tracing.
We define the following packets:
Qbtrace:bts enable branch tracing for the current thread
returns "OK" or "Enn"
Qbtrace:off disable branch tracing for the current thread
returns "OK" or "Enn"
qXfer:btrace:read read the full branch trace data for the current thread
Approved by Jan Kratochvil.
CC: Pedro Alves <palves@redhat.com>
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* target.h (enum target_object): Add TARGET_OBJECT_BTRACE.
* remote.c: Include btrace.h.
(struct btrace_target_info): New struct.
(remote_supports_btrace): New function.
(send_Qbtrace): New function.
(remote_enable_btrace): New function.
(remote_disable_btrace): New function.
(remote_read_btrace): New function.
(init_remote_ops): Add btrace ops.
(enum <unnamed>): Add btrace packets.
(struct protocol_feature remote_protocol_features[]): Add btrace packets.
(_initialize_remote): Add packet configuration for branch tracing.
gdbserver/
* target.h (struct target_ops): Add btrace ops.
(target_supports_btrace): New macro.
(target_enable_btrace): New macro.
(target_disable_btrace): New macro.
(target_read_btrace): New macro.
* gdbthread.h (struct thread_info): Add btrace field.
* server.c: Include btrace-common.h.
(handle_btrace_general_set): New function.
(handle_btrace_enable): New function.
(handle_btrace_disable): New function.
(handle_general_set): Call handle_btrace_general_set.
(handle_qxfer_btrace): New function.
(struct qxfer qxfer_packets[]): Add btrace entry.
* inferiors.c (remove_thread): Disable btrace.
* linux-low: Include linux-btrace.h.
(linux_low_enable_btrace): New function.
(linux_low_read_btrace): New function.
(linux_target_ops): Add btrace ops.
* configure.srv (i[34567]86-*-linux*): Add linux-btrace.o.
Add srv_linux_btrace=yes.
(x86_64-*-linux*): Add linux-btrace.o.
Add srv_linux_btrace=yes.
* configure.ac: Define HAVE_LINUX_BTRACE.
* config.in: Regenerated.
* configure: Regenerated.
---
gdb/gdbserver/config.in | 3 +
gdb/gdbserver/configure | 6 ++
gdb/gdbserver/configure.ac | 5 ++
gdb/gdbserver/configure.srv | 6 +-
gdb/gdbserver/gdbthread.h | 5 ++
gdb/gdbserver/inferiors.c | 3 +
gdb/gdbserver/linux-low.c | 57 +++++++++++++++
gdb/gdbserver/server.c | 161 +++++++++++++++++++++++++++++++++++++++++++
gdb/gdbserver/target.h | 29 ++++++++
gdb/remote.c | 160 ++++++++++++++++++++++++++++++++++++++++++
gdb/target.h | 2 +
11 files changed, 435 insertions(+), 2 deletions(-)
mode change 100644 => 100755 gdb/remote.c
diff --git a/gdb/gdbserver/config.in b/gdb/gdbserver/config.in
index a7c5445..738c322 100644
--- a/gdb/gdbserver/config.in
+++ b/gdb/gdbserver/config.in
@@ -73,6 +73,9 @@
/* Define to 1 if you have the `dl' library (-ldl). */
#undef HAVE_LIBDL
+/* Define if the target supports branch tracing. */
+#undef HAVE_LINUX_BTRACE
+
/* Define to 1 if you have the <linux/elf.h> header file. */
#undef HAVE_LINUX_ELF_H
diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure
index f37f802..da257bb 100755
--- a/gdb/gdbserver/configure
+++ b/gdb/gdbserver/configure
@@ -5344,6 +5344,12 @@ $as_echo "#define HAVE_PTRACE_GETFPXREGS 1" >>confdefs.h
fi
fi
+if test "${srv_linux_btrace}" = "yes"; then
+
+$as_echo "#define HAVE_LINUX_BTRACE 1" >>confdefs.h
+
+fi
+
if test "$ac_cv_header_sys_procfs_h" = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for lwpid_t in sys/procfs.h" >&5
$as_echo_n "checking for lwpid_t in sys/procfs.h... " >&6; }
diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
index 0b30858..f6227d1 100644
--- a/gdb/gdbserver/configure.ac
+++ b/gdb/gdbserver/configure.ac
@@ -292,6 +292,11 @@ if test "${srv_linux_regsets}" = "yes"; then
fi
fi
+if test "${srv_linux_btrace}" = "yes"; then
+ AC_DEFINE(HAVE_LINUX_BTRACE, 1,
+ [Define if the target supports branch tracing.])
+fi
+
if test "$ac_cv_header_sys_procfs_h" = yes; then
BFD_HAVE_SYS_PROCFS_TYPE(lwpid_t)
BFD_HAVE_SYS_PROCFS_TYPE(psaddr_t)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 0bda563..271a0fe 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -112,10 +112,11 @@ case "${target}" in
srv_xmlfiles="${srv_xmlfiles} $srv_amd64_linux_xmlfiles"
fi
srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o"
- srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+ srv_tgtobj="${srv_tgtobj} linux-ptrace.o linux-btrace.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
srv_linux_thread_db=yes
+ srv_linux_btrace=yes
ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
;;
i[34567]86-*-lynxos*) srv_regobj="i386.o"
@@ -314,11 +315,12 @@ case "${target}" in
;;
x86_64-*-linux*) srv_regobj="$srv_amd64_linux_regobj $srv_i386_linux_regobj"
srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o"
- srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+ srv_tgtobj="${srv_tgtobj} linux-ptrace.o linux-btrace.o"
srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles"
srv_linux_usrregs=yes # This is for i386 progs.
srv_linux_regsets=yes
srv_linux_thread_db=yes
+ srv_linux_btrace=yes
ipa_obj="${ipa_amd64_linux_regobj} linux-amd64-ipa.o"
;;
x86_64-*-mingw*) srv_regobj="$srv_amd64_regobj"
diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h
index 85951d2..5d4955b 100644
--- a/gdb/gdbserver/gdbthread.h
+++ b/gdb/gdbserver/gdbthread.h
@@ -21,6 +21,8 @@
#include "server.h"
+struct btrace_target_info;
+
struct thread_info
{
struct inferior_list_entry entry;
@@ -57,6 +59,9 @@ struct thread_info
Each item in the list holds the current step of the while-stepping
action. */
struct wstep_state *while_stepping;
+
+ /* Branch trace target information for this thread. */
+ struct btrace_target_info *btrace;
};
extern struct inferior_list all_threads;
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index ba3c6cd..6953d0e 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -161,6 +161,9 @@ free_one_thread (struct inferior_list_entry *inf)
void
remove_thread (struct thread_info *thread)
{
+ if (thread->btrace != NULL)
+ target_disable_btrace (thread->btrace);
+
remove_inferior (&all_threads, (struct inferior_list_entry *) thread);
free_one_thread (&thread->entry);
}
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 5f03628..b5084c9 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -84,6 +84,10 @@
#endif
#endif
+#ifdef HAVE_LINUX_BTRACE
+# include "linux-btrace.h"
+#endif
+
#ifndef HAVE_ELF32_AUXV_T
/* Copied from glibc's elf.h. */
typedef struct
@@ -5821,6 +5825,47 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
return len;
}
+#ifdef HAVE_LINUX_BTRACE
+
+/* Enable branch tracing. */
+
+static struct btrace_target_info *
+linux_low_enable_btrace (ptid_t ptid)
+{
+ struct btrace_target_info *tinfo;
+
+ tinfo = linux_enable_btrace (ptid);
+ if (tinfo != NULL)
+ tinfo->ptr_bits = register_size (0) * 8;
+
+ return tinfo;
+}
+
+/* Read branch trace data as btrace xml document. */
+
+static void
+linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
+ int type)
+{
+ VEC (btrace_block_s) *btrace;
+ struct btrace_block *block;
+ int i;
+
+ btrace = linux_read_btrace (tinfo, type);
+
+ buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
+ buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
+
+ for (i = 0; VEC_iterate (btrace_block_s, btrace, i, block); i++)
+ buffer_xml_printf (buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
+ paddress (block->begin), paddress (block->end));
+
+ buffer_grow_str (buffer, "</btrace>\n");
+
+ VEC_free (btrace_block_s, btrace);
+}
+#endif /* HAVE_LINUX_BTRACE */
+
static struct target_ops linux_target_ops = {
linux_create_inferior,
linux_attach,
@@ -5885,6 +5930,18 @@ static struct target_ops linux_target_ops = {
linux_get_min_fast_tracepoint_insn_len,
linux_qxfer_libraries_svr4,
linux_supports_agent,
+#ifdef HAVE_LINUX_BTRACE
+ linux_supports_btrace,
+ linux_low_enable_btrace,
+ linux_disable_btrace,
+ linux_low_read_btrace,
+#else
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+#endif
};
static void
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 3738280..fc53dc3 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -28,6 +28,7 @@
#include <signal.h>
#endif
#include "gdb_wait.h"
+#include "btrace-common.h"
/* The thread set with an `Hc' packet. `Hc' is deprecated in favor of
`vCont'. Note the multi-process extensions made `vCont' a
@@ -396,6 +397,88 @@ write_qxfer_response (char *buf, const void *data, int len, int is_more)
PBUFSIZ - 2) + 1;
}
+/* Handle btrace enabling. */
+
+static const char *
+handle_btrace_enable (struct thread_info *thread)
+{
+ if (thread->btrace != NULL)
+ return "E.Btrace already enabled.";
+
+ thread->btrace = target_enable_btrace (thread->entry.id);
+ if (thread->btrace == NULL)
+ return "E.Could not enable btrace.";
+
+ return NULL;
+}
+
+/* Handle btrace disabling. */
+
+static const char *
+handle_btrace_disable (struct thread_info *thread)
+{
+
+ if (thread->btrace == NULL)
+ return "E.Branch tracing not enabled.";
+
+ if (target_disable_btrace (thread->btrace) != 0)
+ return "E.Could not disable branch tracing.";
+
+ thread->btrace = NULL;
+ return NULL;
+}
+
+/* Handle the "Qbtrace" packet. */
+
+static int
+handle_btrace_general_set (char *own_buf)
+{
+ struct thread_info *thread;
+ const char *err;
+ char *op;
+
+ if (strncmp ("Qbtrace:", own_buf, strlen ("Qbtrace:")) != 0)
+ return 0;
+
+ op = own_buf + strlen ("Qbtrace:");
+
+ if (!target_supports_btrace ())
+ {
+ strcpy (own_buf, "E.Target does not support branch tracing.");
+ return -1;
+ }
+
+ if (ptid_equal (general_thread, null_ptid)
+ || ptid_equal (general_thread, minus_one_ptid))
+ {
+ strcpy (own_buf, "E.Must select a single thread.");
+ return -1;
+ }
+
+ thread = find_thread_ptid (general_thread);
+ if (thread == NULL)
+ {
+ strcpy (own_buf, "E.No such thread.");
+ return -1;
+ }
+
+ err = NULL;
+
+ if (strcmp (op, "bts") == 0)
+ err = handle_btrace_enable (thread);
+ else if (strcmp (op, "off") == 0)
+ err = handle_btrace_disable (thread);
+ else
+ err = "E.Bad Qbtrace operation. Use bts or off.";
+
+ if (err != 0)
+ strcpy (own_buf, err);
+ else
+ write_ok (own_buf);
+
+ return 1;
+}
+
/* Handle all of the extended 'Q' packets. */
static void
@@ -552,6 +635,9 @@ handle_general_set (char *own_buf)
return;
}
+ if (handle_btrace_general_set (own_buf))
+ return;
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@@ -1251,9 +1337,77 @@ handle_qxfer_fdpic (const char *annex, gdb_byte *readbuf,
return (*the_target->read_loadmap) (annex, offset, readbuf, len);
}
+/* Handle qXfer:btrace:read. */
+
+static int
+handle_qxfer_btrace (const char *annex,
+ gdb_byte *readbuf, const gdb_byte *writebuf,
+ ULONGEST offset, LONGEST len)
+{
+ static struct buffer cache;
+ struct thread_info *thread;
+ int type;
+
+ if (the_target->read_btrace == NULL || writebuf != NULL)
+ return -2;
+
+ if (!target_running ())
+ return -1;
+
+ if (ptid_equal (general_thread, null_ptid)
+ || ptid_equal (general_thread, minus_one_ptid))
+ {
+ strcpy (own_buf, "E.Must select a single thread.");
+ return -3;
+ }
+
+ thread = find_thread_ptid (general_thread);
+ if (thread == NULL)
+ {
+ strcpy (own_buf, "E.No such thread.");
+ return -3;
+ }
+
+ if (thread->btrace == NULL)
+ {
+ strcpy (own_buf, "E.Btrace not enabled.");
+ return -3;
+ }
+
+ if (strcmp (annex, "all") == 0)
+ type = btrace_read_all;
+ else if (strcmp (annex, "new") == 0)
+ type = btrace_read_new;
+ else
+ {
+ strcpy (own_buf, "E.Bad annex.");
+ return -3;
+ }
+
+ if (offset == 0)
+ {
+ buffer_free (&cache);
+
+ target_read_btrace (thread->btrace, &cache, type);
+ }
+ else if (offset > cache.used_size)
+ {
+ buffer_free (&cache);
+ return -3;
+ }
+
+ if (len > cache.used_size - offset)
+ len = cache.used_size - offset;
+
+ memcpy (readbuf, cache.buffer + offset, len);
+
+ return len;
+}
+
static const struct qxfer qxfer_packets[] =
{
{ "auxv", handle_qxfer_auxv },
+ { "btrace", handle_qxfer_btrace },
{ "fdpic", handle_qxfer_fdpic},
{ "features", handle_qxfer_features },
{ "libraries", handle_qxfer_libraries },
@@ -1655,6 +1809,13 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_agent ())
strcat (own_buf, ";QAgent+");
+ if (target_supports_btrace ())
+ {
+ strcat (own_buf, ";Qbtrace:bts+");
+ strcat (own_buf, ";Qbtrace:off+");
+ strcat (own_buf, ";qXfer:btrace:read+");
+ }
+
return;
}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index cc9a910..f257459 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -22,6 +22,8 @@
#define TARGET_H
struct emit_ops;
+struct btrace_target_info;
+struct buffer;
/* Ways to "resume" a thread. */
@@ -397,6 +399,21 @@ struct target_ops
/* Return true if target supports debugging agent. */
int (*supports_agent) (void);
+
+ /* Check whether the target supports branch tracing. */
+ int (*supports_btrace) (void);
+
+ /* Enable branch tracing for @ptid and allocate a branch trace target
+ information struct for reading and for disabling branch trace. */
+ struct btrace_target_info *(*enable_btrace) (ptid_t ptid);
+
+ /* Disable branch tracing. */
+ int (*disable_btrace) (struct btrace_target_info *tinfo);
+
+ /* Read branch trace data into buffer. We use an int to specify the type
+ to break a cyclic dependency. */
+ void (*read_btrace) (struct btrace_target_info *, struct buffer *, int type);
+
};
extern struct target_ops *the_target;
@@ -520,6 +537,18 @@ int kill_inferior (int);
(the_target->supports_agent ? \
(*the_target->supports_agent) () : 0)
+#define target_supports_btrace() \
+ (the_target->supports_btrace ? (*the_target->supports_btrace) () : 0)
+
+#define target_enable_btrace(ptid) \
+ (*the_target->enable_btrace) (ptid)
+
+#define target_disable_btrace(tinfo) \
+ (*the_target->disable_btrace) (tinfo)
+
+#define target_read_btrace(tinfo, buffer, type) \
+ (*the_target->read_btrace) (tinfo, buffer, type)
+
/* Start non-stop mode, returns 0 on success, -1 on failure. */
int start_non_stop (int nonstop);
diff --git a/gdb/remote.c b/gdb/remote.c
old mode 100644
new mode 100755
index b69c8a8..7ee0695
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -68,6 +68,7 @@
#include "ax.h"
#include "ax-gdb.h"
#include "agent.h"
+#include "btrace.h"
/* Temp hacks for tracepoint encoding migration. */
static char *target_buf;
@@ -1280,6 +1281,9 @@ enum {
PACKET_qXfer_fdpic,
PACKET_QDisableRandomization,
PACKET_QAgent,
+ PACKET_Qbtrace_off,
+ PACKET_Qbtrace_bts,
+ PACKET_qXfer_btrace,
PACKET_MAX
};
@@ -3991,6 +3995,10 @@ static struct protocol_feature remote_protocol_features[] = {
{ "QAgent", PACKET_DISABLE, remote_supported_packet, PACKET_QAgent},
{ "tracenz", PACKET_DISABLE,
remote_string_tracing_feature, -1 },
+ { "Qbtrace:off", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_off },
+ { "Qbtrace:bts", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_bts },
+ { "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_btrace }
};
static char *remote_support_xml;
@@ -8792,6 +8800,10 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
return remote_read_qxfer (ops, "uib", annex, readbuf, offset, len,
&remote_protocol_packets[PACKET_qXfer_uib]);
+ case TARGET_OBJECT_BTRACE:
+ return remote_read_qxfer (ops, "btrace", annex, readbuf, offset, len,
+ &remote_protocol_packets[PACKET_qXfer_btrace]);
+
default:
return -1;
}
@@ -11111,6 +11123,141 @@ remote_can_use_agent (void)
return (remote_protocol_packets[PACKET_QAgent].support != PACKET_DISABLE);
}
+struct btrace_target_info
+{
+ /* The ptid of the traced thread. */
+ ptid_t ptid;
+};
+
+/* Check whether the target supports branch tracing. */
+
+static int
+remote_supports_btrace (void)
+{
+ if (remote_protocol_packets[PACKET_Qbtrace_off].support != PACKET_ENABLE)
+ return 0;
+ if (remote_protocol_packets[PACKET_Qbtrace_bts].support != PACKET_ENABLE)
+ return 0;
+ if (remote_protocol_packets[PACKET_qXfer_btrace].support != PACKET_ENABLE)
+ return 0;
+
+ return 1;
+}
+
+/* Enable branch tracing. */
+
+static struct btrace_target_info *
+remote_enable_btrace (ptid_t ptid)
+{
+ struct btrace_target_info *tinfo = NULL;
+ struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace_bts];
+ struct remote_state *rs = get_remote_state ();
+ char *buf = rs->buf;
+ char *endbuf = rs->buf + get_remote_packet_size ();
+
+ if (packet->support != PACKET_ENABLE)
+ error (_("Target does not support branch tracing."));
+
+ set_general_thread (ptid);
+
+ buf += xsnprintf (buf, endbuf - buf, "%s", packet->name);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (packet_ok (rs->buf, packet) == PACKET_ERROR)
+ {
+ if (rs->buf[0] == 'E' && rs->buf[1] == '.')
+ error (_("Could not enable branch tracing for %s: %s"),
+ target_pid_to_str (ptid), rs->buf + 2);
+ else
+ error (_("Could not enable branch tracing for %s."),
+ target_pid_to_str (ptid));
+ }
+
+ tinfo = xzalloc (sizeof (*tinfo));
+ tinfo->ptid = ptid;
+
+ return tinfo;
+}
+
+/* Disable branch tracing. */
+
+static void
+remote_disable_btrace (struct btrace_target_info *tinfo)
+{
+ struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace_off];
+ struct remote_state *rs = get_remote_state ();
+ char *buf = rs->buf;
+ char *endbuf = rs->buf + get_remote_packet_size ();
+
+ if (packet->support != PACKET_ENABLE)
+ error (_("Target does not support branch tracing."));
+
+ set_general_thread (tinfo->ptid);
+
+ buf += xsnprintf (buf, endbuf - buf, "%s", packet->name);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (packet_ok (rs->buf, packet) == PACKET_ERROR)
+ {
+ if (rs->buf[0] == 'E' && rs->buf[1] == '.')
+ error (_("Could not disable branch tracing for %s: %s"),
+ target_pid_to_str (tinfo->ptid), rs->buf + 2);
+ else
+ error (_("Could not disable branch tracing for %s."),
+ target_pid_to_str (tinfo->ptid));
+ }
+
+ xfree (tinfo);
+}
+
+/* Read the branch trace. */
+
+static VEC (btrace_block_s) *
+remote_read_btrace (struct btrace_target_info *tinfo,
+ enum btrace_read_type type)
+{
+ struct packet_config *packet = &remote_protocol_packets[PACKET_qXfer_btrace];
+ struct remote_state *rs = get_remote_state ();
+ VEC (btrace_block_s) *btrace = NULL;
+ const char *annex;
+ char *xml;
+
+ if (packet->support != PACKET_ENABLE)
+ error (_("Target does not support branch tracing."));
+
+#if !defined(HAVE_LIBEXPAT)
+ error (_("Cannot process branch tracing result. XML parsing not supported."));
+#endif
+
+ switch (type)
+ {
+ case btrace_read_all:
+ annex = "all";
+ break;
+ case btrace_read_new:
+ annex = "new";
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Bad branch tracing read type: %u."),
+ (unsigned int) type);
+ }
+
+ xml = target_read_stralloc (¤t_target,
+ TARGET_OBJECT_BTRACE, annex);
+ if (xml != NULL)
+ {
+ struct cleanup *cleanup = make_cleanup (xfree, xml);
+
+ btrace = parse_xml_btrace (xml);
+ do_cleanups (cleanup);
+ }
+
+ return btrace;
+}
+
static void
init_remote_ops (void)
{
@@ -11227,6 +11374,10 @@ Specify the serial device it is connected to\n\
remote_ops.to_traceframe_info = remote_traceframe_info;
remote_ops.to_use_agent = remote_use_agent;
remote_ops.to_can_use_agent = remote_can_use_agent;
+ remote_ops.to_supports_btrace = remote_supports_btrace;
+ remote_ops.to_enable_btrace = remote_enable_btrace;
+ remote_ops.to_disable_btrace = remote_disable_btrace;
+ remote_ops.to_read_btrace = remote_read_btrace;
}
/* Set up the extended remote vector by making a copy of the standard
@@ -11751,6 +11902,15 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_QAgent],
"QAgent", "agent", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_off],
+ "Qbtrace:off", "disable-btrace", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_bts],
+ "Qbtrace:bts", "enable-btrace", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace],
+ "qXfer:btrace", "read-btrace", 0);
+
/* Keep the old ``set remote Z-packet ...'' working. Each individual
Z sub-packet has its own set and show commands, but users may
have sets to this variable in their .gdbinit files (or in their
diff --git a/gdb/target.h b/gdb/target.h
index f513264..aa0ae2a 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -288,6 +288,8 @@ enum target_object
TARGET_OBJECT_DARWIN_DYLD_INFO,
/* OpenVMS Unwind Information Block. */
TARGET_OBJECT_OPENVMS_UIB,
+ /* Branch trace data, in XML format. */
+ TARGET_OBJECT_BTRACE
/* Possible future objects: TARGET_OBJECT_FILE, ... */
};
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 14/21] record: default target methods.
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
2013-03-08 9:16 ` [patch v10 07/21] btrace, doc: document remote serial protocol Markus Metzger
2013-03-08 9:17 ` [patch v10 06/21] remote, gdbserver: add btrace support Markus Metzger
@ 2013-03-08 9:17 ` Markus Metzger
2013-03-08 9:17 ` [patch v10 04/21] xml, btrace: define btrace xml document style Markus Metzger
` (19 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:17 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Provide default target methods for record targets that are likely to be shared
between different record targets.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* record.h (record_disconnect): New.
(record_detach): New.
(record_mourn_inferior): New.
(record_kill): New.
* record-full.c (record_disconnect, record_detach,
record_mourn_inferior, record_kill): Move to...
* record.c: ...here.
(DEBUG): New.
(record_unpush): New.
(cmd_record_stop): Use record_unpush.
(record_disconnect, record_detach, record_mourn_inferior,
record_kill): Use record_unpush and DEBUG.
---
gdb/record-full.c | 58 +++---------------------------------------
gdb/record.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++---
gdb/record.h | 12 +++++++++
3 files changed, 84 insertions(+), 58 deletions(-)
diff --git a/gdb/record-full.c b/gdb/record-full.c
index 5ffa6b7..e7af504 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -1523,56 +1523,6 @@ record_full_stopped_by_watchpoint (void)
return record_full_beneath_to_stopped_by_watchpoint ();
}
-/* "to_disconnect" method for process record target. */
-
-static void
-record_full_disconnect (struct target_ops *target, char *args, int from_tty)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_full_disconnect\n");
-
- unpush_target (&record_full_ops);
- target_disconnect (args, from_tty);
-}
-
-/* "to_detach" method for process record target. */
-
-static void
-record_full_detach (struct target_ops *ops, char *args, int from_tty)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_full_detach\n");
-
- unpush_target (&record_full_ops);
- target_detach (args, from_tty);
-}
-
-/* "to_mourn_inferior" method for process record target. */
-
-static void
-record_full_mourn_inferior (struct target_ops *ops)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: "
- "record_full_mourn_inferior\n");
-
- unpush_target (&record_full_ops);
- target_mourn_inferior ();
-}
-
-/* Close process record target before killing the inferior process. */
-
-static void
-record_full_kill (struct target_ops *ops)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_full_kill\n");
-
- unpush_target (&record_full_ops);
- target_kill ();
-}
-
static int
record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
{
@@ -2117,10 +2067,10 @@ init_record_full_ops (void)
record_full_ops.to_close = record_full_close;
record_full_ops.to_resume = record_full_resume;
record_full_ops.to_wait = record_full_wait;
- record_full_ops.to_disconnect = record_full_disconnect;
- record_full_ops.to_detach = record_full_detach;
- record_full_ops.to_mourn_inferior = record_full_mourn_inferior;
- record_full_ops.to_kill = record_full_kill;
+ record_full_ops.to_disconnect = record_disconnect;
+ record_full_ops.to_detach = record_detach;
+ record_full_ops.to_mourn_inferior = record_mourn_inferior;
+ record_full_ops.to_kill = record_kill;
record_full_ops.to_create_inferior = find_default_create_inferior;
record_full_ops.to_store_registers = record_full_store_registers;
record_full_ops.to_xfer_partial = record_full_xfer_partial;
diff --git a/gdb/record.c b/gdb/record.c
index 8b44717..abd8216 100644
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -33,6 +33,10 @@ struct cmd_list_element *set_record_cmdlist = NULL;
struct cmd_list_element *show_record_cmdlist = NULL;
struct cmd_list_element *info_record_cmdlist = NULL;
+#define DEBUG(msg, args...) \
+ if (record_debug) \
+ fprintf_unfiltered (gdb_stdlog, "record: " msg "\n", ##args)
+
/* Find the record target in the target stack. */
static struct target_ops *
@@ -71,13 +75,73 @@ record_read_memory (struct gdbarch *gdbarch,
{
int ret = target_read_memory (memaddr, myaddr, len);
- if (ret && record_debug)
- printf_unfiltered (_("Process record: error reading memory "
- "at addr %s len = %ld.\n"),
- paddress (gdbarch, memaddr), (long) len);
+ if (ret != 0)
+ DEBUG ("error reading memory at addr %s len = %ld.\n",
+ paddress (gdbarch, memaddr), (long) len);
+
return ret;
}
+/* Unpush the record target. */
+
+static void
+record_unpush (void)
+{
+ struct target_ops *t;
+
+ t = find_record_target ();
+ if (t == NULL)
+ internal_error (__FILE__, __LINE__, _("Couldn't find record target."));
+
+ DEBUG ("unpush %s", t->to_shortname);
+
+ unpush_target (t);
+}
+
+/* See record.h. */
+
+void
+record_disconnect (struct target_ops *target, char *args, int from_tty)
+{
+ DEBUG ("disconnect");
+
+ record_unpush ();
+ target_disconnect (args, from_tty);
+}
+
+/* See record.h. */
+
+void
+record_detach (struct target_ops *ops, char *args, int from_tty)
+{
+ DEBUG ("detach");
+
+ record_unpush ();
+ target_detach (args, from_tty);
+}
+
+/* See record.h. */
+
+void
+record_mourn_inferior (struct target_ops *ops)
+{
+ DEBUG ("mourn_inferior");
+
+ record_unpush ();
+ target_mourn_inferior ();
+}
+
+/* See record.h. */
+
+void
+record_kill (struct target_ops *ops)
+{
+ DEBUG ("kill");
+
+ record_unpush ();
+ target_kill ();
+}
+
/* Implement "show record debug" command. */
static void
diff --git a/gdb/record.h b/gdb/record.h
index b428eaf..04d6b4a 100644
--- a/gdb/record.h
+++ b/gdb/record.h
@@ -41,4 +41,16 @@ extern int record_read_memory (struct gdbarch *gdbarch,
/* The "record goto" command. */
extern void cmd_record_goto (char *arg, int from_tty);
+/* The default "to_disconnect" target method for record targets. */
+extern void record_disconnect (struct target_ops *, char *, int);
+
+/* The default "to_detach" target method for record targets. */
+extern void record_detach (struct target_ops *, char *, int);
+
+/* The default "to_mourn_inferior" target method for record targets. */
+extern void record_mourn_inferior (struct target_ops *);
+
+/* The default "to_kill" target method for record targets. */
+extern void record_kill (struct target_ops *);
+
#endif /* _RECORD_H_ */
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 04/21] xml, btrace: define btrace xml document style
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (2 preceding siblings ...)
2013-03-08 9:17 ` [patch v10 14/21] record: default target methods Markus Metzger
@ 2013-03-08 9:17 ` Markus Metzger
2013-03-08 9:17 ` [patch v10 08/21] btrace, x86: disable on some processors Markus Metzger
` (18 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:17 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Define the xml document style for transferring branch trace data.
Add a function to parse a btrace xml document into a vector of branch trace
blocks.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* features/btrace.dtd: New file.
* Makefile.in (XMLFILES): Add btrace.dtd.
* btrace.h (parse_xml_btrace): New declaration.
* btrace.c: Include xml-support.h.
(parse_xml_btrace): New function.
(parse_xml_btrace_block): New function.
(block_attributes): New struct.
(btrace_attributes): New struct.
(btrace_children): New struct.
(btrace_elements): New struct.
---
gdb/Makefile.in | 3 +-
gdb/btrace.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++
gdb/btrace.h | 3 +
gdb/features/btrace.dtd | 12 ++++++
4 files changed, 111 insertions(+), 1 deletions(-)
create mode 100644 gdb/features/btrace.dtd
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index de48caa..e11e3d1 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -497,7 +497,8 @@ RUNTESTFLAGS=
XMLFILES = $(srcdir)/features/gdb-target.dtd $(srcdir)/features/xinclude.dtd \
$(srcdir)/features/library-list.dtd \
$(srcdir)/features/library-list-svr4.dtd $(srcdir)/features/osdata.dtd \
- $(srcdir)/features/threads.dtd $(srcdir)/features/traceframe-info.dtd
+ $(srcdir)/features/threads.dtd $(srcdir)/features/traceframe-info.dtd \
+ $(srcdir)/features/btrace.dtd
# This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX
# interface to the serial port. Hopefully if get ported to OS/2, VMS,
diff --git a/gdb/btrace.c b/gdb/btrace.c
index cb9ebe8..75ede3a 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -29,6 +29,7 @@
#include "disasm.h"
#include "source.h"
#include "filenames.h"
+#include "xml-support.h"
/* Print a record debug message. Use do ... while (0) to avoid ambiguities
when used in if statements. */
@@ -428,3 +429,96 @@ btrace_free_objfile (struct objfile *objfile)
ALL_THREADS (tp)
btrace_clear (tp);
}
+
+#if defined (HAVE_LIBEXPAT)
+
+/* Check the btrace document version. */
+
+static void
+check_xml_btrace_version (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, VEC (gdb_xml_value_s) *attributes)
+{
+ const char *version = xml_find_attribute (attributes, "version")->value;
+
+ if (strcmp (version, "1.0") != 0)
+ gdb_xml_error (parser, _("Unsupported btrace version: \"%s\""), version);
+}
+
+/* Parse a btrace "block" xml record. */
+
+static void
+parse_xml_btrace_block (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, VEC (gdb_xml_value_s) *attributes)
+{
+ VEC (btrace_block_s) **btrace;
+ struct btrace_block *block;
+ ULONGEST *begin, *end;
+
+ btrace = user_data;
+ block = VEC_safe_push (btrace_block_s, *btrace, NULL);
+
+ begin = xml_find_attribute (attributes, "begin")->value;
+ end = xml_find_attribute (attributes, "end")->value;
+
+ block->begin = *begin;
+ block->end = *end;
+}
+
+static const struct gdb_xml_attribute block_attributes[] = {
+ { "begin", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "end", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute btrace_attributes[] = {
+ { "version", GDB_XML_AF_NONE, NULL, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element btrace_children[] = {
+ { "block", block_attributes, NULL,
+ GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, parse_xml_btrace_block, NULL },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element btrace_elements[] = {
+ { "btrace", btrace_attributes, btrace_children, GDB_XML_EF_NONE,
+ check_xml_btrace_version, NULL },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+#endif /* defined (HAVE_LIBEXPAT) */
+
+/* See btrace.h. */
+
+VEC (btrace_block_s) *
+parse_xml_btrace (const char *buffer)
+{
+ VEC (btrace_block_s) *btrace = NULL;
+ struct cleanup *cleanup;
+ int errcode;
+
+#if defined (HAVE_LIBEXPAT)
+
+ cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace);
+ errcode = gdb_xml_parse_quick (_("btrace"), "btrace.dtd", btrace_elements,
+ buffer, &btrace);
+ if (errcode != 0)
+ {
+ do_cleanups (cleanup);
+ return NULL;
+ }
+
+ /* Keep parse results. */
+ discard_cleanups (cleanup);
+
+#else /* !defined (HAVE_LIBEXPAT) */
+
+ error (_("Cannot process branch trace. XML parsing is not supported."));
+
+#endif /* !defined (HAVE_LIBEXPAT) */
+
+ return btrace;
+}
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 7159313..35fb13a 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -131,4 +131,7 @@ extern void btrace_clear (struct thread_info *);
/* Clear the branch trace for all threads when an object file goes away. */
extern void btrace_free_objfile (struct objfile *);
+/* Parse a branch trace xml document into a block vector. */
+extern VEC (btrace_block_s) *parse_xml_btrace (const char*);
+
#endif /* BTRACE_H */
diff --git a/gdb/features/btrace.dtd b/gdb/features/btrace.dtd
new file mode 100644
index 0000000..6fe0cd6
--- /dev/null
+++ b/gdb/features/btrace.dtd
@@ -0,0 +1,12 @@
+<!-- Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!ELEMENT btrace (block)* >
+<!ATTLIST btrace version CDATA #FIXED "1.0">
+
+<!ELEMENT block EMPTY>
+<!ATTLIST block begin CDATA #REQUIRED
+ end CDATA #REQUIRED>
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 08/21] btrace, x86: disable on some processors
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (3 preceding siblings ...)
2013-03-08 9:17 ` [patch v10 04/21] xml, btrace: define btrace xml document style Markus Metzger
@ 2013-03-08 9:17 ` Markus Metzger
2013-03-08 9:17 ` [patch v10 01/21] thread, btrace: add generic branch trace support Markus Metzger
` (17 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:17 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
LBR, BTM, or BTS records may have incorrect branch "from" information afer an
EIST transition, T-states, C1E, or Adaptive Thermal Throttling (AAJ122).
This results in sporadic test fails. Disable btrace on those processors.
I added a kernel check before checking cpuid requested by Mark Kettenis.
I added the cpuid vendor check requested by HJ.
Approved by Jan Kratochvil.
Approved by Mark Kettenis.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* common/linux-btrace.c: Include sys/ptrace, sys/types, sys/wait.h,
and signal.h.
(linux_supports_btrace): Add kernel and
cpuid check.
(kernel_supports_btrace): New function.
(cpu_supports_btrace): New function.
(intel_supports_btrace): New function.
---
gdb/common/linux-btrace.c | 187 ++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 186 insertions(+), 1 deletions(-)
diff --git a/gdb/common/linux-btrace.c b/gdb/common/linux-btrace.c
index 2f8c1cf..ed0cb24 100644
--- a/gdb/common/linux-btrace.c
+++ b/gdb/common/linux-btrace.c
@@ -40,6 +40,10 @@
#include <sys/syscall.h>
#include <sys/mman.h>
#include <sys/user.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
/* A branch trace record in perf_event. */
struct perf_event_bts
@@ -247,12 +251,193 @@ perf_event_read_bts (struct btrace_target_info* tinfo, const uint8_t *begin,
return btrace;
}
+/* Check whether the kernel supports branch tracing. */
+
+static int
+kernel_supports_btrace (void)
+{
+ struct perf_event_attr attr;
+ pid_t child, pid;
+ int status, file;
+
+ errno = 0;
+ child = fork ();
+ switch (child)
+ {
+ case -1:
+ warning (_("test branch tracing: cannot fork: %s."), strerror (errno));
+ return 0;
+
+ case 0:
+ status = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
+ if (status != 0)
+ {
+ warning (_("test branch tracing: cannot PTRACE_TRACEME: %s."),
+ strerror (errno));
+ _exit (1);
+ }
+
+ status = raise (SIGTRAP);
+ if (status != 0)
+ {
+ warning (_("test branch tracing: cannot raise SIGTRAP: %s."),
+ strerror (errno));
+ _exit (1);
+ }
+
+ _exit (1);
+
+ default:
+ pid = waitpid (child, &status, 0);
+ if (pid != child)
+ {
+ warning (_("test branch tracing: bad pid %ld, error: %s."),
+ (long) pid, strerror (errno));
+ return 0;
+ }
+
+ if (!WIFSTOPPED (status))
+ {
+ warning (_("test branch tracing: expected stop. status: %d."),
+ status);
+ return 0;
+ }
+
+ memset (&attr, 0, sizeof (attr));
+
+ attr.type = PERF_TYPE_HARDWARE;
+ attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
+ attr.sample_period = 1;
+ attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR;
+ attr.exclude_kernel = 1;
+ attr.exclude_hv = 1;
+ attr.exclude_idle = 1;
+
+ file = syscall (SYS_perf_event_open, &attr, child, -1, -1, 0);
+ if (file >= 0)
+ close (file);
+
+ kill (child, SIGKILL);
+ ptrace (PTRACE_KILL, child, NULL, NULL);
+
+ pid = waitpid (child, &status, 0);
+ if (pid != child)
+ {
+ warning (_("test branch tracing: bad pid %ld, error: %s."),
+ (long) pid, strerror (errno));
+ if (!WIFSIGNALED (status))
+ warning (_("test branch tracing: expected killed. status: %d."),
+ status);
+ }
+
+ return (file >= 0);
+ }
+}
+
+/* Check whether an Intel cpu supports branch tracing. */
+
+static int
+intel_supports_btrace (void)
+{
+#if defined __i386__ || defined __x86_64__
+ unsigned int cpuid, model, family;
+
+ __asm__ __volatile__ ("movl $1, %%eax;"
+ "cpuid;"
+ : "=a" (cpuid)
+ :: "%ebx", "%ecx", "%edx");
+
+ family = (cpuid >> 8) & 0xf;
+ model = (cpuid >> 4) & 0xf;
+
+ switch (family)
+ {
+ case 0x6:
+ model += (cpuid >> 12) & 0xf0;
+
+ switch (model)
+ {
+ case 0x1a: /* Nehalem */
+ case 0x1f:
+ case 0x1e:
+ case 0x2e:
+ case 0x25: /* Westmere */
+ case 0x2c:
+ case 0x2f:
+ case 0x2a: /* Sandy Bridge */
+ case 0x2d:
+ case 0x3a: /* Ivy Bridge */
+
+ /* AAJ122: LBR, BTM, or BTS records may have incorrect branch
+ "from" information afer an EIST transition, T-states, C1E, or
+ Adaptive Thermal Throttling. */
+ return 0;
+ }
+ }
+
+ return 1;
+
+#else /* !defined __i386__ && !defined __x86_64__ */
+
+ return 0;
+
+#endif /* !defined __i386__ && !defined __x86_64__ */
+}
+
+/* Check whether the cpu supports branch tracing. */
+
+static int
+cpu_supports_btrace (void)
+{
+#if defined __i386__ || defined __x86_64__
+ char vendor[13];
+
+ __asm__ __volatile__ ("xorl %%ebx, %%ebx;"
+ "xorl %%ecx, %%ecx;"
+ "xorl %%edx, %%edx;"
+ "movl $0, %%eax;"
+ "cpuid;"
+ "movl %%ebx, %0;"
+ "movl %%edx, %1;"
+ "movl %%ecx, %2;"
+ : "=m" (vendor[0]),
+ "=m" (vendor[4]),
+ "=m" (vendor[8])
+ :
+ : "%eax", "%ebx", "%ecx", "%edx");
+ vendor[12] = '\0';
+
+ if (strcmp (vendor, "GenuineIntel") == 0)
+ return intel_supports_btrace ();
+
+ /* Don't know about others. Let's assume they do. */
+ return 1;
+
+#else /* !defined __i386__ && !defined __x86_64__ */
+
+ return 0;
+
+#endif /* !defined __i386__ && !defined __x86_64__ */
+}
+
/* See linux-btrace.h. */
int
linux_supports_btrace (void)
{
- return 1;
+ static int cached;
+
+ if (cached == 0)
+ {
+ if (!kernel_supports_btrace ())
+ cached = -1;
+ else if (!cpu_supports_btrace ())
+ cached = -1;
+ else
+ cached = 1;
+ }
+
+ return cached > 0;
}
/* See linux-btrace.h. */
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 01/21] thread, btrace: add generic branch trace support
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (4 preceding siblings ...)
2013-03-08 9:17 ` [patch v10 08/21] btrace, x86: disable on some processors Markus Metzger
@ 2013-03-08 9:17 ` Markus Metzger
2013-03-08 9:17 ` [patch v10 16/21] record: add "record function-call-history" command Markus Metzger
` (16 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:17 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Add branch trace information to struct thread_info to hold the branch trace
information for that thread.
Add functions to enable, disable, clear, and fetch a thread's branch trace.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* target.h: Include btrace.h.
(struct target_ops): Add btrace ops.
* target.c (update_current_target): Initialize btrace ops.
(target_supports_btrace): New function.
(target_enable_btrace): New function.
(target_disable_btrace): New function.
(target_read_btrace): New function.
* btrace.h: New file.
* btrace.c: New file.
* Makefile.in: Add btrace.c.
* gdbthread.h: Include btrace.h.
(struct thread_info): Add btrace field.
* thread.c: Include btrace.h.
(clear_thread_inferior_resources): Call btrace_disable.
* common/btrace-common.h: New file.
---
gdb/Makefile.in | 4 +-
gdb/btrace.c | 430 ++++++++++++++++++++++++++++++++++++++++++++
gdb/btrace.h | 134 ++++++++++++++
gdb/common/btrace-common.h | 73 ++++++++
gdb/gdbthread.h | 4 +
gdb/target.c | 59 ++++++
gdb/target.h | 33 ++++-
gdb/thread.c | 3 +
8 files changed, 737 insertions(+), 3 deletions(-)
create mode 100644 gdb/btrace.c
create mode 100644 gdb/btrace.h
create mode 100644 gdb/common/btrace-common.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ed30db5..1cf8134 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -759,7 +759,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
regset.c sol-thread.c windows-termcap.c \
common/gdb_vecs.c common/common-utils.c common/xml-utils.c \
common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c \
- common/format.c
+ common/format.c btrace.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -928,7 +928,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
inferior.o osdata.o gdb_usleep.o record.o gcore.o \
gdb_vecs.o jit.o progspace.o skip.o probe.o \
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
- format.o registry.o
+ format.o registry.o btrace.o
TSOBS = inflow.o
diff --git a/gdb/btrace.c b/gdb/btrace.c
new file mode 100644
index 0000000..cb9ebe8
--- /dev/null
+++ b/gdb/btrace.c
@@ -0,0 +1,430 @@
+/* Branch trace support for GDB, the GNU debugger.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <markus.t.metzger@intel.com>
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "btrace.h"
+#include "gdbthread.h"
+#include "exceptions.h"
+#include "inferior.h"
+#include "target.h"
+#include "record.h"
+#include "symtab.h"
+#include "disasm.h"
+#include "source.h"
+#include "filenames.h"
+
+/* Print a record debug message. Use do ... while (0) to avoid ambiguities
+ when used in if statements. */
+
+#define DEBUG(msg, args...) \
+ do \
+ { \
+ if (record_debug != 0) \
+ fprintf_unfiltered (gdb_stdlog, \
+ "[btrace] " msg "\n", ##args); \
+ } \
+ while (0)
+
+#define DEBUG_FTRACE(msg, args...) DEBUG ("[ftrace] " msg, ##args)
+
+/* Initialize the instruction iterator. */
+
+static void
+btrace_init_insn_iterator (struct btrace_thread_info *btinfo)
+{
+ DEBUG ("init insn iterator");
+
+ btinfo->insn_iterator.begin = 1;
+ btinfo->insn_iterator.end = 0;
+}
+
+/* Initialize the function iterator. */
+
+static void
+btrace_init_func_iterator (struct btrace_thread_info *btinfo)
+{
+ DEBUG ("init func iterator");
+
+ btinfo->func_iterator.begin = 1;
+ btinfo->func_iterator.end = 0;
+}
+
+/* Compute the instruction trace from the block trace. */
+
+static VEC (btrace_inst_s) *
+compute_itrace (VEC (btrace_block_s) *btrace)
+{
+ VEC (btrace_inst_s) *itrace;
+ struct gdbarch *gdbarch;
+ unsigned int b;
+
+ DEBUG ("compute itrace");
+
+ itrace = NULL;
+ gdbarch = target_gdbarch ();
+ b = VEC_length (btrace_block_s, btrace);
+
+ while (b-- != 0)
+ {
+ btrace_block_s *block;
+ CORE_ADDR pc;
+
+ block = VEC_index (btrace_block_s, btrace, b);
+ pc = block->begin;
+
+ /* Add instructions for this block. */
+ for (;;)
+ {
+ btrace_inst_s *inst;
+ int size;
+
+ /* We should hit the end of the block. Warn if we went too far. */
+ if (block->end < pc)
+ {
+ warning (_("Recorded trace may be corrupted."));
+ break;
+ }
+
+ inst = VEC_safe_push (btrace_inst_s, itrace, NULL);
+ inst->pc = pc;
+
+ /* We're done once we pushed the instruction at the end. */
+ if (block->end == pc)
+ break;
+
+ size = gdb_insn_length (gdbarch, pc);
+
+ /* Make sure we terminate if we fail to compute the size. */
+ if (size <= 0)
+ {
+ warning (_("Recorded trace may be incomplete."));
+ break;
+ }
+
+ pc += size;
+ }
+ }
+
+ return itrace;
+}
+
+/* Return the function name of a recorded function segment for printing.
+ This function never returns NULL. */
+
+static const char *
+ftrace_print_function_name (struct btrace_func *bfun)
+{
+ struct minimal_symbol *msym;
+ struct symbol *sym;
+
+ msym = bfun->msym;
+ sym = bfun->sym;
+
+ if (sym != NULL)
+ return SYMBOL_PRINT_NAME (sym);
+
+ if (msym != NULL)
+ return SYMBOL_PRINT_NAME (msym);
+
+ return "<unknown>";
+}
+
+/* Return the file name of a recorded function segment for printing.
+ This function never returns NULL. */
+
+static const char *
+ftrace_print_filename (struct btrace_func *bfun)
+{
+ struct symbol *sym;
+ const char *filename;
+
+ sym = bfun->sym;
+
+ if (sym != NULL)
+ filename = symtab_to_filename_for_display (sym->symtab);
+ else
+ filename = "<unknown>";
+
+ return filename;
+}
+
+/* Print an ftrace debug status message. */
+
+static void
+ftrace_debug (struct btrace_func *bfun, const char *prefix)
+{
+ DEBUG_FTRACE ("%s: fun = %s, file = %s, lines = [%d; %d], insn = [%u; %u]",
+ prefix, ftrace_print_function_name (bfun),
+ ftrace_print_filename (bfun), bfun->lbegin, bfun->lend,
+ bfun->ibegin, bfun->iend);
+}
+
+/* Initialize a recorded function segment. */
+
+static void
+ftrace_init_func (struct btrace_func *bfun, struct minimal_symbol *mfun,
+ struct symbol *fun, unsigned int idx)
+{
+ bfun->msym = mfun;
+ bfun->sym = fun;
+ bfun->lbegin = INT_MAX;
+ bfun->lend = 0;
+ bfun->ibegin = idx;
+ bfun->iend = idx;
+}
+
+/* Check whether the function has changed. */
+
+static int
+ftrace_function_switched (struct btrace_func *bfun,
+ struct minimal_symbol *mfun, struct symbol *fun)
+{
+ struct minimal_symbol *msym;
+ struct symbol *sym;
+
+ /* The function changed if we did not have one before. */
+ if (bfun == NULL)
+ return 1;
+
+ msym = bfun->msym;
+ sym = bfun->sym;
+
+ /* If the minimal symbol changed, we certainly switched functions. */
+ if (mfun != NULL && msym != NULL
+ && strcmp (SYMBOL_LINKAGE_NAME (mfun), SYMBOL_LINKAGE_NAME (msym)) != 0)
+ return 1;
+
+ /* If the symbol changed, we certainly switched functions. */
+ if (fun != NULL && sym != NULL)
+ {
+ const char *bfname, *fname;
+
+ /* Check the function name. */
+ if (strcmp (SYMBOL_LINKAGE_NAME (fun), SYMBOL_LINKAGE_NAME (sym)) != 0)
+ return 1;
+
+ /* Check the location of those functions, as well. */
+ bfname = symtab_to_fullname (sym->symtab);
+ fname = symtab_to_fullname (fun->symtab);
+ if (filename_cmp (fname, bfname) != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Check if we should skip this file when generating the function call
+ history. We would want to do that if, say, a macro that is defined
+ in another file is expanded in this function. */
+
+static int
+ftrace_skip_file (struct btrace_func *bfun, const char *filename)
+{
+ struct symbol *sym;
+ const char *bfile;
+
+ sym = bfun->sym;
+
+ if (sym != NULL)
+ bfile = symtab_to_fullname (sym->symtab);
+ else
+ bfile = "";
+
+ if (filename == NULL)
+ filename = "";
+
+ return (filename_cmp (bfile, filename) != 0);
+}
+
+/* Compute the function trace from the instruction trace. */
+
+static VEC (btrace_func_s) *
+compute_ftrace (VEC (btrace_inst_s) *itrace)
+{
+ VEC (btrace_func_s) *ftrace;
+ struct btrace_inst *binst;
+ struct btrace_func *bfun;
+ unsigned int idx;
+
+ DEBUG ("compute ftrace");
+
+ ftrace = NULL;
+ bfun = NULL;
+
+ for (idx = 0; VEC_iterate (btrace_inst_s, itrace, idx, binst); ++idx)
+ {
+ struct symtab_and_line sal;
+ struct minimal_symbol *mfun;
+ struct symbol *fun;
+ const char *filename;
+ CORE_ADDR pc;
+
+ pc = binst->pc;
+
+ /* Try to determine the function we're in. We use both types of symbols
+ to avoid surprises when we sometimes get a full symbol and sometimes
+ only a minimal symbol. */
+ fun = find_pc_function (pc);
+ mfun = lookup_minimal_symbol_by_pc (pc);
+
+ if (fun == NULL && mfun == NULL)
+ {
+ DEBUG_FTRACE ("no symbol at %u, pc=%s", idx,
+ core_addr_to_string_nz (pc));
+ continue;
+ }
+
+ /* If we're switching functions, we start over. */
+ if (ftrace_function_switched (bfun, mfun, fun))
+ {
+ bfun = VEC_safe_push (btrace_func_s, ftrace, NULL);
+
+ ftrace_init_func (bfun, mfun, fun, idx);
+ ftrace_debug (bfun, "init");
+ }
+
+ /* Update the instruction range. */
+ bfun->iend = idx;
+ ftrace_debug (bfun, "update insns");
+
+ /* Let's see if we have source correlation, as well. */
+ sal = find_pc_line (pc, 0);
+ if (sal.symtab == NULL || sal.line == 0)
+ {
+ DEBUG_FTRACE ("no lines at %u, pc=%s", idx,
+ core_addr_to_string_nz (pc));
+ continue;
+ }
+
+ /* Check if we switched files. This could happen if, say, a macro that
+ is defined in another file is expanded here. */
+ filename = symtab_to_fullname (sal.symtab);
+ if (ftrace_skip_file (bfun, filename))
+ {
+ DEBUG_FTRACE ("ignoring file at %u, pc=%s, file=%s", idx,
+ core_addr_to_string_nz (pc), filename);
+ continue;
+ }
+
+ /* Update the line range. */
+ bfun->lbegin = min (bfun->lbegin, sal.line);
+ bfun->lend = max (bfun->lend, sal.line);
+ ftrace_debug (bfun, "update lines");
+ }
+
+ return ftrace;
+}
+
+/* See btrace.h. */
+
+void
+btrace_enable (struct thread_info *tp)
+{
+ if (tp->btrace.target != NULL)
+ return;
+
+ if (!target_supports_btrace ())
+ error (_("Target does not support branch tracing."));
+
+ DEBUG ("enable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+
+ tp->btrace.target = target_enable_btrace (tp->ptid);
+}
+
+/* See btrace.h. */
+
+void
+btrace_disable (struct thread_info *tp)
+{
+ struct btrace_thread_info *btp = &tp->btrace;
+ int errcode = 0;
+
+ if (btp->target == NULL)
+ return;
+
+ DEBUG ("disable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+
+ target_disable_btrace (btp->target);
+ btp->target = NULL;
+
+ btrace_clear (tp);
+}
+
+/* See btrace.h. */
+
+void
+btrace_fetch (struct thread_info *tp)
+{
+ struct btrace_thread_info *btinfo;
+ VEC (btrace_block_s) *btrace;
+
+ DEBUG ("fetch thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+
+ btinfo = &tp->btrace;
+ if (btinfo->target == NULL)
+ return;
+
+ btrace = target_read_btrace (btinfo->target, btrace_read_new);
+ if (VEC_empty (btrace_block_s, btrace))
+ return;
+
+ btrace_clear (tp);
+
+ btinfo->btrace = btrace;
+ btinfo->itrace = compute_itrace (btinfo->btrace);
+ btinfo->ftrace = compute_ftrace (btinfo->itrace);
+
+ /* Initialize branch trace iterators. */
+ btrace_init_insn_iterator (btinfo);
+ btrace_init_func_iterator (btinfo);
+}
+
+/* See btrace.h. */
+
+void
+btrace_clear (struct thread_info *tp)
+{
+ struct btrace_thread_info *btinfo;
+
+ DEBUG ("clear thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+
+ btinfo = &tp->btrace;
+
+ VEC_free (btrace_block_s, btinfo->btrace);
+ VEC_free (btrace_inst_s, btinfo->itrace);
+ VEC_free (btrace_func_s, btinfo->ftrace);
+
+ btinfo->btrace = NULL;
+ btinfo->itrace = NULL;
+ btinfo->ftrace = NULL;
+}
+
+/* See btrace.h. */
+
+void
+btrace_free_objfile (struct objfile *objfile)
+{
+ struct thread_info *tp;
+
+ DEBUG ("free objfile");
+
+ ALL_THREADS (tp)
+ btrace_clear (tp);
+}
diff --git a/gdb/btrace.h b/gdb/btrace.h
new file mode 100644
index 0000000..7159313
--- /dev/null
+++ b/gdb/btrace.h
@@ -0,0 +1,134 @@
+/* Branch trace support for GDB, the GNU debugger.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <markus.t.metzger@intel.com>.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifndef BTRACE_H
+#define BTRACE_H
+
+/* Branch tracing (btrace) is a per-thread control-flow execution trace of the
+ inferior. For presentation purposes, the branch trace is represented as a
+ list of sequential control-flow blocks, one such list per thread. */
+
+#include "btrace-common.h"
+
+struct thread_info;
+
+/* A branch trace instruction.
+
+ This represents a single instruction in a branch trace. */
+struct btrace_inst
+{
+ /* The address of this instruction. */
+ CORE_ADDR pc;
+};
+
+/* A branch trace function.
+
+ This represents a function segment in a branch trace, i.e. a consecutive
+ number of instructions belonging to the same function. */
+struct btrace_func
+{
+ /* The full and minimal symbol for the function. One of them may be NULL. */
+ struct minimal_symbol *msym;
+ struct symbol *sym;
+
+ /* The source line range of this function segment (both inclusive). */
+ int lbegin, lend;
+
+ /* The instruction number range in the instruction trace corresponding
+ to this function segment (both inclusive). */
+ unsigned int ibegin, iend;
+};
+
+/* Branch trace may also be represented as a vector of:
+
+ - branch trace instructions starting with the oldest instruction.
+ - branch trace functions starting with the oldest function. */
+typedef struct btrace_inst btrace_inst_s;
+typedef struct btrace_func btrace_func_s;
+
+/* Define functions operating on branch trace vectors. */
+DEF_VEC_O (btrace_inst_s);
+DEF_VEC_O (btrace_func_s);
+
+/* Branch trace iteration state for "record instruction-history". */
+struct btrace_insn_iterator
+{
+ /* The instruction index range from begin (inclusive) to end (exclusive)
+ that has been covered last time.
+ If end < begin, the branch trace has just been updated. */
+ unsigned int begin;
+ unsigned int end;
+};
+
+/* Branch trace iteration state for "record function-call-history". */
+struct btrace_func_iterator
+{
+ /* The function index range from begin (inclusive) to end (exclusive)
+ that has been covered last time.
+ If end < begin, the branch trace has just been updated. */
+ unsigned int begin;
+ unsigned int end;
+};
+
+/* Branch trace information per thread.
+
+ This represents the branch trace configuration as well as the entry point
+ into the branch trace data. For the latter, it also contains the index into
+ an array of branch trace blocks used for iterating though the branch trace
+ blocks of a thread. */
+struct btrace_thread_info
+{
+ /* The target branch trace information for this thread.
+
+ This contains the branch trace configuration as well as any
+ target-specific information necessary for implementing branch tracing on
+ the underlying architecture. */
+ struct btrace_target_info *target;
+
+ /* The current branch trace for this thread. */
+ VEC (btrace_block_s) *btrace;
+ VEC (btrace_inst_s) *itrace;
+ VEC (btrace_func_s) *ftrace;
+
+ /* The instruction history iterator. */
+ struct btrace_insn_iterator insn_iterator;
+
+ /* The function call history iterator. */
+ struct btrace_func_iterator func_iterator;
+};
+
+/* Enable branch tracing for a thread. */
+extern void btrace_enable (struct thread_info *tp);
+
+/* Disable branch tracing for a thread.
+ This will also delete the current branch trace data. */
+extern void btrace_disable (struct thread_info *);
+
+/* Fetch the branch trace for a single thread. */
+extern void btrace_fetch (struct thread_info *);
+
+/* Clear the branch trace for a single thread. */
+extern void btrace_clear (struct thread_info *);
+
+/* Clear the branch trace for all threads when an object file goes away. */
+extern void btrace_free_objfile (struct objfile *);
+
+#endif /* BTRACE_H */
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
new file mode 100644
index 0000000..b157c7c
--- /dev/null
+++ b/gdb/common/btrace-common.h
@@ -0,0 +1,73 @@
+/* Branch trace support for GDB, the GNU debugger.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <markus.t.metzger@intel.com>.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifndef BTRACE_COMMON_H
+#define BTRACE_COMMON_H
+
+/* Branch tracing (btrace) is a per-thread control-flow execution trace of the
+ inferior. For presentation purposes, the branch trace is represented as a
+ list of sequential control-flow blocks, one such list per thread. */
+
+#ifdef GDBSERVER
+# include "server.h"
+#else
+# include "defs.h"
+#endif
+
+#include "vec.h"
+
+/* A branch trace block.
+
+ This represents a block of sequential control-flow. Adjacent blocks will be
+ connected via calls, returns, or jumps. The latter can be direct or
+ indirect, conditional or unconditional. Branches can further be
+ asynchronous, e.g. interrupts. */
+struct btrace_block
+{
+ /* The address of the first byte of the first instruction in the block. */
+ CORE_ADDR begin;
+
+ /* The address of the first byte of the last instruction in the block. */
+ CORE_ADDR end;
+};
+
+/* Branch trace is represented as a vector of branch trace blocks starting with
+ the most recent block. */
+typedef struct btrace_block btrace_block_s;
+
+/* Define functions operating on a vector of branch trace blocks. */
+DEF_VEC_O (btrace_block_s);
+
+/* Target specific branch trace information. */
+struct btrace_target_info;
+
+/* Enumeration of btrace read types. */
+
+enum btrace_read_type
+{
+ /* Send all available trace. */
+ btrace_read_all,
+
+ /* Send all available trace, if it changed. */
+ btrace_read_new
+};
+
+#endif /* BTRACE_COMMON_H */
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 824e4d0..0846322 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -27,6 +27,7 @@ struct symtab;
#include "frame.h"
#include "ui-out.h"
#include "inferior.h"
+#include "btrace.h"
/* Frontend view of the thread state. Possible extensions: stepping,
finishing, until(ling),... */
@@ -226,6 +227,9 @@ struct thread_info
/* Function that is called to free PRIVATE. If this is NULL, then
xfree will be called on PRIVATE. */
void (*private_dtor) (struct private_thread_info *);
+
+ /* Branch trace information for this thread. */
+ struct btrace_thread_info btrace;
};
/* Create an empty thread list, or empty the existing one. */
diff --git a/gdb/target.c b/gdb/target.c
index eaf8b31..93ce9c8 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4149,6 +4149,65 @@ target_ranged_break_num_registers (void)
return -1;
}
+/* See target.h. */
+
+int
+target_supports_btrace (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_supports_btrace != NULL)
+ return t->to_supports_btrace ();
+
+ return 0;
+}
+
+/* See target.h. */
+
+struct btrace_target_info *
+target_enable_btrace (ptid_t ptid)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_enable_btrace != NULL)
+ return t->to_enable_btrace (ptid);
+
+ tcomplain ();
+ return NULL;
+}
+
+/* See target.h. */
+
+void
+target_disable_btrace (struct btrace_target_info *btinfo)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_disable_btrace != NULL)
+ return t->to_disable_btrace (btinfo);
+
+ tcomplain ();
+}
+
+/* See target.h. */
+
+VEC (btrace_block_s) *
+target_read_btrace (struct btrace_target_info *btinfo,
+ enum btrace_read_type type)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_read_btrace != NULL)
+ return t->to_read_btrace (btinfo, type);
+
+ tcomplain ();
+ return NULL;
+}
+
static void
debug_to_prepare_to_store (struct regcache *regcache)
{
diff --git a/gdb/target.h b/gdb/target.h
index 1971265..f513264 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -62,6 +62,7 @@ struct expression;
#include "memattr.h"
#include "vec.h"
#include "gdb_signals.h"
+#include "btrace.h"
enum strata
{
@@ -286,7 +287,7 @@ enum target_object
/* Darwin dynamic linker info data. */
TARGET_OBJECT_DARWIN_DYLD_INFO,
/* OpenVMS Unwind Information Block. */
- TARGET_OBJECT_OPENVMS_UIB
+ TARGET_OBJECT_OPENVMS_UIB,
/* Possible future objects: TARGET_OBJECT_FILE, ... */
};
@@ -857,6 +858,20 @@ struct target_ops
/* Is the target able to use agent in current state? */
int (*to_can_use_agent) (void);
+ /* Check whether the target supports branch tracing. */
+ int (*to_supports_btrace) (void);
+
+ /* Enable branch tracing for @ptid and allocate a branch trace target
+ information struct for reading and for disabling branch trace. */
+ struct btrace_target_info *(*to_enable_btrace) (ptid_t ptid);
+
+ /* Disable branch tracing and deallocate @tinfo. */
+ void (*to_disable_btrace) (struct btrace_target_info *tinfo);
+
+ /* Read branch trace data. */
+ VEC (btrace_block_s) *(*to_read_btrace) (struct btrace_target_info *,
+ enum btrace_read_type);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -1897,4 +1912,20 @@ extern void update_target_permissions (void);
/* Blank target vector entries are initialized to target_ignore. */
void target_ignore (void);
+/* Check whether the target supports branch tracing. */
+extern int target_supports_btrace (void);
+
+/* Enable branch tracing for @ptid.
+ Returns a branch tracing target info object. */
+extern struct btrace_target_info *target_enable_btrace (ptid_t ptid);
+
+/* Disable branch tracing. Deallocates @btinfo. */
+extern void target_disable_btrace (struct btrace_target_info *btinfo);
+
+/* Read branch tracing data.
+ Returns a vector of branch trace blocks with the latest entry at index 0. */
+extern VEC (btrace_block_s) *target_read_btrace (struct btrace_target_info *,
+ enum btrace_read_type);
+
+
#endif /* !defined (TARGET_H) */
diff --git a/gdb/thread.c b/gdb/thread.c
index 24e6413..0d913dd 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -33,6 +33,7 @@
#include "regcache.h"
#include "gdb.h"
#include "gdb_string.h"
+#include "btrace.h"
#include <ctype.h>
#include <sys/types.h>
@@ -116,6 +117,8 @@ clear_thread_inferior_resources (struct thread_info *tp)
bpstat_clear (&tp->control.stop_bpstat);
+ btrace_disable (tp);
+
do_all_intermediate_continuations_thread (tp, 1);
do_all_continuations_thread (tp, 1);
}
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 16/21] record: add "record function-call-history" command
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (5 preceding siblings ...)
2013-03-08 9:17 ` [patch v10 01/21] thread, btrace: add generic branch trace support Markus Metzger
@ 2013-03-08 9:17 ` Markus Metzger
2013-03-08 9:17 ` [patch v10 21/21] btrace: fix crash when losing the remote connection on process exit Markus Metzger
` (15 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:17 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Add command to print the function names from recorded instructions.
The command supports iterating over the execution log similar to the "list"
command.
This command provides a quick high-level overview over the recorded execution
log at function granularity without having to reverse-step.
Doc approved by Eli Zaretskii.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* target.c (target_call_history, target_call_history_from,
target_call_history_range): New.
* target.h (target_ops) <to_call_history, to_call_history_from,
to_call_history_range>: New fields.
(target_call_history, target_call_history_from,
target_call_history_range): New declaration.
* record.c (get_call_history_modifiers, cmd_record_call_history,
record_call_history_size): New.
(_initialize_record): Add the "record function-call-history" command.
Add "set/show record function-call-history-size" commands.
* record.h (record_print_flag): New.
---
gdb/record.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/record.h | 10 ++++
gdb/target.c | 51 ++++++++++++++++++++
gdb/target.h | 24 +++++++++
4 files changed, 234 insertions(+), 0 deletions(-)
diff --git a/gdb/record.c b/gdb/record.c
index c71842f..12ab179 100644
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -35,6 +35,9 @@ unsigned int record_debug = 0;
/* The number of instructions to print in "record instruction-history". */
static unsigned int record_insn_history_size = 10;
+/* The number of functions to print in "record function-call-history". */
+static unsigned int record_call_history_size = 10;
+
struct cmd_list_element *record_cmdlist = NULL;
struct cmd_list_element *set_record_cmdlist = NULL;
struct cmd_list_element *show_record_cmdlist = NULL;
@@ -466,6 +469,126 @@ cmd_record_insn_history (char *arg, int from_tty)
}
}
+/* Read function-call-history modifiers from an argument string. */
+
+static int
+get_call_history_modifiers (char **arg)
+{
+ int modifiers;
+ char *args;
+
+ modifiers = 0;
+ args = *arg;
+
+ if (args == NULL)
+ return modifiers;
+
+ while (*args == '/')
+ {
+ ++args;
+
+ if (*args == '\0')
+ error (_("Missing modifier."));
+
+ for (; *args; ++args)
+ {
+ if (isspace (*args))
+ break;
+
+ if (*args == '/')
+ continue;
+
+ switch (*args)
+ {
+ case 'l':
+ modifiers |= record_print_src_line;
+ break;
+ case 'i':
+ modifiers |= record_print_insn_range;
+ break;
+ default:
+ error (_("Invalid modifier: %c."), *args);
+ }
+ }
+
+ args = skip_spaces (args);
+ }
+
+ /* Update the argument string. */
+ *arg = args;
+
+ return modifiers;
+}
+
+/* The "record function-call-history" command. */
+
+static void
+cmd_record_call_history (char *arg, int from_tty)
+{
+ int flags, size;
+
+ require_record_target ();
+
+ flags = get_call_history_modifiers (&arg);
+
+ /* We use a signed size to also indicate the direction. Make sure that
+ unlimited remains unlimited. */
+ size = (int) record_call_history_size;
+ if (size < 0)
+ size = INT_MAX;
+
+ if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0)
+ target_call_history (size, flags);
+ else if (strcmp (arg, "-") == 0)
+ target_call_history (-size, flags);
+ else
+ {
+ ULONGEST begin, end;
+
+ begin = get_insn_number (&arg);
+
+ if (*arg == ',')
+ {
+ arg = skip_spaces (++arg);
+
+ if (*arg == '+')
+ {
+ arg += 1;
+ size = get_context_size (&arg);
+
+ no_chunk (arg);
+
+ target_call_history_from (begin, size, flags);
+ }
+ else if (*arg == '-')
+ {
+ arg += 1;
+ size = get_context_size (&arg);
+
+ no_chunk (arg);
+
+ target_call_history_from (begin, -size, flags);
+ }
+ else
+ {
+ end = get_insn_number (&arg);
+
+ no_chunk (arg);
+
+ target_call_history_range (begin, end, flags);
+ }
+ }
+ else
+ {
+ no_chunk (arg);
+
+ target_call_history_from (begin, size, flags);
+ }
+
+ dont_repeat ();
+ }
+}
+
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_record;
@@ -489,6 +612,13 @@ Show number of instructions to print in \"record instruction-history\"."),
NULL, NULL, NULL, &set_record_cmdlist,
&show_record_cmdlist);
+ add_setshow_uinteger_cmd ("function-call-history-size", no_class,
+ &record_call_history_size, _("\
+Set number of function to print in \"record function-call-history\"."), _("\
+Show number of functions to print in \"record function-call-history\"."),
+ NULL, NULL, NULL, &set_record_cmdlist,
+ &show_record_cmdlist);
+
c = add_prefix_cmd ("record", class_obscure, cmd_record_start,
_("Start recording."),
&record_cmdlist, "record ", 0, &cmdlist);
@@ -549,4 +679,23 @@ from the first argument.\n\
The number of instructions to disassemble can be defined with \"set record \
instruction-history-size\"."),
&record_cmdlist);
+
+ add_cmd ("function-call-history", class_obscure, cmd_record_call_history, _("\
+Prints the execution history at function granularity.\n\
+It prints one line for each sequence of instructions that belong to the same \
+function.\n\
+Without modifiers, it prints the function name.\n\
+With a /l modifier, the source file and line number range is included.\n\
+With a /i modifier, the instruction number range is included.\n\
+With no argument, prints ten more lines after the previous ten-line print.\n\
+\"record function-call-history -\" prints ten lines before a previous ten-line \
+print.\n\
+One argument specifies a function number as shown by 'info record', and \
+ten lines are printed after that function.\n\
+Two arguments with comma between them specify a range of functions to print.\n\
+If the second argument is preceded by '+' or '-', it specifies the distance \
+from the first argument.\n\
+The number of functions to print can be defined with \"set record \
+function-call-history-size\"."),
+ &record_cmdlist);
}
diff --git a/gdb/record.h b/gdb/record.h
index 04d6b4a..86e6bc6 100644
--- a/gdb/record.h
+++ b/gdb/record.h
@@ -32,6 +32,16 @@ extern struct cmd_list_element *set_record_cmdlist;
extern struct cmd_list_element *show_record_cmdlist;
extern struct cmd_list_element *info_record_cmdlist;
+/* A list of flags specifying what record target methods should print. */
+enum record_print_flag
+{
+ /* Print the source file and line (if applicable). */
+ record_print_src_line = (1 << 0),
+
+ /* Print the instruction number range (if applicable). */
+ record_print_insn_range = (1 << 1),
+};
+
/* Wrapper for target_read_memory that prints a debug message if
reading memory fails. */
extern int record_read_memory (struct gdbarch *gdbarch,
diff --git a/gdb/target.c b/gdb/target.c
index 797163f..5b5f784 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4404,6 +4404,57 @@ target_insn_history_range (ULONGEST begin, ULONGEST end, int flags)
tcomplain ();
}
+/* See target.h. */
+
+void
+target_call_history (int size, int flags)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_call_history != NULL)
+ {
+ t->to_call_history (size, flags);
+ return;
+ }
+
+ tcomplain ();
+}
+
+/* See target.h. */
+
+void
+target_call_history_from (ULONGEST begin, int size, int flags)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_call_history_from != NULL)
+ {
+ t->to_call_history_from (begin, size, flags);
+ return;
+ }
+
+ tcomplain ();
+}
+
+/* See target.h. */
+
+void
+target_call_history_range (ULONGEST begin, ULONGEST end, int flags)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_call_history_range != NULL)
+ {
+ t->to_call_history_range (begin, end, flags);
+ return;
+ }
+
+ tcomplain ();
+}
+
static void
debug_to_prepare_to_store (struct regcache *regcache)
{
diff --git a/gdb/target.h b/gdb/target.h
index 47fa6a3..7403221 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -911,6 +911,21 @@ struct target_ops
BEGIN (inclusive) to instruction END (exclusive). */
void (*to_insn_history_range) (ULONGEST begin, ULONGEST end, int flags);
+ /* Print a function trace of the recorded execution trace.
+ If SIZE < 0, print abs (SIZE) preceding functions; otherwise, print SIZE
+ succeeding functions. */
+ void (*to_call_history) (int size, int flags);
+
+ /* Print a function trace of the recorded execution trace starting
+ at function FROM.
+ If SIZE < 0, print abs (SIZE) functions before FROM; otherwise, print
+ SIZE functions after FROM. */
+ void (*to_call_history_from) (ULONGEST begin, int size, int flags);
+
+ /* Print a function trace of an execution trace section from function BEGIN
+ (inclusive) to function END (exclusive). */
+ void (*to_call_history_range) (ULONGEST begin, ULONGEST end, int flags);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -2004,4 +2019,13 @@ extern void target_insn_history_from (ULONGEST from, int size, int flags);
/* See to_insn_history_range. */
extern void target_insn_history_range (ULONGEST begin, ULONGEST end, int flags);
+/* See to_call_history. */
+extern void target_call_history (int size, int flags);
+
+/* See to_call_history_from. */
+extern void target_call_history_from (ULONGEST begin, int size, int flags);
+
+/* See to_call_history_range. */
+extern void target_call_history_range (ULONGEST begin, ULONGEST end, int flags);
+
#endif /* !defined (TARGET_H) */
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 21/21] btrace: fix crash when losing the remote connection on process exit
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (6 preceding siblings ...)
2013-03-08 9:17 ` [patch v10 16/21] record: add "record function-call-history" command Markus Metzger
@ 2013-03-08 9:17 ` Markus Metzger
2013-03-08 13:58 ` Jan Kratochvil
2013-03-08 9:17 ` [patch v10 09/21] target: add add_deprecated_target_alias Markus Metzger
` (14 subsequent siblings)
22 siblings, 1 reply; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:17 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Fix a crash reported by Jan Kratochvil.
When a branch traced process exits in a remote debug scenario and we try to
disable branch tracing, we would realize that the target connection is gone and
thus pop all targets.
This causes another attempt to disable branch tracing when we discard all
threads, thus crashing GDB.
This patch adds another path to disable branch tracing that is used when freeing
the resources for a thread. Branch tracing is disabled normally on native
targets - except that errors are silently ignored. For remote targets, the
resources are freed when the threads are discarded.
We further split to_close into to_stop_recording and to_close so we avdoid
making any target access in to_close. In fact, to_close is empty, now.
The patch will be split and merged into the btrace patch series.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
---
gdb/amd64-linux-nat.c | 10 ++++++++
gdb/btrace.c | 19 +++++++++++++++
gdb/btrace.h | 5 ++++
gdb/i386-linux-nat.c | 10 ++++++++
gdb/record-btrace.c | 22 ++++++++++-------
gdb/record.c | 61 ++++++++++++++++++++++++++++++++++--------------
gdb/remote.c | 10 ++++++++
gdb/target.c | 31 +++++++++++++++++++++++++
gdb/target.h | 15 ++++++++++++
gdb/thread.c | 2 +-
10 files changed, 157 insertions(+), 28 deletions(-)
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index 6f13fca..8dfe7c5 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -1154,6 +1154,15 @@ amd64_linux_disable_btrace (struct btrace_target_info *tinfo)
error (_("Could not disable branch tracing: %s."), safe_strerror (errcode));
}
+/* Teardown branch tracing. */
+
+static void
+amd64_linux_teardown_btrace (struct btrace_target_info *tinfo)
+{
+ /* Ignore errors. */
+ linux_disable_btrace (tinfo);
+}
+
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_amd64_linux_nat (void);
@@ -1196,6 +1205,7 @@ _initialize_amd64_linux_nat (void)
t->to_supports_btrace = linux_supports_btrace;
t->to_enable_btrace = amd64_linux_enable_btrace;
t->to_disable_btrace = amd64_linux_disable_btrace;
+ t->to_teardown_btrace = amd64_linux_teardown_btrace;
t->to_read_btrace = linux_read_btrace;
/* Register the target. */
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 75ede3a..c39a32d 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -371,6 +371,25 @@ btrace_disable (struct thread_info *tp)
/* See btrace.h. */
void
+btrace_teardown (struct thread_info *tp)
+{
+ struct btrace_thread_info *btp = &tp->btrace;
+ int errcode = 0;
+
+ if (btp->target == NULL)
+ return;
+
+ DEBUG ("teardown thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+
+ target_teardown_btrace (btp->target);
+ btp->target = NULL;
+
+ btrace_clear (tp);
+}
+
+/* See btrace.h. */
+
+void
btrace_fetch (struct thread_info *tp)
{
struct btrace_thread_info *btinfo;
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 35fb13a..bd8425d 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -122,6 +122,11 @@ extern void btrace_enable (struct thread_info *tp);
This will also delete the current branch trace data. */
extern void btrace_disable (struct thread_info *);
+/* Disable branch tracing for a thread during teardown.
+ This is similar to btrace_disable, except that it will use
+ target_teardown_btrace instead of target_disable_btrace. */
+extern void btrace_teardown (struct thread_info *);
+
/* Fetch the branch trace for a single thread. */
extern void btrace_fetch (struct thread_info *);
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 715c6d4..be2b6c9 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -1081,6 +1081,15 @@ i386_linux_disable_btrace (struct btrace_target_info *tinfo)
error (_("Could not disable branch tracing: %s."), safe_strerror (errcode));
}
+/* Teardown branch tracing. */
+
+static void
+i386_linux_teardown_btrace (struct btrace_target_info *tinfo)
+{
+ /* Ignore errors. */
+ linux_disable_btrace (tinfo);
+}
+
/* -Wmissing-prototypes */
extern initialize_file_ftype _initialize_i386_linux_nat;
@@ -1118,6 +1127,7 @@ _initialize_i386_linux_nat (void)
t->to_supports_btrace = linux_supports_btrace;
t->to_enable_btrace = i386_linux_enable_btrace;
t->to_disable_btrace = i386_linux_disable_btrace;
+ t->to_teardown_btrace = i386_linux_teardown_btrace;
t->to_read_btrace = linux_read_btrace;
/* Register the target. */
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 66b4a3d..bbb0bd5 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -99,16 +99,11 @@ record_btrace_enable_warn (struct thread_info *tp)
static void
record_btrace_disable_callback (void *arg)
{
- volatile struct gdb_exception error;
struct thread_info *tp;
tp = arg;
- TRY_CATCH (error, RETURN_MASK_ERROR)
- btrace_disable (tp);
-
- if (error.message != NULL)
- warning ("%s", error.message);
+ btrace_disable (tp);
}
/* Enable automatic tracing of new threads. */
@@ -176,14 +171,14 @@ record_btrace_open (char *args, int from_tty)
discard_cleanups (disable_chain);
}
-/* The to_close method of target record-btrace. */
+/* The to_stop_recording method of target record-btrace. */
static void
-record_btrace_close (int quitting)
+record_btrace_stop_recording (void)
{
struct thread_info *tp;
- DEBUG ("close");
+ DEBUG ("stop recording");
record_btrace_auto_disable ();
@@ -192,6 +187,14 @@ record_btrace_close (int quitting)
btrace_disable (tp);
}
+/* The to_close method of target record-btrace. */
+
+static void
+record_btrace_close (int quitting)
+{
+ /* We already stopped recording. */
+}
+
/* The to_info_record method of target record-btrace. */
static void
@@ -649,6 +652,7 @@ init_record_btrace_ops (void)
ops->to_mourn_inferior = record_mourn_inferior;
ops->to_kill = record_kill;
ops->to_create_inferior = find_default_create_inferior;
+ ops->to_stop_recording = record_btrace_stop_recording;
ops->to_info_record = record_btrace_info;
ops->to_insn_history = record_btrace_insn_history;
ops->to_insn_history_from = record_btrace_insn_history_from;
diff --git a/gdb/record.c b/gdb/record.c
index 83f4e1b..2426885 100644
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -92,17 +92,22 @@ record_read_memory (struct gdbarch *gdbarch,
return ret;
}
-/* Unpush the record target. */
+/* Stop recording. */
static void
-record_unpush (void)
+record_stop (struct target_ops *t)
{
- struct target_ops *t;
+ DEBUG ("stop %s", t->to_shortname);
- t = find_record_target ();
- if (t == NULL)
- internal_error (__FILE__, __LINE__, _("Couldn't find record target."));
+ if (t->to_stop_recording != NULL)
+ t->to_stop_recording ();
+}
+/* Unpush the record target. */
+
+static void
+record_unpush (struct target_ops *t)
+{
DEBUG ("unpush %s", t->to_shortname);
unpush_target (t);
@@ -111,44 +116,62 @@ record_unpush (void)
/* See record.h. */
void
-record_disconnect (struct target_ops *target, char *args, int from_tty)
+record_disconnect (struct target_ops *t, char *args, int from_tty)
{
- DEBUG ("disconnect");
+ gdb_assert (t->to_stratum == record_stratum);
+
+ DEBUG ("disconnect %s", t->to_shortname);
+
+ record_stop (t);
+ record_unpush (t);
- record_unpush ();
target_disconnect (args, from_tty);
}
/* See record.h. */
void
-record_detach (struct target_ops *ops, char *args, int from_tty)
+record_detach (struct target_ops *t, char *args, int from_tty)
{
- DEBUG ("detach");
+ gdb_assert (t->to_stratum == record_stratum);
+
+ DEBUG ("detach %s", t->to_shortname);
+
+ record_stop (t);
+ record_unpush (t);
- record_unpush ();
target_detach (args, from_tty);
}
/* See record.h. */
void
-record_mourn_inferior (struct target_ops *ops)
+record_mourn_inferior (struct target_ops *t)
{
- DEBUG ("mourn_inferior");
+ gdb_assert (t->to_stratum == record_stratum);
+
+ DEBUG ("mourn inferior %s", t->to_shortname);
+
+ /* It is safer to not stop recording. Resources will be freed when
+ threads are discarded. */
+ record_unpush (t);
- record_unpush ();
target_mourn_inferior ();
}
/* See record.h. */
void
-record_kill (struct target_ops *ops)
+record_kill (struct target_ops *t)
{
- DEBUG ("kill");
+ gdb_assert (t->to_stratum == record_stratum);
+
+ DEBUG ("kill %s", t->to_shortname);
+
+ /* It is safer to not stop recording. Resources will be freed when
+ threads are discarded. */
+ record_unpush (t);
- record_unpush ();
target_kill ();
}
@@ -205,6 +228,8 @@ cmd_record_stop (char *args, int from_tty)
struct target_ops *t;
t = require_record_target ();
+
+ record_stop (t);
unpush_target (t);
printf_unfiltered (_("Process record is stopped and all execution "
diff --git a/gdb/remote.c b/gdb/remote.c
index 7ee0695..39cf5ab 100755
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -11212,6 +11212,15 @@ remote_disable_btrace (struct btrace_target_info *tinfo)
xfree (tinfo);
}
+/* Teardown branch tracing. */
+
+static void
+remote_teardown_btrace (struct btrace_target_info *tinfo)
+{
+ /* We must not talk to the target during teardown. */
+ xfree (tinfo);
+}
+
/* Read the branch trace. */
static VEC (btrace_block_s) *
@@ -11377,6 +11386,7 @@ Specify the serial device it is connected to\n\
remote_ops.to_supports_btrace = remote_supports_btrace;
remote_ops.to_enable_btrace = remote_enable_btrace;
remote_ops.to_disable_btrace = remote_disable_btrace;
+ remote_ops.to_teardown_btrace = remote_teardown_btrace;
remote_ops.to_read_btrace = remote_read_btrace;
}
diff --git a/gdb/target.c b/gdb/target.c
index 5b5f784..2d8dc36 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4209,6 +4209,20 @@ target_disable_btrace (struct btrace_target_info *btinfo)
/* See target.h. */
+void
+target_teardown_btrace (struct btrace_target_info *btinfo)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_teardown_btrace != NULL)
+ return t->to_teardown_btrace (btinfo);
+
+ tcomplain ();
+}
+
+/* See target.h. */
+
VEC (btrace_block_s) *
target_read_btrace (struct btrace_target_info *btinfo,
enum btrace_read_type type)
@@ -4226,6 +4240,23 @@ target_read_btrace (struct btrace_target_info *btinfo,
/* See target.h. */
void
+target_stop_recording (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_stop_recording != NULL)
+ {
+ t->to_stop_recording ();
+ return;
+ }
+
+ /* This is optional. */
+}
+
+/* See target.h. */
+
+void
target_info_record (void)
{
struct target_ops *t;
diff --git a/gdb/target.h b/gdb/target.h
index 7403221..7a70e83 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -870,10 +870,19 @@ struct target_ops
/* Disable branch tracing and deallocate @tinfo. */
void (*to_disable_btrace) (struct btrace_target_info *tinfo);
+ /* Disable branch tracing and deallocate @tinfo. This function is similar
+ to to_disable_btrace, except that it is called during teardown and is
+ only allowed to perform actions that are safe. A counter-example would
+ be attempting to talk to a remote target. */
+ void (*to_teardown_btrace) (struct btrace_target_info *tinfo);
+
/* Read branch trace data. */
VEC (btrace_block_s) *(*to_read_btrace) (struct btrace_target_info *,
enum btrace_read_type);
+ /* Stop trace recording. */
+ void (*to_stop_recording) (void);
+
/* Print information about the recording. */
void (*to_info_record) (void);
@@ -1981,11 +1990,17 @@ extern struct btrace_target_info *target_enable_btrace (ptid_t ptid);
/* Disable branch tracing. Deallocates @btinfo. */
extern void target_disable_btrace (struct btrace_target_info *btinfo);
+/* See to_teardown_btrace in struct target_ops. */
+extern void target_teardown_btrace (struct btrace_target_info *btinfo);
+
/* Read branch tracing data.
Returns a vector of branch trace blocks with the latest entry at index 0. */
extern VEC (btrace_block_s) *target_read_btrace (struct btrace_target_info *,
enum btrace_read_type);
+/* See to_stop_recording in struct target_ops. */
+extern void target_stop_recording (void);
+
/* See to_info_record in struct target_ops. */
extern void target_info_record (void);
diff --git a/gdb/thread.c b/gdb/thread.c
index 0d913dd..2a1d723 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -117,7 +117,7 @@ clear_thread_inferior_resources (struct thread_info *tp)
bpstat_clear (&tp->control.stop_bpstat);
- btrace_disable (tp);
+ btrace_teardown (tp);
do_all_intermediate_continuations_thread (tp, 1);
do_all_continuations_thread (tp, 1);
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [patch v10 21/21] btrace: fix crash when losing the remote connection on process exit
2013-03-08 9:17 ` [patch v10 21/21] btrace: fix crash when losing the remote connection on process exit Markus Metzger
@ 2013-03-08 13:58 ` Jan Kratochvil
2013-03-08 14:18 ` Metzger, Markus T
0 siblings, 1 reply; 34+ messages in thread
From: Jan Kratochvil @ 2013-03-08 13:58 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Fri, 08 Mar 2013 10:16:08 +0100, Markus Metzger wrote:
> The patch will be split and merged into the btrace patch series.
OK for the merge.
> --- a/gdb/record-btrace.c
> +++ b/gdb/record-btrace.c
> @@ -99,16 +99,11 @@ record_btrace_enable_warn (struct thread_info *tp)
> static void
> record_btrace_disable_callback (void *arg)
> {
> - volatile struct gdb_exception error;
> struct thread_info *tp;
>
> tp = arg;
>
> - TRY_CATCH (error, RETURN_MASK_ERROR)
> - btrace_disable (tp);
> -
> - if (error.message != NULL)
> - warning ("%s", error.message);
> + btrace_disable (tp);
> }
I do not see how is it related to this patch. But OK with it.
> --- a/gdb/target.h
> +++ b/gdb/target.h
> @@ -870,10 +870,19 @@ struct target_ops
> /* Disable branch tracing and deallocate @tinfo. */
> void (*to_disable_btrace) (struct btrace_target_info *tinfo);
>
> + /* Disable branch tracing and deallocate @tinfo. This function is similar
@tinfo -> TINFO
in the GNU Coding Standards style (I see it used multiple times already),
sorry for the nitpick.
> + to to_disable_btrace, except that it is called during teardown and is
> + only allowed to perform actions that are safe. A counter-example would
> + be attempting to talk to a remote target. */
> + void (*to_teardown_btrace) (struct btrace_target_info *tinfo);
Thanks,
Jan
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [patch v10 21/21] btrace: fix crash when losing the remote connection on process exit
2013-03-08 13:58 ` Jan Kratochvil
@ 2013-03-08 14:18 ` Metzger, Markus T
0 siblings, 0 replies; 34+ messages in thread
From: Metzger, Markus T @ 2013-03-08 14:18 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, markus.t.metzger
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Friday, March 08, 2013 2:58 PM
> > /* Disable branch tracing and deallocate @tinfo. */
> > void (*to_disable_btrace) (struct btrace_target_info *tinfo);
> >
> > + /* Disable branch tracing and deallocate @tinfo. This function is similar
>
> @tinfo -> TINFO
>
> in the GNU Coding Standards style (I see it used multiple times already),
> sorry for the nitpick.
Thanks. I'm still learning the style.
I fixed all occurrences in target.h.
Regards,
Markus.
Intel GmbH
Dornacher Strasse 1
85622 Feldkirchen/Muenchen, Deutschland
Sitz der Gesellschaft: Feldkirchen bei Muenchen
Geschaeftsfuehrer: Christian Lamprechter, Hannes Schwaderer, Douglas Lusk
Registergericht: Muenchen HRB 47456
Ust.-IdNr./VAT Registration No.: DE129385895
Citibank Frankfurt a.M. (BLZ 502 109 00) 600119052
^ permalink raw reply [flat|nested] 34+ messages in thread
* [patch v10 09/21] target: add add_deprecated_target_alias
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (7 preceding siblings ...)
2013-03-08 9:17 ` [patch v10 21/21] btrace: fix crash when losing the remote connection on process exit Markus Metzger
@ 2013-03-08 9:17 ` Markus Metzger
2013-03-08 9:18 ` [patch v10 02/21] linux, btrace: perf_event based branch tracing Markus Metzger
` (13 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:17 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Add a new function to target.h to add an alias command for a target and mark it
deprecated. This is useful when renaming targets.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* target.h (add_deprecated_target_alias): New.
* target.c (add_deprecated_target_alias): New.
---
gdb/target.c | 15 +++++++++++++++
gdb/target.h | 5 +++++
2 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/gdb/target.c b/gdb/target.c
index 93ce9c8..8bb6814 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -434,6 +434,21 @@ information on the arguments for a particular protocol, type\n\
add_cmd (t->to_shortname, no_class, t->to_open, t->to_doc, &targetlist);
}
+/* See target.h. */
+
+void
+add_deprecated_target_alias (struct target_ops *t, char *alias)
+{
+ struct cmd_list_element *c;
+ char *alt;
+
+ /* If we use add_alias_cmd, here, we do not get the deprecated warning,
+ see PR cli/15104. */
+ c = add_cmd (alias, no_class, t->to_open, t->to_doc, &targetlist);
+ alt = xstrprintf ("target %s", t->to_shortname);
+ deprecate_cmd (c, alt);
+}
+
/* Stub functions */
void
diff --git a/gdb/target.h b/gdb/target.h
index aa0ae2a..93b9444 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1777,6 +1777,11 @@ int target_verify_memory (const gdb_byte *data,
extern void add_target (struct target_ops *);
+/* Adds a command ALIAS for target T and marks it deprecated. This is useful
+ for maintaining backwards compatibility when renaming targets. */
+
+extern void add_deprecated_target_alias (struct target_ops *t, char *alias);
+
extern void push_target (struct target_ops *);
extern int unpush_target (struct target_ops *);
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 02/21] linux, btrace: perf_event based branch tracing
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (8 preceding siblings ...)
2013-03-08 9:17 ` [patch v10 09/21] target: add add_deprecated_target_alias Markus Metzger
@ 2013-03-08 9:18 ` Markus Metzger
2013-03-08 9:18 ` [patch v10 20/21] testsuite, gdb.btrace: add btrace tests Markus Metzger
` (12 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:18 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Implement branch tracing on Linux based on perf_event such taht it can be shared
between gdb and gdbserver.
The actual btrace target ops will be implemented on top.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* common/linux_btrace.h: New file.
* common/linux_btrace.c: New file.
* Makefile.in (SFILES): Add btrace.c.
(HFILES_NO_SRCDIR): Add common/linux-btrace.h.
(COMMON_OBS): Add btrace.o.
(linux-btrace.o): New rule.
gdbserver/
* Makefile.in (SFILES): Add $(srcdir)/common/linux-btrace.c.
(linux_btrace_h): New variable.
(linux-btrace.o): New rule.
---
gdb/Makefile.in | 6 +-
gdb/common/linux-btrace.c | 425 +++++++++++++++++++++++++++++++++++++++++++++
gdb/common/linux-btrace.h | 77 ++++++++
gdb/gdbserver/Makefile.in | 7 +-
4 files changed, 513 insertions(+), 2 deletions(-)
create mode 100644 gdb/common/linux-btrace.c
create mode 100644 gdb/common/linux-btrace.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 1cf8134..de48caa 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -835,7 +835,7 @@ gnulib/import/stddef.in.h gnulib/import/inttypes.in.h inline-frame.h skip.h \
common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
common/format.h common/host-defs.h utils.h common/queue.h \
common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h \
-gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h
+gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h common/linux-btrace.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -1965,6 +1965,10 @@ vec.o: ${srcdir}/common/vec.c
$(COMPILE) $(srcdir)/common/vec.c
$(POSTCOMPILE)
+linux-btrace.o: ${srcdir}/common/linux-btrace.c
+ $(COMPILE) $(srcdir)/common/linux-btrace.c
+ $(POSTCOMPILE)
+
#
# gdb/tui/ dependencies
#
diff --git a/gdb/common/linux-btrace.c b/gdb/common/linux-btrace.c
new file mode 100644
index 0000000..2f8c1cf
--- /dev/null
+++ b/gdb/common/linux-btrace.c
@@ -0,0 +1,425 @@
+/* Linux-dependent part of branch trace support for GDB, and GDBserver.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <markus.t.metzger@intel.com>
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifdef GDBSERVER
+#include "server.h"
+#else
+#include "defs.h"
+#endif
+
+#include "linux-btrace.h"
+#include "common-utils.h"
+#include "gdb_assert.h"
+#include "regcache.h"
+#include "gdbthread.h"
+
+#if HAVE_LINUX_PERF_EVENT_H
+
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+
+/* A branch trace record in perf_event. */
+struct perf_event_bts
+{
+ /* The linear address of the branch source. */
+ uint64_t from;
+
+ /* The linear address of the branch destination. */
+ uint64_t to;
+};
+
+/* A perf_event branch trace sample. */
+struct perf_event_sample
+{
+ /* The perf_event sample header. */
+ struct perf_event_header header;
+
+ /* The perf_event branch tracing payload. */
+ struct perf_event_bts bts;
+};
+
+/* Get the perf_event header. */
+
+static inline volatile struct perf_event_mmap_page *
+perf_event_header (struct btrace_target_info* tinfo)
+{
+ return tinfo->buffer;
+}
+
+/* Get the size of the perf_event mmap buffer. */
+
+static inline size_t
+perf_event_mmap_size (const struct btrace_target_info *tinfo)
+{
+ /* The branch trace buffer is preceded by a configuration page. */
+ return (tinfo->size + 1) * PAGE_SIZE;
+}
+
+/* Get the size of the perf_event buffer. */
+
+static inline size_t
+perf_event_buffer_size (struct btrace_target_info* tinfo)
+{
+ return tinfo->size * PAGE_SIZE;
+}
+
+/* Get the start address of the perf_event buffer. */
+
+static inline const uint8_t *
+perf_event_buffer_begin (struct btrace_target_info* tinfo)
+{
+ return ((const uint8_t *) tinfo->buffer) + PAGE_SIZE;
+}
+
+/* Get the end address of the perf_event buffer. */
+
+static inline const uint8_t *
+perf_event_buffer_end (struct btrace_target_info* tinfo)
+{
+ return perf_event_buffer_begin (tinfo) + perf_event_buffer_size (tinfo);
+}
+
+/* Check whether an address is in the kernel. */
+
+static inline int
+perf_event_is_kernel_addr (const struct btrace_target_info *tinfo,
+ uint64_t addr)
+{
+ uint64_t mask;
+
+ /* If we don't know the size of a pointer, we can't check. Let's assume it's
+ not a kernel address in this case. */
+ if (tinfo->ptr_bits == 0)
+ return 0;
+
+ /* A bit mask for the most significant bit in an address. */
+ mask = (uint64_t) 1 << (tinfo->ptr_bits - 1);
+
+ /* Check whether the most significant bit in the address is set. */
+ return (addr & mask) != 0;
+}
+
+/* Check whether a perf event record should be skipped. */
+
+static inline int
+perf_event_skip_record (const struct btrace_target_info *tinfo,
+ const struct perf_event_bts *bts)
+{
+ /* The hardware may report branches from kernel into user space. Branches
+ from user into kernel space will be suppressed. We filter the former to
+ provide a consistent branch trace excluding kernel. */
+ return perf_event_is_kernel_addr (tinfo, bts->from);
+}
+
+/* Perform a few consistency checks on a perf event sample record. This is
+ meant to catch cases when we get out of sync with the perf event stream. */
+
+static inline int
+perf_event_sample_ok (const struct perf_event_sample *sample)
+{
+ if (sample->header.type != PERF_RECORD_SAMPLE)
+ return 0;
+
+ if (sample->header.size != sizeof (*sample))
+ return 0;
+
+ return 1;
+}
+
+/* Branch trace is collected in a circular buffer [begin; end) as pairs of from
+ and to addresses (plus a header).
+
+ Start points into that buffer at the next sample position.
+ We read the collected samples backwards from start.
+
+ While reading the samples, we convert the information into a list of blocks.
+ For two adjacent samples s1 and s2, we form a block b such that b.begin =
+ s1.to and b.end = s2.from.
+
+ In case the buffer overflows during sampling, one sample may have its lower
+ part at the end and its upper part at the beginning of the buffer. */
+
+static VEC (btrace_block_s) *
+perf_event_read_bts (struct btrace_target_info* tinfo, const uint8_t *begin,
+ const uint8_t *end, const uint8_t *start)
+{
+ VEC (btrace_block_s) *btrace = NULL;
+ struct perf_event_sample sample;
+ size_t read = 0, size = (end - begin);
+ struct btrace_block block = { 0, 0 };
+ struct regcache *regcache;
+
+ gdb_assert (begin <= start);
+ gdb_assert (start <= end);
+
+ /* The first block ends at the current pc. */
+#ifdef GDBSERVER
+ regcache = get_thread_regcache (find_thread_ptid (tinfo->ptid), 1);
+#else
+ regcache = get_thread_regcache (tinfo->ptid);
+#endif
+ block.end = regcache_read_pc (regcache);
+
+ /* The buffer may contain a partial record as its last entry (i.e. when the
+ buffer size is not a multiple of the sample size). */
+ read = sizeof (sample) - 1;
+
+ for (; read < size; read += sizeof (sample))
+ {
+ const struct perf_event_sample *psample;
+
+ /* Find the next perf_event sample in a backwards traversal. */
+ start -= sizeof (sample);
+
+ /* If we're still inside the buffer, we're done. */
+ if (begin <= start)
+ psample = (const struct perf_event_sample *) start;
+ else
+ {
+ int missing;
+
+ /* We're to the left of the ring buffer, we will wrap around and
+ reappear at the very right of the ring buffer. */
+
+ missing = (begin - start);
+ start = (end - missing);
+
+ /* If the entire sample is missing, we're done. */
+ if (missing == sizeof (sample))
+ psample = (const struct perf_event_sample *) start;
+ else
+ {
+ uint8_t *stack;
+
+ /* The sample wrapped around. The lower part is at the end and
+ the upper part is at the beginning of the buffer. */
+ stack = (uint8_t *) &sample;
+
+ /* Copy the two parts so we have a contiguous sample. */
+ memcpy (stack, start, missing);
+ memcpy (stack + missing, begin, sizeof (sample) - missing);
+
+ psample = &sample;
+ }
+ }
+
+ if (!perf_event_sample_ok (psample))
+ {
+ warning (_("Branch trace may be incomplete."));
+ break;
+ }
+
+ if (perf_event_skip_record (tinfo, &psample->bts))
+ continue;
+
+ /* We found a valid sample, so we can complete the current block. */
+ block.begin = psample->bts.to;
+
+ VEC_safe_push (btrace_block_s, btrace, &block);
+
+ /* Start the next block. */
+ block.end = psample->bts.from;
+ }
+
+ return btrace;
+}
+
+/* See linux-btrace.h. */
+
+int
+linux_supports_btrace (void)
+{
+ return 1;
+}
+
+/* See linux-btrace.h. */
+
+struct btrace_target_info *
+linux_enable_btrace (ptid_t ptid)
+{
+ struct btrace_target_info *tinfo;
+ int pid;
+
+ tinfo = xzalloc (sizeof (*tinfo));
+ tinfo->ptid = ptid;
+
+ tinfo->attr.size = sizeof (tinfo->attr);
+ tinfo->attr.type = PERF_TYPE_HARDWARE;
+ tinfo->attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
+ tinfo->attr.sample_period = 1;
+
+ /* We sample from and to address. */
+ tinfo->attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR;
+
+ tinfo->attr.exclude_kernel = 1;
+ tinfo->attr.exclude_hv = 1;
+ tinfo->attr.exclude_idle = 1;
+
+ tinfo->ptr_bits = 0;
+
+ pid = ptid_get_lwp (ptid);
+ if (pid == 0)
+ pid = ptid_get_pid (ptid);
+
+ errno = 0;
+ tinfo->file = syscall (SYS_perf_event_open, &tinfo->attr, pid, -1, -1, 0);
+ if (tinfo->file < 0)
+ goto err;
+
+ /* We hard-code the trace buffer size.
+ At some later time, we should make this configurable. */
+ tinfo->size = 1;
+ tinfo->buffer = mmap (NULL, perf_event_mmap_size (tinfo),
+ PROT_READ, MAP_SHARED, tinfo->file, 0);
+ if (tinfo->buffer == MAP_FAILED)
+ goto err_file;
+
+ return tinfo;
+
+ err_file:
+ close (tinfo->file);
+
+ err:
+ xfree (tinfo);
+ return NULL;
+}
+
+/* See linux-btrace.h. */
+
+int
+linux_disable_btrace (struct btrace_target_info *tinfo)
+{
+ int errcode;
+
+ errno = 0;
+ errcode = munmap (tinfo->buffer, perf_event_mmap_size (tinfo));
+ if (errcode != 0)
+ return errno;
+
+ close (tinfo->file);
+ xfree (tinfo);
+
+ return 0;
+}
+
+/* Check whether the branch trace has changed. */
+
+static int
+linux_btrace_has_changed (struct btrace_target_info *tinfo)
+{
+ volatile struct perf_event_mmap_page *header = perf_event_header (tinfo);
+
+ return header->data_head != tinfo->data_head;
+}
+
+/* See linux-btrace.h. */
+
+VEC (btrace_block_s) *
+linux_read_btrace (struct btrace_target_info *tinfo,
+ enum btrace_read_type type)
+{
+ VEC (btrace_block_s) *btrace = NULL;
+ volatile struct perf_event_mmap_page *header;
+ const uint8_t *begin, *end, *start;
+ unsigned long data_head, retries = 5;
+ size_t buffer_size;
+
+ if (type == btrace_read_new && !linux_btrace_has_changed (tinfo))
+ return NULL;
+
+ header = perf_event_header (tinfo);
+ buffer_size = perf_event_buffer_size (tinfo);
+
+ /* We may need to retry reading the trace. See below. */
+ while (retries--)
+ {
+ data_head = header->data_head;
+
+ /* If there's new trace, let's read it. */
+ if (data_head != tinfo->data_head)
+ {
+ /* Data_head keeps growing; the buffer itself is circular. */
+ begin = perf_event_buffer_begin (tinfo);
+ start = begin + data_head % buffer_size;
+
+ if (data_head <= buffer_size)
+ end = start;
+ else
+ end = perf_event_buffer_end (tinfo);
+
+ btrace = perf_event_read_bts (tinfo, begin, end, start);
+ }
+
+ /* The stopping thread notifies its ptracer before it is scheduled out.
+ On multi-core systems, the debugger might therefore run while the
+ kernel might be writing the last branch trace records.
+
+ Let's check whether the data head moved while we read the trace. */
+ if (data_head == header->data_head)
+ break;
+ }
+
+ tinfo->data_head = data_head;
+
+ return btrace;
+}
+
+#else /* !HAVE_LINUX_PERF_EVENT_H */
+
+/* See linux-btrace.h. */
+
+int
+linux_supports_btrace (void)
+{
+ return 0;
+}
+
+/* See linux-btrace.h. */
+
+struct btrace_target_info *
+linux_enable_btrace (ptid_t ptid)
+{
+ return NULL;
+}
+
+/* See linux-btrace.h. */
+
+int
+linux_disable_btrace (struct btrace_target_info *tinfo)
+{
+ return ENOSYS;
+}
+
+/* See linux-btrace.h. */
+
+VEC (btrace_block_s) *
+linux_read_btrace (struct btrace_target_info *tinfo,
+ enum btrace_read_type type)
+{
+ return NULL;
+}
+
+#endif /* !HAVE_LINUX_PERF_EVENT_H */
diff --git a/gdb/common/linux-btrace.h b/gdb/common/linux-btrace.h
new file mode 100644
index 0000000..d4e8402
--- /dev/null
+++ b/gdb/common/linux-btrace.h
@@ -0,0 +1,77 @@
+/* Linux-dependent part of branch trace support for GDB, and GDBserver.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <markus.t.metzger@intel.com>
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifndef LINUX_BTRACE_H
+#define LINUX_BTRACE_H
+
+#include "btrace-common.h"
+#include "config.h"
+#include "vec.h"
+#include "ptid.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#if HAVE_LINUX_PERF_EVENT_H
+# include <linux/perf_event.h>
+#endif
+
+/* Branch trace target information per thread. */
+struct btrace_target_info
+{
+#if HAVE_LINUX_PERF_EVENT_H
+ /* The Linux perf_event configuration for collecting the branch trace. */
+ struct perf_event_attr attr;
+
+ /* The ptid of this thread. */
+ ptid_t ptid;
+
+ /* The mmap configuration mapping the branch trace perf_event buffer.
+
+ file .. the file descriptor
+ buffer .. the mmapped memory buffer
+ size .. the buffer's size in pages without the configuration page
+ data_head .. the data head from the last read */
+ int file;
+ void *buffer;
+ size_t size;
+ unsigned long data_head;
+#endif /* HAVE_LINUX_PERF_EVENT_H */
+
+ /* The size of a pointer in bits for this thread.
+ The information is used to identify kernel addresses in order to skip
+ records from/to kernel space. */
+ int ptr_bits;
+};
+
+/* Check whether branch tracing is supported. */
+extern int linux_supports_btrace (void);
+
+/* Enable branch tracing for @ptid. */
+extern struct btrace_target_info *linux_enable_btrace (ptid_t ptid);
+
+/* Disable branch tracing and deallocate @tinfo. */
+extern int linux_disable_btrace (struct btrace_target_info *tinfo);
+
+/* Read branch trace data. */
+extern VEC (btrace_block_s) *linux_read_btrace (struct btrace_target_info *,
+ enum btrace_read_type);
+
+#endif /* LINUX_BTRACE_H */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index ee2c400..67124e1 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -155,7 +155,7 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
$(srcdir)/common/vec.c $(srcdir)/common/gdb_vecs.c \
$(srcdir)/common/common-utils.c $(srcdir)/common/xml-utils.c \
$(srcdir)/common/linux-osdata.c $(srcdir)/common/ptid.c \
- $(srcdir)/common/buffer.c
+ $(srcdir)/common/buffer.c $(srcdir)/common/linux-btrace.c
DEPFILES = @GDBSERVER_DEPFILES@
@@ -425,6 +425,8 @@ signals_h = $(srcdir)/../../include/gdb/signals.h $(signals_def)
ptid_h = $(srcdir)/../common/ptid.h
ax_h = $(srcdir)/ax.h
agent_h = $(srcdir)/../common/agent.h
+linux_btrace_h = $(srcdir)/../common/linux-btrace.h \
+ $(srcdir)/../common/btrace-common.h $(vec_h) $(ptid_h)
linux_osdata_h = $(srcdir)/../common/linux-osdata.h
vec_h = $(srcdir)/../common/vec.h
gdb_vecs_h = $(srcdir)/../common/gdb_vecs.h
@@ -544,6 +546,9 @@ agent.o: ../common/agent.c
$(COMPILE) $<
$(POSTCOMPILE)
+linux-btrace.o: ../common/linux-btrace.c $(linux_btrace_h) $(server_h)
+ $(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
+
# We build vasprintf with -DHAVE_CONFIG_H because we want that unit to
# include our config.h file. Otherwise, some system headers do not get
# included, and the compiler emits a warning about implicitly defined
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 20/21] testsuite, gdb.btrace: add btrace tests
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (9 preceding siblings ...)
2013-03-08 9:18 ` [patch v10 02/21] linux, btrace: perf_event based branch tracing Markus Metzger
@ 2013-03-08 9:18 ` Markus Metzger
2013-03-08 13:22 ` Jan Kratochvil
2013-03-08 9:18 ` [patch v10 11/21] record: make it build again Markus Metzger
` (11 subsequent siblings)
22 siblings, 1 reply; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:18 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger, Christian Himpel
From: Christian Himpel <christian.himpel@intel.com>
Recursive function calls are listed as only one function call. This is
marked as a KFAIL with PR gdb/15420.
The discussed crash of gdbserver after continue with btrace target
enabled is tested now as well in the end of the enable.exp. In case of
a gdbserver crash it reports UNRESOLVED, is that appropriate?
2013-03-04 Christian Himpel <christian.himpel@intel.com>
gdb/testsuite
* Makefile.in: Add btrace testsuite.
* configure: Regenerated.
* configure.ac: Add btrace testsuite.
* gdb.btrace/Makefile.in: New file.
* gdb.btrace/enable.c: New file.
* gdb.btrace/enable.exp: New file.
* gdb.btrace/function_call_history.c: New file.
* gdb.btrace/function_call_history.exp: New file.
* gdb.btrace/instruction_history.c: New file.
* gdb.btrace/instruction_history.exp: New file.
* gdb.btrace/x86-instruction_history.S: New file.
* lib/gdb.exp: Add btrace skip proc.
---
gdb/testsuite/Makefile.in | 4 +-
gdb/testsuite/configure | 3 +-
gdb/testsuite/configure.ac | 2 +-
gdb/testsuite/gdb.btrace/Makefile.in | 17 ++
gdb/testsuite/gdb.btrace/enable.c | 24 +++
gdb/testsuite/gdb.btrace/enable.exp | 84 ++++++++
gdb/testsuite/gdb.btrace/function_call_history.c | 45 ++++
gdb/testsuite/gdb.btrace/function_call_history.exp | 219 ++++++++++++++++++++
gdb/testsuite/gdb.btrace/instruction_history.S | 32 +++
gdb/testsuite/gdb.btrace/instruction_history.c | 26 +++
gdb/testsuite/gdb.btrace/instruction_history.exp | 195 +++++++++++++++++
gdb/testsuite/lib/gdb.exp | 68 ++++++
12 files changed, 715 insertions(+), 4 deletions(-)
create mode 100644 gdb/testsuite/gdb.btrace/Makefile.in
create mode 100644 gdb/testsuite/gdb.btrace/enable.c
create mode 100644 gdb/testsuite/gdb.btrace/enable.exp
create mode 100644 gdb/testsuite/gdb.btrace/function_call_history.c
create mode 100644 gdb/testsuite/gdb.btrace/function_call_history.exp
create mode 100644 gdb/testsuite/gdb.btrace/instruction_history.S
create mode 100644 gdb/testsuite/gdb.btrace/instruction_history.c
create mode 100644 gdb/testsuite/gdb.btrace/instruction_history.exp
diff --git a/gdb/testsuite/Makefile.in b/gdb/testsuite/Makefile.in
index b0ace40..348901c 100644
--- a/gdb/testsuite/Makefile.in
+++ b/gdb/testsuite/Makefile.in
@@ -32,8 +32,8 @@ SHELL = @SHELL@
EXEEXT = @EXEEXT@
SUBDIRS = @subdirs@
RPATH_ENVVAR = @RPATH_ENVVAR@
-ALL_SUBDIRS = gdb.ada gdb.arch gdb.asm gdb.base gdb.cell gdb.cp gdb.disasm \
- gdb.dwarf2 gdb.fortran gdb.gdb gdb.hp \
+ALL_SUBDIRS = gdb.ada gdb.arch gdb.asm gdb.base gdb.btrace gdb.cell gdb.cp \
+ gdb.disasm gdb.dwarf2 gdb.fortran gdb.gdb gdb.hp \
gdb.java gdb.linespec gdb.mi gdb.modula2 gdb.multi \
gdb.objc gdb.opencl gdb.opt gdb.pascal gdb.python gdb.server \
gdb.stabs gdb.reverse gdb.threads gdb.trace gdb.xml \
diff --git a/gdb/testsuite/configure b/gdb/testsuite/configure
index 0c8c344..a40c144 100755
--- a/gdb/testsuite/configure
+++ b/gdb/testsuite/configure
@@ -3448,7 +3448,7 @@ done
-ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
+ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.btrace/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -4153,6 +4153,7 @@ do
"gdb.arch/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.arch/Makefile" ;;
"gdb.asm/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.asm/Makefile" ;;
"gdb.base/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.base/Makefile" ;;
+ "gdb.btrace/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.btrace/Makefile" ;;
"gdb.cell/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.cell/Makefile" ;;
"gdb.cp/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.cp/Makefile" ;;
"gdb.disasm/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.disasm/Makefile" ;;
diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac
index 66de8da..9e07021 100644
--- a/gdb/testsuite/configure.ac
+++ b/gdb/testsuite/configure.ac
@@ -89,7 +89,7 @@ AC_EXEEXT
AC_OUTPUT([Makefile \
gdb.ada/Makefile \
- gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile \
+ gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.btrace/Makefile \
gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile \
gdb.fortran/Makefile gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile \
gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile \
diff --git a/gdb/testsuite/gdb.btrace/Makefile.in b/gdb/testsuite/gdb.btrace/Makefile.in
new file mode 100644
index 0000000..f4c06d1
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/Makefile.in
@@ -0,0 +1,17 @@
+VPATH = @srcdir@
+srcdir = @srcdir@
+
+EXECUTABLES = enable function_call_history instruction_history
+
+MISCELLANEOUS =
+
+all info install-info dvi install uninstall installcheck check:
+ @echo "Nothing to be done for $@..."
+
+clean mostlyclean:
+ rm -f *~ *.o *.x *.ci *.sl a.out core
+ rm -f *.dwo *.dwp
+ rm -f $(EXECUTABLES) $(MISCELLANEOUS)
+
+distclean maintainer-clean realclean: clean
+ rm -f Makefile config.status config.log site.* gdb.log gdb.sum
diff --git a/gdb/testsuite/gdb.btrace/enable.c b/gdb/testsuite/gdb.btrace/enable.c
new file mode 100644
index 0000000..ce77651
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/enable.c
@@ -0,0 +1,24 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <christian.himpel@intel.com>
+
+ 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/>. */
+
+int
+main (void)
+{
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.btrace/enable.exp b/gdb/testsuite/gdb.btrace/enable.exp
new file mode 100644
index 0000000..f3acbf8
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/enable.exp
@@ -0,0 +1,84 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# Contributed by Intel Corp. <christian.himpel@intel.com>
+#
+# 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/>.
+
+# check for btrace support
+if { [skip_btrace_tests] } { return -1 }
+
+# start fresh - without an executable
+gdb_exit
+gdb_start
+
+# record cannot be stopped, if it was never active
+gdb_test "record stop" "No record target is currently active\\..*" "record stop without target"
+
+# btrace cannot be enabled without a running inferior
+gdb_test "record btrace" "The program is not being run\\." "record btrace without running program"
+
+# no function and no instruction history without btrace enabled
+gdb_test "record function-call-history" "No record target is currently active\\..*" "record function-call-history without target"
+gdb_test "record instruction-history" "No record target is currently active\\..*" "record instruction-history without target"
+gdb_test "info record" "No record target is currently active\\." "info record without target"
+
+# start inferior
+standard_testfile
+if [prepare_for_testing $testfile.exp $testfile {} {debug}] {
+ return -1
+}
+if ![runto_main] {
+ return -1
+}
+
+# enable btrace
+gdb_test_no_output "record btrace" "record btrace"
+gdb_test "record function-call-history" "No trace\\." "record function-call-history without trace"
+gdb_test "record instruction-history" "No trace\\." "record instruction-history without trace"
+
+# btrace cannot be enabled twice
+gdb_test "record btrace" "The process is already being recorded\\." "record btrace the second time"
+
+# full record cannot be activated as long as btrace is active
+gdb_test "record full" "Process record target already running\\. Use \"record stop\" to stop record target first\\." "record full cannot be enabled"
+
+# no trace recorded yet
+gdb_test "info record" "Active record target: record-btrace\r\nRecorded 0 instructions in 0 functions for thread 1.*\\." "info record without trace"
+
+# stop btrace record
+gdb_test "record stop" "Process record is stopped and all execution logs are deleted\\." "record stop"
+gdb_test "record stop" "No record target is currently active\\..*" "record stop the second time"
+
+# enable btrace again
+gdb_test_no_output "record btrace" "record btrace re-enable"
+gdb_test "record btrace" "The process is already being recorded\\." "record btrace re-enable twice"
+
+# continue to the end and make sure we don't die
+gdb_test "continue" ".*Inferior.*exited.*" "continue to end"
+
+# skip the rerun test when using gdbserver
+# otherwise rerun twice, target should be automatically disabled
+load_lib gdbserver-support.exp
+if [skip_gdbserver_tests] {
+ return 0
+}
+clean_restart $testfile
+if ![runto_main] {
+ return -1
+}
+if ![runto_main] {
+ return -1
+}
diff --git a/gdb/testsuite/gdb.btrace/function_call_history.c b/gdb/testsuite/gdb.btrace/function_call_history.c
new file mode 100644
index 0000000..a76b7c3
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/function_call_history.c
@@ -0,0 +1,45 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <christian.himpel@intel.com>
+
+ 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/>. */
+
+int
+inc (int i)
+{
+ return i+1;
+}
+
+int
+fib (int n)
+{
+ if (n <= 1)
+ return n;
+
+ return fib(n-2) + fib(n-1);
+}
+
+int
+main (void)
+{
+ int i, j;
+
+ for (i = 0; i < 10; i++)
+ j += inc(i);
+
+ j += fib(3); /* bp.1 */
+ return j; /* bp.2 */
+}
diff --git a/gdb/testsuite/gdb.btrace/function_call_history.exp b/gdb/testsuite/gdb.btrace/function_call_history.exp
new file mode 100644
index 0000000..97447e1
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/function_call_history.exp
@@ -0,0 +1,219 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# Contributed by Intel Corp. <christian.himpel@intel.com>
+#
+# 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/>.
+
+# check for btrace support
+if { [skip_btrace_tests] } { return -1 }
+
+# start inferior
+standard_testfile
+if [prepare_for_testing function_call_history.exp $testfile {} {debug}] {
+ return -1
+}
+if ![runto_main] {
+ return -1
+}
+
+# start btrace
+gdb_test_no_output "record btrace"
+
+# set bp after increment loop and continue
+set bp_location [gdb_get_line_number "bp.1" $testfile.c]
+gdb_breakpoint $bp_location
+gdb_continue_to_breakpoint "cont to $bp_location" ".*$testfile.c:$bp_location.*"
+
+# show function call history with unlimited size, we expect to see all 21 entries
+gdb_test_no_output "set record function-call-history-size 0"
+gdb_test "record function-call-history" "
+0\tmain\r
+1\tinc\r
+2\tmain\r
+3\tinc\r
+4\tmain\r
+5\tinc\r
+6\tmain\r
+7\tinc\r
+8\tmain\r
+9\tinc\r
+10\tmain\r
+11\tinc\r
+12\tmain\r
+13\tinc\r
+14\tmain\r
+15\tinc\r
+16\tmain\r
+17\tinc\r
+18\tmain\r
+19\tinc\r
+20\tmain\r" "record function-call-history - with size unlimited"
+
+# show function call history with size of 21, we expect to see all 21 entries
+gdb_test_no_output "set record function-call-history-size 21"
+# show function call history
+gdb_test "record function-call-history 0" "
+0\tmain\r
+1\tinc\r
+2\tmain\r
+3\tinc\r
+4\tmain\r
+5\tinc\r
+6\tmain\r
+7\tinc\r
+8\tmain\r
+9\tinc\r
+10\tmain\r
+11\tinc\r
+12\tmain\r
+13\tinc\r
+14\tmain\r
+15\tinc\r
+16\tmain\r
+17\tinc\r
+18\tmain\r
+19\tinc\r
+20\tmain\r" "record function-call-history - show all 21 entries"
+
+# show first 15 entries
+gdb_test_no_output "set record function-call-history-size 15"
+gdb_test "record function-call-history 0" "
+0\tmain\r
+1\tinc\r
+2\tmain\r
+3\tinc\r
+4\tmain\r
+5\tinc\r
+6\tmain\r
+7\tinc\r
+8\tmain\r
+9\tinc\r
+10\tmain\r
+11\tinc\r
+12\tmain\r
+13\tinc\r
+14\tmain\r" "record function-call-history - show first 15 entries"
+
+# show last 6 entries
+gdb_test "record function-call-history +" "
+15\tinc\r
+16\tmain\r
+17\tinc\r
+18\tmain\r
+19\tinc\r
+20\tmain\r" "record function-call-history - show last 6 entries"
+
+# moving further should not work
+gdb_test "record function-call-history +" "At the end of the branch trace record\\." "record function-call-history - at the end (1)"
+
+# make sure we cannot move any further a second time
+gdb_test "record function-call-history +" "At the end of the branch trace record\\." "record function-call-history - at the end (2)"
+
+# moving back showing the latest 15 function calls
+gdb_test "record function-call-history -" "
+6\tmain\r
+7\tinc\r
+8\tmain\r
+9\tinc\r
+10\tmain\r
+11\tinc\r
+12\tmain\r
+13\tinc\r
+14\tmain\r
+15\tinc\r
+16\tmain\r
+17\tinc\r
+18\tmain\r
+19\tinc\r
+20\tmain\r" "record function-call-history - show last 15 entries"
+
+# moving further back shows the 6 first function calls
+gdb_test "record function-call-history -" "
+0\tmain\r
+1\tinc\r
+2\tmain\r
+3\tinc\r
+4\tmain\r
+5\tinc\r" "record function-call-history - show first 6 entries"
+
+# moving further back shouldn't work
+gdb_test "record function-call-history -" "At the start of the branch trace record\\." "record function-call-history - at the start (1)"
+
+# make sure we cannot move any further back
+gdb_test "record function-call-history -" "At the start of the branch trace record\\." "record function-call-history - at the start (2)"
+
+# moving forward again, but this time with file and line number, expected to see the first 15 entries
+gdb_test "record function-call-history /l +" "
+.*$srcfile:40-41\tmain\r
+.*$srcfile:22-24\tinc\r
+.*$srcfile:40-41\tmain\r
+.*$srcfile:22-24\tinc\r
+.*$srcfile:40-41\tmain\r
+.*$srcfile:22-24\tinc\r
+.*$srcfile:40-41\tmain\r
+.*$srcfile:22-24\tinc\r
+.*$srcfile:40-41\tmain\r
+.*$srcfile:22-24\tinc\r
+.*$srcfile:40-41\tmain\r
+.*$srcfile:22-24\tinc\r
+.*$srcfile:40-41\tmain\r
+.*$srcfile:22-24\tinc\r
+.*$srcfile:40-41\tmain\r" "record function-call-history /l - show first 15 entries"
+
+# moving forward and expect to see the latest 6 entries
+gdb_test "record function-call-history /l +" "
+.*$srcfile:22-24\tinc\r
+.*$srcfile:40-41\tmain\r
+.*$srcfile:22-24\tinc\r
+.*$srcfile:40-41\tmain\r
+.*$srcfile:22-24\tinc\r
+.*$srcfile:40-43\tmain\r" "record function-call-history /l - show last 6 entries"
+
+# moving further forward shouldn't work
+gdb_test "record function-call-history /l +" "At the end of the branch trace record\\." "record function-call-history /l - at the end (1)"
+gdb_test "record function-call-history /l" "At the end of the branch trace record\\." "record function-call-history /l - at the end (2)"
+
+set expected_range "3\tinc\r
+4\tmain\r
+5\tinc\r
+6\tmain\r
+7\tinc\r
+8\tmain\r
+9\tinc\r"
+
+# show functions in instruction range
+gdb_test "record function-call-history 3,10" $expected_range "absolute instruction range"
+gdb_test "record function-call-history 3,+7" $expected_range "relative positive instruction range"
+gdb_test "record function-call-history 10,-7" $expected_range "relative negative instruction range"
+
+# set bp after fib recursion and continue
+set bp_location [gdb_get_line_number "bp.2" $testfile.c]
+gdb_breakpoint $bp_location
+gdb_continue_to_breakpoint "cont to $bp_location" ".*$testfile.c:$bp_location.*"
+
+# at this point we expect to have main, fib, ..., fib, main, where fib occurs 8 times,
+# so we limit the output to only show the latest 10 function calls
+gdb_test_no_output "set record function-call-history-size 10"
+set message "show recursive function call history"
+gdb_test_multiple "record function-call-history" $message {
+ -re "13\tmain\r\n14\tfib\r\n15\tfib\r\n16\tfib\r\n17\tfib\r\n18\tfib\r\n19\tfib\r\n20\tfib\r\n21\tfib\r\n22 main\r\n$gdb_prompt $" {
+ pass $message
+ }
+ -re "13\tinc\r\n14\tmain\r\n15\tinc\r\n16\tmain\r\n17\tinc\r\n18\tmain\r\n19\tinc\r\n20\tmain\r\n21\tfib\r\n22\tmain\r\n$gdb_prompt $" {
+ # recursive function calls appear only as 1 call
+ kfail "gdb/15240" $message
+ }
+}
diff --git a/gdb/testsuite/gdb.btrace/instruction_history.S b/gdb/testsuite/gdb.btrace/instruction_history.S
new file mode 100644
index 0000000..5c74b46
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/instruction_history.S
@@ -0,0 +1,32 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <christian.himpel@intel.com>
+
+ 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/>. */
+
+ .text
+ .globl loop
+ .type loop, @function
+
+loop:
+ movl $0x2, %eax /* bp.1 */
+.L1:
+ cmpl $0, %eax
+ je .L2
+ decl %eax
+ jmp .L1
+.L2:
+ ret /* bp.2 */
diff --git a/gdb/testsuite/gdb.btrace/instruction_history.c b/gdb/testsuite/gdb.btrace/instruction_history.c
new file mode 100644
index 0000000..c2814fb
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/instruction_history.c
@@ -0,0 +1,26 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <christian.himpel@intel.com>
+
+ 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/>. */
+
+int
+main (void)
+{
+ /* loop is declared in x86-instruction_history.S */
+ loop ();
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.btrace/instruction_history.exp b/gdb/testsuite/gdb.btrace/instruction_history.exp
new file mode 100644
index 0000000..c1a61b7
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/instruction_history.exp
@@ -0,0 +1,195 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# Contributed by Intel Corp. <christian.himpel@intel.com>
+#
+# 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/>.
+
+# check for btrace support
+if { [skip_btrace_tests] } { return -1 }
+
+# compile and run to main
+standard_testfile .c .S
+if [prepare_for_testing $testfile.exp $testfile "$srcfile $srcfile2" {debug}] {
+ return -1
+}
+if ![runto_main] {
+ return -1
+}
+
+# set bp before loop and continue
+set bp_location [gdb_get_line_number "bp.1" $srcfile2]
+gdb_breakpoint $srcfile2:$bp_location
+gdb_continue_to_breakpoint "cont to $bp_location" ".*$srcfile2:$bp_location.*"
+
+# start btrace
+gdb_test_no_output "record btrace"
+
+# set bp after loop and continue
+set bp_location [gdb_get_line_number "bp.2" $srcfile2]
+gdb_breakpoint $srcfile2:$bp_location
+gdb_continue_to_breakpoint "cont to $bp_location" ".*$srcfile2:$bp_location.*"
+
+# The following test cases test if "browsing" through the
+# instruction history works as expected. So for the tests
+# it is necessary to count the number of lines that are
+# shown by the "record instruction-history" command.
+
+set testname "determine number of recorded instructions"
+gdb_test_multiple "info record" $testname {
+ -re "Active record target: record-btrace\r\nRecorded \(\[0-9\]*\) instructions in \(\[0-9\]*\) functions for thread 1 .*\\.\r\n$gdb_prompt $" {
+ set traced $expect_out(1,string)
+ set traced_functions $expect_out(2,string)
+ pass $testname
+ }
+}
+
+# we have exactly 7 instructions here
+set message "exactly 7 instructions"
+if { $traced != 7 } {
+ fail $message
+} else {
+ pass $message
+}
+
+# test that we see the expected instructions
+gdb_test "record instruction-history 1,6" "
+1\t 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>:\tje 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r
+2\t 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>:\tdec %eax\r
+3\t 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>:\tjmp 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r
+4\t 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>:\tcmp \\\$0x0,%eax\r
+5\t 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>:\tje 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r"
+
+gdb_test "record instruction-history /f 1,+5" "
+1\t 0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tje 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r
+2\t 0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tdec %eax\r
+3\t 0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tjmp 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r
+4\t 0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tcmp \\\$0x0,%eax\r
+5\t 0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tje 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r"
+
+gdb_test "record instruction-history /p 6,-5" "
+1\t0x\[0-9a-f\]+ <loop\\+\[0-9\]+>:\tje 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r
+2\t0x\[0-9a-f\]+ <loop\\+\[0-9\]+>:\tdec %eax\r
+3\t0x\[0-9a-f\]+ <loop\\+\[0-9\]+>:\tjmp 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r
+4\t0x\[0-9a-f\]+ <loop\\+\[0-9\]+>:\tcmp \\\$0x0,%eax\r
+5\t0x\[0-9a-f\]+ <loop\\+\[0-9\]+>:\tje 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r"
+
+gdb_test "record instruction-history /pf 1,6" "
+1\t0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tje 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r
+2\t0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tdec %eax\r
+3\t0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tjmp 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r
+4\t0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tcmp \\\$0x0,%eax\r
+5\t0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tje 0x\[0-9a-f\]+ <loop\\+\[0-9\]+>\r"
+
+# the following tests are checking the iterators
+# to avoid lots of regexps, we just check the number of lines that
+# were printed during command execution.
+
+# test_lines_output returns the output lines from command as a list.
+proc test_lines_output { command message } {
+ global gdb_prompt
+ set message "test_lines_output: $message"
+ gdb_test_multiple $command $message {
+ -re "\n\(.*\)\r\n$gdb_prompt $" {
+ return [split [string trim $expect_out(1,string)] "\n"]
+ }
+ }
+}
+
+# test_lines_length returns the number of lines from command.
+proc test_lines_length { command message } {
+ return [llength [test_lines_output $command $message]]
+}
+
+# show instruction history with unlimited size, we expect to see
+# all $traced instructions
+gdb_test_no_output "set record instruction-history-size 0"
+set message "record instruction-history - unlimited"
+set lines [test_lines_length "record instruction-history 0" $message]
+if { $traced != $lines } {
+ fail $message
+} else {
+ pass $message
+}
+
+gdb_test_no_output "set record instruction-history-size $traced"
+set message "record instruction-history - traced"
+set lines [test_lines_length "record instruction-history 0" $message]
+if { $traced != $lines } {
+ fail $message
+} else {
+ pass $message
+}
+
+# test that the iterator works
+set history_size 3
+gdb_test_no_output "set record instruction-history-size $history_size"
+set message "browse history forward start"
+set lines [test_lines_length "record instruction-history 0" $message]
+if { $lines != $history_size } {
+ fail $message
+} else {
+ pass $message
+}
+
+set message "browse history forward middle"
+set lines [test_lines_length "record instruction-history +" $message]
+if { $lines != $history_size } {
+ fail $message
+} else {
+ pass $message
+}
+
+set message "browse history forward last"
+set lines [test_lines_length "record instruction-history +" $message]
+if { $lines != 1 } {
+ fail $message
+} else {
+ pass $message
+}
+
+gdb_test "record instruction-history" "At the end of the branch trace record\\." "browse history forward beyond 1"
+
+# make sure we cannot move further
+gdb_test "record instruction-history" "At the end of the branch trace record\\." "browse history forward beyond 2"
+
+set message "browse history backward last"
+set lines [test_lines_length "record instruction-history -" $message]
+if { $lines != $history_size } {
+ fail $message
+} else {
+ pass $message
+}
+
+set message "browse history backward middle"
+set lines [test_lines_length "record instruction-history -" $message]
+if { $lines != $history_size } {
+ fail $message
+} else {
+ pass $message
+}
+
+set message "browse history backward first"
+set lines [test_lines_length "record instruction-history -" $message]
+if { $lines != 1 } {
+ fail $message
+} else {
+ pass $message
+}
+
+gdb_test "record instruction-history -" "At the start of the branch trace record\\." "browse history backward beyond 1"
+
+# make sure we cannot move further back
+gdb_test "record instruction-history -" "At the start of the branch trace record\\." "browse history backward beyond 2"
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 8b16b38..f7f2ac9 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -2097,6 +2097,74 @@ proc skip_vsx_tests {} {
return $skip_vsx_tests_saved
}
+# Run a test on the target to see if it supports btrace hardware. Return 0 if so,
+# 1 if it does not. Based on 'check_vmx_hw_available' from the GCC testsuite.
+
+proc skip_btrace_tests {} {
+ global skip_btrace_tests_saved
+ global srcdir subdir gdb_prompt inferior_exited_re
+
+ # Use the cached value, if it exists.
+ set me "skip_btrace_tests"
+ if [info exists skip_btrace_tests_saved] {
+ verbose "$me: returning saved $skip_btrace_tests_saved" 2
+ return $skip_btrace_tests_saved
+ }
+
+ if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } {
+ verbose "$me: target does not support btrace, returning 1" 2
+ return [set skip_btrace_tests_saved 1]
+ }
+
+ # Set up, compile, and execute a test program.
+ # Include the current process ID in the file names to prevent conflicts
+ # with invocations for multiple testsuites.
+ set src [standard_output_file btrace[pid].c]
+ set exe [standard_output_file btrace[pid].x]
+
+ set f [open $src "w"]
+ puts $f "int main(void) { return 0; }"
+ close $f
+
+ verbose "$me: compiling testfile $src" 2
+ set compile_flags {debug nowarnings quiet}
+ set lines [gdb_compile $src $exe executable $compile_flags]
+ file delete $src
+
+ if ![string match "" $lines] then {
+ verbose "$me: testfile compilation failed, returning 1" 2
+ return [set skip_btrace_tests_saved 1]
+ }
+
+ # No error message, compilation succeeded so now run it via gdb.
+
+ clean_restart btrace[pid].x
+ if ![runto_main] {
+ return [set skip_btrace_tests_saved 1]
+ }
+ # In case of an unexpected output, we return 2 as a fail value.
+ set skip_btrace_tests_saved 2
+ gdb_test_multiple "record btrace" "check btrace support" {
+ -re "You can't do that when your target is.*\r\n$gdb_prompt $" {
+ set skip_btrace_tests_saved 1
+ }
+ -re "Target does not support branch tracing.*\r\n$gdb_prompt $" {
+ set skip_btrace_tests_saved 1
+ }
+ -re "Could not enable branch tracing.*\r\n$gdb_prompt $" {
+ set skip_btrace_tests_saved 1
+ }
+ -re "^record btrace\r\n$gdb_prompt $" {
+ set skip_btrace_tests_saved 0
+ }
+ }
+ gdb_exit
+ remote_file build delete $exe
+
+ verbose "$me: returning $skip_btrace_tests_saved" 2
+ return $skip_btrace_tests_saved
+}
+
# Skip all the tests in the file if you are not on an hppa running
# hpux target.
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [patch v10 20/21] testsuite, gdb.btrace: add btrace tests
2013-03-08 9:18 ` [patch v10 20/21] testsuite, gdb.btrace: add btrace tests Markus Metzger
@ 2013-03-08 13:22 ` Jan Kratochvil
2013-03-08 13:28 ` Metzger, Markus T
0 siblings, 1 reply; 34+ messages in thread
From: Jan Kratochvil @ 2013-03-08 13:22 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger, Christian Himpel
On Fri, 08 Mar 2013 10:16:07 +0100, Markus Metzger wrote:
> From: Christian Himpel <christian.himpel@intel.com>
>
> Recursive function calls are listed as only one function call. This is
> marked as a KFAIL with PR gdb/15420.
typo: 15240
But it is OK in the sources.
> The discussed crash of gdbserver after continue with btrace target
> enabled is tested now as well in the end of the enable.exp. In case of
> a gdbserver crash it reports UNRESOLVED, is that appropriate?
PASS: gdb.btrace/enable.exp: record btrace re-enable twice
ERROR: Process no longer exists
UNRESOLVED: gdb.btrace/enable.exp: continue to end
OK.
> gdb/testsuite
> * Makefile.in: Add btrace testsuite.
> * configure: Regenerated.
> * configure.ac: Add btrace testsuite.
> * gdb.btrace/Makefile.in: New file.
> * gdb.btrace/enable.c: New file.
> * gdb.btrace/enable.exp: New file.
> * gdb.btrace/function_call_history.c: New file.
> * gdb.btrace/function_call_history.exp: New file.
> * gdb.btrace/instruction_history.c: New file.
> * gdb.btrace/instruction_history.exp: New file.
> * gdb.btrace/x86-instruction_history.S: New file.
> * lib/gdb.exp: Add btrace skip proc.
OK with the bit below.
> --- /dev/null
> +++ b/gdb/testsuite/gdb.btrace/instruction_history.c
> @@ -0,0 +1,26 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2013 Free Software Foundation, Inc.
> +
> + Contributed by Intel Corp. <christian.himpel@intel.com>
> +
> + 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/>. */
> +
> +int
> +main (void)
> +{
> + /* loop is declared in x86-instruction_history.S */
/* loop is defined in 'instruction_history.S'. */
> + loop ();
> + return 0;
> +}
Thanks,
Jan
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [patch v10 20/21] testsuite, gdb.btrace: add btrace tests
2013-03-08 13:22 ` Jan Kratochvil
@ 2013-03-08 13:28 ` Metzger, Markus T
2013-03-08 13:33 ` Jan Kratochvil
0 siblings, 1 reply; 34+ messages in thread
From: Metzger, Markus T @ 2013-03-08 13:28 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, markus.t.metzger, Himpel, Christian
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Friday, March 08, 2013 2:22 PM
> > + /* loop is declared in x86-instruction_history.S */
>
> /* loop is defined in 'instruction_history.S'. */
I got the feedback in a review of the earlier btrace tests that x86-specific
assembly files need to be prefixed with either x86-, ia32-, or amd64- depending
on the architecture for which they are intended.
Regards,
Markus.
Intel GmbH
Dornacher Strasse 1
85622 Feldkirchen/Muenchen, Deutschland
Sitz der Gesellschaft: Feldkirchen bei Muenchen
Geschaeftsfuehrer: Christian Lamprechter, Hannes Schwaderer, Douglas Lusk
Registergericht: Muenchen HRB 47456
Ust.-IdNr./VAT Registration No.: DE129385895
Citibank Frankfurt a.M. (BLZ 502 109 00) 600119052
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [patch v10 20/21] testsuite, gdb.btrace: add btrace tests
2013-03-08 13:28 ` Metzger, Markus T
@ 2013-03-08 13:33 ` Jan Kratochvil
0 siblings, 0 replies; 34+ messages in thread
From: Jan Kratochvil @ 2013-03-08 13:33 UTC (permalink / raw)
To: Metzger, Markus T; +Cc: gdb-patches, markus.t.metzger, Himpel, Christian
On Fri, 08 Mar 2013 14:27:44 +0100, Metzger, Markus T wrote:
> > > + /* loop is declared in x86-instruction_history.S */
> >
> > /* loop is defined in 'instruction_history.S'. */
>
> I got the feedback in a review of the earlier btrace tests that x86-specific
> assembly files need to be prefixed with either x86-, ia32-, or amd64- depending
> on the architecture for which they are intended.
OK but the file is already renamed in the patch. BTW the ChangeLog is not
updated for the rename:
* gdb.btrace/x86-instruction_history.S: New file.
->
* gdb.btrace/instruction_history.S: New file.
I won't argue against another maintainer opinion, follow either way you
prefer. Just the code comment should contain the name actually used in the
patch.
Thanks,
Jan
^ permalink raw reply [flat|nested] 34+ messages in thread
* [patch v10 11/21] record: make it build again
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (10 preceding siblings ...)
2013-03-08 9:18 ` [patch v10 20/21] testsuite, gdb.btrace: add btrace tests Markus Metzger
@ 2013-03-08 9:18 ` Markus Metzger
2013-03-08 9:19 ` [patch v10 12/21] record-full.c: rename record_ in record_full_ Markus Metzger
` (10 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:18 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Complete the split of record into record.c and record-full.c
I ran the gdb.reverse suite on 64bit IA gnu/linux - no regressions.
This will be merged with the previous patch to make each commit build.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* target.h (target_ops): Add new fields to_info_record,
to_save_record, to_delete_record, to_record_is_replaying,
to_goto_record_begin, to_goto_record_end, to_goto_record.
(target_info_record): New.
(target_save_record): New.
(target_supports_delete_record): New.
(target_delete_record): New.
(target_record_is_replaying): New.
(target_goto_record_begin): New.
(target_goto_record_end): New.
(target_goto_record): New.
* target.c (target_info_record): New.
(target_save_record): New.
(target_supports_delete_record): New.
(target_delete_record): New.
(target_record_is_replaying): New.
(target_goto_record_begin): New.
(target_goto_record_end): New.
(target_goto_record): New.
* record.h: Declare struct cmd_list_element.
(record_cmdlist): New declaration.
(set_record_cmdlist): New declaration.
(show_record_cmdlist): New declaration.
(info_record_cmdlist): New declaration.
(cmd_record_goto): New declaration.
* record.c: Remove unnecessary includes.
Include inferior.h.
(cmd_record_goto): Remove declaration.
(record_cmdlist): Now extern. Initialize.
(set_record_cmdlist): Now extern. Initialize.
(show_record_cmdlist): Now extern. Initialize.
(info_record_cmdlist): Now extern. Initialize.
(find_record_target): New.
(require_record_target): New.
(cmd_record_start): Update.
(cmd_record_delete): Remove target-specific code.
Call target_delete_record.
(cmd_record_stop): Unpush any record target.
(set_record_insn_max_num): Move to record-full.c
(set_record_command): Add comment.
(show_record_command): Add comment.
(info_record_command): Update comment.
Remove target-specific code.
Call the record target's to_info_record.
(cmd_record_start): New.
(cmd_record_goto): Now extern.
Remove target-specific code.
Call target_goto_begin, target_goto_end, or target_goto.
(_initialize_record): Move record target ops initialization to
record-full.c.
Change "record" command help text.
Move "record restore", "record set", and "record show" commands to
record-full.c.
* Makefile.in (SFILES): Add record-full.c.
(HFILES_NO_SRCDIR): Add record-full.h.
(COMMON_OBS): Add record-full.o.
* amd64-linux-tdep.c: Include record-full.h instead of record.h.
* arm-tdep.c: Include record-full.h.
* i386-linux-tdep.c: Include record-full.h instead of record.h.
* i386-tdep.c: Include record-full.h.
* infrun.c: Include record-full.h.
* linux-record.c: Include record-full.h.
* moxie-tdep.c: Include record-full.h.
* record-full.c: Include record-full.h.
Change module comment.
(set_record_full_cmdlist): New.
(show_record_full_cmdlist): New.
(record_full_cmdlist): New.
(record_goto_insn): New declaration.
(record_save): New declaration.
(record_check_insn_num): Change query string.
(record_info): New.
(record_delete): New.
(record_is_replaying): New.
(record_goto_entry): New.
(record_goto_begin): New.
(record_goto_end): New.
(record_goto): New.
(init_record_ops): Update.
(init_record_core_ops): Update.
(cmd_record_save): Rename to record_save. Remove target and arg checks.
(cmd_record_start): New.
(set_record_insn_max_num): Moved from record.c
(set_record_full_command): New.
(show_record_full_command): New.
(_initialize_record_full): New.
---
gdb/Makefile.in | 5 +-
gdb/amd64-linux-tdep.c | 2 +-
gdb/arm-tdep.c | 1 +
gdb/i386-linux-tdep.c | 2 +-
gdb/i386-tdep.c | 1 +
gdb/infrun.c | 1 +
gdb/linux-record.c | 1 +
gdb/moxie-tdep.c | 1 +
gdb/record-full.c | 319 +++++++++++++++++++++++++++++++++++++++++++++---
gdb/record.c | 288 +++++++++++++++-----------------------------
gdb/record.h | 11 ++
gdb/target.c | 130 ++++++++++++++++++++
gdb/target.h | 44 +++++++
13 files changed, 592 insertions(+), 214 deletions(-)
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index e11e3d1..a36d576 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -753,7 +753,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
valarith.c valops.c valprint.c value.c varobj.c common/vec.c \
xml-tdesc.c xml-support.c \
inferior.c gdb_usleep.c \
- record.c gcore.c \
+ record.c record-full.c gcore.c \
jit.c \
xml-syscall.c \
annotate.c common/signals.c copying.c dfp.c gdb.c inf-child.c \
@@ -829,6 +829,7 @@ dicos-tdep.h filesystem.h gcore.h gdb_wchar.h hppabsd-tdep.h \
i386-darwin-tdep.h i386-nat.h linux-record.h moxie-tdep.h \
osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
python/python-internal.h python/python.h ravenscar-thread.h record.h \
+record-full.h \
solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
gnulib/import/extra/snippet/arg-nonnull.h gnulib/import/extra/snippet/c++defs.h \
gnulib/import/extra/snippet/warn-on-use.h \
@@ -926,7 +927,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
prologue-value.o memory-map.o memrange.o \
xml-support.o xml-syscall.o xml-utils.o \
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
- inferior.o osdata.o gdb_usleep.o record.o gcore.o \
+ inferior.o osdata.o gdb_usleep.o record.o record-full.o gcore.o \
gdb_vecs.o jit.o progspace.o skip.o probe.o \
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
format.o registry.o btrace.o
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index e262c19..4f383db 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -48,7 +48,7 @@
/* The syscall's XML filename for i386. */
#define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
-#include "record.h"
+#include "record-full.h"
#include "linux-record.h"
/* Supported register note sections. */
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index d890dcb..33b8d5d 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -56,6 +56,7 @@
#include "vec.h"
#include "record.h"
+#include "record-full.h"
#include "features/arm-with-m.c"
#include "features/arm-with-m-fpa-layout.c"
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
index 15a1247..f96fc81 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -44,7 +44,7 @@
/* The syscall's XML filename for i386. */
#define XML_SYSCALL_FILENAME_I386 "syscalls/i386-linux.xml"
-#include "record.h"
+#include "record-full.h"
#include "linux-record.h"
#include <stdint.h>
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 637c44d..a36a83d 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -52,6 +52,7 @@
#include "i386-xstate.h"
#include "record.h"
+#include "record-full.h"
#include <stdint.h>
#include "features/i386/i386.c"
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 1cf30fe..1e2addc 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -49,6 +49,7 @@
#include "mi/mi-common.h"
#include "event-top.h"
#include "record.h"
+#include "record-full.h"
#include "inline-frame.h"
#include "jit.h"
#include "tracepoint.h"
diff --git a/gdb/linux-record.c b/gdb/linux-record.c
index c769700..2b62219 100644
--- a/gdb/linux-record.c
+++ b/gdb/linux-record.c
@@ -22,6 +22,7 @@
#include "gdbtypes.h"
#include "regcache.h"
#include "record.h"
+#include "record-full.h"
#include "linux-record.h"
/* These macros are the values of the first argument of system call
diff --git a/gdb/moxie-tdep.c b/gdb/moxie-tdep.c
index 4b250f8..fc0f85c 100644
--- a/gdb/moxie-tdep.c
+++ b/gdb/moxie-tdep.c
@@ -37,6 +37,7 @@
#include "trad-frame.h"
#include "dis-asm.h"
#include "record.h"
+#include "record-full.h"
#include "gdb_assert.h"
diff --git a/gdb/record-full.c b/gdb/record-full.c
index ff22b95..1cbd724 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -28,6 +28,7 @@
#include "gdbcore.h"
#include "exec.h"
#include "record.h"
+#include "record-full.h"
#include "elf-bfd.h"
#include "gcore.h"
#include "event-loop.h"
@@ -37,7 +38,7 @@
#include <signal.h>
-/* This module implements "target record", also known as "process
+/* This module implements "target record-full", also known as "process
record and replay". This target sits on top of a "normal" target
(a target that "has execution"), and provides a record and replay
functionality, including reverse debugging.
@@ -205,6 +206,13 @@ static ULONGEST record_insn_count;
static struct target_ops record_ops;
static struct target_ops record_core_ops;
+/* Command lists for "set/show record full". */
+static struct cmd_list_element *set_record_full_cmdlist;
+static struct cmd_list_element *show_record_full_cmdlist;
+
+/* Command list for "record full". */
+static struct cmd_list_element *record_full_cmdlist;
+
/* The beneath function pointers. */
static struct target_ops *record_beneath_to_resume_ops;
static void (*record_beneath_to_resume) (struct target_ops *, ptid_t, int,
@@ -234,6 +242,10 @@ static int (*record_beneath_to_stopped_data_address) (struct target_ops *,
CORE_ADDR *);
static void (*record_beneath_to_async) (void (*) (enum inferior_event_type, void *), void *);
+static void record_goto_insn (struct record_entry *entry,
+ enum exec_direction_kind dir);
+static void record_save (char *recfilename);
+
/* Alloc and free functions for record_reg, record_mem, and record_end
entries. */
@@ -550,7 +562,7 @@ record_check_insn_num (int set_terminal)
target_terminal_ours ();
q = yquery (_("Do you want to auto delete previous execution "
"log entries when record/replay buffer becomes "
- "full (record stop-at-limit)?"));
+ "full (record full stop-at-limit)?"));
if (set_terminal)
target_terminal_inferior ();
if (q)
@@ -1934,9 +1946,140 @@ record_execution_direction (void)
}
static void
+record_info (void)
+{
+ struct record_entry *p;
+
+ if (RECORD_IS_REPLAY)
+ printf_filtered (_("Replay mode:\n"));
+ else
+ printf_filtered (_("Record mode:\n"));
+
+ /* Find entry for first actual instruction in the log. */
+ for (p = record_first.next;
+ p != NULL && p->type != record_end;
+ p = p->next)
+ ;
+
+ /* Do we have a log at all? */
+ if (p != NULL && p->type == record_end)
+ {
+ /* Display instruction number for first instruction in the log. */
+ printf_filtered (_("Lowest recorded instruction number is %s.\n"),
+ pulongest (p->u.end.insn_num));
+
+ /* If in replay mode, display where we are in the log. */
+ if (RECORD_IS_REPLAY)
+ printf_filtered (_("Current instruction number is %s.\n"),
+ pulongest (record_list->u.end.insn_num));
+
+ /* Display instruction number for last instruction in the log. */
+ printf_filtered (_("Highest recorded instruction number is %s.\n"),
+ pulongest (record_insn_count));
+
+ /* Display log count. */
+ printf_filtered (_("Log contains %d instructions.\n"),
+ record_insn_num);
+ }
+ else
+ printf_filtered (_("No instructions have been logged.\n"));
+
+ /* Display max log size. */
+ printf_filtered (_("Max logged instructions is %d.\n"),
+ record_insn_max_num);
+}
+
+/* The "to_record_delete" target method. */
+
+static void
+record_delete (void)
+{
+ record_list_release_following (record_list);
+}
+
+/* The "to_record_is_replaying" target method. */
+
+static int
+record_is_replaying (void)
+{
+ return RECORD_IS_REPLAY;
+}
+
+/* Go to a specific entry. */
+
+static void
+record_goto_entry (struct record_entry *p)
+{
+ if (p == NULL)
+ error (_("Target insn not found."));
+ else if (p == record_list)
+ error (_("Already at target insn."));
+ else if (p->u.end.insn_num > record_list->u.end.insn_num)
+ {
+ printf_filtered (_("Go forward to insn number %s\n"),
+ pulongest (p->u.end.insn_num));
+ record_goto_insn (p, EXEC_FORWARD);
+ }
+ else
+ {
+ printf_filtered (_("Go backward to insn number %s\n"),
+ pulongest (p->u.end.insn_num));
+ record_goto_insn (p, EXEC_REVERSE);
+ }
+
+ registers_changed ();
+ reinit_frame_cache ();
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+}
+
+/* The "to_goto_record_begin" target method. */
+
+static void
+record_goto_begin (void)
+{
+ struct record_entry *p = NULL;
+
+ for (p = &record_first; p != NULL; p = p->next)
+ if (p->type == record_end)
+ break;
+
+ record_goto_entry (p);
+}
+
+/* The "to_goto_record_end" target method. */
+
+static void
+record_goto_end (void)
+{
+ struct record_entry *p = NULL;
+
+ for (p = record_list; p->next != NULL; p = p->next)
+ ;
+ for (; p!= NULL; p = p->prev)
+ if (p->type == record_end)
+ break;
+
+ record_goto_entry (p);
+}
+
+/* The "to_goto_record" target method. */
+
+static void
+record_goto (ULONGEST target_insn)
+{
+ struct record_entry *p = NULL;
+
+ for (p = &record_first; p != NULL; p = p->next)
+ if (p->type == record_end && p->u.end.insn_num == target_insn)
+ break;
+
+ record_goto_entry (p);
+}
+
+static void
init_record_ops (void)
{
- record_ops.to_shortname = "record";
+ record_ops.to_shortname = "record-full";
record_ops.to_longname = "Process record and replay target";
record_ops.to_doc =
"Log program while executing and replay execution from log.";
@@ -1964,6 +2107,13 @@ init_record_ops (void)
record_ops.to_can_async_p = record_can_async_p;
record_ops.to_is_async_p = record_is_async_p;
record_ops.to_execution_direction = record_execution_direction;
+ record_ops.to_info_record = record_info;
+ record_ops.to_save_record = record_save;
+ record_ops.to_delete_record = record_delete;
+ record_ops.to_record_is_replaying = record_is_replaying;
+ record_ops.to_goto_record_begin = record_goto_begin;
+ record_ops.to_goto_record_end = record_goto_end;
+ record_ops.to_goto_record = record_goto;
record_ops.to_magic = OPS_MAGIC;
}
@@ -2189,6 +2339,12 @@ init_record_core_ops (void)
record_core_ops.to_can_async_p = record_can_async_p;
record_core_ops.to_is_async_p = record_is_async_p;
record_core_ops.to_execution_direction = record_execution_direction;
+ record_core_ops.to_info_record = record_info;
+ record_core_ops.to_delete_record = record_delete;
+ record_core_ops.to_record_is_replaying = record_is_replaying;
+ record_core_ops.to_goto_record_begin = record_goto_begin;
+ record_core_ops.to_goto_record_end = record_goto_end;
+ record_core_ops.to_goto_record = record_goto;
record_core_ops.to_magic = OPS_MAGIC;
}
@@ -2493,9 +2649,8 @@ record_save_cleanups (void *data)
format, with an extra section for our data. */
static void
-cmd_record_save (char *args, int from_tty)
+record_save (char *recfilename)
{
- char *recfilename, recfilename_buffer[40];
struct record_entry *cur_record_list;
uint32_t magic;
struct regcache *regcache;
@@ -2507,20 +2662,6 @@ cmd_record_save (char *args, int from_tty)
asection *osec = NULL;
int bfd_offset = 0;
- if (strcmp (current_target.to_shortname, "record") != 0)
- error (_("This command can only be used with target 'record'.\n"
- "Use 'target record' first.\n"));
-
- if (args && *args)
- recfilename = args;
- else
- {
- /* Default recfile name is "gdb_record.PID". */
- snprintf (recfilename_buffer, sizeof (recfilename_buffer),
- "gdb_record.%d", PIDGET (inferior_ptid));
- recfilename = recfilename_buffer;
- }
-
/* Open the save file. */
if (record_debug)
fprintf_unfiltered (gdb_stdlog, "Saving execution log to core file '%s'\n",
@@ -2736,3 +2877,143 @@ record_goto_insn (struct record_entry *entry,
} while (record_list != entry);
do_cleanups (set_cleanups);
}
+
+/* Alias for "target record-full". */
+
+static void
+cmd_record_start (char *args, int from_tty)
+{
+ execute_command ("target record-full", from_tty);
+}
+
+static void
+set_record_insn_max_num (char *args, int from_tty, struct cmd_list_element *c)
+{
+ if (record_insn_num > record_insn_max_num && record_insn_max_num)
+ {
+ /* Count down record_insn_num while releasing records from list. */
+ while (record_insn_num > record_insn_max_num)
+ {
+ record_list_release_first ();
+ record_insn_num--;
+ }
+ }
+}
+
+/* The "set record full" command. */
+
+static void
+set_record_full_command (char *args, int from_tty)
+{
+ printf_unfiltered (_("\"set record full\" must be followed "
+ "by an apporpriate subcommand.\n"));
+ help_list (set_record_full_cmdlist, "set record full ", all_commands,
+ gdb_stdout);
+}
+
+/* The "show record full" command. */
+
+static void
+show_record_full_command (char *args, int from_tty)
+{
+ cmd_show_list (show_record_full_cmdlist, from_tty, "");
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_record_full;
+
+void
+_initialize_record_full (void)
+{
+ struct cmd_list_element *c;
+
+ /* Init record_first. */
+ record_first.prev = NULL;
+ record_first.next = NULL;
+ record_first.type = record_end;
+
+ init_record_ops ();
+ add_target (&record_ops);
+ add_deprecated_target_alias (&record_ops, "record");
+ init_record_core_ops ();
+ add_target (&record_core_ops);
+
+ add_prefix_cmd ("full", class_obscure, cmd_record_start,
+ _("Start full execution recording."), &record_full_cmdlist,
+ "record full ", 0, &record_cmdlist);
+
+ c = add_cmd ("restore", class_obscure, cmd_record_restore,
+ _("Restore the execution log from a file.\n\
+Argument is filename. File must be created with 'record save'."),
+ &record_full_cmdlist);
+ set_cmd_completer (c, filename_completer);
+
+ /* Deprecate the old version without "full" prefix. */
+ c = add_alias_cmd ("restore", "full restore", class_obscure, 1,
+ &record_cmdlist);
+ set_cmd_completer (c, filename_completer);
+ deprecate_cmd (c, "record full restore");
+
+ add_prefix_cmd ("full", class_support, set_record_full_command,
+ _("Set record options"), &set_record_full_cmdlist,
+ "set record full ", 0, &set_record_cmdlist);
+
+ add_prefix_cmd ("full", class_support, show_record_full_command,
+ _("Show record options"), &show_record_full_cmdlist,
+ "show record full ", 0, &show_record_cmdlist);
+
+ /* Record instructions number limit command. */
+ add_setshow_boolean_cmd ("stop-at-limit", no_class,
+ &record_stop_at_limit, _("\
+Set whether record/replay stops when record/replay buffer becomes full."), _("\
+Show whether record/replay stops when record/replay buffer becomes full."),
+ _("Default is ON.\n\
+When ON, if the record/replay buffer becomes full, ask user what to do.\n\
+When OFF, if the record/replay buffer becomes full,\n\
+delete the oldest recorded instruction to make room for each new one."),
+ NULL, NULL,
+ &set_record_full_cmdlist, &show_record_full_cmdlist);
+
+ c = add_alias_cmd ("stop-at-limit", "full stop-at-limit", no_class, 1,
+ &set_record_cmdlist);
+ deprecate_cmd (c, "set record full stop-at-limit");
+
+ c = add_alias_cmd ("stop-at-limit", "full stop-at-limit", no_class, 1,
+ &show_record_cmdlist);
+ deprecate_cmd (c, "show record full stop-at-limit");
+
+ add_setshow_uinteger_cmd ("insn-number-max", no_class, &record_insn_max_num,
+ _("Set record/replay buffer limit."),
+ _("Show record/replay buffer limit."), _("\
+Set the maximum number of instructions to be stored in the\n\
+record/replay buffer. Zero means unlimited. Default is 200000."),
+ set_record_insn_max_num,
+ NULL, &set_record_full_cmdlist,
+ &show_record_full_cmdlist);
+
+ c = add_alias_cmd ("insn-number-max", "full insn-number-max", no_class, 1,
+ &set_record_cmdlist);
+ deprecate_cmd (c, "set record full insn-number-max");
+
+ c = add_alias_cmd ("insn-number-max", "full insn-number-max", no_class, 1,
+ &show_record_cmdlist);
+ deprecate_cmd (c, "show record full insn-number-max");
+
+ add_setshow_boolean_cmd ("memory-query", no_class, &record_memory_query, _("\
+Set whether query if PREC cannot record memory change of next instruction."),
+ _("\
+Show whether query if PREC cannot record memory change of next instruction."),
+ _("\
+Default is OFF.\n\
+When ON, query if PREC cannot record memory change of next instruction."),
+ NULL, NULL,
+ &set_record_full_cmdlist, &show_record_full_cmdlist);
+
+ c = add_alias_cmd ("memory-query", "full memory-query", no_class, 1,
+ &set_record_cmdlist);
+ deprecate_cmd (c, "set record full memory-query");
+
+ c = add_alias_cmd ("memory-query", "full memory-query", no_class, 1,
+ &show_record_cmdlist);
+ deprecate_cmd (c, "show record full memory-query");
+}
diff --git a/gdb/record.c b/gdb/record.c
index c06bcae..8b44717 100644
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -19,29 +19,48 @@
#include "defs.h"
#include "gdbcmd.h"
-#include "regcache.h"
-#include "gdbthread.h"
-#include "event-top.h"
-#include "exceptions.h"
#include "completer.h"
-#include "arch-utils.h"
-#include "gdbcore.h"
-#include "exec.h"
#include "record.h"
-#include "elf-bfd.h"
-#include "gcore.h"
-#include "event-loop.h"
-#include "inf-loop.h"
-#include "gdb_bfd.h"
#include "observer.h"
-
-#include <signal.h>
+#include "inferior.h"
+#include "common/common-utils.h"
/* This is the debug switch for process record. */
unsigned int record_debug = 0;
-/* The implementation of the command "record goto". */
-static void cmd_record_goto (char *, int);
+struct cmd_list_element *record_cmdlist = NULL;
+struct cmd_list_element *set_record_cmdlist = NULL;
+struct cmd_list_element *show_record_cmdlist = NULL;
+struct cmd_list_element *info_record_cmdlist = NULL;
+
+/* Find the record target in the target stack. */
+
+static struct target_ops *
+find_record_target (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_stratum == record_stratum)
+ return t;
+
+ return NULL;
+}
+
+/* Check that recording is active. Throw an error, if it isn't. */
+
+static struct target_ops *
+require_record_target (void)
+{
+ struct target_ops *t;
+
+ t = find_record_target ();
+ if (t == NULL)
+ error (_("No record target is currently active.\n"
+ "Use one of the \"target record-<tab><tab>\" commands first."));
+
+ return t;
+}
/* See record.h. */
@@ -74,7 +93,7 @@ show_record_debug (struct ui_file *file, int from_tty,
static void
cmd_record_start (char *args, int from_tty)
{
- execute_command ("target record", from_tty);
+ execute_command ("target record-full", from_tty);
}
/* Truncate the record log from the present point
@@ -83,21 +102,25 @@ cmd_record_start (char *args, int from_tty)
static void
cmd_record_delete (char *args, int from_tty)
{
- if (current_target.to_stratum == record_stratum)
+ require_record_target ();
+
+ if (!target_record_is_replaying ())
{
- if (RECORD_IS_REPLAY)
- {
- if (!from_tty || query (_("Delete the log from this point forward "
- "and begin to record the running message "
- "at current PC?")))
- record_list_release_following (record_list);
- }
- else
- printf_unfiltered (_("Already at end of record list.\n"));
+ printf_unfiltered (_("Already at end of record list.\n"));
+ return;
+ }
+ if (!target_supports_delete_record ())
+ {
+ printf_unfiltered (_("The current record target does not support "
+ "this operation.\n"));
+ return;
}
- else
- printf_unfiltered (_("Process record is not started.\n"));
+
+ if (!from_tty || query (_("Delete the log from this point forward "
+ "and begin to record the running message "
+ "at current PC?")))
+ target_delete_record ();
}
/* Implement the "stoprecord" or "record stop" command. */
@@ -105,36 +128,18 @@ cmd_record_delete (char *args, int from_tty)
static void
cmd_record_stop (char *args, int from_tty)
{
- if (current_target.to_stratum == record_stratum)
- {
- unpush_target (&record_ops);
- printf_unfiltered (_("Process record is stopped and all execution "
- "logs are deleted.\n"));
+ struct target_ops *t;
- observer_notify_record_changed (current_inferior (), 0);
- }
- else
- printf_unfiltered (_("Process record is not started.\n"));
-}
+ t = require_record_target ();
+ unpush_target (t);
-/* Set upper limit of record log size. */
+ printf_unfiltered (_("Process record is stopped and all execution "
+ "logs are deleted.\n"));
-static void
-set_record_insn_max_num (char *args, int from_tty, struct cmd_list_element *c)
-{
- if (record_insn_num > record_insn_max_num && record_insn_max_num)
- {
- /* Count down record_insn_num while releasing records from list. */
- while (record_insn_num > record_insn_max_num)
- {
- record_list_release_first ();
- record_insn_num--;
- }
- }
+ observer_notify_record_changed (current_inferior (), 0);
}
-static struct cmd_list_element *record_cmdlist, *set_record_cmdlist,
- *show_record_cmdlist, *info_record_cmdlist;
+/* The "set record" command. */
static void
set_record_command (char *args, int from_tty)
@@ -144,65 +149,53 @@ set_record_command (char *args, int from_tty)
help_list (set_record_cmdlist, "set record ", all_commands, gdb_stdout);
}
+/* The "show record" command. */
+
static void
show_record_command (char *args, int from_tty)
{
cmd_show_list (show_record_cmdlist, from_tty, "");
}
-/* Display some statistics about the execution log. */
+/* The "info record" command. */
static void
info_record_command (char *args, int from_tty)
{
- struct record_entry *p;
+ struct target_ops *t;
- if (current_target.to_stratum == record_stratum)
+ t = find_record_target ();
+ if (t == NULL)
{
- if (RECORD_IS_REPLAY)
- printf_filtered (_("Replay mode:\n"));
- else
- printf_filtered (_("Record mode:\n"));
-
- /* Find entry for first actual instruction in the log. */
- for (p = record_first.next;
- p != NULL && p->type != record_end;
- p = p->next)
- ;
-
- /* Do we have a log at all? */
- if (p != NULL && p->type == record_end)
- {
- /* Display instruction number for first instruction in the log. */
- printf_filtered (_("Lowest recorded instruction number is %s.\n"),
- pulongest (p->u.end.insn_num));
-
- /* If in replay mode, display where we are in the log. */
- if (RECORD_IS_REPLAY)
- printf_filtered (_("Current instruction number is %s.\n"),
- pulongest (record_list->u.end.insn_num));
-
- /* Display instruction number for last instruction in the log. */
- printf_filtered (_("Highest recorded instruction number is %s.\n"),
- pulongest (record_insn_count));
-
- /* Display log count. */
- printf_filtered (_("Log contains %d instructions.\n"),
- record_insn_num);
- }
- else
- {
- printf_filtered (_("No instructions have been logged.\n"));
- }
+ printf_filtered (_("No record target is currently active.\n"));
+ return;
}
+
+ printf_filtered (_("Active record target: %s\n"), t->to_shortname);
+ if (t->to_info_record != NULL)
+ t->to_info_record ();
+}
+
+/* The "record save" command. */
+
+static void
+cmd_record_save (char *args, int from_tty)
+{
+ char *recfilename, recfilename_buffer[40];
+
+ require_record_target ();
+
+ if (args != NULL && *args != 0)
+ recfilename = args;
else
{
- printf_filtered (_("target record is not active.\n"));
+ /* Default recfile name is "gdb_record.PID". */
+ xsnprintf (recfilename_buffer, sizeof (recfilename_buffer),
+ "gdb_record.%d", PIDGET (inferior_ptid));
+ recfilename = recfilename_buffer;
}
- /* Display max log size. */
- printf_filtered (_("Max logged instructions is %d.\n"),
- record_insn_max_num);
+ target_save_record (recfilename);
}
/* "record goto" command. Argument is an instruction number,
@@ -210,65 +203,26 @@ info_record_command (char *args, int from_tty)
Rewinds the recording (forward or backward) to the given instruction. */
-static void
+void
cmd_record_goto (char *arg, int from_tty)
{
- struct record_entry *p = NULL;
- ULONGEST target_insn = 0;
+ require_record_target ();
if (arg == NULL || *arg == '\0')
error (_("Command requires an argument (insn number to go to)."));
if (strncmp (arg, "start", strlen ("start")) == 0
|| strncmp (arg, "begin", strlen ("begin")) == 0)
- {
- /* Special case. Find first insn. */
- for (p = &record_first; p != NULL; p = p->next)
- if (p->type == record_end)
- break;
- if (p)
- target_insn = p->u.end.insn_num;
- }
+ target_goto_record_begin ();
else if (strncmp (arg, "end", strlen ("end")) == 0)
- {
- /* Special case. Find last insn. */
- for (p = record_list; p->next != NULL; p = p->next)
- ;
- for (; p!= NULL; p = p->prev)
- if (p->type == record_end)
- break;
- if (p)
- target_insn = p->u.end.insn_num;
- }
+ target_goto_record_end ();
else
{
- /* General case. Find designated insn. */
- target_insn = parse_and_eval_long (arg);
+ ULONGEST insn;
- for (p = &record_first; p != NULL; p = p->next)
- if (p->type == record_end && p->u.end.insn_num == target_insn)
- break;
+ insn = parse_and_eval_long (arg);
+ target_goto_record (insn);
}
-
- if (p == NULL)
- error (_("Target insn '%s' not found."), arg);
- else if (p == record_list)
- error (_("Already at insn '%s'."), arg);
- else if (p->u.end.insn_num > record_list->u.end.insn_num)
- {
- printf_filtered (_("Go forward to insn number %s\n"),
- pulongest (target_insn));
- record_goto_insn (p, EXEC_FORWARD);
- }
- else
- {
- printf_filtered (_("Go backward to insn number %s\n"),
- pulongest (target_insn));
- record_goto_insn (p, EXEC_REVERSE);
- }
- registers_changed ();
- reinit_frame_cache ();
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
@@ -279,16 +233,6 @@ _initialize_record (void)
{
struct cmd_list_element *c;
- /* Init record_first. */
- record_first.prev = NULL;
- record_first.next = NULL;
- record_first.type = record_end;
-
- init_record_ops ();
- add_target (&record_ops);
- init_record_core_ops ();
- add_target (&record_core_ops);
-
add_setshow_zuinteger_cmd ("record", no_class, &record_debug,
_("Set debugging of record/replay feature."),
_("Show debugging of record/replay feature."),
@@ -298,7 +242,7 @@ _initialize_record (void)
&showdebuglist);
c = add_prefix_cmd ("record", class_obscure, cmd_record_start,
- _("Abbreviated form of \"target record\" command."),
+ _("Start recording."),
&record_cmdlist, "record ", 0, &cmdlist);
set_cmd_completer (c, filename_completer);
@@ -323,12 +267,6 @@ Default filename is 'gdb_record.<process_id>'."),
&record_cmdlist);
set_cmd_completer (c, filename_completer);
- c = add_cmd ("restore", class_obscure, cmd_record_restore,
- _("Restore the execution log from a file.\n\
-Argument is filename. File must be created with 'record save'."),
- &record_cmdlist);
- set_cmd_completer (c, filename_completer);
-
add_cmd ("delete", class_obscure, cmd_record_delete,
_("Delete the rest of execution log and start recording it anew."),
&record_cmdlist);
@@ -340,40 +278,8 @@ Argument is filename. File must be created with 'record save'."),
&record_cmdlist);
add_alias_cmd ("s", "stop", class_obscure, 1, &record_cmdlist);
- /* Record instructions number limit command. */
- add_setshow_boolean_cmd ("stop-at-limit", no_class,
- &record_stop_at_limit, _("\
-Set whether record/replay stops when record/replay buffer becomes full."), _("\
-Show whether record/replay stops when record/replay buffer becomes full."),
- _("Default is ON.\n\
-When ON, if the record/replay buffer becomes full, ask user what to do.\n\
-When OFF, if the record/replay buffer becomes full,\n\
-delete the oldest recorded instruction to make room for each new one."),
- NULL, NULL,
- &set_record_cmdlist, &show_record_cmdlist);
- add_setshow_uinteger_cmd ("insn-number-max", no_class,
- &record_insn_max_num,
- _("Set record/replay buffer limit."),
- _("Show record/replay buffer limit."), _("\
-Set the maximum number of instructions to be stored in the\n\
-record/replay buffer. Zero means unlimited. Default is 200000."),
- set_record_insn_max_num,
- NULL, &set_record_cmdlist, &show_record_cmdlist);
-
add_cmd ("goto", class_obscure, cmd_record_goto, _("\
Restore the program to its state at instruction number N.\n\
Argument is instruction number, as shown by 'info record'."),
&record_cmdlist);
-
- add_setshow_boolean_cmd ("memory-query", no_class,
- &record_memory_query, _("\
-Set whether query if PREC cannot record memory change of next instruction."),
- _("\
-Show whether query if PREC cannot record memory change of next instruction."),
- _("\
-Default is OFF.\n\
-When ON, query if PREC cannot record memory change of next instruction."),
- NULL, NULL,
- &set_record_cmdlist, &show_record_cmdlist);
-
}
diff --git a/gdb/record.h b/gdb/record.h
index 88e59e2..b428eaf 100644
--- a/gdb/record.h
+++ b/gdb/record.h
@@ -20,14 +20,25 @@
#ifndef _RECORD_H_
#define _RECORD_H_
+struct cmd_list_element;
+
#define RECORD_IS_USED (current_target.to_stratum == record_stratum)
extern unsigned int record_debug;
+/* Allow record targets to add their own sub-commands. */
+extern struct cmd_list_element *record_cmdlist;
+extern struct cmd_list_element *set_record_cmdlist;
+extern struct cmd_list_element *show_record_cmdlist;
+extern struct cmd_list_element *info_record_cmdlist;
+
/* Wrapper for target_read_memory that prints a debug message if
reading memory fails. */
extern int record_read_memory (struct gdbarch *gdbarch,
CORE_ADDR memaddr, gdb_byte *myaddr,
ssize_t len);
+/* The "record goto" command. */
+extern void cmd_record_goto (char *arg, int from_tty);
+
#endif /* _RECORD_H_ */
diff --git a/gdb/target.c b/gdb/target.c
index 8bb6814..78736ad 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4223,6 +4223,136 @@ target_read_btrace (struct btrace_target_info *btinfo,
return NULL;
}
+/* See target.h. */
+
+void
+target_info_record (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_info_record != NULL)
+ {
+ t->to_info_record ();
+ return;
+ }
+
+ tcomplain ();
+}
+
+/* See target.h. */
+
+void
+target_save_record (char *filename)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_save_record != NULL)
+ {
+ t->to_save_record (filename);
+ return;
+ }
+
+ tcomplain ();
+}
+
+/* See target.h. */
+
+int
+target_supports_delete_record (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_delete_record != NULL)
+ return 1;
+
+ return 0;
+}
+
+/* See target.h. */
+
+void
+target_delete_record (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_delete_record != NULL)
+ {
+ t->to_delete_record ();
+ return;
+ }
+
+ tcomplain ();
+}
+
+/* See target.h. */
+
+int
+target_record_is_replaying (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_record_is_replaying != NULL)
+ return t->to_record_is_replaying ();
+
+ return 0;
+}
+
+/* See target.h. */
+
+void
+target_goto_record_begin (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_goto_record_begin != NULL)
+ {
+ t->to_goto_record_begin ();
+ return;
+ }
+
+ tcomplain ();
+}
+
+/* See target.h. */
+
+void
+target_goto_record_end (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_goto_record_end != NULL)
+ {
+ t->to_goto_record_end ();
+ return;
+ }
+
+ tcomplain ();
+}
+
+/* See target.h. */
+
+void
+target_goto_record (ULONGEST insn)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_goto_record != NULL)
+ {
+ t->to_goto_record (insn);
+ return;
+ }
+
+ tcomplain ();
+}
+
static void
debug_to_prepare_to_store (struct regcache *regcache)
{
diff --git a/gdb/target.h b/gdb/target.h
index 93b9444..821085c 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -874,6 +874,27 @@ struct target_ops
VEC (btrace_block_s) *(*to_read_btrace) (struct btrace_target_info *,
enum btrace_read_type);
+ /* Print information about the recording. */
+ void (*to_info_record) (void);
+
+ /* Save the recorded execution trace into a file. */
+ void (*to_save_record) (char *filename);
+
+ /* Delete the recorded execution trace from the current position onwards. */
+ void (*to_delete_record) (void);
+
+ /* Query if the record target is currently replaying. */
+ int (*to_record_is_replaying) (void);
+
+ /* Go to the begin of the execution trace. */
+ void (*to_goto_record_begin) (void);
+
+ /* Go to the end of the execution trace. */
+ void (*to_goto_record_end) (void);
+
+ /* Go to a specific location in the recorded execution trace. */
+ void (*to_goto_record) (ULONGEST insn);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -1934,5 +1955,28 @@ extern void target_disable_btrace (struct btrace_target_info *btinfo);
extern VEC (btrace_block_s) *target_read_btrace (struct btrace_target_info *,
enum btrace_read_type);
+/* See to_info_record in struct target_ops. */
+extern void target_info_record (void);
+
+/* See to_save_record in struct target_ops. */
+extern void target_save_record (char *filename);
+
+/* Query if the target supports deleting the execution log. */
+extern int target_supports_delete_record (void);
+
+/* See to_delete_record in struct target_ops. */
+extern void target_delete_record (void);
+
+/* See to_record_is_replaying in struct target_ops. */
+extern int target_record_is_replaying (void);
+
+/* See to_goto_record_begin in struct target_ops. */
+extern void target_goto_record_begin (void);
+
+/* See to_goto_record_end in struct target_ops. */
+extern void target_goto_record_end (void);
+
+/* See to_goto_record in struct target_ops. */
+extern void target_goto_record (ULONGEST insn);
#endif /* !defined (TARGET_H) */
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 12/21] record-full.c: rename record_ in record_full_.
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (11 preceding siblings ...)
2013-03-08 9:18 ` [patch v10 11/21] record: make it build again Markus Metzger
@ 2013-03-08 9:19 ` Markus Metzger
2013-03-08 9:19 ` [patch v10 05/21] gdbserver: preserve error message in handle_qXfer Markus Metzger
` (9 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:19 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Rename record_ prefixes in record-full.c into record_full_.
I ran the gdb.reverse suite on 64bit IA gnu/linux - no regressions.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* record-full.c (DEFAULT_RECORD_INSN_MAX_NUM): Renamed to ...
(DEFAULT_RECORD_FULL_INSN_MAX_NUM): ... this. Updated all users.
(RECORD_IS_REPLAY): Renamed to ...
(RECORD_FULL_IS_REPLAY): ... this. Updated all users.
(RECORD_FILE_MAGIC): Renamed to ...
(RECORD_FULL_FILE_MAGIC): ... this. Updated all users.
(record_mem_entry): Renamed to ...
(record_full_mem_entry): ... this. Updated all users.
(record_reg_entry): Renamed to ...
(record_full_reg_entry): ... this. Updated all users.
(record_end_entry): Renamed to ...
(record_full_end_entry): ... this. Updated all users.
(record_type) <record_end, record_reg, record_mem>: Renamed
to ...
(record_full_type) <record_full_end, record_full_reg,
record_full_mem>: ... this. Updated all users.
(record_entry): Renamed to ...
(record_full_entry): ... this. Updated all users.
(record_core_buf_entry): Renamed to ...
(record_full_core_buf_entry): ... this. Updated all users.
(record_core_regbuf): Renamed to ...
(record_full_core_regbuf): ... this. Updated all users.
(record_core_start): Renamed to ...
(record_full_core_start): ... this. Updated all users.
(record_core_end): Renamed to ...
(record_full_core_end): ... this. Updated all users.
(record_core_buf_list): Renamed to ...
(record_full_core_buf_list): ... this. Updated all users.
(record_first): Renamed to ...
(record_full_first): ... this. Updated all users.
(record_list): Renamed to ...
(record_full_list): ... this. Updated all users.
(record_arch_list_head): Renamed to ...
(record_full_arch_list_head): ... this. Updated all users.
(record_arch_list_tail): Renamed to ...
(record_full_arch_list_tail): ... this. Updated all users.
(record_stop_at_limit): Renamed to ...
(record_full_stop_at_limit): ... this. Updated all users.
(record_insn_max_num): Renamed to ...
(record_full_insn_max_num): ... this. Updated all users.
(record_insn_num): Renamed to ...
(record_full_insn_num): ... this. Updated all users.
(record_insn_count): Renamed to ...
(record_full_insn_count): ... this. Updated all users.
(record_ops): Renamed to ...
(record_full_ops): ... this. Updated all users.
(record_core_ops): Renamed to ...
(record_full_core_ops): ... this. Updated all users.
(set_record_cmdlist): Renamed to ...
(set_record_full_cmdlist): ... this. Updated all users.
(show_record_cmdlist): Renamed to ...
(show_record_full_cmdlist): ... this. Updated all users.
(record_cmdlist): Renamed to ...
(record_full_cmdlist): ... this. Updated all users.
(record_beneath_to_resume_ops): Renamed to ...
(record_full_beneath_to_resume_ops): ... this. Updated all users.
(record_beneath_to_resume): Renamed to ...
(record_full_beneath_to_resume): ... this. Updated all users.
(record_beneath_to_wait_ops): Renamed to ...
(record_full_beneath_to_wait_ops): ... this. Updated all users.
(record_beneath_to_wait): Renamed to ...
(record_full_beneath_to_wait): ... this. Updated all users.
(record_beneath_to_store_registers_ops): Renamed to ...
(record_full_beneath_to_store_registers_ops): ... this.
Updated all users.
(record_beneath_to_store_registers): Renamed to ...
(record_full_beneath_to_store_registers): ... this.
Updated all users.
(record_beneath_to_xfer_partial_ops): Renamed to ...
(record_full_beneath_to_xfer_partial_ops): ... this.
Updated all users.
(record_beneath_to_xfer_partial): Renamed to ...
(record_full_beneath_to_xfer_partial): ... this.
Updated all users.
(record_beneath_to_insert_breakpoint): Renamed to ...
(record_full_beneath_to_insert_breakpoint): ... this.
Updated all users.
(record_beneath_to_stopped_by_watchpoint): Renamed to ...
(record_full_beneath_to_stopped_by_watchpoint): ... this.
Updated all users.
(record_beneath_to_stopped_data_address): Renamed to ...
(record_full_beneath_to_stopped_data_address): ... this.
Updated all users.
(record_beneath_to_async): Renamed to ...
(record_full_beneath_to_async): ... this. Updated all users.
(record_goto_insn): Renamed to ...
(record_full_goto_insn): ... this. Updated all users.
(record_save): Renamed to ...
(record_full_save): ... this. Updated all users.
(record_reg_alloc): Renamed to ...
(record_full_reg_alloc): ... this. Updated all users.
(record_reg_release): Renamed to ...
(record_full_reg_release): ... this. Updated all users.
(record_mem_alloc): Renamed to ...
(record_full_mem_alloc): ... this. Updated all users.
(record_mem_release): Renamed to ...
(record_full_mem_release): ... this. Updated all users.
(record_end_alloc): Renamed to ...
(record_full_end_alloc): ... this. Updated all users.
(record_end_release): Renamed to ...
(record_full_end_release): ... this. Updated all users.
(record_entry_release): Renamed to ...
(record_full_entry_release): ... this. Updated all users.
(record_list_release): Renamed to ...
(record_full_list_release): ... this. Updated all users.
(record_list_release_following): Renamed to ...
(record_full_list_release_following): ... this.
Updated all users.
(record_list_release_first): Renamed to ...
(record_full_list_release_first): ... this. Updated all users.
(record_arch_list_add): Renamed to ...
(record_full_arch_list_add): ... this. Updated all users.
(record_get_loc): Renamed to ...
(record_full_get_loc): ... this. Updated all users.
(record_check_insn_num): Renamed to ...
(record_full_check_insn_num): ... this. Updated all users.
(record_arch_list_cleanups): Renamed to ...
(record_full_arch_list_cleanups): ... this. Updated all users.
(record_message): Renamed to ...
(record_full_message): ... this. Updated all users.
(record_message_wrapper): Renamed to ...
(record_full_message_wrapper): ... this. Updated all users.
(record_message_wrapper_safe): Renamed to ...
(record_full_message_wrapper_safe): ... this. Updated all users.
(record_gdb_operation_disable): Renamed to ...
(record_full_gdb_operation_disable): ... this. Updated all users.
(record_hw_watchpoint): Renamed to ...
(record_full_hw_watchpoint): ... this. Updated all users.
(record_exec_insn): Renamed to ...
(record_full_exec_insn): ... this. Updated all users.
(record_restore): Renamed to ...
(record_full_restore): ... this. Updated all users.
(record_async_inferior_event_token): Renamed to ...
(record_full_async_inferior_event_token): ... this.
Updated all users.
(record_async_inferior_event_handler): Renamed to ...
(record_full_async_inferior_event_handler): ... this.
Updated all users.
(record_core_open_1): Renamed to ...
(record_full_core_open_1): ... this. Updated all users.
(record_open_1): Renamed to ...
(record_full_open_1): ... this. Updated all users.
(record_open): Renamed to ...
(record_full_open): ... this. Updated all users.
(record_close): Renamed to ...
(record_full_close): ... this. Updated all users.
(record_resume_step): Renamed to ...
(record_full_resume_step): ... this. Updated all users.
(record_resumed): Renamed to ...
(record_full_resumed): ... this. Updated all users.
(record_execution_dir): Renamed to ...
(record_full_execution_dir): ... this. Updated all users.
(record_resume): Renamed to ...
(record_full_resume): ... this. Updated all users.
(record_get_sig): Renamed to ...
(record_full_get_sig): ... this. Updated all users.
(record_sig_handler): Renamed to ...
(record_full_sig_handler): ... this. Updated all users.
(record_wait_cleanups): Renamed to ...
(record_full_wait_cleanups): ... this. Updated all users.
(record_wait_1): Renamed to ...
(record_full_wait_1): ... this. Updated all users.
(record_wait): Renamed to ...
(record_full_wait): ... this. Updated all users.
(record_stopped_by_watchpoint): Renamed to ...
(record_full_stopped_by_watchpoint): ... this. Updated all users.
(record_disconnect): Renamed to ...
(record_full_disconnect): ... this. Updated all users.
(record_detach): Renamed to ...
(record_full_detach): ... this. Updated all users.
(record_mourn_inferior): Renamed to ...
(record_full_mourn_inferior): ... this. Updated all users.
(record_kill): Renamed to ...
(record_full_kill): ... this. Updated all users.
(record_stopped_data_address): Renamed to ...
(record_full_stopped_data_address): ... this. Updated all users.
(record_registers_change): Renamed to ...
(record_full_registers_change): ... this. Updated all users.
(record_store_registers): Renamed to ...
(record_full_store_registers): ... this. Updated all users.
(record_xfer_partial): Renamed to ...
(record_full_xfer_partial): ... this. Updated all users.
(record_breakpoint): Renamed to ...
(record_full_breakpoint): ... this. Updated all users.
(record_breakpoint_p): Renamed to ...
(record_full_breakpoint_p): ... this. Updated all users.
(record_breakpoints): Renamed to ...
(record_full_breakpoints): ... this. Updated all users.
(record_sync_record_breakpoints): Renamed to ...
(record_full_sync_record_breakpoints): ... this.
Updated all users.
(record_init_record_breakpoints): Renamed to ...
(record_full_init_record_breakpoints): ... this.
Updated all users.
(record_insert_breakpoint): Renamed to ...
(record_full_insert_breakpoint): ... this. Updated all users.
(record_remove_breakpoint): Renamed to ...
(record_full_remove_breakpoint): ... this. Updated all users.
(record_can_execute_reverse): Renamed to ...
(record_full_can_execute_reverse): ... this. Updated all users.
(record_get_bookmark): Renamed to ...
(record_full_get_bookmark): ... this. Updated all users.
(record_goto_bookmark): Renamed to ...
(record_full_goto_bookmark): ... this. Updated all users.
(record_async): Renamed to ...
(record_full_async): ... this. Updated all users.
(record_can_async_p): Renamed to ...
(record_full_can_async_p): ... this. Updated all users.
(record_is_async_p): Renamed to ...
(record_full_is_async_p): ... this. Updated all users.
(record_execution_direction): Renamed to ...
(record_full_execution_direction): ... this. Updated all users.
(record_info): Renamed to ...
(record_full_info): ... this. Updated all users.
(record_delete): Renamed to ...
(record_full_delete): ... this. Updated all users.
(record_is_replaying): Renamed to ...
(record_full_is_replaying): ... this. Updated all users.
(record_goto_entry): Renamed to ...
(record_full_goto_entry): ... this. Updated all users.
(record_goto_begin): Renamed to ...
(record_full_goto_begin): ... this. Updated all users.
(record_goto_end): Renamed to ...
(record_full_goto_end): ... this. Updated all users.
(record_goto): Renamed to ...
(record_full_goto): ... this. Updated all users.
(init_record_ops): Renamed to ...
(init_record_full_ops): ... this. Updated all users.
(record_core_resume): Renamed to ...
(record_full_core_resume): ... this. Updated all users.
(record_core_kill): Renamed to ...
(record_full_core_kill): ... this. Updated all users.
(record_core_fetch_registers): Renamed to ...
(record_full_core_fetch_registers): ... this. Updated all users.
(record_core_prepare_to_store): Renamed to ...
(record_full_core_prepare_to_store): ... this. Updated all users.
(record_core_store_registers): Renamed to ...
(record_full_core_store_registers): ... this. Updated all users.
(record_core_xfer_partial): Renamed to ...
(record_full_core_xfer_partial): ... this. Updated all users.
(record_core_insert_breakpoint): Renamed to ...
(record_full_core_insert_breakpoint): ... this. Updated all users.
(record_core_remove_breakpoint): Renamed to ...
(record_full_core_remove_breakpoint): ... this. Updated all users.
(record_core_has_execution): Renamed to ...
(record_full_core_has_execution): ... this. Updated all users.
(init_record_core_ops): Renamed to ...
(init_record_full_core_ops): ... this. Updated all users.
(cmd_record_restore): Renamed to ...
(cmd_record_full_restore): ... this. Updated all users.
(record_save_cleanups): Renamed to ...
(record_full_save_cleanups): ... this. Updated all users.
(cmd_record_start): Renamed to ...
(cmd_record_full_start): ... this. Updated all users.
(set_record_insn_max_num): Renamed to ...
(set_record_full_insn_max_num): ... this. Updated all users.
(set_record_command): Renamed to ...
(set_record_full_command): ... this. Updated all users.
(show_record_command): Renamed to ...
(show_record_full_command): ... this. Updated all users.
(_initialize_record): Renamed to ...
(_initialize_record_full): ... this. Updated all users.
---
gdb/record-full.c | 1553 +++++++++++++++++++++++++++--------------------------
1 files changed, 799 insertions(+), 754 deletions(-)
diff --git a/gdb/record-full.c b/gdb/record-full.c
index 1cbd724..14f4400 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -58,25 +58,25 @@
instruction's side effects by duplicating the changes that it would
have made on memory and registers. */
-#define DEFAULT_RECORD_INSN_MAX_NUM 200000
+#define DEFAULT_RECORD_FULL_INSN_MAX_NUM 200000
-#define RECORD_IS_REPLAY \
- (record_list->next || execution_direction == EXEC_REVERSE)
+#define RECORD_FULL_IS_REPLAY \
+ (record_full_list->next || execution_direction == EXEC_REVERSE)
-#define RECORD_FILE_MAGIC netorder32(0x20091016)
+#define RECORD_FULL_FILE_MAGIC netorder32(0x20091016)
/* These are the core structs of the process record functionality.
- A record_entry is a record of the value change of a register
- ("record_reg") or a part of memory ("record_mem"). And each
- instruction must have a struct record_entry ("record_end") that
- indicates that this is the last struct record_entry of this
+ A record_full_entry is a record of the value change of a register
+ ("record_full_reg") or a part of memory ("record_full_mem"). And each
+ instruction must have a struct record_full_entry ("record_full_end")
+ that indicates that this is the last struct record_full_entry of this
instruction.
- Each struct record_entry is linked to "record_list" by "prev" and
- "next" pointers. */
+ Each struct record_full_entry is linked to "record_full_list" by "prev"
+ and "next" pointers. */
-struct record_mem_entry
+struct record_full_mem_entry
{
CORE_ADDR addr;
int len;
@@ -90,7 +90,7 @@ struct record_mem_entry
} u;
};
-struct record_reg_entry
+struct record_full_reg_entry
{
unsigned short num;
unsigned short len;
@@ -101,33 +101,33 @@ struct record_reg_entry
} u;
};
-struct record_end_entry
+struct record_full_end_entry
{
enum gdb_signal sigval;
ULONGEST insn_num;
};
-enum record_type
+enum record_full_type
{
- record_end = 0,
- record_reg,
- record_mem
+ record_full_end = 0,
+ record_full_reg,
+ record_full_mem
};
/* This is the data structure that makes up the execution log.
The execution log consists of a single linked list of entries
- of type "struct record_entry". It is doubly linked so that it
+ of type "struct record_full_entry". It is doubly linked so that it
can be traversed in either direction.
The start of the list is anchored by a struct called
- "record_first". The pointer "record_list" either points to the
- last entry that was added to the list (in record mode), or to the
- next entry in the list that will be executed (in replay mode).
+ "record_full_first". The pointer "record_full_list" either points
+ to the last entry that was added to the list (in record mode), or to
+ the next entry in the list that will be executed (in replay mode).
- Each list element (struct record_entry), in addition to next and
- prev pointers, consists of a union of three entry types: mem, reg,
- and end. A field called "type" determines which entry type is
+ Each list element (struct record_full_entry), in addition to next
+ and prev pointers, consists of a union of three entry types: mem,
+ reg, and end. A field called "type" determines which entry type is
represented by a given list element.
Each instruction that is added to the execution log is represented
@@ -138,19 +138,19 @@ enum record_type
each instruction will have an "end" entry that separates it from
the changes associated with the next instruction. */
-struct record_entry
+struct record_full_entry
{
- struct record_entry *prev;
- struct record_entry *next;
- enum record_type type;
+ struct record_full_entry *prev;
+ struct record_full_entry *next;
+ enum record_full_type type;
union
{
/* reg */
- struct record_reg_entry reg;
+ struct record_full_reg_entry reg;
/* mem */
- struct record_mem_entry mem;
+ struct record_full_mem_entry mem;
/* end */
- struct record_end_entry end;
+ struct record_full_end_entry end;
} u;
};
@@ -158,53 +158,55 @@ struct record_entry
change of next instruction. */
int record_memory_query = 0;
-struct record_core_buf_entry
+struct record_full_core_buf_entry
{
- struct record_core_buf_entry *prev;
+ struct record_full_core_buf_entry *prev;
struct target_section *p;
bfd_byte *buf;
};
/* Record buf with core target. */
-static gdb_byte *record_core_regbuf = NULL;
-static struct target_section *record_core_start;
-static struct target_section *record_core_end;
-static struct record_core_buf_entry *record_core_buf_list = NULL;
+static gdb_byte *record_full_core_regbuf = NULL;
+static struct target_section *record_full_core_start;
+static struct target_section *record_full_core_end;
+static struct record_full_core_buf_entry *record_full_core_buf_list = NULL;
/* The following variables are used for managing the linked list that
represents the execution log.
- record_first is the anchor that holds down the beginning of the list.
+ record_full_first is the anchor that holds down the beginning of
+ the list.
- record_list serves two functions:
+ record_full_list serves two functions:
1) In record mode, it anchors the end of the list.
2) In replay mode, it traverses the list and points to
the next instruction that must be emulated.
- record_arch_list_head and record_arch_list_tail are used to manage
- a separate list, which is used to build up the change elements of
- the currently executing instruction during record mode. When this
- instruction has been completely annotated in the "arch list", it
- will be appended to the main execution log. */
+ record_full_arch_list_head and record_full_arch_list_tail are used
+ to manage a separate list, which is used to build up the change
+ elements of the currently executing instruction during record mode.
+ When this instruction has been completely annotated in the "arch
+ list", it will be appended to the main execution log. */
-static struct record_entry record_first;
-static struct record_entry *record_list = &record_first;
-static struct record_entry *record_arch_list_head = NULL;
-static struct record_entry *record_arch_list_tail = NULL;
+static struct record_full_entry record_full_first;
+static struct record_full_entry *record_full_list = &record_full_first;
+static struct record_full_entry *record_full_arch_list_head = NULL;
+static struct record_full_entry *record_full_arch_list_tail = NULL;
-/* 1 ask user. 0 auto delete the last struct record_entry. */
-static int record_stop_at_limit = 1;
+/* 1 ask user. 0 auto delete the last struct record_full_entry. */
+static int record_full_stop_at_limit = 1;
/* Maximum allowed number of insns in execution log. */
-static unsigned int record_insn_max_num = DEFAULT_RECORD_INSN_MAX_NUM;
+static unsigned int record_full_insn_max_num
+ = DEFAULT_RECORD_FULL_INSN_MAX_NUM;
/* Actual count of insns presently in execution log. */
-static int record_insn_num = 0;
+static int record_full_insn_num = 0;
/* Count of insns logged so far (may be larger
than count of insns presently in execution log). */
-static ULONGEST record_insn_count;
+static ULONGEST record_full_insn_count;
/* The target_ops of process record. */
-static struct target_ops record_ops;
-static struct target_ops record_core_ops;
+static struct target_ops record_full_ops;
+static struct target_ops record_full_core_ops;
/* Command lists for "set/show record full". */
static struct cmd_list_element *set_record_full_cmdlist;
@@ -214,51 +216,56 @@ static struct cmd_list_element *show_record_full_cmdlist;
static struct cmd_list_element *record_full_cmdlist;
/* The beneath function pointers. */
-static struct target_ops *record_beneath_to_resume_ops;
-static void (*record_beneath_to_resume) (struct target_ops *, ptid_t, int,
- enum gdb_signal);
-static struct target_ops *record_beneath_to_wait_ops;
-static ptid_t (*record_beneath_to_wait) (struct target_ops *, ptid_t,
- struct target_waitstatus *,
- int);
-static struct target_ops *record_beneath_to_store_registers_ops;
-static void (*record_beneath_to_store_registers) (struct target_ops *,
- struct regcache *,
- int regno);
-static struct target_ops *record_beneath_to_xfer_partial_ops;
-static LONGEST (*record_beneath_to_xfer_partial) (struct target_ops *ops,
- enum target_object object,
- const char *annex,
- gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset,
- LONGEST len);
-static int (*record_beneath_to_insert_breakpoint) (struct gdbarch *,
- struct bp_target_info *);
-static int (*record_beneath_to_remove_breakpoint) (struct gdbarch *,
- struct bp_target_info *);
-static int (*record_beneath_to_stopped_by_watchpoint) (void);
-static int (*record_beneath_to_stopped_data_address) (struct target_ops *,
- CORE_ADDR *);
-static void (*record_beneath_to_async) (void (*) (enum inferior_event_type, void *), void *);
-
-static void record_goto_insn (struct record_entry *entry,
- enum exec_direction_kind dir);
-static void record_save (char *recfilename);
-
-/* Alloc and free functions for record_reg, record_mem, and record_end
- entries. */
-
-/* Alloc a record_reg record entry. */
-
-static inline struct record_entry *
-record_reg_alloc (struct regcache *regcache, int regnum)
-{
- struct record_entry *rec;
+static struct target_ops *record_full_beneath_to_resume_ops;
+static void (*record_full_beneath_to_resume) (struct target_ops *, ptid_t, int,
+ enum gdb_signal);
+static struct target_ops *record_full_beneath_to_wait_ops;
+static ptid_t (*record_full_beneath_to_wait) (struct target_ops *, ptid_t,
+ struct target_waitstatus *,
+ int);
+static struct target_ops *record_full_beneath_to_store_registers_ops;
+static void (*record_full_beneath_to_store_registers) (struct target_ops *,
+ struct regcache *,
+ int regno);
+static struct target_ops *record_full_beneath_to_xfer_partial_ops;
+static LONGEST
+ (*record_full_beneath_to_xfer_partial) (struct target_ops *ops,
+ enum target_object object,
+ const char *annex,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset,
+ LONGEST len);
+static int
+ (*record_full_beneath_to_insert_breakpoint) (struct gdbarch *,
+ struct bp_target_info *);
+static int
+ (*record_full_beneath_to_remove_breakpoint) (struct gdbarch *,
+ struct bp_target_info *);
+static int (*record_full_beneath_to_stopped_by_watchpoint) (void);
+static int (*record_full_beneath_to_stopped_data_address) (struct target_ops *,
+ CORE_ADDR *);
+static void
+ (*record_full_beneath_to_async) (void (*) (enum inferior_event_type, void *),
+ void *);
+
+static void record_full_goto_insn (struct record_full_entry *entry,
+ enum exec_direction_kind dir);
+static void record_full_save (char *recfilename);
+
+/* Alloc and free functions for record_full_reg, record_full_mem, and
+ record_full_end entries. */
+
+/* Alloc a record_full_reg record entry. */
+
+static inline struct record_full_entry *
+record_full_reg_alloc (struct regcache *regcache, int regnum)
+{
+ struct record_full_entry *rec;
struct gdbarch *gdbarch = get_regcache_arch (regcache);
- rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry));
- rec->type = record_reg;
+ rec = xcalloc (1, sizeof (struct record_full_entry));
+ rec->type = record_full_reg;
rec->u.reg.num = regnum;
rec->u.reg.len = register_size (gdbarch, regnum);
if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
@@ -267,26 +274,26 @@ record_reg_alloc (struct regcache *regcache, int regnum)
return rec;
}
-/* Free a record_reg record entry. */
+/* Free a record_full_reg record entry. */
static inline void
-record_reg_release (struct record_entry *rec)
+record_full_reg_release (struct record_full_entry *rec)
{
- gdb_assert (rec->type == record_reg);
+ gdb_assert (rec->type == record_full_reg);
if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
xfree (rec->u.reg.u.ptr);
xfree (rec);
}
-/* Alloc a record_mem record entry. */
+/* Alloc a record_full_mem record entry. */
-static inline struct record_entry *
-record_mem_alloc (CORE_ADDR addr, int len)
+static inline struct record_full_entry *
+record_full_mem_alloc (CORE_ADDR addr, int len)
{
- struct record_entry *rec;
+ struct record_full_entry *rec;
- rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry));
- rec->type = record_mem;
+ rec = xcalloc (1, sizeof (struct record_full_entry));
+ rec->type = record_full_mem;
rec->u.mem.addr = addr;
rec->u.mem.len = len;
if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
@@ -295,34 +302,34 @@ record_mem_alloc (CORE_ADDR addr, int len)
return rec;
}
-/* Free a record_mem record entry. */
+/* Free a record_full_mem record entry. */
static inline void
-record_mem_release (struct record_entry *rec)
+record_full_mem_release (struct record_full_entry *rec)
{
- gdb_assert (rec->type == record_mem);
+ gdb_assert (rec->type == record_full_mem);
if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
xfree (rec->u.mem.u.ptr);
xfree (rec);
}
-/* Alloc a record_end record entry. */
+/* Alloc a record_full_end record entry. */
-static inline struct record_entry *
-record_end_alloc (void)
+static inline struct record_full_entry *
+record_full_end_alloc (void)
{
- struct record_entry *rec;
+ struct record_full_entry *rec;
- rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry));
- rec->type = record_end;
+ rec = xcalloc (1, sizeof (struct record_full_entry));
+ rec->type = record_full_end;
return rec;
}
-/* Free a record_end record entry. */
+/* Free a record_full_end record entry. */
static inline void
-record_end_release (struct record_entry *rec)
+record_full_end_release (struct record_full_entry *rec)
{
xfree (rec);
}
@@ -330,20 +337,20 @@ record_end_release (struct record_entry *rec)
/* Free one record entry, any type.
Return entry->type, in case caller wants to know. */
-static inline enum record_type
-record_entry_release (struct record_entry *rec)
+static inline enum record_full_type
+record_full_entry_release (struct record_full_entry *rec)
{
- enum record_type type = rec->type;
+ enum record_full_type type = rec->type;
switch (type) {
- case record_reg:
- record_reg_release (rec);
+ case record_full_reg:
+ record_full_reg_release (rec);
break;
- case record_mem:
- record_mem_release (rec);
+ case record_full_mem:
+ record_full_mem_release (rec);
break;
- case record_end:
- record_end_release (rec);
+ case record_full_end:
+ record_full_end_release (rec);
break;
}
return type;
@@ -352,7 +359,7 @@ record_entry_release (struct record_entry *rec)
/* Free all record entries in list pointed to by REC. */
static void
-record_list_release (struct record_entry *rec)
+record_full_list_release (struct record_full_entry *rec)
{
if (!rec)
return;
@@ -363,33 +370,33 @@ record_list_release (struct record_entry *rec)
while (rec->prev)
{
rec = rec->prev;
- record_entry_release (rec->next);
+ record_full_entry_release (rec->next);
}
- if (rec == &record_first)
+ if (rec == &record_full_first)
{
- record_insn_num = 0;
- record_first.next = NULL;
+ record_full_insn_num = 0;
+ record_full_first.next = NULL;
}
else
- record_entry_release (rec);
+ record_full_entry_release (rec);
}
/* Free all record entries forward of the given list position. */
static void
-record_list_release_following (struct record_entry *rec)
+record_full_list_release_following (struct record_full_entry *rec)
{
- struct record_entry *tmp = rec->next;
+ struct record_full_entry *tmp = rec->next;
rec->next = NULL;
while (tmp)
{
rec = tmp->next;
- if (record_entry_release (tmp) == record_end)
+ if (record_full_entry_release (tmp) == record_full_end)
{
- record_insn_num--;
- record_insn_count--;
+ record_full_insn_num--;
+ record_full_insn_count--;
}
tmp = rec;
}
@@ -398,87 +405,87 @@ record_list_release_following (struct record_entry *rec)
/* Delete the first instruction from the beginning of the log, to make
room for adding a new instruction at the end of the log.
- Note -- this function does not modify record_insn_num. */
+ Note -- this function does not modify record_full_insn_num. */
static void
-record_list_release_first (void)
+record_full_list_release_first (void)
{
- struct record_entry *tmp;
+ struct record_full_entry *tmp;
- if (!record_first.next)
+ if (!record_full_first.next)
return;
- /* Loop until a record_end. */
+ /* Loop until a record_full_end. */
while (1)
{
- /* Cut record_first.next out of the linked list. */
- tmp = record_first.next;
- record_first.next = tmp->next;
- tmp->next->prev = &record_first;
+ /* Cut record_full_first.next out of the linked list. */
+ tmp = record_full_first.next;
+ record_full_first.next = tmp->next;
+ tmp->next->prev = &record_full_first;
/* tmp is now isolated, and can be deleted. */
- if (record_entry_release (tmp) == record_end)
- break; /* End loop at first record_end. */
+ if (record_full_entry_release (tmp) == record_full_end)
+ break; /* End loop at first record_full_end. */
- if (!record_first.next)
+ if (!record_full_first.next)
{
- gdb_assert (record_insn_num == 1);
+ gdb_assert (record_full_insn_num == 1);
break; /* End loop when list is empty. */
}
}
}
-/* Add a struct record_entry to record_arch_list. */
+/* Add a struct record_full_entry to record_full_arch_list. */
static void
-record_arch_list_add (struct record_entry *rec)
+record_full_arch_list_add (struct record_full_entry *rec)
{
if (record_debug > 1)
fprintf_unfiltered (gdb_stdlog,
- "Process record: record_arch_list_add %s.\n",
+ "Process record: record_full_arch_list_add %s.\n",
host_address_to_string (rec));
- if (record_arch_list_tail)
+ if (record_full_arch_list_tail)
{
- record_arch_list_tail->next = rec;
- rec->prev = record_arch_list_tail;
- record_arch_list_tail = rec;
+ record_full_arch_list_tail->next = rec;
+ rec->prev = record_full_arch_list_tail;
+ record_full_arch_list_tail = rec;
}
else
{
- record_arch_list_head = rec;
- record_arch_list_tail = rec;
+ record_full_arch_list_head = rec;
+ record_full_arch_list_tail = rec;
}
}
/* Return the value storage location of a record entry. */
static inline gdb_byte *
-record_get_loc (struct record_entry *rec)
+record_full_get_loc (struct record_full_entry *rec)
{
switch (rec->type) {
- case record_mem:
+ case record_full_mem:
if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
return rec->u.mem.u.ptr;
else
return rec->u.mem.u.buf;
- case record_reg:
+ case record_full_reg:
if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
return rec->u.reg.u.ptr;
else
return rec->u.reg.u.buf;
- case record_end:
+ case record_full_end:
default:
- gdb_assert_not_reached ("unexpected record_entry type");
+ gdb_assert_not_reached ("unexpected record_full_entry type");
return NULL;
}
}
-/* Record the value of a register NUM to record_arch_list. */
+/* Record the value of a register NUM to record_full_arch_list. */
int
record_arch_list_add_reg (struct regcache *regcache, int regnum)
{
- struct record_entry *rec;
+ struct record_full_entry *rec;
if (record_debug > 1)
fprintf_unfiltered (gdb_stdlog,
@@ -486,22 +493,22 @@ record_arch_list_add_reg (struct regcache *regcache, int regnum)
"record list.\n",
regnum);
- rec = record_reg_alloc (regcache, regnum);
+ rec = record_full_reg_alloc (regcache, regnum);
- regcache_raw_read (regcache, regnum, record_get_loc (rec));
+ regcache_raw_read (regcache, regnum, record_full_get_loc (rec));
- record_arch_list_add (rec);
+ record_full_arch_list_add (rec);
return 0;
}
/* Record the value of a region of memory whose address is ADDR and
- length is LEN to record_arch_list. */
+ length is LEN to record_full_arch_list. */
int
record_arch_list_add_mem (CORE_ADDR addr, int len)
{
- struct record_entry *rec;
+ struct record_full_entry *rec;
if (record_debug > 1)
fprintf_unfiltered (gdb_stdlog,
@@ -512,49 +519,51 @@ record_arch_list_add_mem (CORE_ADDR addr, int len)
if (!addr) /* FIXME: Why? Some arch must permit it... */
return 0;
- rec = record_mem_alloc (addr, len);
+ rec = record_full_mem_alloc (addr, len);
- if (record_read_memory (target_gdbarch (), addr, record_get_loc (rec), len))
+ if (record_read_memory (target_gdbarch (), addr,
+ record_full_get_loc (rec), len))
{
- record_mem_release (rec);
+ record_full_mem_release (rec);
return -1;
}
- record_arch_list_add (rec);
+ record_full_arch_list_add (rec);
return 0;
}
-/* Add a record_end type struct record_entry to record_arch_list. */
+/* Add a record_full_end type struct record_full_entry to
+ record_full_arch_list. */
int
record_arch_list_add_end (void)
{
- struct record_entry *rec;
+ struct record_full_entry *rec;
if (record_debug > 1)
fprintf_unfiltered (gdb_stdlog,
"Process record: add end to arch list.\n");
- rec = record_end_alloc ();
+ rec = record_full_end_alloc ();
rec->u.end.sigval = GDB_SIGNAL_0;
- rec->u.end.insn_num = ++record_insn_count;
+ rec->u.end.insn_num = ++record_full_insn_count;
- record_arch_list_add (rec);
+ record_full_arch_list_add (rec);
return 0;
}
static void
-record_check_insn_num (int set_terminal)
+record_full_check_insn_num (int set_terminal)
{
- if (record_insn_max_num)
+ if (record_full_insn_max_num)
{
- gdb_assert (record_insn_num <= record_insn_max_num);
- if (record_insn_num == record_insn_max_num)
+ gdb_assert (record_full_insn_num <= record_full_insn_max_num);
+ if (record_full_insn_num == record_full_insn_max_num)
{
/* Ask user what to do. */
- if (record_stop_at_limit)
+ if (record_full_stop_at_limit)
{
int q;
@@ -566,7 +575,7 @@ record_check_insn_num (int set_terminal)
if (set_terminal)
target_terminal_inferior ();
if (q)
- record_stop_at_limit = 0;
+ record_full_stop_at_limit = 0;
else
error (_("Process record: stopped by user."));
}
@@ -575,29 +584,30 @@ record_check_insn_num (int set_terminal)
}
static void
-record_arch_list_cleanups (void *ignore)
+record_full_arch_list_cleanups (void *ignore)
{
- record_list_release (record_arch_list_tail);
+ record_full_list_release (record_full_arch_list_tail);
}
/* Before inferior step (when GDB record the running message, inferior
only can step), GDB will call this function to record the values to
- record_list. This function will call gdbarch_process_record to
+ record_full_list. This function will call gdbarch_process_record to
record the running message of inferior and set them to
- record_arch_list, and add it to record_list. */
+ record_full_arch_list, and add it to record_full_list. */
static int
-record_message (struct regcache *regcache, enum gdb_signal signal)
+record_full_message (struct regcache *regcache, enum gdb_signal signal)
{
int ret;
struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct cleanup *old_cleanups = make_cleanup (record_arch_list_cleanups, 0);
+ struct cleanup *old_cleanups
+ = make_cleanup (record_full_arch_list_cleanups, 0);
- record_arch_list_head = NULL;
- record_arch_list_tail = NULL;
+ record_full_arch_list_head = NULL;
+ record_full_arch_list_tail = NULL;
- /* Check record_insn_num. */
- record_check_insn_num (1);
+ /* Check record_full_insn_num. */
+ record_full_check_insn_num (1);
/* If gdb sends a signal value to target_resume,
save it in the 'end' field of the previous instruction.
@@ -620,11 +630,12 @@ record_message (struct regcache *regcache, enum gdb_signal signal)
But we should still deliver the signal to gdb during the replay,
if we delivered it during the recording. Therefore we should
- record the signal during record_wait, not record_resume. */
- if (record_list != &record_first) /* FIXME better way to check */
+ record the signal during record_full_wait, not
+ record_full_resume. */
+ if (record_full_list != &record_full_first) /* FIXME better way to check */
{
- gdb_assert (record_list->type == record_end);
- record_list->u.end.sigval = signal;
+ gdb_assert (record_full_list->type == record_full_end);
+ record_full_list->u.end.sigval = signal;
}
if (signal == GDB_SIGNAL_0
@@ -644,47 +655,50 @@ record_message (struct regcache *regcache, enum gdb_signal signal)
discard_cleanups (old_cleanups);
- record_list->next = record_arch_list_head;
- record_arch_list_head->prev = record_list;
- record_list = record_arch_list_tail;
+ record_full_list->next = record_full_arch_list_head;
+ record_full_arch_list_head->prev = record_full_list;
+ record_full_list = record_full_arch_list_tail;
- if (record_insn_num == record_insn_max_num && record_insn_max_num)
- record_list_release_first ();
+ if (record_full_insn_num == record_full_insn_max_num
+ && record_full_insn_max_num)
+ record_full_list_release_first ();
else
- record_insn_num++;
+ record_full_insn_num++;
return 1;
}
-struct record_message_args {
+struct record_full_message_args {
struct regcache *regcache;
enum gdb_signal signal;
};
static int
-record_message_wrapper (void *args)
+record_full_message_wrapper (void *args)
{
- struct record_message_args *record_args = args;
+ struct record_full_message_args *record_full_args = args;
- return record_message (record_args->regcache, record_args->signal);
+ return record_full_message (record_full_args->regcache,
+ record_full_args->signal);
}
static int
-record_message_wrapper_safe (struct regcache *regcache,
- enum gdb_signal signal)
+record_full_message_wrapper_safe (struct regcache *regcache,
+ enum gdb_signal signal)
{
- struct record_message_args args;
+ struct record_full_message_args args;
args.regcache = regcache;
args.signal = signal;
- return catch_errors (record_message_wrapper, &args, NULL, RETURN_MASK_ALL);
+ return catch_errors (record_full_message_wrapper, &args, NULL,
+ RETURN_MASK_ALL);
}
-/* Set to 1 if record_store_registers and record_xfer_partial
+/* Set to 1 if record_full_store_registers and record_full_xfer_partial
doesn't need record. */
-static int record_gdb_operation_disable = 0;
+static int record_full_gdb_operation_disable = 0;
struct cleanup *
record_gdb_operation_disable_set (void)
@@ -692,44 +706,45 @@ record_gdb_operation_disable_set (void)
struct cleanup *old_cleanups = NULL;
old_cleanups =
- make_cleanup_restore_integer (&record_gdb_operation_disable);
- record_gdb_operation_disable = 1;
+ make_cleanup_restore_integer (&record_full_gdb_operation_disable);
+ record_full_gdb_operation_disable = 1;
return old_cleanups;
}
/* Flag set to TRUE for target_stopped_by_watchpoint. */
-static int record_hw_watchpoint = 0;
+static int record_full_hw_watchpoint = 0;
/* Execute one instruction from the record log. Each instruction in
the log will be represented by an arbitrary sequence of register
entries and memory entries, followed by an 'end' entry. */
static inline void
-record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
- struct record_entry *entry)
+record_full_exec_insn (struct regcache *regcache,
+ struct gdbarch *gdbarch,
+ struct record_full_entry *entry)
{
switch (entry->type)
{
- case record_reg: /* reg */
+ case record_full_reg: /* reg */
{
gdb_byte reg[MAX_REGISTER_SIZE];
if (record_debug > 1)
fprintf_unfiltered (gdb_stdlog,
- "Process record: record_reg %s to "
+ "Process record: record_full_reg %s to "
"inferior num = %d.\n",
host_address_to_string (entry),
entry->u.reg.num);
regcache_cooked_read (regcache, entry->u.reg.num, reg);
regcache_cooked_write (regcache, entry->u.reg.num,
- record_get_loc (entry));
- memcpy (record_get_loc (entry), reg, entry->u.reg.len);
+ record_full_get_loc (entry));
+ memcpy (record_full_get_loc (entry), reg, entry->u.reg.len);
}
break;
- case record_mem: /* mem */
+ case record_full_mem: /* mem */
{
/* Nothing to do if the entry is flagged not_accessible. */
if (!entry->u.mem.mem_entry_not_accessible)
@@ -738,7 +753,7 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
if (record_debug > 1)
fprintf_unfiltered (gdb_stdlog,
- "Process record: record_mem %s to "
+ "Process record: record_full_mem %s to "
"inferior addr = %s len = %d.\n",
host_address_to_string (entry),
paddress (gdbarch, entry->u.mem.addr),
@@ -750,7 +765,7 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
else
{
if (target_write_memory (entry->u.mem.addr,
- record_get_loc (entry),
+ record_full_get_loc (entry),
entry->u.mem.len))
{
entry->u.mem.mem_entry_not_accessible = 1;
@@ -762,7 +777,8 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
}
else
{
- memcpy (record_get_loc (entry), mem, entry->u.mem.len);
+ memcpy (record_full_get_loc (entry), mem,
+ entry->u.mem.len);
/* We've changed memory --- check if a hardware
watchpoint should trap. Note that this
@@ -775,7 +791,7 @@ record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
if (hardware_watchpoint_inserted_in_range
(get_regcache_aspace (regcache),
entry->u.mem.addr, entry->u.mem.len))
- record_hw_watchpoint = 1;
+ record_full_hw_watchpoint = 1;
}
}
}
@@ -812,15 +828,15 @@ static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
static void (*tmp_to_async) (void (*) (enum inferior_event_type, void *), void *);
-static void record_restore (void);
+static void record_full_restore (void);
/* Asynchronous signal handle registered as event loop source for when
we have pending events ready to be passed to the core. */
-static struct async_event_handler *record_async_inferior_event_token;
+static struct async_event_handler *record_full_async_inferior_event_token;
static void
-record_async_inferior_event_handler (gdb_client_data data)
+record_full_async_inferior_event_handler (gdb_client_data data)
{
inferior_event_handler (INF_REG_EVENT, NULL);
}
@@ -828,39 +844,40 @@ record_async_inferior_event_handler (gdb_client_data data)
/* Open the process record target. */
static void
-record_core_open_1 (char *name, int from_tty)
+record_full_core_open_1 (char *name, int from_tty)
{
struct regcache *regcache = get_current_regcache ();
int regnum = gdbarch_num_regs (get_regcache_arch (regcache));
int i;
- /* Get record_core_regbuf. */
+ /* Get record_full_core_regbuf. */
target_fetch_registers (regcache, -1);
- record_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum);
+ record_full_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum);
for (i = 0; i < regnum; i ++)
regcache_raw_collect (regcache, i,
- record_core_regbuf + MAX_REGISTER_SIZE * i);
+ record_full_core_regbuf + MAX_REGISTER_SIZE * i);
- /* Get record_core_start and record_core_end. */
- if (build_section_table (core_bfd, &record_core_start, &record_core_end))
+ /* Get record_full_core_start and record_full_core_end. */
+ if (build_section_table (core_bfd, &record_full_core_start,
+ &record_full_core_end))
{
- xfree (record_core_regbuf);
- record_core_regbuf = NULL;
+ xfree (record_full_core_regbuf);
+ record_full_core_regbuf = NULL;
error (_("\"%s\": Can't find sections: %s"),
bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ()));
}
- push_target (&record_core_ops);
- record_restore ();
+ push_target (&record_full_core_ops);
+ record_full_restore ();
}
/* "to_open" target method for 'live' processes. */
static void
-record_open_1 (char *name, int from_tty)
+record_full_open_1 (char *name, int from_tty)
{
if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n");
/* check exec */
if (!target_has_execution)
@@ -893,20 +910,20 @@ record_open_1 (char *name, int from_tty)
error (_("Could not find 'to_stopped_data_address' "
"method on the target stack."));
- push_target (&record_ops);
+ push_target (&record_full_ops);
}
-static void record_init_record_breakpoints (void);
+static void record_full_init_record_breakpoints (void);
/* "to_open" target method. Open the process record target. */
static void
-record_open (char *name, int from_tty)
+record_full_open (char *name, int from_tty)
{
struct target_ops *t;
if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n");
/* Check if record target is already running. */
if (current_target.to_stratum == record_stratum)
@@ -966,37 +983,37 @@ record_open (char *name, int from_tty)
error (_("Could not find 'to_xfer_partial' method on the target stack."));
/* Reset */
- record_insn_num = 0;
- record_insn_count = 0;
- record_list = &record_first;
- record_list->next = NULL;
+ record_full_insn_num = 0;
+ record_full_insn_count = 0;
+ record_full_list = &record_full_first;
+ record_full_list->next = NULL;
/* Set the tmp beneath pointers to beneath pointers. */
- record_beneath_to_resume_ops = tmp_to_resume_ops;
- record_beneath_to_resume = tmp_to_resume;
- record_beneath_to_wait_ops = tmp_to_wait_ops;
- record_beneath_to_wait = tmp_to_wait;
- record_beneath_to_store_registers_ops = tmp_to_store_registers_ops;
- record_beneath_to_store_registers = tmp_to_store_registers;
- record_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops;
- record_beneath_to_xfer_partial = tmp_to_xfer_partial;
- record_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint;
- record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
- record_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint;
- record_beneath_to_stopped_data_address = tmp_to_stopped_data_address;
- record_beneath_to_async = tmp_to_async;
+ record_full_beneath_to_resume_ops = tmp_to_resume_ops;
+ record_full_beneath_to_resume = tmp_to_resume;
+ record_full_beneath_to_wait_ops = tmp_to_wait_ops;
+ record_full_beneath_to_wait = tmp_to_wait;
+ record_full_beneath_to_store_registers_ops = tmp_to_store_registers_ops;
+ record_full_beneath_to_store_registers = tmp_to_store_registers;
+ record_full_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops;
+ record_full_beneath_to_xfer_partial = tmp_to_xfer_partial;
+ record_full_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint;
+ record_full_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
+ record_full_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint;
+ record_full_beneath_to_stopped_data_address = tmp_to_stopped_data_address;
+ record_full_beneath_to_async = tmp_to_async;
if (core_bfd)
- record_core_open_1 (name, from_tty);
+ record_full_core_open_1 (name, from_tty);
else
- record_open_1 (name, from_tty);
+ record_full_open_1 (name, from_tty);
/* Register extra event sources in the event loop. */
- record_async_inferior_event_token
- = create_async_event_handler (record_async_inferior_event_handler,
+ record_full_async_inferior_event_token
+ = create_async_event_handler (record_full_async_inferior_event_handler,
NULL);
- record_init_record_breakpoints ();
+ record_full_init_record_breakpoints ();
observer_notify_record_changed (current_inferior (), 1);
}
@@ -1004,50 +1021,51 @@ record_open (char *name, int from_tty)
/* "to_close" target method. Close the process record target. */
static void
-record_close (int quitting)
+record_full_close (int quitting)
{
- struct record_core_buf_entry *entry;
+ struct record_full_core_buf_entry *entry;
if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n");
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_full_close\n");
- record_list_release (record_list);
+ record_full_list_release (record_full_list);
- /* Release record_core_regbuf. */
- if (record_core_regbuf)
+ /* Release record_full_core_regbuf. */
+ if (record_full_core_regbuf)
{
- xfree (record_core_regbuf);
- record_core_regbuf = NULL;
+ xfree (record_full_core_regbuf);
+ record_full_core_regbuf = NULL;
}
- /* Release record_core_buf_list. */
- if (record_core_buf_list)
+ /* Release record_full_core_buf_list. */
+ if (record_full_core_buf_list)
{
- for (entry = record_core_buf_list->prev; entry; entry = entry->prev)
+ for (entry = record_full_core_buf_list->prev; entry;
+ entry = entry->prev)
{
- xfree (record_core_buf_list);
- record_core_buf_list = entry;
+ xfree (record_full_core_buf_list);
+ record_full_core_buf_list = entry;
}
- record_core_buf_list = NULL;
+ record_full_core_buf_list = NULL;
}
- if (record_async_inferior_event_token)
- delete_async_event_handler (&record_async_inferior_event_token);
+ if (record_full_async_inferior_event_token)
+ delete_async_event_handler (&record_full_async_inferior_event_token);
}
-static int record_resume_step = 0;
+static int record_full_resume_step = 0;
-/* True if we've been resumed, and so each record_wait call should
- advance execution. If this is false, record_wait will return a
+/* True if we've been resumed, and so each record_full_wait call should
+ advance execution. If this is false, record_full_wait will return a
TARGET_WAITKIND_IGNORE. */
-static int record_resumed = 0;
+static int record_full_resumed = 0;
/* The execution direction of the last resume we got. This is
necessary for async mode. Vis (order is not strictly accurate):
1. user has the global execution direction set to forward
2. user does a reverse-step command
- 3. record_resume is called with global execution direction
+ 3. record_full_resume is called with global execution direction
temporarily switched to reverse
4. GDB's execution direction is reverted back to forward
5. target record notifies event loop there's an event to handle
@@ -1056,23 +1074,23 @@ static int record_resumed = 0;
7. infrun polls an event out of the record target, and handles it
8. GDB goes back to the event loop, and goto #4.
*/
-static enum exec_direction_kind record_execution_dir = EXEC_FORWARD;
+static enum exec_direction_kind record_full_execution_dir = EXEC_FORWARD;
/* "to_resume" target method. Resume the process record target. */
static void
-record_resume (struct target_ops *ops, ptid_t ptid, int step,
- enum gdb_signal signal)
+record_full_resume (struct target_ops *ops, ptid_t ptid, int step,
+ enum gdb_signal signal)
{
- record_resume_step = step;
- record_resumed = 1;
- record_execution_dir = execution_direction;
+ record_full_resume_step = step;
+ record_full_resumed = 1;
+ record_full_execution_dir = execution_direction;
- if (!RECORD_IS_REPLAY)
+ if (!RECORD_FULL_IS_REPLAY)
{
struct gdbarch *gdbarch = target_thread_architecture (ptid);
- record_message (get_current_regcache (), signal);
+ record_full_message (get_current_regcache (), signal);
if (!step)
{
@@ -1088,7 +1106,7 @@ record_resume (struct target_ops *ops, ptid_t ptid, int step,
if (single_step_breakpoints_inserted ())
{
/* This is a soft single step. */
- record_resume_step = 1;
+ record_full_resume_step = 1;
}
else
{
@@ -1108,8 +1126,8 @@ record_resume (struct target_ops *ops, ptid_t ptid, int step,
/* Make sure the target beneath reports all signals. */
target_pass_signals (0, NULL);
- record_beneath_to_resume (record_beneath_to_resume_ops,
- ptid, step, signal);
+ record_full_beneath_to_resume (record_full_beneath_to_resume_ops,
+ ptid, step, signal);
}
/* We are about to start executing the inferior (or simulate it),
@@ -1118,39 +1136,39 @@ record_resume (struct target_ops *ops, ptid_t ptid, int step,
{
target_async (inferior_event_handler, 0);
/* Notify the event loop there's an event to wait for. We do
- most of the work in record_wait. */
- mark_async_event_handler (record_async_inferior_event_token);
+ most of the work in record_full_wait. */
+ mark_async_event_handler (record_full_async_inferior_event_token);
}
}
-static int record_get_sig = 0;
+static int record_full_get_sig = 0;
/* SIGINT signal handler, registered by "to_wait" method. */
static void
-record_sig_handler (int signo)
+record_full_sig_handler (int signo)
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog, "Process record: get a signal\n");
/* It will break the running inferior in replay mode. */
- record_resume_step = 1;
+ record_full_resume_step = 1;
- /* It will let record_wait set inferior status to get the signal
+ /* It will let record_full_wait set inferior status to get the signal
SIGINT. */
- record_get_sig = 1;
+ record_full_get_sig = 1;
}
static void
-record_wait_cleanups (void *ignore)
+record_full_wait_cleanups (void *ignore)
{
if (execution_direction == EXEC_REVERSE)
{
- if (record_list->next)
- record_list = record_list->next;
+ if (record_full_list->next)
+ record_full_list = record_full_list->next;
}
else
- record_list = record_list->prev;
+ record_full_list = record_full_list->prev;
}
/* "to_wait" target method for process record target.
@@ -1167,20 +1185,22 @@ record_wait_cleanups (void *ignore)
where to stop. */
static ptid_t
-record_wait_1 (struct target_ops *ops,
- ptid_t ptid, struct target_waitstatus *status,
- int options)
+record_full_wait_1 (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *status,
+ int options)
{
struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
- "Process record: record_wait "
- "record_resume_step = %d, record_resumed = %d, direction=%s\n",
- record_resume_step, record_resumed,
- record_execution_dir == EXEC_FORWARD ? "forward" : "reverse");
-
- if (!record_resumed)
+ "Process record: record_full_wait "
+ "record_full_resume_step = %d, "
+ "record_full_resumed = %d, direction=%s\n",
+ record_full_resume_step, record_full_resumed,
+ record_full_execution_dir == EXEC_FORWARD
+ ? "forward" : "reverse");
+
+ if (!record_full_resumed)
{
gdb_assert ((options & TARGET_WNOHANG) != 0);
@@ -1189,16 +1209,16 @@ record_wait_1 (struct target_ops *ops,
return minus_one_ptid;
}
- record_get_sig = 0;
- signal (SIGINT, record_sig_handler);
+ record_full_get_sig = 0;
+ signal (SIGINT, record_full_sig_handler);
- if (!RECORD_IS_REPLAY && ops != &record_core_ops)
+ if (!RECORD_FULL_IS_REPLAY && ops != &record_full_core_ops)
{
- if (record_resume_step)
+ if (record_full_resume_step)
{
/* This is a single step. */
- return record_beneath_to_wait (record_beneath_to_wait_ops,
- ptid, status, options);
+ return record_full_beneath_to_wait (record_full_beneath_to_wait_ops,
+ ptid, status, options);
}
else
{
@@ -1209,13 +1229,13 @@ record_wait_1 (struct target_ops *ops,
while (1)
{
- ret = record_beneath_to_wait (record_beneath_to_wait_ops,
- ptid, status, options);
+ ret = record_full_beneath_to_wait
+ (record_full_beneath_to_wait_ops, ptid, status, options);
if (status->kind == TARGET_WAITKIND_IGNORE)
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
- "Process record: record_wait "
+ "Process record: record_full_wait "
"target beneath not done yet\n");
return ret;
}
@@ -1223,7 +1243,7 @@ record_wait_1 (struct target_ops *ops,
if (single_step_breakpoints_inserted ())
remove_single_step_breakpoints ();
- if (record_resume_step)
+ if (record_full_resume_step)
return ret;
/* Is this a SIGTRAP? */
@@ -1269,8 +1289,8 @@ record_wait_1 (struct target_ops *ops,
But GDB cannot handle it. */
int step = 1;
- if (!record_message_wrapper_safe (regcache,
- GDB_SIGNAL_0))
+ if (!record_full_message_wrapper_safe (regcache,
+ GDB_SIGNAL_0))
{
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = GDB_SIGNAL_0;
@@ -1291,11 +1311,12 @@ record_wait_1 (struct target_ops *ops,
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
- "Process record: record_wait "
- "issuing one more step in the target beneath\n");
- record_beneath_to_resume (record_beneath_to_resume_ops,
- ptid, step,
- GDB_SIGNAL_0);
+ "Process record: record_full_wait "
+ "issuing one more step in the "
+ "target beneath\n");
+ record_full_beneath_to_resume
+ (record_full_beneath_to_resume_ops, ptid, step,
+ GDB_SIGNAL_0);
continue;
}
}
@@ -1313,11 +1334,12 @@ record_wait_1 (struct target_ops *ops,
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct address_space *aspace = get_regcache_aspace (regcache);
int continue_flag = 1;
- int first_record_end = 1;
- struct cleanup *old_cleanups = make_cleanup (record_wait_cleanups, 0);
+ int first_record_full_end = 1;
+ struct cleanup *old_cleanups
+ = make_cleanup (record_full_wait_cleanups, 0);
CORE_ADDR tmp_pc;
- record_hw_watchpoint = 0;
+ record_full_hw_watchpoint = 0;
status->kind = TARGET_WAITKIND_STOPPED;
/* Check breakpoint when forward execute. */
@@ -1334,7 +1356,7 @@ record_wait_1 (struct target_ops *ops,
paddress (gdbarch, tmp_pc));
if (decr_pc_after_break
- && !record_resume_step
+ && !record_full_resume_step
&& software_breakpoint_inserted_here_p (aspace, tmp_pc))
regcache_write_pc (regcache,
tmp_pc + decr_pc_after_break);
@@ -1348,54 +1370,54 @@ record_wait_1 (struct target_ops *ops,
Then set it to terminal_ours to make GDB get the signal. */
target_terminal_ours ();
- /* In EXEC_FORWARD mode, record_list points to the tail of prev
+ /* In EXEC_FORWARD mode, record_full_list points to the tail of prev
instruction. */
- if (execution_direction == EXEC_FORWARD && record_list->next)
- record_list = record_list->next;
+ if (execution_direction == EXEC_FORWARD && record_full_list->next)
+ record_full_list = record_full_list->next;
- /* Loop over the record_list, looking for the next place to
+ /* Loop over the record_full_list, looking for the next place to
stop. */
do
{
/* Check for beginning and end of log. */
if (execution_direction == EXEC_REVERSE
- && record_list == &record_first)
+ && record_full_list == &record_full_first)
{
/* Hit beginning of record log in reverse. */
status->kind = TARGET_WAITKIND_NO_HISTORY;
break;
}
- if (execution_direction != EXEC_REVERSE && !record_list->next)
+ if (execution_direction != EXEC_REVERSE && !record_full_list->next)
{
/* Hit end of record log going forward. */
status->kind = TARGET_WAITKIND_NO_HISTORY;
break;
}
- record_exec_insn (regcache, gdbarch, record_list);
+ record_full_exec_insn (regcache, gdbarch, record_full_list);
- if (record_list->type == record_end)
+ if (record_full_list->type == record_full_end)
{
if (record_debug > 1)
fprintf_unfiltered (gdb_stdlog,
- "Process record: record_end %s to "
+ "Process record: record_full_end %s to "
"inferior.\n",
- host_address_to_string (record_list));
+ host_address_to_string (record_full_list));
- if (first_record_end && execution_direction == EXEC_REVERSE)
+ if (first_record_full_end && execution_direction == EXEC_REVERSE)
{
- /* When reverse excute, the first record_end is the part of
- current instruction. */
- first_record_end = 0;
+ /* When reverse excute, the first record_full_end is the
+ part of current instruction. */
+ first_record_full_end = 0;
}
else
{
- /* In EXEC_REVERSE mode, this is the record_end of prev
+ /* In EXEC_REVERSE mode, this is the record_full_end of prev
instruction.
- In EXEC_FORWARD mode, this is the record_end of current
- instruction. */
+ In EXEC_FORWARD mode, this is the record_full_end of
+ current instruction. */
/* step */
- if (record_resume_step)
+ if (record_full_resume_step)
{
if (record_debug > 1)
fprintf_unfiltered (gdb_stdlog,
@@ -1417,7 +1439,7 @@ record_wait_1 (struct target_ops *ops,
paddress (gdbarch, tmp_pc));
if (decr_pc_after_break
&& execution_direction == EXEC_FORWARD
- && !record_resume_step
+ && !record_full_resume_step
&& software_breakpoint_inserted_here_p (aspace,
tmp_pc))
regcache_write_pc (regcache,
@@ -1425,7 +1447,7 @@ record_wait_1 (struct target_ops *ops,
continue_flag = 0;
}
- if (record_hw_watchpoint)
+ if (record_full_hw_watchpoint)
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
@@ -1434,7 +1456,7 @@ record_wait_1 (struct target_ops *ops,
continue_flag = 0;
}
/* Check target signal */
- if (record_list->u.end.sigval != GDB_SIGNAL_0)
+ if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
/* FIXME: better way to check */
continue_flag = 0;
}
@@ -1444,24 +1466,24 @@ record_wait_1 (struct target_ops *ops,
{
if (execution_direction == EXEC_REVERSE)
{
- if (record_list->prev)
- record_list = record_list->prev;
+ if (record_full_list->prev)
+ record_full_list = record_full_list->prev;
}
else
{
- if (record_list->next)
- record_list = record_list->next;
+ if (record_full_list->next)
+ record_full_list = record_full_list->next;
}
}
}
while (continue_flag);
replay_out:
- if (record_get_sig)
+ if (record_full_get_sig)
status->value.sig = GDB_SIGNAL_INT;
- else if (record_list->u.end.sigval != GDB_SIGNAL_0)
+ else if (record_full_list->u.end.sigval != GDB_SIGNAL_0)
/* FIXME: better way to check */
- status->value.sig = record_list->u.end.sigval;
+ status->value.sig = record_full_list->u.end.sigval;
else
status->value.sig = GDB_SIGNAL_TRAP;
@@ -1475,100 +1497,101 @@ replay_out:
}
static ptid_t
-record_wait (struct target_ops *ops,
- ptid_t ptid, struct target_waitstatus *status,
- int options)
+record_full_wait (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *status,
+ int options)
{
ptid_t return_ptid;
- return_ptid = record_wait_1 (ops, ptid, status, options);
+ return_ptid = record_full_wait_1 (ops, ptid, status, options);
if (status->kind != TARGET_WAITKIND_IGNORE)
{
/* We're reporting a stop. Make sure any spurious
target_wait(WNOHANG) doesn't advance the target until the
core wants us resumed again. */
- record_resumed = 0;
+ record_full_resumed = 0;
}
return return_ptid;
}
static int
-record_stopped_by_watchpoint (void)
+record_full_stopped_by_watchpoint (void)
{
- if (RECORD_IS_REPLAY)
- return record_hw_watchpoint;
+ if (RECORD_FULL_IS_REPLAY)
+ return record_full_hw_watchpoint;
else
- return record_beneath_to_stopped_by_watchpoint ();
+ return record_full_beneath_to_stopped_by_watchpoint ();
}
/* "to_disconnect" method for process record target. */
static void
-record_disconnect (struct target_ops *target, char *args, int from_tty)
+record_full_disconnect (struct target_ops *target, char *args, int from_tty)
{
if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_disconnect\n");
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_full_disconnect\n");
- unpush_target (&record_ops);
+ unpush_target (&record_full_ops);
target_disconnect (args, from_tty);
}
/* "to_detach" method for process record target. */
static void
-record_detach (struct target_ops *ops, char *args, int from_tty)
+record_full_detach (struct target_ops *ops, char *args, int from_tty)
{
if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_detach\n");
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_full_detach\n");
- unpush_target (&record_ops);
+ unpush_target (&record_full_ops);
target_detach (args, from_tty);
}
/* "to_mourn_inferior" method for process record target. */
static void
-record_mourn_inferior (struct target_ops *ops)
+record_full_mourn_inferior (struct target_ops *ops)
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog, "Process record: "
- "record_mourn_inferior\n");
+ "record_full_mourn_inferior\n");
- unpush_target (&record_ops);
+ unpush_target (&record_full_ops);
target_mourn_inferior ();
}
/* Close process record target before killing the inferior process. */
static void
-record_kill (struct target_ops *ops)
+record_full_kill (struct target_ops *ops)
{
if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_kill\n");
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_full_kill\n");
- unpush_target (&record_ops);
+ unpush_target (&record_full_ops);
target_kill ();
}
static int
-record_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
+record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
{
- if (RECORD_IS_REPLAY)
+ if (RECORD_FULL_IS_REPLAY)
return 0;
else
- return record_beneath_to_stopped_data_address (ops, addr_p);
+ return record_full_beneath_to_stopped_data_address (ops, addr_p);
}
/* Record registers change (by user or by GDB) to list as an instruction. */
static void
-record_registers_change (struct regcache *regcache, int regnum)
+record_full_registers_change (struct regcache *regcache, int regnum)
{
- /* Check record_insn_num. */
- record_check_insn_num (0);
+ /* Check record_full_insn_num. */
+ record_full_check_insn_num (0);
- record_arch_list_head = NULL;
- record_arch_list_tail = NULL;
+ record_full_arch_list_head = NULL;
+ record_full_arch_list_tail = NULL;
if (regnum < 0)
{
@@ -1578,7 +1601,7 @@ record_registers_change (struct regcache *regcache, int regnum)
{
if (record_arch_list_add_reg (regcache, i))
{
- record_list_release (record_arch_list_tail);
+ record_full_list_release (record_full_arch_list_tail);
error (_("Process record: failed to record execution log."));
}
}
@@ -1587,34 +1610,36 @@ record_registers_change (struct regcache *regcache, int regnum)
{
if (record_arch_list_add_reg (regcache, regnum))
{
- record_list_release (record_arch_list_tail);
+ record_full_list_release (record_full_arch_list_tail);
error (_("Process record: failed to record execution log."));
}
}
if (record_arch_list_add_end ())
{
- record_list_release (record_arch_list_tail);
+ record_full_list_release (record_full_arch_list_tail);
error (_("Process record: failed to record execution log."));
}
- record_list->next = record_arch_list_head;
- record_arch_list_head->prev = record_list;
- record_list = record_arch_list_tail;
+ record_full_list->next = record_full_arch_list_head;
+ record_full_arch_list_head->prev = record_full_list;
+ record_full_list = record_full_arch_list_tail;
- if (record_insn_num == record_insn_max_num && record_insn_max_num)
- record_list_release_first ();
+ if (record_full_insn_num == record_full_insn_max_num
+ && record_full_insn_max_num)
+ record_full_list_release_first ();
else
- record_insn_num++;
+ record_full_insn_num++;
}
/* "to_store_registers" method for process record target. */
static void
-record_store_registers (struct target_ops *ops, struct regcache *regcache,
- int regno)
+record_full_store_registers (struct target_ops *ops,
+ struct regcache *regcache,
+ int regno)
{
- if (!record_gdb_operation_disable)
+ if (!record_full_gdb_operation_disable)
{
- if (RECORD_IS_REPLAY)
+ if (RECORD_FULL_IS_REPLAY)
{
int n;
@@ -1653,29 +1678,31 @@ record_store_registers (struct target_ops *ops, struct regcache *regcache,
}
/* Destroy the record from here forward. */
- record_list_release_following (record_list);
+ record_full_list_release_following (record_full_list);
}
- record_registers_change (regcache, regno);
+ record_full_registers_change (regcache, regno);
}
- record_beneath_to_store_registers (record_beneath_to_store_registers_ops,
- regcache, regno);
+ record_full_beneath_to_store_registers
+ (record_full_beneath_to_store_registers_ops, regcache, regno);
}
-/* "to_xfer_partial" method. Behavior is conditional on RECORD_IS_REPLAY.
+/* "to_xfer_partial" method. Behavior is conditional on
+ RECORD_FULL_IS_REPLAY.
In replay mode, we cannot write memory unles we are willing to
invalidate the record/replay log from this point forward. */
static LONGEST
-record_xfer_partial (struct target_ops *ops, enum target_object object,
- const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+record_full_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset,
+ LONGEST len)
{
- if (!record_gdb_operation_disable
+ if (!record_full_gdb_operation_disable
&& (object == TARGET_OBJECT_MEMORY
|| object == TARGET_OBJECT_RAW_MEMORY) && writebuf)
{
- if (RECORD_IS_REPLAY)
+ if (RECORD_FULL_IS_REPLAY)
{
/* Let user choose if he wants to write memory or not. */
if (!query (_("Because GDB is in replay mode, writing to memory "
@@ -1685,18 +1712,18 @@ record_xfer_partial (struct target_ops *ops, enum target_object object,
error (_("Process record canceled the operation."));
/* Destroy the record from here forward. */
- record_list_release_following (record_list);
+ record_full_list_release_following (record_full_list);
}
- /* Check record_insn_num */
- record_check_insn_num (0);
+ /* Check record_full_insn_num */
+ record_full_check_insn_num (0);
/* Record registers change to list as an instruction. */
- record_arch_list_head = NULL;
- record_arch_list_tail = NULL;
+ record_full_arch_list_head = NULL;
+ record_full_arch_list_tail = NULL;
if (record_arch_list_add_mem (offset, len))
{
- record_list_release (record_arch_list_tail);
+ record_full_list_release (record_full_arch_list_tail);
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
"Process record: failed to record "
@@ -1705,26 +1732,27 @@ record_xfer_partial (struct target_ops *ops, enum target_object object,
}
if (record_arch_list_add_end ())
{
- record_list_release (record_arch_list_tail);
+ record_full_list_release (record_full_arch_list_tail);
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
"Process record: failed to record "
"execution log.");
return -1;
}
- record_list->next = record_arch_list_head;
- record_arch_list_head->prev = record_list;
- record_list = record_arch_list_tail;
+ record_full_list->next = record_full_arch_list_head;
+ record_full_arch_list_head->prev = record_full_list;
+ record_full_list = record_full_arch_list_tail;
- if (record_insn_num == record_insn_max_num && record_insn_max_num)
- record_list_release_first ();
+ if (record_full_insn_num == record_full_insn_max_num
+ && record_full_insn_max_num)
+ record_full_list_release_first ();
else
- record_insn_num++;
+ record_full_insn_num++;
}
- return record_beneath_to_xfer_partial (record_beneath_to_xfer_partial_ops,
- object, annex, readbuf, writebuf,
- offset, len);
+ return record_full_beneath_to_xfer_partial
+ (record_full_beneath_to_xfer_partial_ops, object, annex,
+ readbuf, writebuf, offset, len);
}
/* This structure represents a breakpoint inserted while the record
@@ -1734,7 +1762,7 @@ record_xfer_partial (struct target_ops *ops, enum target_object object,
recording. In that case, the breakpoint had not been inserted on
the target beneath, so we should not try to remove it there. */
-struct record_breakpoint
+struct record_full_breakpoint
{
/* The address and address space the breakpoint was set at. */
struct address_space *address_space;
@@ -1746,54 +1774,54 @@ struct record_breakpoint
int in_target_beneath;
};
-typedef struct record_breakpoint *record_breakpoint_p;
-DEF_VEC_P(record_breakpoint_p);
+typedef struct record_full_breakpoint *record_full_breakpoint_p;
+DEF_VEC_P(record_full_breakpoint_p);
/* The list of breakpoints inserted while the record target is
active. */
-VEC(record_breakpoint_p) *record_breakpoints = NULL;
+VEC(record_full_breakpoint_p) *record_full_breakpoints = NULL;
static void
-record_sync_record_breakpoints (struct bp_location *loc, void *data)
+record_full_sync_record_breakpoints (struct bp_location *loc, void *data)
{
if (loc->loc_type != bp_loc_software_breakpoint)
return;
if (loc->inserted)
{
- struct record_breakpoint *bp = XNEW (struct record_breakpoint);
+ struct record_full_breakpoint *bp = XNEW (struct record_full_breakpoint);
bp->addr = loc->target_info.placed_address;
bp->address_space = loc->target_info.placed_address_space;
bp->in_target_beneath = 1;
- VEC_safe_push (record_breakpoint_p, record_breakpoints, bp);
+ VEC_safe_push (record_full_breakpoint_p, record_full_breakpoints, bp);
}
}
-/* Sync existing breakpoints to record_breakpoints. */
+/* Sync existing breakpoints to record_full_breakpoints. */
static void
-record_init_record_breakpoints (void)
+record_full_init_record_breakpoints (void)
{
- VEC_free (record_breakpoint_p, record_breakpoints);
+ VEC_free (record_full_breakpoint_p, record_full_breakpoints);
- iterate_over_bp_locations (record_sync_record_breakpoints);
+ iterate_over_bp_locations (record_full_sync_record_breakpoints);
}
-/* Behavior is conditional on RECORD_IS_REPLAY. We will not actually
+/* Behavior is conditional on RECORD_FULL_IS_REPLAY. We will not actually
insert or remove breakpoints in the real target when replaying, nor
when recording. */
static int
-record_insert_breakpoint (struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
+record_full_insert_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
- struct record_breakpoint *bp;
+ struct record_full_breakpoint *bp;
int in_target_beneath = 0;
- if (!RECORD_IS_REPLAY)
+ if (!RECORD_FULL_IS_REPLAY)
{
/* When recording, we currently always single-step, so we don't
really need to install regular breakpoints in the inferior.
@@ -1804,7 +1832,7 @@ record_insert_breakpoint (struct gdbarch *gdbarch,
int ret;
old_cleanups = record_gdb_operation_disable_set ();
- ret = record_beneath_to_insert_breakpoint (gdbarch, bp_tgt);
+ ret = record_full_beneath_to_insert_breakpoint (gdbarch, bp_tgt);
do_cleanups (old_cleanups);
if (ret != 0)
@@ -1813,25 +1841,26 @@ record_insert_breakpoint (struct gdbarch *gdbarch,
in_target_beneath = 1;
}
- bp = XNEW (struct record_breakpoint);
+ bp = XNEW (struct record_full_breakpoint);
bp->addr = bp_tgt->placed_address;
bp->address_space = bp_tgt->placed_address_space;
bp->in_target_beneath = in_target_beneath;
- VEC_safe_push (record_breakpoint_p, record_breakpoints, bp);
+ VEC_safe_push (record_full_breakpoint_p, record_full_breakpoints, bp);
return 0;
}
/* "to_remove_breakpoint" method for process record target. */
static int
-record_remove_breakpoint (struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
+record_full_remove_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
- struct record_breakpoint *bp;
+ struct record_full_breakpoint *bp;
int ix;
for (ix = 0;
- VEC_iterate (record_breakpoint_p, record_breakpoints, ix, bp);
+ VEC_iterate (record_full_breakpoint_p,
+ record_full_breakpoints, ix, bp);
++ix)
{
if (bp->addr == bp_tgt->placed_address
@@ -1843,14 +1872,15 @@ record_remove_breakpoint (struct gdbarch *gdbarch,
int ret;
old_cleanups = record_gdb_operation_disable_set ();
- ret = record_beneath_to_remove_breakpoint (gdbarch, bp_tgt);
+ ret = record_full_beneath_to_remove_breakpoint (gdbarch, bp_tgt);
do_cleanups (old_cleanups);
if (ret != 0)
return ret;
}
- VEC_unordered_remove (record_breakpoint_p, record_breakpoints, ix);
+ VEC_unordered_remove (record_full_breakpoint_p,
+ record_full_breakpoints, ix);
return 0;
}
}
@@ -1861,7 +1891,7 @@ record_remove_breakpoint (struct gdbarch *gdbarch,
/* "to_can_execute_reverse" method for process record target. */
static int
-record_can_execute_reverse (void)
+record_full_can_execute_reverse (void)
{
return 1;
}
@@ -1869,22 +1899,22 @@ record_can_execute_reverse (void)
/* "to_get_bookmark" method for process record and prec over core. */
static gdb_byte *
-record_get_bookmark (char *args, int from_tty)
+record_full_get_bookmark (char *args, int from_tty)
{
gdb_byte *ret = NULL;
/* Return stringified form of instruction count. */
- if (record_list && record_list->type == record_end)
- ret = xstrdup (pulongest (record_list->u.end.insn_num));
+ if (record_full_list && record_full_list->type == record_full_end)
+ ret = xstrdup (pulongest (record_full_list->u.end.insn_num));
if (record_debug)
{
if (ret)
fprintf_unfiltered (gdb_stdlog,
- "record_get_bookmark returns %s\n", ret);
+ "record_full_get_bookmark returns %s\n", ret);
else
fprintf_unfiltered (gdb_stdlog,
- "record_get_bookmark returns NULL\n");
+ "record_full_get_bookmark returns NULL\n");
}
return ret;
}
@@ -1892,11 +1922,11 @@ record_get_bookmark (char *args, int from_tty)
/* "to_goto_bookmark" method for process record and prec over core. */
static void
-record_goto_bookmark (gdb_byte *bookmark, int from_tty)
+record_full_goto_bookmark (gdb_byte *bookmark, int from_tty)
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
- "record_goto_bookmark receives %s\n", bookmark);
+ "record_full_goto_bookmark receives %s\n", bookmark);
if (bookmark[0] == '\'' || bookmark[0] == '\"')
{
@@ -1907,7 +1937,7 @@ record_goto_bookmark (gdb_byte *bookmark, int from_tty)
bookmark[strlen (bookmark) - 1] = '\0';
/* Strip leading quote. */
bookmark++;
- /* Pass along to cmd_record_goto. */
+ /* Pass along to cmd_record_full_goto. */
}
cmd_record_goto ((char *) bookmark, from_tty);
@@ -1915,116 +1945,116 @@ record_goto_bookmark (gdb_byte *bookmark, int from_tty)
}
static void
-record_async (void (*callback) (enum inferior_event_type event_type,
- void *context), void *context)
+record_full_async (void (*callback) (enum inferior_event_type event_type,
+ void *context), void *context)
{
/* If we're on top of a line target (e.g., linux-nat, remote), then
set it to async mode as well. Will be NULL if we're sitting on
top of the core target, for "record restore". */
- if (record_beneath_to_async != NULL)
- record_beneath_to_async (callback, context);
+ if (record_full_beneath_to_async != NULL)
+ record_full_beneath_to_async (callback, context);
}
static int
-record_can_async_p (void)
+record_full_can_async_p (void)
{
/* We only enable async when the user specifically asks for it. */
return target_async_permitted;
}
static int
-record_is_async_p (void)
+record_full_is_async_p (void)
{
/* We only enable async when the user specifically asks for it. */
return target_async_permitted;
}
static enum exec_direction_kind
-record_execution_direction (void)
+record_full_execution_direction (void)
{
- return record_execution_dir;
+ return record_full_execution_dir;
}
static void
-record_info (void)
+record_full_info (void)
{
- struct record_entry *p;
+ struct record_full_entry *p;
- if (RECORD_IS_REPLAY)
+ if (RECORD_FULL_IS_REPLAY)
printf_filtered (_("Replay mode:\n"));
else
printf_filtered (_("Record mode:\n"));
/* Find entry for first actual instruction in the log. */
- for (p = record_first.next;
- p != NULL && p->type != record_end;
+ for (p = record_full_first.next;
+ p != NULL && p->type != record_full_end;
p = p->next)
;
/* Do we have a log at all? */
- if (p != NULL && p->type == record_end)
+ if (p != NULL && p->type == record_full_end)
{
/* Display instruction number for first instruction in the log. */
printf_filtered (_("Lowest recorded instruction number is %s.\n"),
pulongest (p->u.end.insn_num));
/* If in replay mode, display where we are in the log. */
- if (RECORD_IS_REPLAY)
+ if (RECORD_FULL_IS_REPLAY)
printf_filtered (_("Current instruction number is %s.\n"),
- pulongest (record_list->u.end.insn_num));
+ pulongest (record_full_list->u.end.insn_num));
/* Display instruction number for last instruction in the log. */
printf_filtered (_("Highest recorded instruction number is %s.\n"),
- pulongest (record_insn_count));
+ pulongest (record_full_insn_count));
/* Display log count. */
printf_filtered (_("Log contains %d instructions.\n"),
- record_insn_num);
+ record_full_insn_num);
}
else
printf_filtered (_("No instructions have been logged.\n"));
/* Display max log size. */
printf_filtered (_("Max logged instructions is %d.\n"),
- record_insn_max_num);
+ record_full_insn_max_num);
}
/* The "to_record_delete" target method. */
static void
-record_delete (void)
+record_full_delete (void)
{
- record_list_release_following (record_list);
+ record_full_list_release_following (record_full_list);
}
/* The "to_record_is_replaying" target method. */
static int
-record_is_replaying (void)
+record_full_is_replaying (void)
{
- return RECORD_IS_REPLAY;
+ return RECORD_FULL_IS_REPLAY;
}
/* Go to a specific entry. */
static void
-record_goto_entry (struct record_entry *p)
+record_full_goto_entry (struct record_full_entry *p)
{
if (p == NULL)
error (_("Target insn not found."));
- else if (p == record_list)
+ else if (p == record_full_list)
error (_("Already at target insn."));
- else if (p->u.end.insn_num > record_list->u.end.insn_num)
+ else if (p->u.end.insn_num > record_full_list->u.end.insn_num)
{
printf_filtered (_("Go forward to insn number %s\n"),
pulongest (p->u.end.insn_num));
- record_goto_insn (p, EXEC_FORWARD);
+ record_full_goto_insn (p, EXEC_FORWARD);
}
else
{
printf_filtered (_("Go backward to insn number %s\n"),
pulongest (p->u.end.insn_num));
- record_goto_insn (p, EXEC_REVERSE);
+ record_full_goto_insn (p, EXEC_REVERSE);
}
registers_changed ();
@@ -2035,97 +2065,97 @@ record_goto_entry (struct record_entry *p)
/* The "to_goto_record_begin" target method. */
static void
-record_goto_begin (void)
+record_full_goto_begin (void)
{
- struct record_entry *p = NULL;
+ struct record_full_entry *p = NULL;
- for (p = &record_first; p != NULL; p = p->next)
- if (p->type == record_end)
+ for (p = &record_full_first; p != NULL; p = p->next)
+ if (p->type == record_full_end)
break;
- record_goto_entry (p);
+ record_full_goto_entry (p);
}
/* The "to_goto_record_end" target method. */
static void
-record_goto_end (void)
+record_full_goto_end (void)
{
- struct record_entry *p = NULL;
+ struct record_full_entry *p = NULL;
- for (p = record_list; p->next != NULL; p = p->next)
+ for (p = record_full_list; p->next != NULL; p = p->next)
;
for (; p!= NULL; p = p->prev)
- if (p->type == record_end)
+ if (p->type == record_full_end)
break;
- record_goto_entry (p);
+ record_full_goto_entry (p);
}
/* The "to_goto_record" target method. */
static void
-record_goto (ULONGEST target_insn)
+record_full_goto (ULONGEST target_insn)
{
- struct record_entry *p = NULL;
+ struct record_full_entry *p = NULL;
- for (p = &record_first; p != NULL; p = p->next)
- if (p->type == record_end && p->u.end.insn_num == target_insn)
+ for (p = &record_full_first; p != NULL; p = p->next)
+ if (p->type == record_full_end && p->u.end.insn_num == target_insn)
break;
- record_goto_entry (p);
+ record_full_goto_entry (p);
}
static void
-init_record_ops (void)
+init_record_full_ops (void)
{
- record_ops.to_shortname = "record-full";
- record_ops.to_longname = "Process record and replay target";
- record_ops.to_doc =
+ record_full_ops.to_shortname = "record-full";
+ record_full_ops.to_longname = "Process record and replay target";
+ record_full_ops.to_doc =
"Log program while executing and replay execution from log.";
- record_ops.to_open = record_open;
- record_ops.to_close = record_close;
- record_ops.to_resume = record_resume;
- record_ops.to_wait = record_wait;
- record_ops.to_disconnect = record_disconnect;
- record_ops.to_detach = record_detach;
- record_ops.to_mourn_inferior = record_mourn_inferior;
- record_ops.to_kill = record_kill;
- record_ops.to_create_inferior = find_default_create_inferior;
- record_ops.to_store_registers = record_store_registers;
- record_ops.to_xfer_partial = record_xfer_partial;
- record_ops.to_insert_breakpoint = record_insert_breakpoint;
- record_ops.to_remove_breakpoint = record_remove_breakpoint;
- record_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint;
- record_ops.to_stopped_data_address = record_stopped_data_address;
- record_ops.to_can_execute_reverse = record_can_execute_reverse;
- record_ops.to_stratum = record_stratum;
+ record_full_ops.to_open = record_full_open;
+ record_full_ops.to_close = record_full_close;
+ record_full_ops.to_resume = record_full_resume;
+ record_full_ops.to_wait = record_full_wait;
+ record_full_ops.to_disconnect = record_full_disconnect;
+ record_full_ops.to_detach = record_full_detach;
+ record_full_ops.to_mourn_inferior = record_full_mourn_inferior;
+ record_full_ops.to_kill = record_full_kill;
+ record_full_ops.to_create_inferior = find_default_create_inferior;
+ record_full_ops.to_store_registers = record_full_store_registers;
+ record_full_ops.to_xfer_partial = record_full_xfer_partial;
+ record_full_ops.to_insert_breakpoint = record_full_insert_breakpoint;
+ record_full_ops.to_remove_breakpoint = record_full_remove_breakpoint;
+ record_full_ops.to_stopped_by_watchpoint = record_full_stopped_by_watchpoint;
+ record_full_ops.to_stopped_data_address = record_full_stopped_data_address;
+ record_full_ops.to_can_execute_reverse = record_full_can_execute_reverse;
+ record_full_ops.to_stratum = record_stratum;
/* Add bookmark target methods. */
- record_ops.to_get_bookmark = record_get_bookmark;
- record_ops.to_goto_bookmark = record_goto_bookmark;
- record_ops.to_async = record_async;
- record_ops.to_can_async_p = record_can_async_p;
- record_ops.to_is_async_p = record_is_async_p;
- record_ops.to_execution_direction = record_execution_direction;
- record_ops.to_info_record = record_info;
- record_ops.to_save_record = record_save;
- record_ops.to_delete_record = record_delete;
- record_ops.to_record_is_replaying = record_is_replaying;
- record_ops.to_goto_record_begin = record_goto_begin;
- record_ops.to_goto_record_end = record_goto_end;
- record_ops.to_goto_record = record_goto;
- record_ops.to_magic = OPS_MAGIC;
+ record_full_ops.to_get_bookmark = record_full_get_bookmark;
+ record_full_ops.to_goto_bookmark = record_full_goto_bookmark;
+ record_full_ops.to_async = record_full_async;
+ record_full_ops.to_can_async_p = record_full_can_async_p;
+ record_full_ops.to_is_async_p = record_full_is_async_p;
+ record_full_ops.to_execution_direction = record_full_execution_direction;
+ record_full_ops.to_info_record = record_full_info;
+ record_full_ops.to_save_record = record_full_save;
+ record_full_ops.to_delete_record = record_full_delete;
+ record_full_ops.to_record_is_replaying = record_full_is_replaying;
+ record_full_ops.to_goto_record_begin = record_full_goto_begin;
+ record_full_ops.to_goto_record_end = record_full_goto_end;
+ record_full_ops.to_goto_record = record_full_goto;
+ record_full_ops.to_magic = OPS_MAGIC;
}
/* "to_resume" method for prec over corefile. */
static void
-record_core_resume (struct target_ops *ops, ptid_t ptid, int step,
- enum gdb_signal signal)
+record_full_core_resume (struct target_ops *ops, ptid_t ptid, int step,
+ enum gdb_signal signal)
{
- record_resume_step = step;
- record_resumed = 1;
- record_execution_dir = execution_direction;
+ record_full_resume_step = step;
+ record_full_resumed = 1;
+ record_full_execution_dir = execution_direction;
/* We are about to start executing the inferior (or simulate it),
let's register it with the event loop. */
@@ -2134,27 +2164,27 @@ record_core_resume (struct target_ops *ops, ptid_t ptid, int step,
target_async (inferior_event_handler, 0);
/* Notify the event loop there's an event to wait for. */
- mark_async_event_handler (record_async_inferior_event_token);
+ mark_async_event_handler (record_full_async_inferior_event_token);
}
}
/* "to_kill" method for prec over corefile. */
static void
-record_core_kill (struct target_ops *ops)
+record_full_core_kill (struct target_ops *ops)
{
if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_core_kill\n");
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_full_core_kill\n");
- unpush_target (&record_core_ops);
+ unpush_target (&record_full_core_ops);
}
/* "to_fetch_registers" method for prec over corefile. */
static void
-record_core_fetch_registers (struct target_ops *ops,
- struct regcache *regcache,
- int regno)
+record_full_core_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache,
+ int regno)
{
if (regno < 0)
{
@@ -2163,30 +2193,30 @@ record_core_fetch_registers (struct target_ops *ops,
for (i = 0; i < num; i ++)
regcache_raw_supply (regcache, i,
- record_core_regbuf + MAX_REGISTER_SIZE * i);
+ record_full_core_regbuf + MAX_REGISTER_SIZE * i);
}
else
regcache_raw_supply (regcache, regno,
- record_core_regbuf + MAX_REGISTER_SIZE * regno);
+ record_full_core_regbuf + MAX_REGISTER_SIZE * regno);
}
/* "to_prepare_to_store" method for prec over corefile. */
static void
-record_core_prepare_to_store (struct regcache *regcache)
+record_full_core_prepare_to_store (struct regcache *regcache)
{
}
/* "to_store_registers" method for prec over corefile. */
static void
-record_core_store_registers (struct target_ops *ops,
+record_full_core_store_registers (struct target_ops *ops,
struct regcache *regcache,
int regno)
{
- if (record_gdb_operation_disable)
+ if (record_full_gdb_operation_disable)
regcache_raw_collect (regcache, regno,
- record_core_regbuf + MAX_REGISTER_SIZE * regno);
+ record_full_core_regbuf + MAX_REGISTER_SIZE * regno);
else
error (_("You can't do that without a process to debug."));
}
@@ -2194,22 +2224,23 @@ record_core_store_registers (struct target_ops *ops,
/* "to_xfer_partial" method for prec over corefile. */
static LONGEST
-record_core_xfer_partial (struct target_ops *ops, enum target_object object,
- const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf, ULONGEST offset,
- LONGEST len)
+record_full_core_xfer_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset,
+ LONGEST len)
{
if (object == TARGET_OBJECT_MEMORY)
{
- if (record_gdb_operation_disable || !writebuf)
+ if (record_full_gdb_operation_disable || !writebuf)
{
struct target_section *p;
- for (p = record_core_start; p < record_core_end; p++)
+ for (p = record_full_core_start; p < record_full_core_end; p++)
{
if (offset >= p->addr)
{
- struct record_core_buf_entry *entry;
+ struct record_full_core_buf_entry *entry;
ULONGEST sec_offset;
if (offset >= p->endaddr)
@@ -2229,8 +2260,8 @@ record_core_xfer_partial (struct target_ops *ops, enum target_object object,
memset (readbuf, 0, len);
return len;
}
- /* Get record_core_buf_entry. */
- for (entry = record_core_buf_list; entry;
+ /* Get record_full_core_buf_entry. */
+ for (entry = record_full_core_buf_list; entry;
entry = entry->prev)
if (entry->p == p)
break;
@@ -2239,8 +2270,9 @@ record_core_xfer_partial (struct target_ops *ops, enum target_object object,
if (!entry)
{
/* Add a new entry. */
- entry = (struct record_core_buf_entry *)
- xmalloc (sizeof (struct record_core_buf_entry));
+ entry = (struct record_full_core_buf_entry *)
+ xmalloc
+ (sizeof (struct record_full_core_buf_entry));
entry->p = p;
if (!bfd_malloc_and_get_section (p->bfd,
p->the_bfd_section,
@@ -2249,8 +2281,8 @@ record_core_xfer_partial (struct target_ops *ops, enum target_object object,
xfree (entry);
return 0;
}
- entry->prev = record_core_buf_list;
- record_core_buf_list = entry;
+ entry->prev = record_full_core_buf_list;
+ record_full_core_buf_list = entry;
}
memcpy (entry->buf + sec_offset, writebuf,
@@ -2259,8 +2291,8 @@ record_core_xfer_partial (struct target_ops *ops, enum target_object object,
else
{
if (!entry)
- return record_beneath_to_xfer_partial
- (record_beneath_to_xfer_partial_ops,
+ return record_full_beneath_to_xfer_partial
+ (record_full_beneath_to_xfer_partial_ops,
object, annex, readbuf, writebuf,
offset, len);
@@ -2278,16 +2310,16 @@ record_core_xfer_partial (struct target_ops *ops, enum target_object object,
error (_("You can't do that without a process to debug."));
}
- return record_beneath_to_xfer_partial (record_beneath_to_xfer_partial_ops,
- object, annex, readbuf, writebuf,
- offset, len);
+ return record_full_beneath_to_xfer_partial
+ (record_full_beneath_to_xfer_partial_ops, object, annex,
+ readbuf, writebuf, offset, len);
}
/* "to_insert_breakpoint" method for prec over corefile. */
static int
-record_core_insert_breakpoint (struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
+record_full_core_insert_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
return 0;
}
@@ -2295,8 +2327,8 @@ record_core_insert_breakpoint (struct gdbarch *gdbarch,
/* "to_remove_breakpoint" method for prec over corefile. */
static int
-record_core_remove_breakpoint (struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
+record_full_core_remove_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
return 0;
}
@@ -2304,48 +2336,54 @@ record_core_remove_breakpoint (struct gdbarch *gdbarch,
/* "to_has_execution" method for prec over corefile. */
static int
-record_core_has_execution (struct target_ops *ops, ptid_t the_ptid)
+record_full_core_has_execution (struct target_ops *ops, ptid_t the_ptid)
{
return 1;
}
static void
-init_record_core_ops (void)
+init_record_full_core_ops (void)
{
- record_core_ops.to_shortname = "record-core";
- record_core_ops.to_longname = "Process record and replay target";
- record_core_ops.to_doc =
+ record_full_core_ops.to_shortname = "record-core";
+ record_full_core_ops.to_longname = "Process record and replay target";
+ record_full_core_ops.to_doc =
"Log program while executing and replay execution from log.";
- record_core_ops.to_open = record_open;
- record_core_ops.to_close = record_close;
- record_core_ops.to_resume = record_core_resume;
- record_core_ops.to_wait = record_wait;
- record_core_ops.to_kill = record_core_kill;
- record_core_ops.to_fetch_registers = record_core_fetch_registers;
- record_core_ops.to_prepare_to_store = record_core_prepare_to_store;
- record_core_ops.to_store_registers = record_core_store_registers;
- record_core_ops.to_xfer_partial = record_core_xfer_partial;
- record_core_ops.to_insert_breakpoint = record_core_insert_breakpoint;
- record_core_ops.to_remove_breakpoint = record_core_remove_breakpoint;
- record_core_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint;
- record_core_ops.to_stopped_data_address = record_stopped_data_address;
- record_core_ops.to_can_execute_reverse = record_can_execute_reverse;
- record_core_ops.to_has_execution = record_core_has_execution;
- record_core_ops.to_stratum = record_stratum;
+ record_full_core_ops.to_open = record_full_open;
+ record_full_core_ops.to_close = record_full_close;
+ record_full_core_ops.to_resume = record_full_core_resume;
+ record_full_core_ops.to_wait = record_full_wait;
+ record_full_core_ops.to_kill = record_full_core_kill;
+ record_full_core_ops.to_fetch_registers = record_full_core_fetch_registers;
+ record_full_core_ops.to_prepare_to_store = record_full_core_prepare_to_store;
+ record_full_core_ops.to_store_registers = record_full_core_store_registers;
+ record_full_core_ops.to_xfer_partial = record_full_core_xfer_partial;
+ record_full_core_ops.to_insert_breakpoint
+ = record_full_core_insert_breakpoint;
+ record_full_core_ops.to_remove_breakpoint
+ = record_full_core_remove_breakpoint;
+ record_full_core_ops.to_stopped_by_watchpoint
+ = record_full_stopped_by_watchpoint;
+ record_full_core_ops.to_stopped_data_address
+ = record_full_stopped_data_address;
+ record_full_core_ops.to_can_execute_reverse
+ = record_full_can_execute_reverse;
+ record_full_core_ops.to_has_execution = record_full_core_has_execution;
+ record_full_core_ops.to_stratum = record_stratum;
/* Add bookmark target methods. */
- record_core_ops.to_get_bookmark = record_get_bookmark;
- record_core_ops.to_goto_bookmark = record_goto_bookmark;
- record_core_ops.to_async = record_async;
- record_core_ops.to_can_async_p = record_can_async_p;
- record_core_ops.to_is_async_p = record_is_async_p;
- record_core_ops.to_execution_direction = record_execution_direction;
- record_core_ops.to_info_record = record_info;
- record_core_ops.to_delete_record = record_delete;
- record_core_ops.to_record_is_replaying = record_is_replaying;
- record_core_ops.to_goto_record_begin = record_goto_begin;
- record_core_ops.to_goto_record_end = record_goto_end;
- record_core_ops.to_goto_record = record_goto;
- record_core_ops.to_magic = OPS_MAGIC;
+ record_full_core_ops.to_get_bookmark = record_full_get_bookmark;
+ record_full_core_ops.to_goto_bookmark = record_full_goto_bookmark;
+ record_full_core_ops.to_async = record_full_async;
+ record_full_core_ops.to_can_async_p = record_full_can_async_p;
+ record_full_core_ops.to_is_async_p = record_full_is_async_p;
+ record_full_core_ops.to_execution_direction
+ = record_full_execution_direction;
+ record_full_core_ops.to_info_record = record_full_info;
+ record_full_core_ops.to_delete_record = record_full_delete;
+ record_full_core_ops.to_record_is_replaying = record_full_is_replaying;
+ record_full_core_ops.to_goto_record_begin = record_full_goto_begin;
+ record_full_core_ops.to_goto_record_end = record_full_goto_end;
+ record_full_core_ops.to_goto_record = record_full_goto;
+ record_full_core_ops.to_magic = OPS_MAGIC;
}
/* Record log save-file format
@@ -2356,14 +2394,14 @@ init_record_core_ops (void)
NOTE: be sure to change whenever this file format changes!
Records:
- record_end:
- 1 byte: record type (record_end, see enum record_type).
- record_reg:
- 1 byte: record type (record_reg, see enum record_type).
+ record_full_end:
+ 1 byte: record type (record_full_end, see enum record_full_type).
+ record_full_reg:
+ 1 byte: record type (record_full_reg, see enum record_full_type).
8 bytes: register id (network byte order).
MAX_REGISTER_SIZE bytes: register value.
- record_mem:
- 1 byte: record type (record_mem, see enum record_type).
+ record_full_mem:
+ 1 byte: record type (record_full_mem, see enum record_full_type).
8 bytes: memory length (network byte order).
8 bytes: memory address (network byte order).
n bytes: memory value (n == memory length).
@@ -2373,17 +2411,17 @@ init_record_core_ops (void)
NOTE: be sure to change whenever this file format changes!
Records:
- record_end:
- 1 byte: record type (record_end, see enum record_type).
+ record_full_end:
+ 1 byte: record type (record_full_end, see enum record_full_type).
4 bytes: signal
4 bytes: instruction count
- record_reg:
- 1 byte: record type (record_reg, see enum record_type).
+ record_full_reg:
+ 1 byte: record type (record_full_reg, see enum record_full_type).
4 bytes: register id (network byte order).
n bytes: register value (n == actual register size).
(eg. 4 bytes for x86 general registers).
- record_mem:
- 1 byte: record type (record_mem, see enum record_type).
+ record_full_mem:
+ 1 byte: record type (record_full_mem, see enum record_full_type).
4 bytes: memory length (network byte order).
8 bytes: memory address (network byte order).
n bytes: memory value (n == memory length).
@@ -2437,11 +2475,11 @@ netorder16 (uint16_t input)
/* Restore the execution log from a core_bfd file. */
static void
-record_restore (void)
+record_full_restore (void)
{
uint32_t magic;
struct cleanup *old_cleanups;
- struct record_entry *rec;
+ struct record_full_entry *rec;
asection *osec;
uint32_t osec_size;
int bfd_offset = 0;
@@ -2452,8 +2490,8 @@ record_restore (void)
if (core_bfd == NULL)
return;
- /* "record_restore" can only be called when record list is empty. */
- gdb_assert (record_first.next == NULL);
+ /* "record_full_restore" can only be called when record list is empty. */
+ gdb_assert (record_full_first.next == NULL);
if (record_debug)
fprintf_unfiltered (gdb_stdlog, "Restoring recording from core file.\n");
@@ -2471,21 +2509,21 @@ record_restore (void)
/* Check the magic code. */
bfdcore_read (core_bfd, osec, &magic, sizeof (magic), &bfd_offset);
- if (magic != RECORD_FILE_MAGIC)
+ if (magic != RECORD_FULL_FILE_MAGIC)
error (_("Version mis-match or file format error in core file %s."),
bfd_get_filename (core_bfd));
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
" Reading 4-byte magic cookie "
- "RECORD_FILE_MAGIC (0x%s)\n",
+ "RECORD_FULL_FILE_MAGIC (0x%s)\n",
phex_nz (netorder32 (magic), 4));
- /* Restore the entries in recfd into record_arch_list_head and
- record_arch_list_tail. */
- record_arch_list_head = NULL;
- record_arch_list_tail = NULL;
- record_insn_num = 0;
- old_cleanups = make_cleanup (record_arch_list_cleanups, 0);
+ /* Restore the entries in recfd into record_full_arch_list_head and
+ record_full_arch_list_tail. */
+ record_full_arch_list_head = NULL;
+ record_full_arch_list_tail = NULL;
+ record_full_insn_num = 0;
+ old_cleanups = make_cleanup (record_full_arch_list_cleanups, 0);
regcache = get_current_regcache ();
while (1)
@@ -2501,16 +2539,16 @@ record_restore (void)
switch (rectype)
{
- case record_reg: /* reg */
+ case record_full_reg: /* reg */
/* Get register number to regnum. */
bfdcore_read (core_bfd, osec, ®num,
sizeof (regnum), &bfd_offset);
regnum = netorder32 (regnum);
- rec = record_reg_alloc (regcache, regnum);
+ rec = record_full_reg_alloc (regcache, regnum);
/* Get val. */
- bfdcore_read (core_bfd, osec, record_get_loc (rec),
+ bfdcore_read (core_bfd, osec, record_full_get_loc (rec),
rec->u.reg.len, &bfd_offset);
if (record_debug)
@@ -2522,7 +2560,7 @@ record_restore (void)
rec->u.reg.len);
break;
- case record_mem: /* mem */
+ case record_full_mem: /* mem */
/* Get len. */
bfdcore_read (core_bfd, osec, &len,
sizeof (len), &bfd_offset);
@@ -2533,10 +2571,10 @@ record_restore (void)
sizeof (addr), &bfd_offset);
addr = netorder64 (addr);
- rec = record_mem_alloc (addr, len);
+ rec = record_full_mem_alloc (addr, len);
/* Get val. */
- bfdcore_read (core_bfd, osec, record_get_loc (rec),
+ bfdcore_read (core_bfd, osec, record_full_get_loc (rec),
rec->u.mem.len, &bfd_offset);
if (record_debug)
@@ -2550,9 +2588,9 @@ record_restore (void)
rec->u.mem.len);
break;
- case record_end: /* end */
- rec = record_end_alloc ();
- record_insn_num ++;
+ case record_full_end: /* end */
+ rec = record_full_end_alloc ();
+ record_full_insn_num ++;
/* Get signal value. */
bfdcore_read (core_bfd, osec, &signal,
@@ -2565,10 +2603,10 @@ record_restore (void)
sizeof (count), &bfd_offset);
count = netorder32 (count);
rec->u.end.insn_num = count;
- record_insn_count = count + 1;
+ record_full_insn_count = count + 1;
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
- " Reading record_end (1 + "
+ " Reading record_full_end (1 + "
"%lu + %lu bytes), offset == %s\n",
(unsigned long) sizeof (signal),
(unsigned long) sizeof (count),
@@ -2583,23 +2621,23 @@ record_restore (void)
}
/* Add rec to record arch list. */
- record_arch_list_add (rec);
+ record_full_arch_list_add (rec);
}
discard_cleanups (old_cleanups);
- /* Add record_arch_list_head to the end of record list. */
- record_first.next = record_arch_list_head;
- record_arch_list_head->prev = &record_first;
- record_arch_list_tail->next = NULL;
- record_list = &record_first;
+ /* Add record_full_arch_list_head to the end of record list. */
+ record_full_first.next = record_full_arch_list_head;
+ record_full_arch_list_head->prev = &record_full_first;
+ record_full_arch_list_tail->next = NULL;
+ record_full_list = &record_full_first;
- /* Update record_insn_max_num. */
- if (record_insn_num > record_insn_max_num)
+ /* Update record_full_insn_max_num. */
+ if (record_full_insn_num > record_full_insn_max_num)
{
- record_insn_max_num = record_insn_num;
+ record_full_insn_max_num = record_full_insn_num;
warning (_("Auto increase record/replay buffer limit to %d."),
- record_insn_max_num);
+ record_full_insn_max_num);
}
/* Succeeded. */
@@ -2628,14 +2666,14 @@ bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offset)
corefile format, with an extra section for our data. */
static void
-cmd_record_restore (char *args, int from_tty)
+cmd_record_full_restore (char *args, int from_tty)
{
core_file_command (args, from_tty);
- record_open (args, from_tty);
+ record_full_open (args, from_tty);
}
static void
-record_save_cleanups (void *data)
+record_full_save_cleanups (void *data)
{
bfd *obfd = data;
char *pathname = xstrdup (bfd_get_filename (obfd));
@@ -2649,9 +2687,9 @@ record_save_cleanups (void *data)
format, with an extra section for our data. */
static void
-record_save (char *recfilename)
+record_full_save (char *recfilename)
{
- struct record_entry *cur_record_list;
+ struct record_full_entry *cur_record_full_list;
uint32_t magic;
struct regcache *regcache;
struct gdbarch *gdbarch;
@@ -2669,10 +2707,10 @@ record_save (char *recfilename)
/* Open the output file. */
obfd = create_gcore_bfd (recfilename);
- old_cleanups = make_cleanup (record_save_cleanups, obfd);
+ old_cleanups = make_cleanup (record_full_save_cleanups, obfd);
- /* Save the current record entry to "cur_record_list". */
- cur_record_list = record_list;
+ /* Save the current record entry to "cur_record_full_list". */
+ cur_record_full_list = record_full_list;
/* Get the values of regcache and gdbarch. */
regcache = get_current_regcache ();
@@ -2685,29 +2723,29 @@ record_save (char *recfilename)
while (1)
{
/* Check for beginning and end of log. */
- if (record_list == &record_first)
+ if (record_full_list == &record_full_first)
break;
- record_exec_insn (regcache, gdbarch, record_list);
+ record_full_exec_insn (regcache, gdbarch, record_full_list);
- if (record_list->prev)
- record_list = record_list->prev;
+ if (record_full_list->prev)
+ record_full_list = record_full_list->prev;
}
/* Compute the size needed for the extra bfd section. */
save_size = 4; /* magic cookie */
- for (record_list = record_first.next; record_list;
- record_list = record_list->next)
- switch (record_list->type)
+ for (record_full_list = record_full_first.next; record_full_list;
+ record_full_list = record_full_list->next)
+ switch (record_full_list->type)
{
- case record_end:
+ case record_full_end:
save_size += 1 + 4 + 4;
break;
- case record_reg:
- save_size += 1 + 4 + record_list->u.reg.len;
+ case record_full_reg:
+ save_size += 1 + 4 + record_full_list->u.reg.len;
break;
- case record_mem:
- save_size += 1 + 4 + 8 + record_list->u.mem.len;
+ case record_full_mem:
+ save_size += 1 + 4 + 8 + record_full_list->u.mem.len;
break;
}
@@ -2729,89 +2767,91 @@ record_save (char *recfilename)
/* Write out the record log. */
/* Write the magic code. */
- magic = RECORD_FILE_MAGIC;
+ magic = RECORD_FULL_FILE_MAGIC;
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
" Writing 4-byte magic cookie "
- "RECORD_FILE_MAGIC (0x%s)\n",
+ "RECORD_FULL_FILE_MAGIC (0x%s)\n",
phex_nz (magic, 4));
bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset);
/* Save the entries to recfd and forward execute to the end of
record list. */
- record_list = &record_first;
+ record_full_list = &record_full_first;
while (1)
{
/* Save entry. */
- if (record_list != &record_first)
+ if (record_full_list != &record_full_first)
{
uint8_t type;
uint32_t regnum, len, signal, count;
uint64_t addr;
- type = record_list->type;
+ type = record_full_list->type;
bfdcore_write (obfd, osec, &type, sizeof (type), &bfd_offset);
- switch (record_list->type)
+ switch (record_full_list->type)
{
- case record_reg: /* reg */
+ case record_full_reg: /* reg */
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
" Writing register %d (1 "
"plus %lu plus %d bytes)\n",
- record_list->u.reg.num,
+ record_full_list->u.reg.num,
(unsigned long) sizeof (regnum),
- record_list->u.reg.len);
+ record_full_list->u.reg.len);
/* Write regnum. */
- regnum = netorder32 (record_list->u.reg.num);
+ regnum = netorder32 (record_full_list->u.reg.num);
bfdcore_write (obfd, osec, ®num,
sizeof (regnum), &bfd_offset);
/* Write regval. */
- bfdcore_write (obfd, osec, record_get_loc (record_list),
- record_list->u.reg.len, &bfd_offset);
+ bfdcore_write (obfd, osec,
+ record_full_get_loc (record_full_list),
+ record_full_list->u.reg.len, &bfd_offset);
break;
- case record_mem: /* mem */
+ case record_full_mem: /* mem */
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
" Writing memory %s (1 plus "
"%lu plus %lu plus %d bytes)\n",
paddress (gdbarch,
- record_list->u.mem.addr),
+ record_full_list->u.mem.addr),
(unsigned long) sizeof (addr),
(unsigned long) sizeof (len),
- record_list->u.mem.len);
+ record_full_list->u.mem.len);
/* Write memlen. */
- len = netorder32 (record_list->u.mem.len);
+ len = netorder32 (record_full_list->u.mem.len);
bfdcore_write (obfd, osec, &len, sizeof (len), &bfd_offset);
/* Write memaddr. */
- addr = netorder64 (record_list->u.mem.addr);
+ addr = netorder64 (record_full_list->u.mem.addr);
bfdcore_write (obfd, osec, &addr,
sizeof (addr), &bfd_offset);
/* Write memval. */
- bfdcore_write (obfd, osec, record_get_loc (record_list),
- record_list->u.mem.len, &bfd_offset);
+ bfdcore_write (obfd, osec,
+ record_full_get_loc (record_full_list),
+ record_full_list->u.mem.len, &bfd_offset);
break;
- case record_end:
+ case record_full_end:
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
- " Writing record_end (1 + "
+ " Writing record_full_end (1 + "
"%lu + %lu bytes)\n",
(unsigned long) sizeof (signal),
(unsigned long) sizeof (count));
/* Write signal value. */
- signal = netorder32 (record_list->u.end.sigval);
+ signal = netorder32 (record_full_list->u.end.sigval);
bfdcore_write (obfd, osec, &signal,
sizeof (signal), &bfd_offset);
/* Write insn count. */
- count = netorder32 (record_list->u.end.insn_num);
+ count = netorder32 (record_full_list->u.end.insn_num);
bfdcore_write (obfd, osec, &count,
sizeof (count), &bfd_offset);
break;
@@ -2819,25 +2859,25 @@ record_save (char *recfilename)
}
/* Execute entry. */
- record_exec_insn (regcache, gdbarch, record_list);
+ record_full_exec_insn (regcache, gdbarch, record_full_list);
- if (record_list->next)
- record_list = record_list->next;
+ if (record_full_list->next)
+ record_full_list = record_full_list->next;
else
break;
}
- /* Reverse execute to cur_record_list. */
+ /* Reverse execute to cur_record_full_list. */
while (1)
{
/* Check for beginning and end of log. */
- if (record_list == cur_record_list)
+ if (record_full_list == cur_record_full_list)
break;
- record_exec_insn (regcache, gdbarch, record_list);
+ record_full_exec_insn (regcache, gdbarch, record_full_list);
- if (record_list->prev)
- record_list = record_list->prev;
+ if (record_full_list->prev)
+ record_full_list = record_full_list->prev;
}
do_cleanups (set_cleanups);
@@ -2849,13 +2889,13 @@ record_save (char *recfilename)
recfilename);
}
-/* record_goto_insn -- rewind the record log (forward or backward,
+/* record_full_goto_insn -- rewind the record log (forward or backward,
depending on DIR) to the given entry, changing the program state
correspondingly. */
static void
-record_goto_insn (struct record_entry *entry,
- enum exec_direction_kind dir)
+record_full_goto_insn (struct record_full_entry *entry,
+ enum exec_direction_kind dir)
{
struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
struct regcache *regcache = get_current_regcache ();
@@ -2865,37 +2905,39 @@ record_goto_insn (struct record_entry *entry,
and we will not hit the end of the recording. */
if (dir == EXEC_FORWARD)
- record_list = record_list->next;
+ record_full_list = record_full_list->next;
do
{
- record_exec_insn (regcache, gdbarch, record_list);
+ record_full_exec_insn (regcache, gdbarch, record_full_list);
if (dir == EXEC_REVERSE)
- record_list = record_list->prev;
+ record_full_list = record_full_list->prev;
else
- record_list = record_list->next;
- } while (record_list != entry);
+ record_full_list = record_full_list->next;
+ } while (record_full_list != entry);
do_cleanups (set_cleanups);
}
/* Alias for "target record-full". */
static void
-cmd_record_start (char *args, int from_tty)
+cmd_record_full_start (char *args, int from_tty)
{
execute_command ("target record-full", from_tty);
}
static void
-set_record_insn_max_num (char *args, int from_tty, struct cmd_list_element *c)
+set_record_full_insn_max_num (char *args, int from_tty,
+ struct cmd_list_element *c)
{
- if (record_insn_num > record_insn_max_num && record_insn_max_num)
+ if (record_full_insn_num > record_full_insn_max_num
+ && record_full_insn_max_num)
{
- /* Count down record_insn_num while releasing records from list. */
- while (record_insn_num > record_insn_max_num)
+ /* Count down record_full_insn_num while releasing records from list. */
+ while (record_full_insn_num > record_full_insn_max_num)
{
- record_list_release_first ();
- record_insn_num--;
+ record_full_list_release_first ();
+ record_full_insn_num--;
}
}
}
@@ -2927,22 +2969,22 @@ _initialize_record_full (void)
{
struct cmd_list_element *c;
- /* Init record_first. */
- record_first.prev = NULL;
- record_first.next = NULL;
- record_first.type = record_end;
+ /* Init record_full_first. */
+ record_full_first.prev = NULL;
+ record_full_first.next = NULL;
+ record_full_first.type = record_full_end;
- init_record_ops ();
- add_target (&record_ops);
- add_deprecated_target_alias (&record_ops, "record");
- init_record_core_ops ();
- add_target (&record_core_ops);
+ init_record_full_ops ();
+ add_target (&record_full_ops);
+ add_deprecated_target_alias (&record_full_ops, "record");
+ init_record_full_core_ops ();
+ add_target (&record_full_core_ops);
- add_prefix_cmd ("full", class_obscure, cmd_record_start,
+ add_prefix_cmd ("full", class_obscure, cmd_record_full_start,
_("Start full execution recording."), &record_full_cmdlist,
"record full ", 0, &record_cmdlist);
- c = add_cmd ("restore", class_obscure, cmd_record_restore,
+ c = add_cmd ("restore", class_obscure, cmd_record_full_restore,
_("Restore the execution log from a file.\n\
Argument is filename. File must be created with 'record save'."),
&record_full_cmdlist);
@@ -2964,7 +3006,7 @@ Argument is filename. File must be created with 'record save'."),
/* Record instructions number limit command. */
add_setshow_boolean_cmd ("stop-at-limit", no_class,
- &record_stop_at_limit, _("\
+ &record_full_stop_at_limit, _("\
Set whether record/replay stops when record/replay buffer becomes full."), _("\
Show whether record/replay stops when record/replay buffer becomes full."),
_("Default is ON.\n\
@@ -2982,12 +3024,13 @@ delete the oldest recorded instruction to make room for each new one."),
&show_record_cmdlist);
deprecate_cmd (c, "show record full stop-at-limit");
- add_setshow_uinteger_cmd ("insn-number-max", no_class, &record_insn_max_num,
+ add_setshow_uinteger_cmd ("insn-number-max", no_class,
+ &record_full_insn_max_num,
_("Set record/replay buffer limit."),
_("Show record/replay buffer limit."), _("\
Set the maximum number of instructions to be stored in the\n\
record/replay buffer. Zero means unlimited. Default is 200000."),
- set_record_insn_max_num,
+ set_record_full_insn_max_num,
NULL, &set_record_full_cmdlist,
&show_record_full_cmdlist);
@@ -2999,7 +3042,8 @@ record/replay buffer. Zero means unlimited. Default is 200000."),
&show_record_cmdlist);
deprecate_cmd (c, "show record full insn-number-max");
- add_setshow_boolean_cmd ("memory-query", no_class, &record_memory_query, _("\
+ add_setshow_boolean_cmd ("memory-query", no_class,
+ &record_memory_query, _("\
Set whether query if PREC cannot record memory change of next instruction."),
_("\
Show whether query if PREC cannot record memory change of next instruction."),
@@ -3007,7 +3051,8 @@ Show whether query if PREC cannot record memory change of next instruction."),
Default is OFF.\n\
When ON, query if PREC cannot record memory change of next instruction."),
NULL, NULL,
- &set_record_full_cmdlist, &show_record_full_cmdlist);
+ &set_record_full_cmdlist,
+ &show_record_full_cmdlist);
c = add_alias_cmd ("memory-query", "full memory-query", no_class, 1,
&set_record_cmdlist);
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 05/21] gdbserver: preserve error message in handle_qXfer
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (12 preceding siblings ...)
2013-03-08 9:19 ` [patch v10 12/21] record-full.c: rename record_ in record_full_ Markus Metzger
@ 2013-03-08 9:19 ` Markus Metzger
2013-03-08 12:01 ` Jan Kratochvil
2013-03-08 9:19 ` [patch v10 13/21] record-full.h: rename record_ into record_full_ Markus Metzger
` (8 subsequent siblings)
22 siblings, 1 reply; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:19 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger, Pedro Alves
Preserve a verbose error message of xfer functions if they return -3.
CC: Pedro Alves <palves@redhat.com>
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
gdbserver/
* server.c (handle_qxfer): Preserve error message if -3 is
returned.
(qxfer): Document the -3 return value.
---
gdb/gdbserver/server.c | 16 ++++++++++++----
1 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 768eae7..3738280 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -892,10 +892,10 @@ struct qxfer
data-specific information to the target.
Return the number of bytes actually transfered, zero when no
- further transfer is possible, -1 on error, and -2 when the
- transfer is not supported. Return of a positive value smaller
- than LEN does not indicate the end of the object, only the end of
- the transfer.
+ further transfer is possible, -1 on error, -2 when the transfer
+ is not supported, and -3 on a verbose error message that should
+ be preserved. Return of a positive value smaller than LEN does
+ not indicate the end of the object, only the end of the transfer.
One, and only one, of readbuf or writebuf must be non-NULL. */
int (*xfer) (const char *annex,
@@ -1323,6 +1323,10 @@ handle_qxfer (char *own_buf, int packet_len, int *new_packet_len_p)
free (data);
return 0;
}
+ else if (n == -3)
+ {
+ /* Preserve error message. */
+ }
else if (n < 0)
write_enn (own_buf);
else if (n > len)
@@ -1361,6 +1365,10 @@ handle_qxfer (char *own_buf, int packet_len, int *new_packet_len_p)
free (data);
return 0;
}
+ else if (n == -3)
+ {
+ /* Preserve error message. */
+ }
else if (n < 0)
write_enn (own_buf);
else
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 13/21] record-full.h: rename record_ into record_full_
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (13 preceding siblings ...)
2013-03-08 9:19 ` [patch v10 05/21] gdbserver: preserve error message in handle_qXfer Markus Metzger
@ 2013-03-08 9:19 ` Markus Metzger
2013-03-08 9:19 ` [patch v10 19/21] doc, record: document record changes Markus Metzger
` (7 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:19 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Rename record_ prefixes in record-full.h into record_full_.
I ran the gdb.reverse suite on 64bit IA gnu/linux - no regressions.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* record-full.h, record-full.c (record_memory_query): Rename
to ...
(record_full_memory_query): ...this. Update all users.
(record_arch_list_add_reg): Rename to ...
(record_full_arch_list_add_reg): ...this. Update all users.
(record_arch_list_add_mem): Rename to ...
(record_full_arch_list_add_mem): ...this. Update all users.
(record_arch_list_add_end): Rename to ...
(record_full_arch_list_add_end): ...this. Update all users.
(record_gdb_operation_disable_set): Rename to ...
(record_full_gdb_operation_disable_set): ...this.
Update all users.
---
gdb/amd64-linux-tdep.c | 50 +++---
gdb/arm-tdep.c | 12 +-
gdb/i386-linux-tdep.c | 28 ++--
gdb/i386-tdep.c | 488 ++++++++++++++++++++++---------------------
gdb/infrun.c | 2 +-
gdb/linux-record.c | 543 +++++++++++++++++++++++++-----------------------
gdb/moxie-tdep.c | 84 ++++----
gdb/record-full.c | 32 ++--
gdb/record-full.h | 10 +-
9 files changed, 641 insertions(+), 608 deletions(-)
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 4f383db..88c291d 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -313,39 +313,39 @@ amd64_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
static int
amd64_all_but_ip_registers_record (struct regcache *regcache)
{
- if (record_arch_list_add_reg (regcache, AMD64_RAX_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_RAX_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_RCX_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_RCX_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_RDX_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_RDX_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_RBX_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_RBX_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_RSP_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_RSP_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_RBP_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_RBP_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_RSI_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_RSI_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_RDI_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_RDI_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_R8_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_R8_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_R9_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_R9_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_R10_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_R10_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_R11_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_R11_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_R12_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_R12_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_R13_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_R13_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_R14_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_R14_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_R15_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_R15_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_EFLAGS_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_EFLAGS_REGNUM))
return -1;
return 0;
@@ -1164,7 +1164,7 @@ amd64_canonicalize_syscall (enum amd64_syscall syscall_number)
/* Parse the arguments of current system call instruction and record
the values of the registers and memory that will be changed into
- "record_arch_list". This instruction is "syscall".
+ "record_full_arch_list". This instruction is "syscall".
Return -1 if something wrong. */
@@ -1203,8 +1203,8 @@ amd64_linux_syscall_record (struct regcache *regcache)
regcache_raw_read_unsigned (regcache,
amd64_linux_record_tdep.arg2,
&addr);
- if (record_arch_list_add_mem (addr,
- amd64_linux_record_tdep.size_ulong))
+ if (record_full_arch_list_add_mem
+ (addr, amd64_linux_record_tdep.size_ulong))
return -1;
}
goto record_regs;
@@ -1231,9 +1231,9 @@ amd64_linux_syscall_record (struct regcache *regcache)
record_regs:
/* Record the return value of the system call. */
- if (record_arch_list_add_reg (regcache, AMD64_RCX_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_RCX_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_R11_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_R11_REGNUM))
return -1;
return 0;
@@ -1253,7 +1253,7 @@ amd64_linux_record_signal (struct gdbarch *gdbarch,
if (amd64_all_but_ip_registers_record (regcache))
return -1;
- if (record_arch_list_add_reg (regcache, AMD64_RIP_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, AMD64_RIP_REGNUM))
return -1;
/* Record the change in the stack. */
@@ -1267,12 +1267,12 @@ amd64_linux_record_signal (struct gdbarch *gdbarch,
/* This is for frame_size.
sp -= sizeof (struct rt_sigframe); */
rsp -= AMD64_LINUX_frame_size;
- if (record_arch_list_add_mem (rsp, AMD64_LINUX_redzone
+ if (record_full_arch_list_add_mem (rsp, AMD64_LINUX_redzone
+ AMD64_LINUX_xstate
+ AMD64_LINUX_frame_size))
return -1;
- if (record_arch_list_add_end ())
+ if (record_full_arch_list_add_end ())
return -1;
return 0;
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 33b8d5d..1724686 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -12601,13 +12601,13 @@ arm_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
if (0 == ret)
{
/* Record registers. */
- record_arch_list_add_reg (arm_record.regcache, ARM_PC_REGNUM);
+ record_full_arch_list_add_reg (arm_record.regcache, ARM_PC_REGNUM);
if (arm_record.arm_regs)
{
for (no_of_rec = 0; no_of_rec < arm_record.reg_rec_count; no_of_rec++)
{
- if (record_arch_list_add_reg (arm_record.regcache ,
- arm_record.arm_regs[no_of_rec]))
+ if (record_full_arch_list_add_reg
+ (arm_record.regcache , arm_record.arm_regs[no_of_rec]))
ret = -1;
}
}
@@ -12616,14 +12616,14 @@ arm_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
{
for (no_of_rec = 0; no_of_rec < arm_record.mem_rec_count; no_of_rec++)
{
- if (record_arch_list_add_mem
+ if (record_full_arch_list_add_mem
((CORE_ADDR)arm_record.arm_mems[no_of_rec].addr,
- arm_record.arm_mems[no_of_rec].len))
+ arm_record.arm_mems[no_of_rec].len))
ret = -1;
}
}
- if (record_arch_list_add_end ())
+ if (record_full_arch_list_add_end ())
ret = -1;
}
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
index f96fc81..fc9de62 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -370,23 +370,23 @@ i386_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
static int
i386_all_but_ip_registers_record (struct regcache *regcache)
{
- if (record_arch_list_add_reg (regcache, I386_EAX_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, I386_EAX_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, I386_ECX_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, I386_ECX_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, I386_EDX_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, I386_EDX_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, I386_EBX_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, I386_EBX_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, I386_ESP_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, I386_ESP_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, I386_EBP_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, I386_EBP_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, I386_ESI_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, I386_ESI_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, I386_EDI_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, I386_EDI_REGNUM))
return -1;
- if (record_arch_list_add_reg (regcache, I386_EFLAGS_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, I386_EFLAGS_REGNUM))
return -1;
return 0;
@@ -450,7 +450,7 @@ i386_linux_intx80_sysenter_syscall_record (struct regcache *regcache)
return ret;
/* Record the return value of the system call. */
- if (record_arch_list_add_reg (regcache, I386_EAX_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, I386_EAX_REGNUM))
return -1;
return 0;
@@ -469,7 +469,7 @@ i386_linux_record_signal (struct gdbarch *gdbarch,
if (i386_all_but_ip_registers_record (regcache))
return -1;
- if (record_arch_list_add_reg (regcache, I386_EIP_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, I386_EIP_REGNUM))
return -1;
/* Record the change in the stack. */
@@ -480,11 +480,11 @@ i386_linux_record_signal (struct gdbarch *gdbarch,
/* This is for frame_size.
sp -= sizeof (struct rt_sigframe); */
esp -= I386_LINUX_frame_size;
- if (record_arch_list_add_mem (esp,
- I386_LINUX_xstate + I386_LINUX_frame_size))
+ if (record_full_arch_list_add_mem (esp,
+ I386_LINUX_xstate + I386_LINUX_frame_size))
return -1;
- if (record_arch_list_add_end ())
+ if (record_full_arch_list_add_end ())
return -1;
return 0;
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index a36a83d..61ccc3e 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -4205,7 +4205,7 @@ i386_record_lea_modrm (struct i386_record_s *irp)
if (irp->override >= 0)
{
- if (record_memory_query)
+ if (record_full_memory_query)
{
int q;
@@ -4226,7 +4226,7 @@ Do you want to stop the program?"),
if (i386_record_lea_modrm_addr (irp, &addr))
return -1;
- if (record_arch_list_add_mem (addr, 1 << irp->ot))
+ if (record_full_arch_list_add_mem (addr, 1 << irp->ot))
return -1;
return 0;
@@ -4240,13 +4240,13 @@ i386_record_push (struct i386_record_s *irp, int size)
{
ULONGEST addr;
- if (record_arch_list_add_reg (irp->regcache,
- irp->regmap[X86_RECORD_RESP_REGNUM]))
+ if (record_full_arch_list_add_reg (irp->regcache,
+ irp->regmap[X86_RECORD_RESP_REGNUM]))
return -1;
regcache_raw_read_unsigned (irp->regcache,
irp->regmap[X86_RECORD_RESP_REGNUM],
&addr);
- if (record_arch_list_add_mem ((CORE_ADDR) addr - size, size))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) addr - size, size))
return -1;
return 0;
@@ -4278,7 +4278,7 @@ static int i386_record_floats (struct gdbarch *gdbarch,
{
for (i = I387_ST0_REGNUM (tdep); i <= I387_ST0_REGNUM (tdep) + 7; i++)
{
- if (record_arch_list_add_reg (ir->regcache, i))
+ if (record_full_arch_list_add_reg (ir->regcache, i))
return -1;
}
}
@@ -4286,7 +4286,7 @@ static int i386_record_floats (struct gdbarch *gdbarch,
{
for (i = I387_FCTRL_REGNUM (tdep); i <= I387_FOP_REGNUM (tdep); i++)
{
- if (record_arch_list_add_reg (ir->regcache, i))
+ if (record_full_arch_list_add_reg (ir->regcache, i))
return -1;
}
}
@@ -4294,14 +4294,14 @@ static int i386_record_floats (struct gdbarch *gdbarch,
{
for (i = I387_ST0_REGNUM (tdep); i <= I387_FOP_REGNUM (tdep); i++)
{
- if (record_arch_list_add_reg (ir->regcache, i))
+ if (record_full_arch_list_add_reg (ir->regcache, i))
return -1;
}
}
else if ((iregnum >= I387_ST0_REGNUM (tdep)) &&
(iregnum <= I387_FOP_REGNUM (tdep)))
{
- if (record_arch_list_add_reg (ir->regcache,iregnum))
+ if (record_full_arch_list_add_reg (ir->regcache,iregnum))
return -1;
}
else
@@ -4313,7 +4313,7 @@ static int i386_record_floats (struct gdbarch *gdbarch,
{
for (i = I387_FCTRL_REGNUM (tdep); i <= I387_FOP_REGNUM (tdep); i++)
{
- if (record_arch_list_add_reg (ir->regcache, i))
+ if (record_full_arch_list_add_reg (ir->regcache, i))
return -1;
}
}
@@ -4324,8 +4324,8 @@ static int i386_record_floats (struct gdbarch *gdbarch,
registers and memory that will be changed by the current
instruction. Returns -1 if something goes wrong, 0 otherwise. */
-#define I386_RECORD_ARCH_LIST_ADD_REG(regnum) \
- record_arch_list_add_reg (ir.regcache, ir.regmap[(regnum)])
+#define I386_RECORD_FULL_ARCH_LIST_ADD_REG(regnum) \
+ record_full_arch_list_add_reg (ir.regcache, ir.regmap[(regnum)])
int
i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
@@ -4530,7 +4530,7 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
ir.rm |= ir.rex_b;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.rm &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
}
break;
case 1: /* OP Gv, Ev */
@@ -4539,14 +4539,14 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
ir.reg |= rex_r;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.reg &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
break;
case 2: /* OP A, Iv */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
break;
}
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x80: /* GRP1 */
@@ -4573,9 +4573,9 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
return -1;
}
else
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x40: /* inc */
@@ -4596,8 +4596,8 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
case 0x4e:
case 0x4f:
- I386_RECORD_ARCH_LIST_ADD_REG (opcode & 7);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (opcode & 7);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0xf6: /* GRP3 */
@@ -4615,7 +4615,7 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
switch (ir.reg)
{
case 0: /* test */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 2: /* not */
case 3: /* neg */
@@ -4629,19 +4629,19 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
ir.rm |= ir.rex_b;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.rm &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
}
if (ir.reg == 3) /* neg */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 4: /* mul */
case 5: /* imul */
case 6: /* div */
case 7: /* idiv */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
if (ir.ot != OT_BYTE)
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
default:
ir.addr -= 2;
@@ -4679,26 +4679,26 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
ir.rm |= ir.rex_b;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.rm &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 2: /* call */
if (ir.regmap[X86_RECORD_R8_REGNUM] && ir.dflag)
ir.dflag = 2;
if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
return -1;
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 3: /* lcall */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_CS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_CS_REGNUM);
if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
return -1;
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 4: /* jmp */
case 5: /* ljmp */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 6: /* push */
if (ir.regmap[X86_RECORD_R8_REGNUM] && ir.dflag)
@@ -4718,16 +4718,16 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
case 0x85:
case 0xa8:
case 0xa9:
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x98: /* CWDE/CBW */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
break;
case 0x99: /* CDQ/CWD */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
break;
case 0x0faf: /* imul */
@@ -4743,8 +4743,8 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
ir.reg |= rex_r;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.reg &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0fc0: /* xadd */
@@ -4760,10 +4760,10 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
{
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.reg &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.rm &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
}
else
{
@@ -4771,9 +4771,9 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
return -1;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.reg &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0fb0: /* cmpxchg */
@@ -4787,18 +4787,18 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
if (ir.mod == 3)
{
ir.reg |= rex_r;
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.reg &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
}
else
{
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
if (i386_record_lea_modrm (&ir))
return -1;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0fc7: /* cmpxchg8b */
@@ -4810,11 +4810,11 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
opcode = opcode << 8 | ir.modrm;
goto no_support;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
if (i386_record_lea_modrm (&ir))
return -1;
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x50: /* push */
@@ -4875,8 +4875,8 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
case 0x5d:
case 0x5e:
case 0x5f:
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG ((opcode & 0x7) | ir.rex_b);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG ((opcode & 0x7) | ir.rex_b);
break;
case 0x61: /* popa */
@@ -4888,7 +4888,7 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
for (regnum = X86_RECORD_REAX_REGNUM;
regnum <= X86_RECORD_REDI_REGNUM;
regnum++)
- I386_RECORD_ARCH_LIST_ADD_REG (regnum);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (regnum);
break;
case 0x8f: /* pop */
@@ -4899,18 +4899,18 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
if (i386_record_modrm (&ir))
return -1;
if (ir.mod == 3)
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
else
{
ir.popl_esp_hack = 1 << ir.ot;
if (i386_record_lea_modrm (&ir))
return -1;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
break;
case 0xc8: /* enter */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REBP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REBP_REGNUM);
if (ir.regmap[X86_RECORD_R8_REGNUM] && ir.dflag)
ir.dflag = 2;
if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
@@ -4918,8 +4918,8 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
break;
case 0xc9: /* leave */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REBP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REBP_REGNUM);
break;
case 0x07: /* pop es */
@@ -4928,9 +4928,9 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
ir.addr -= 1;
goto no_support;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_ES_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_ES_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x17: /* pop ss */
@@ -4939,9 +4939,9 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
ir.addr -= 1;
goto no_support;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_SS_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_SS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x1f: /* pop ds */
@@ -4950,21 +4950,21 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
ir.addr -= 1;
goto no_support;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_DS_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_DS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0fa1: /* pop fs */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_FS_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_FS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0fa9: /* pop gs */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_GS_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_GS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x88: /* mov */
@@ -4992,7 +4992,7 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
ir.rm |= ir.rex_b;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.rm &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
}
break;
@@ -5007,7 +5007,7 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
ir.reg |= rex_r;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.reg &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
break;
case 0x8c: /* mov seg */
@@ -5021,7 +5021,7 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
}
if (ir.mod == 3)
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
else
{
ir.ot = OT_WORD;
@@ -5056,8 +5056,8 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
goto no_support;
break;
}
- I386_RECORD_ARCH_LIST_ADD_REG (regnum);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (regnum);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0fb6: /* movzbS */
@@ -5066,7 +5066,7 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
case 0x0fbf: /* movswS */
if (i386_record_modrm (&ir))
return -1;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg | rex_r);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg | rex_r);
break;
case 0x8d: /* lea */
@@ -5082,21 +5082,21 @@ i386_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
ir.reg |= rex_r;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.reg &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
break;
case 0xa0: /* mov EAX */
case 0xa1:
case 0xd7: /* xlat */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
break;
case 0xa2: /* mov EAX */
case 0xa3:
if (ir.override >= 0)
{
- if (record_memory_query)
+ if (record_full_memory_query)
{
int q;
@@ -5138,7 +5138,7 @@ Do you want to stop the program?"),
ir.addr += 2;
addr = extract_unsigned_integer (buf, 2, byte_order);
}
- if (record_arch_list_add_mem (addr, 1 << ir.ot))
+ if (record_full_arch_list_add_mem (addr, 1 << ir.ot))
return -1;
}
break;
@@ -5151,9 +5151,9 @@ Do you want to stop the program?"),
case 0xb5:
case 0xb6:
case 0xb7:
- I386_RECORD_ARCH_LIST_ADD_REG ((ir.regmap[X86_RECORD_R8_REGNUM])
- ? ((opcode & 0x7) | ir.rex_b)
- : ((opcode & 0x7) & 0x3));
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG ((ir.regmap[X86_RECORD_R8_REGNUM])
+ ? ((opcode & 0x7) | ir.rex_b)
+ : ((opcode & 0x7) & 0x3));
break;
case 0xb8: /* mov R, Iv */
@@ -5164,7 +5164,7 @@ Do you want to stop the program?"),
case 0xbd:
case 0xbe:
case 0xbf:
- I386_RECORD_ARCH_LIST_ADD_REG ((opcode & 0x7) | ir.rex_b);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG ((opcode & 0x7) | ir.rex_b);
break;
case 0x91: /* xchg R, EAX */
@@ -5174,8 +5174,8 @@ Do you want to stop the program?"),
case 0x95:
case 0x96:
case 0x97:
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (opcode & 0x7);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (opcode & 0x7);
break;
case 0x86: /* xchg Ev, Gv */
@@ -5191,7 +5191,7 @@ Do you want to stop the program?"),
ir.rm |= ir.rex_b;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.rm &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
}
else
{
@@ -5201,7 +5201,7 @@ Do you want to stop the program?"),
ir.reg |= rex_r;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.reg &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
break;
case 0xc4: /* les Gv */
@@ -5244,9 +5244,9 @@ Do you want to stop the program?"),
regnum = X86_RECORD_GS_REGNUM;
break;
}
- I386_RECORD_ARCH_LIST_ADD_REG (regnum);
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg | rex_r);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (regnum);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg | rex_r);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0xc0: /* shifts */
@@ -5271,9 +5271,9 @@ Do you want to stop the program?"),
ir.rm |= ir.rex_b;
if (ir.ot == OT_BYTE && !ir.regmap[X86_RECORD_R8_REGNUM])
ir.rm &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm);
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0fa4:
@@ -5284,7 +5284,7 @@ Do you want to stop the program?"),
return -1;
if (ir.mod == 3)
{
- if (record_arch_list_add_reg (ir.regcache, ir.rm))
+ if (record_full_arch_list_add_reg (ir.regcache, ir.rm))
return -1;
}
else
@@ -5387,17 +5387,17 @@ Do you want to stop the program?"),
switch (ir.reg >> 4)
{
case 0:
- if (record_arch_list_add_mem (addr64, 4))
+ if (record_full_arch_list_add_mem (addr64, 4))
return -1;
break;
case 2:
- if (record_arch_list_add_mem (addr64, 8))
+ if (record_full_arch_list_add_mem (addr64, 8))
return -1;
break;
case 3:
break;
default:
- if (record_arch_list_add_mem (addr64, 2))
+ if (record_full_arch_list_add_mem (addr64, 2))
return -1;
break;
}
@@ -5406,7 +5406,7 @@ Do you want to stop the program?"),
switch (ir.reg >> 4)
{
case 0:
- if (record_arch_list_add_mem (addr64, 4))
+ if (record_full_arch_list_add_mem (addr64, 4))
return -1;
if (3 == (ir.reg & 7))
{
@@ -5417,7 +5417,7 @@ Do you want to stop the program?"),
}
break;
case 1:
- if (record_arch_list_add_mem (addr64, 4))
+ if (record_full_arch_list_add_mem (addr64, 4))
return -1;
if ((3 == (ir.reg & 7))
|| (5 == (ir.reg & 7))
@@ -5430,7 +5430,7 @@ Do you want to stop the program?"),
}
break;
case 2:
- if (record_arch_list_add_mem (addr64, 8))
+ if (record_full_arch_list_add_mem (addr64, 8))
return -1;
if (3 == (ir.reg & 7))
{
@@ -5450,7 +5450,7 @@ Do you want to stop the program?"),
}
/* Fall through */
default:
- if (record_arch_list_add_mem (addr64, 2))
+ if (record_full_arch_list_add_mem (addr64, 2))
return -1;
break;
}
@@ -5477,18 +5477,18 @@ Do you want to stop the program?"),
case 0x0e:
if (ir.dflag)
{
- if (record_arch_list_add_mem (addr64, 28))
+ if (record_full_arch_list_add_mem (addr64, 28))
return -1;
}
else
{
- if (record_arch_list_add_mem (addr64, 14))
+ if (record_full_arch_list_add_mem (addr64, 14))
return -1;
}
break;
case 0x0f:
case 0x2f:
- if (record_arch_list_add_mem (addr64, 2))
+ if (record_full_arch_list_add_mem (addr64, 2))
return -1;
/* Insn fstp, fbstp. */
if (i386_record_floats (gdbarch, &ir, I386_SAVE_FPU_REGS))
@@ -5496,23 +5496,23 @@ Do you want to stop the program?"),
break;
case 0x1f:
case 0x3e:
- if (record_arch_list_add_mem (addr64, 10))
+ if (record_full_arch_list_add_mem (addr64, 10))
return -1;
break;
case 0x2e:
if (ir.dflag)
{
- if (record_arch_list_add_mem (addr64, 28))
+ if (record_full_arch_list_add_mem (addr64, 28))
return -1;
addr64 += 28;
}
else
{
- if (record_arch_list_add_mem (addr64, 14))
+ if (record_full_arch_list_add_mem (addr64, 14))
return -1;
addr64 += 14;
}
- if (record_arch_list_add_mem (addr64, 80))
+ if (record_full_arch_list_add_mem (addr64, 80))
return -1;
/* Insn fsave. */
if (i386_record_floats (gdbarch, &ir,
@@ -5520,7 +5520,7 @@ Do you want to stop the program?"),
return -1;
break;
case 0x3f:
- if (record_arch_list_add_mem (addr64, 8))
+ if (record_full_arch_list_add_mem (addr64, 8))
return -1;
/* Insn fistp. */
if (i386_record_floats (gdbarch, &ir, I386_SAVE_FPU_REGS))
@@ -5726,7 +5726,8 @@ Do you want to stop the program?"),
case 0xdf:
if (0xe0 == ir.modrm)
{
- if (record_arch_list_add_reg (ir.regcache, I386_EAX_REGNUM))
+ if (record_full_arch_list_add_reg (ir.regcache,
+ I386_EAX_REGNUM))
return -1;
}
else if ((0x0f == ir.modrm >> 4) || (0x0e == ir.modrm >> 4))
@@ -5769,7 +5770,7 @@ Do you want to stop the program?"),
if (ir.aflag && (es != ds))
{
/* addr += ((uint32_t) read_register (I386_ES_REGNUM)) << 4; */
- if (record_memory_query)
+ if (record_full_memory_query)
{
int q;
@@ -5786,59 +5787,59 @@ Do you want to stop the program?"),
}
else
{
- if (record_arch_list_add_mem (addr, 1 << ir.ot))
+ if (record_full_arch_list_add_mem (addr, 1 << ir.ot))
return -1;
}
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
if (opcode == 0xa4 || opcode == 0xa5)
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
}
break;
case 0xa6: /* cmpsS */
case 0xa7:
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0xac: /* lodsS */
case 0xad:
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0xae: /* scasS */
case 0xaf:
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x6e: /* outsS */
case 0x6f:
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0xe4: /* port I/O */
case 0xe5:
case 0xec:
case 0xed:
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
break;
case 0xe6:
@@ -5850,16 +5851,16 @@ Do you want to stop the program?"),
/* control */
case 0xc2: /* ret im */
case 0xc3: /* ret */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0xca: /* lret im */
case 0xcb: /* lret */
case 0xcf: /* iret */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_CS_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_CS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0xe8: /* call im */
@@ -5875,7 +5876,7 @@ Do you want to stop the program?"),
ir.addr -= 1;
goto no_support;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_CS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_CS_REGNUM);
if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
return -1;
break;
@@ -5933,13 +5934,13 @@ Do you want to stop the program?"),
case 0x0f9d:
case 0x0f9e:
case 0x0f9f:
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
ir.ot = OT_BYTE;
if (i386_record_modrm (&ir))
return -1;
if (ir.mod == 3)
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rex_b ? (ir.rm | ir.rex_b)
- : (ir.rm & 0x3));
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rex_b ? (ir.rm | ir.rex_b)
+ : (ir.rm & 0x3));
else
{
if (i386_record_lea_modrm (&ir))
@@ -5968,12 +5969,12 @@ Do you want to stop the program?"),
ir.reg |= rex_r;
if (ir.dflag == OT_BYTE)
ir.reg &= 0x3;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
break;
/* flags */
case 0x9c: /* pushf */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
if (ir.regmap[X86_RECORD_R8_REGNUM] && ir.dflag)
ir.dflag = 2;
if (i386_record_push (&ir, 1 << (ir.dflag + 1)))
@@ -5981,8 +5982,8 @@ Do you want to stop the program?"),
break;
case 0x9d: /* popf */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x9e: /* sahf */
@@ -5997,7 +5998,7 @@ Do you want to stop the program?"),
case 0xf9: /* stc */
case 0xfc: /* cld */
case 0xfd: /* std */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x9f: /* lahf */
@@ -6006,8 +6007,8 @@ Do you want to stop the program?"),
ir.addr -= 1;
goto no_support;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
break;
/* bit operations */
@@ -6024,18 +6025,18 @@ Do you want to stop the program?"),
if (ir.reg != 4)
{
if (ir.mod == 3)
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
else
{
if (i386_record_lea_modrm (&ir))
return -1;
}
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0fa3: /* bt Gv, Ev */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0fab: /* bts */
@@ -6045,7 +6046,7 @@ Do you want to stop the program?"),
if (i386_record_modrm (&ir))
return -1;
if (ir.mod == 3)
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
else
{
uint64_t addr64;
@@ -6066,18 +6067,18 @@ Do you want to stop the program?"),
addr64 += ((int64_t) addr >> 6) << 6;
break;
}
- if (record_arch_list_add_mem (addr64, 1 << ir.ot))
+ if (record_full_arch_list_add_mem (addr64, 1 << ir.ot))
return -1;
if (i386_record_lea_modrm (&ir))
return -1;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0fbc: /* bsf */
case 0x0fbd: /* bsr */
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg | rex_r);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg | rex_r);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
/* bcd */
@@ -6092,8 +6093,8 @@ Do you want to stop the program?"),
ir.addr -= 1;
goto no_support;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
/* misc */
@@ -6171,7 +6172,7 @@ Do you want to stop the program?"),
case 0x0fcd:
case 0x0fce:
case 0x0fcf:
- I386_RECORD_ARCH_LIST_ADD_REG ((opcode & 7) | ir.rex_b);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG ((opcode & 7) | ir.rex_b);
break;
case 0xd6: /* salc */
@@ -6180,16 +6181,16 @@ Do you want to stop the program?"),
ir.addr -= 1;
goto no_support;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0xe0: /* loopnz */
case 0xe1: /* loopz */
case 0xe2: /* loop */
case 0xe3: /* jecxz */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0f30: /* wrmsr */
@@ -6207,8 +6208,8 @@ Do you want to stop the program?"),
break;
case 0x0f31: /* rdtsc */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
break;
case 0x0f34: /* sysenter */
@@ -6263,10 +6264,10 @@ Do you want to stop the program?"),
break;
case 0x0fa2: /* cpuid */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REBX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REBX_REGNUM);
break;
case 0xf4: /* hlt */
@@ -6284,7 +6285,7 @@ Do you want to stop the program?"),
case 0: /* sldt */
case 1: /* str */
if (ir.mod == 3)
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
else
{
ir.ot = OT_WORD;
@@ -6297,7 +6298,7 @@ Do you want to stop the program?"),
break;
case 4: /* verr */
case 5: /* verw */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
default:
ir.addr -= 3;
@@ -6324,7 +6325,7 @@ Do you want to stop the program?"),
}
if (ir.override >= 0)
{
- if (record_memory_query)
+ if (record_full_memory_query)
{
int q;
@@ -6343,17 +6344,17 @@ Do you want to stop the program?"),
{
if (i386_record_lea_modrm_addr (&ir, &addr64))
return -1;
- if (record_arch_list_add_mem (addr64, 2))
+ if (record_full_arch_list_add_mem (addr64, 2))
return -1;
addr64 += 2;
if (ir.regmap[X86_RECORD_R8_REGNUM])
{
- if (record_arch_list_add_mem (addr64, 8))
+ if (record_full_arch_list_add_mem (addr64, 8))
return -1;
}
else
{
- if (record_arch_list_add_mem (addr64, 4))
+ if (record_full_arch_list_add_mem (addr64, 4))
return -1;
}
}
@@ -6367,7 +6368,7 @@ Do you want to stop the program?"),
case 0: /* monitor */
break;
case 1: /* mwait */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
default:
ir.addr -= 3;
@@ -6381,7 +6382,7 @@ Do you want to stop the program?"),
/* sidt */
if (ir.override >= 0)
{
- if (record_memory_query)
+ if (record_full_memory_query)
{
int q;
@@ -6402,17 +6403,17 @@ Do you want to stop the program?"),
if (i386_record_lea_modrm_addr (&ir, &addr64))
return -1;
- if (record_arch_list_add_mem (addr64, 2))
+ if (record_full_arch_list_add_mem (addr64, 2))
return -1;
addr64 += 2;
if (ir.regmap[X86_RECORD_R8_REGNUM])
{
- if (record_arch_list_add_mem (addr64, 8))
+ if (record_full_arch_list_add_mem (addr64, 8))
return -1;
}
else
{
- if (record_arch_list_add_mem (addr64, 4))
+ if (record_full_arch_list_add_mem (addr64, 4))
return -1;
}
}
@@ -6424,8 +6425,8 @@ Do you want to stop the program?"),
/* xgetbv */
if (ir.rm == 0)
{
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
break;
}
/* xsetbv */
@@ -6443,7 +6444,7 @@ Do you want to stop the program?"),
case 4: /* smsw */
if (ir.mod == 3)
{
- if (record_arch_list_add_reg (ir.regcache, ir.rm | ir.rex_b))
+ if (record_full_arch_list_add_reg (ir.regcache, ir.rm | ir.rex_b))
return -1;
}
else
@@ -6452,16 +6453,16 @@ Do you want to stop the program?"),
if (i386_record_lea_modrm (&ir))
return -1;
}
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 6: /* lmsw */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 7: /* invlpg */
if (ir.mod == 3)
{
if (ir.rm == 0 && ir.regmap[X86_RECORD_R8_REGNUM])
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_GS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_GS_REGNUM);
else
{
ir.addr -= 3;
@@ -6470,7 +6471,7 @@ Do you want to stop the program?"),
}
}
else
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
default:
ir.addr -= 3;
@@ -6489,8 +6490,8 @@ Do you want to stop the program?"),
return -1;
if (ir.mod == 3 || ir.regmap[X86_RECORD_R8_REGNUM])
{
- I386_RECORD_ARCH_LIST_ADD_REG (ir.regmap[X86_RECORD_R8_REGNUM]
- ? (ir.reg | rex_r) : ir.rm);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.regmap[X86_RECORD_R8_REGNUM]
+ ? (ir.reg | rex_r) : ir.rm);
}
else
{
@@ -6499,15 +6500,15 @@ Do you want to stop the program?"),
return -1;
}
if (!ir.regmap[X86_RECORD_R8_REGNUM])
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0f02: /* lar */
case 0x0f03: /* lsl */
if (i386_record_modrm (&ir))
return -1;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg | rex_r);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg | rex_r);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0f18:
@@ -6549,9 +6550,9 @@ Do you want to stop the program?"),
case 4:
case 8:
if (opcode & 2)
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
else
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
break;
default:
ir.addr -= 3;
@@ -6573,13 +6574,13 @@ Do you want to stop the program?"),
goto no_support;
}
if (opcode & 2)
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
else
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
break;
case 0x0f06: /* clts */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
/* MMX 3DNow! SSE SSE2 SSE3 SSSE3 SSE4 */
@@ -6591,7 +6592,7 @@ Do you want to stop the program?"),
case 0x0f77: /* emms */
if (i386_fpc_regnum_p (gdbarch, I387_FTAG_REGNUM(tdep)))
goto no_support;
- record_arch_list_add_reg (ir.regcache, I387_FTAG_REGNUM(tdep));
+ record_full_arch_list_add_reg (ir.regcache, I387_FTAG_REGNUM(tdep));
break;
case 0x0f0f: /* 3DNow! data */
@@ -6628,7 +6629,7 @@ Do you want to stop the program?"),
case 0xbf: /* 3DNow! pavgusb */
if (!i386_mmx_regnum_p (gdbarch, I387_MM0_REGNUM (tdep) + ir.reg))
goto no_support_3dnow_data;
- record_arch_list_add_reg (ir.regcache, ir.reg);
+ record_full_arch_list_add_reg (ir.regcache, ir.reg);
break;
default:
@@ -6640,15 +6641,15 @@ no_support_3dnow_data:
break;
case 0x0faa: /* rsm */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REBX_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REBP_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RECX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REBX_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REBP_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_RESI_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REDI_REGNUM);
break;
case 0x0fae:
@@ -6660,10 +6661,10 @@ no_support_3dnow_data:
{
uint64_t tmpu64;
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
if (i386_record_lea_modrm_addr (&ir, &tmpu64))
return -1;
- if (record_arch_list_add_mem (tmpu64, 512))
+ if (record_full_arch_list_add_mem (tmpu64, 512))
return -1;
}
break;
@@ -6672,33 +6673,34 @@ no_support_3dnow_data:
{
int i;
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
for (i = I387_MM0_REGNUM (tdep);
i386_mmx_regnum_p (gdbarch, i); i++)
- record_arch_list_add_reg (ir.regcache, i);
+ record_full_arch_list_add_reg (ir.regcache, i);
for (i = I387_XMM0_REGNUM (tdep);
i386_xmm_regnum_p (gdbarch, i); i++)
- record_arch_list_add_reg (ir.regcache, i);
+ record_full_arch_list_add_reg (ir.regcache, i);
if (i386_mxcsr_regnum_p (gdbarch, I387_MXCSR_REGNUM(tdep)))
- record_arch_list_add_reg (ir.regcache, I387_MXCSR_REGNUM(tdep));
+ record_full_arch_list_add_reg (ir.regcache,
+ I387_MXCSR_REGNUM(tdep));
for (i = I387_ST0_REGNUM (tdep);
i386_fp_regnum_p (gdbarch, i); i++)
- record_arch_list_add_reg (ir.regcache, i);
+ record_full_arch_list_add_reg (ir.regcache, i);
for (i = I387_FCTRL_REGNUM (tdep);
i386_fpc_regnum_p (gdbarch, i); i++)
- record_arch_list_add_reg (ir.regcache, i);
+ record_full_arch_list_add_reg (ir.regcache, i);
}
break;
case 2: /* ldmxcsr */
if (!i386_mxcsr_regnum_p (gdbarch, I387_MXCSR_REGNUM(tdep)))
goto no_support;
- record_arch_list_add_reg (ir.regcache, I387_MXCSR_REGNUM(tdep));
+ record_full_arch_list_add_reg (ir.regcache, I387_MXCSR_REGNUM(tdep));
break;
case 3: /* stmxcsr */
@@ -7076,10 +7078,10 @@ reswitch_prefix_add:
ir.reg |= rex_r;
if (!i386_xmm_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.reg))
goto no_support;
- record_arch_list_add_reg (ir.regcache,
- I387_XMM0_REGNUM (tdep) + ir.reg);
+ record_full_arch_list_add_reg (ir.regcache,
+ I387_XMM0_REGNUM (tdep) + ir.reg);
if ((opcode & 0xfffffffc) == 0x660f3a60)
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0f11: /* movups */
@@ -7109,8 +7111,8 @@ reswitch_prefix_add:
if (!i386_xmm_regnum_p (gdbarch,
I387_XMM0_REGNUM (tdep) + ir.rm))
goto no_support;
- record_arch_list_add_reg (ir.regcache,
- I387_XMM0_REGNUM (tdep) + ir.rm);
+ record_full_arch_list_add_reg (ir.regcache,
+ I387_XMM0_REGNUM (tdep) + ir.rm);
}
else
{
@@ -7163,7 +7165,7 @@ reswitch_prefix_add:
case 0x660fc5: /* pextrw */
case 0x0fd7: /* pmovmskb */
case 0x660fd7: /* pmovmskb */
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg | rex_r);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg | rex_r);
break;
case 0x0f3800: /* pshufb */
@@ -7264,8 +7266,8 @@ reswitch_prefix_add:
return -1;
if (!i386_mmx_regnum_p (gdbarch, I387_MM0_REGNUM (tdep) + ir.reg))
goto no_support;
- record_arch_list_add_reg (ir.regcache,
- I387_MM0_REGNUM (tdep) + ir.reg);
+ record_full_arch_list_add_reg (ir.regcache,
+ I387_MM0_REGNUM (tdep) + ir.reg);
break;
case 0x0f71: /* psllw */
@@ -7275,8 +7277,8 @@ reswitch_prefix_add:
return -1;
if (!i386_mmx_regnum_p (gdbarch, I387_MM0_REGNUM (tdep) + ir.rm))
goto no_support;
- record_arch_list_add_reg (ir.regcache,
- I387_MM0_REGNUM (tdep) + ir.rm);
+ record_full_arch_list_add_reg (ir.regcache,
+ I387_MM0_REGNUM (tdep) + ir.rm);
break;
case 0x660f71: /* psllw */
@@ -7287,8 +7289,8 @@ reswitch_prefix_add:
ir.rm |= ir.rex_b;
if (!i386_xmm_regnum_p (gdbarch, I387_XMM0_REGNUM (tdep) + ir.rm))
goto no_support;
- record_arch_list_add_reg (ir.regcache,
- I387_XMM0_REGNUM (tdep) + ir.rm);
+ record_full_arch_list_add_reg (ir.regcache,
+ I387_XMM0_REGNUM (tdep) + ir.rm);
break;
case 0x0f7e: /* movd */
@@ -7296,7 +7298,7 @@ reswitch_prefix_add:
if (i386_record_modrm (&ir))
return -1;
if (ir.mod == 3)
- I386_RECORD_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.rm | ir.rex_b);
else
{
if (ir.dflag == 2)
@@ -7315,8 +7317,8 @@ reswitch_prefix_add:
{
if (!i386_mmx_regnum_p (gdbarch, I387_MM0_REGNUM (tdep) + ir.rm))
goto no_support;
- record_arch_list_add_reg (ir.regcache,
- I387_MM0_REGNUM (tdep) + ir.rm);
+ record_full_arch_list_add_reg (ir.regcache,
+ I387_MM0_REGNUM (tdep) + ir.rm);
}
else
{
@@ -7329,8 +7331,8 @@ reswitch_prefix_add:
case 0xf30fb8: /* popcnt */
if (i386_record_modrm (&ir))
return -1;
- I386_RECORD_ARCH_LIST_ADD_REG (ir.reg);
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (ir.reg);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x660fd6: /* movq */
@@ -7342,8 +7344,8 @@ reswitch_prefix_add:
if (!i386_xmm_regnum_p (gdbarch,
I387_XMM0_REGNUM (tdep) + ir.rm))
goto no_support;
- record_arch_list_add_reg (ir.regcache,
- I387_XMM0_REGNUM (tdep) + ir.rm);
+ record_full_arch_list_add_reg (ir.regcache,
+ I387_XMM0_REGNUM (tdep) + ir.rm);
}
else
{
@@ -7358,14 +7360,14 @@ reswitch_prefix_add:
case 0x660f2e: /* ucomisd */
case 0x0f2f: /* comiss */
case 0x660f2f: /* comisd */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_EFLAGS_REGNUM);
break;
case 0x0ff7: /* maskmovq */
regcache_raw_read_unsigned (ir.regcache,
ir.regmap[X86_RECORD_REDI_REGNUM],
&addr);
- if (record_arch_list_add_mem (addr, 64))
+ if (record_full_arch_list_add_mem (addr, 64))
return -1;
break;
@@ -7373,7 +7375,7 @@ reswitch_prefix_add:
regcache_raw_read_unsigned (ir.regcache,
ir.regmap[X86_RECORD_REDI_REGNUM],
&addr);
- if (record_arch_list_add_mem (addr, 128))
+ if (record_full_arch_list_add_mem (addr, 128))
return -1;
break;
@@ -7389,8 +7391,8 @@ reswitch_prefix_add:
}
/* In the future, maybe still need to deal with need_dasm. */
- I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REIP_REGNUM);
- if (record_arch_list_add_end ())
+ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REIP_REGNUM);
+ if (record_full_arch_list_add_end ())
return -1;
return 0;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 1e2addc..92874e2 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3011,7 +3011,7 @@ adjust_pc_after_break (struct execution_control_state *ecs)
struct cleanup *old_cleanups = NULL;
if (RECORD_IS_USED)
- old_cleanups = record_gdb_operation_disable_set ();
+ old_cleanups = record_full_gdb_operation_disable_set ();
/* When using hardware single-step, a SIGTRAP is reported for both
a completed single-step and a software breakpoint. Need to
diff --git a/gdb/linux-record.c b/gdb/linux-record.c
index 2b62219..616f08f 100644
--- a/gdb/linux-record.c
+++ b/gdb/linux-record.c
@@ -100,7 +100,7 @@ record_linux_sockaddr (struct regcache *regcache,
a = alloca (tdep->size_int);
- if (record_arch_list_add_mem ((CORE_ADDR) len, tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) len, tdep->size_int))
return -1;
/* Get the addrlen. */
@@ -118,7 +118,7 @@ record_linux_sockaddr (struct regcache *regcache,
if (addrlen <= 0 || addrlen > tdep->size_sockaddr)
addrlen = tdep->size_sockaddr;
- if (record_arch_list_add_mem ((CORE_ADDR) addr, addrlen))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) addr, addrlen))
return -1;
return 0;
@@ -137,7 +137,7 @@ record_linux_msghdr (struct regcache *regcache,
if (!addr)
return 0;
- if (record_arch_list_add_mem ((CORE_ADDR) addr, tdep->size_msghdr))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) addr, tdep->size_msghdr))
return -1;
a = alloca (tdep->size_msghdr);
@@ -156,10 +156,11 @@ record_linux_msghdr (struct regcache *regcache,
/* msg_name msg_namelen */
addr = extract_unsigned_integer (a, tdep->size_pointer, byte_order);
a += tdep->size_pointer;
- if (record_arch_list_add_mem ((CORE_ADDR) addr,
- (int) extract_unsigned_integer (a,
- tdep->size_int,
- byte_order)))
+ if (record_full_arch_list_add_mem
+ ((CORE_ADDR) addr,
+ (int) extract_unsigned_integer (a,
+ tdep->size_int,
+ byte_order)))
return -1;
a += tdep->size_int;
@@ -193,7 +194,7 @@ record_linux_msghdr (struct regcache *regcache,
tmpint = (int) extract_unsigned_integer (iov + tdep->size_pointer,
tdep->size_size_t,
byte_order);
- if (record_arch_list_add_mem (tmpaddr, tmpint))
+ if (record_full_arch_list_add_mem (tmpaddr, tmpint))
return -1;
addr += tdep->size_iovec;
}
@@ -204,7 +205,7 @@ record_linux_msghdr (struct regcache *regcache,
addr = extract_unsigned_integer (a, tdep->size_pointer, byte_order);
a += tdep->size_pointer;
tmpint = (int) extract_unsigned_integer (a, tdep->size_size_t, byte_order);
- if (record_arch_list_add_mem ((CORE_ADDR) addr, tmpint))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) addr, tmpint))
return -1;
return 0;
@@ -261,7 +262,7 @@ record_linux_system_call (enum gdb_syscall syscall,
regcache_raw_read_unsigned (regcache, tdep->arg2, &addr);
regcache_raw_read_unsigned (regcache, tdep->arg3, &count);
- if (record_arch_list_add_mem ((CORE_ADDR) addr, (int) count))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) addr, (int) count))
return -1;
}
break;
@@ -286,8 +287,8 @@ record_linux_system_call (enum gdb_syscall syscall,
case gdb_sys_fstat:
case gdb_sys_lstat:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size__old_kernel_stat))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size__old_kernel_stat))
return -1;
break;
@@ -308,7 +309,7 @@ record_linux_system_call (enum gdb_syscall syscall,
{
regcache_raw_read_unsigned (regcache, tdep->arg4,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, 4))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest, 4))
return -1;
}
break;
@@ -332,7 +333,8 @@ record_linux_system_call (enum gdb_syscall syscall,
case gdb_sys_times:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_tms))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_tms))
return -1;
break;
@@ -404,8 +406,8 @@ record_linux_system_call (enum gdb_syscall syscall,
{
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_termios))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_termios))
return -1;
}
else if (tmpulongest == tdep->ioctl_TIOCGPGRP
@@ -413,8 +415,8 @@ record_linux_system_call (enum gdb_syscall syscall,
{
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_pid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_pid_t))
return -1;
}
else if (tmpulongest == tdep->ioctl_TIOCOUTQ
@@ -428,16 +430,16 @@ record_linux_system_call (enum gdb_syscall syscall,
{
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
}
else if (tmpulongest == tdep->ioctl_TIOCGWINSZ)
{
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_winsize))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_winsize))
return -1;
}
else if (tmpulongest == tdep->ioctl_TIOCLINUX)
@@ -445,47 +447,47 @@ record_linux_system_call (enum gdb_syscall syscall,
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
/* This syscall affects a char-size memory. */
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, 1))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest, 1))
return -1;
}
else if (tmpulongest == tdep->ioctl_TIOCGSERIAL)
{
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_serial_struct))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_serial_struct))
return -1;
}
else if (tmpulongest == tdep->ioctl_TCGETS2)
{
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_termios2))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_termios2))
return -1;
}
else if (tmpulongest == tdep->ioctl_FIOQSIZE)
{
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_loff_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_loff_t))
return -1;
}
else if (tmpulongest == tdep->ioctl_TIOCGICOUNT)
{
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_serial_icounter_struct))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_serial_icounter_struct))
return -1;
}
else if (tmpulongest == tdep->ioctl_TIOCGHAYESESP)
{
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_hayes_esp_config))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_hayes_esp_config))
return -1;
}
else if (tmpulongest == tdep->ioctl_TIOCSERGSTRUCT)
@@ -511,8 +513,8 @@ record_linux_system_call (enum gdb_syscall syscall,
{
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_flock))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_flock))
return -1;
}
break;
@@ -524,8 +526,8 @@ record_linux_system_call (enum gdb_syscall syscall,
case gdb_sys_olduname:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_oldold_utsname))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_oldold_utsname))
return -1;
break;
@@ -535,8 +537,8 @@ record_linux_system_call (enum gdb_syscall syscall,
case gdb_sys_ustat:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_ustat))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_ustat))
return -1;
break;
@@ -548,8 +550,8 @@ record_linux_system_call (enum gdb_syscall syscall,
case gdb_sys_sigaction:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_sigaction))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_sigaction))
return -1;
break;
@@ -562,8 +564,8 @@ record_linux_system_call (enum gdb_syscall syscall,
case gdb_sys_sigpending:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_sigset_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_sigset_t))
return -1;
break;
@@ -573,26 +575,26 @@ record_linux_system_call (enum gdb_syscall syscall,
case gdb_sys_old_getrlimit:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_rlimit))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_rlimit))
return -1;
break;
case gdb_sys_getrusage:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_rusage))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_rusage))
return -1;
break;
case gdb_sys_gettimeofday:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_timeval))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_timeval))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_timezone))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_timezone))
return -1;
break;
@@ -601,15 +603,15 @@ record_linux_system_call (enum gdb_syscall syscall,
case gdb_sys_getgroups16:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_gid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_gid_t))
return -1;
break;
case gdb_sys_setgroups16:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_gid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_gid_t))
return -1;
break;
@@ -639,13 +641,13 @@ record_linux_system_call (enum gdb_syscall syscall,
(unsigned long) sizeof (sel));
return -1;
}
- if (record_arch_list_add_mem (sel.inp, tdep->size_fd_set))
+ if (record_full_arch_list_add_mem (sel.inp, tdep->size_fd_set))
return -1;
- if (record_arch_list_add_mem (sel.outp, tdep->size_fd_set))
+ if (record_full_arch_list_add_mem (sel.outp, tdep->size_fd_set))
return -1;
- if (record_arch_list_add_mem (sel.exp, tdep->size_fd_set))
+ if (record_full_arch_list_add_mem (sel.exp, tdep->size_fd_set))
return -1;
- if (record_arch_list_add_mem (sel.tvp, tdep->size_timeval))
+ if (record_full_arch_list_add_mem (sel.tvp, tdep->size_timeval))
return -1;
}
}
@@ -661,7 +663,7 @@ record_linux_system_call (enum gdb_syscall syscall,
regcache_raw_read_unsigned (regcache, tdep->arg2,
&tmpulongest);
regcache_raw_read_unsigned (regcache, tdep->arg3, &len);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, (int) len))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest, (int) len))
return -1;
}
break;
@@ -686,8 +688,8 @@ record_linux_system_call (enum gdb_syscall syscall,
case gdb_old_readdir:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_dirent))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_dirent))
return -1;
break;
@@ -701,7 +703,7 @@ record_linux_system_call (enum gdb_syscall syscall,
regcache_raw_read_unsigned (regcache, tdep->arg1,
&tmpulongest);
regcache_raw_read_unsigned (regcache, tdep->arg2, &len);
- if (record_memory_query)
+ if (record_full_memory_query)
{
int q;
@@ -731,8 +733,8 @@ Do you want to stop the program?"),
case gdb_sys_statfs:
case gdb_sys_fstatfs:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_statfs))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_statfs))
return -1;
break;
@@ -779,7 +781,8 @@ Do you want to stop the program?"),
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
regcache_raw_read_unsigned (regcache, tdep->arg3, &size);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, (int) size))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (int) size))
return -1;
}
break;
@@ -792,7 +795,8 @@ Do you want to stop the program?"),
case gdb_sys_socketpair:
regcache_raw_read_unsigned (regcache, tdep->arg4, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
break;
@@ -818,10 +822,10 @@ Do you want to stop the program?"),
regcache_raw_read_unsigned (regcache, tdep->arg4, &optvalp);
tmpint = (int) extract_signed_integer (optlenp, tdep->size_int,
byte_order);
- if (record_arch_list_add_mem ((CORE_ADDR) optvalp, tmpint))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) optvalp, tmpint))
return -1;
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
}
break;
@@ -892,7 +896,7 @@ Do you want to stop the program?"),
tmpaddr
= (CORE_ADDR) extract_unsigned_integer (a, tdep->size_ulong,
byte_order);
- if (record_arch_list_add_mem (tmpaddr, tdep->size_int))
+ if (record_full_arch_list_add_mem (tmpaddr, tdep->size_int))
return -1;
}
}
@@ -953,8 +957,8 @@ Do you want to stop the program?"),
a += tdep->size_ulong;
tmpint = (int) extract_unsigned_integer (a, tdep->size_ulong,
byte_order);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tmpint))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tmpint))
return -1;
}
}
@@ -1008,14 +1012,15 @@ Do you want to stop the program?"),
tmpint = (int) extract_unsigned_integer (av,
tdep->size_int,
byte_order);
- if (record_arch_list_add_mem (tmpaddr, tmpint))
+ if (record_full_arch_list_add_mem (tmpaddr, tmpint))
return -1;
a += tdep->size_ulong;
tmpaddr
= (CORE_ADDR) extract_unsigned_integer (a,
tdep->size_ulong,
byte_order);
- if (record_arch_list_add_mem (tmpaddr, tdep->size_int))
+ if (record_full_arch_list_add_mem (tmpaddr,
+ tdep->size_int))
return -1;
}
}
@@ -1064,15 +1069,15 @@ Do you want to stop the program?"),
case gdb_sys_setitimer:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_itimerval))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_itimerval))
return -1;
break;
case gdb_sys_getitimer:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_itimerval))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_itimerval))
return -1;
break;
@@ -1081,14 +1086,15 @@ Do you want to stop the program?"),
case gdb_sys_newfstat:
case gdb_sys_newfstatat:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_stat))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_stat))
return -1;
break;
case gdb_sys_uname:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_utsname))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_utsname))
return -1;
break;
@@ -1100,12 +1106,12 @@ Do you want to stop the program?"),
case gdb_sys_wait4:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg4, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_rusage))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_rusage))
return -1;
break;
@@ -1114,8 +1120,8 @@ Do you want to stop the program?"),
case gdb_sys_sysinfo:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_sysinfo))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_sysinfo))
return -1;
break;
@@ -1131,15 +1137,15 @@ Do you want to stop the program?"),
case gdb_sys_shmat:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_ulong))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_ulong))
return -1;
break;
case gdb_sys_shmctl:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_shmid_ds))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_shmid_ds))
return -1;
break;
@@ -1154,15 +1160,15 @@ Do you want to stop the program?"),
regcache_raw_read_signed (regcache, tdep->arg3, &l);
regcache_raw_read_unsigned (regcache, tdep->arg2, &msgp);
tmpint = l + tdep->size_long;
- if (record_arch_list_add_mem ((CORE_ADDR) msgp, tmpint))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) msgp, tmpint))
return -1;
}
break;
case gdb_sys_msgctl:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_msqid_ds))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_msqid_ds))
return -1;
break;
@@ -1188,29 +1194,29 @@ Do you want to stop the program?"),
regcache_raw_read_signed (regcache, tdep->arg3, &second);
regcache_raw_read_unsigned (regcache, tdep->arg5, &ptr);
tmpint = (int) second + tdep->size_long;
- if (record_arch_list_add_mem ((CORE_ADDR) ptr, tmpint))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) ptr, tmpint))
return -1;
}
break;
case RECORD_MSGCTL:
regcache_raw_read_unsigned (regcache, tdep->arg5,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_msqid_ds))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_msqid_ds))
return -1;
break;
case RECORD_SHMAT:
regcache_raw_read_unsigned (regcache, tdep->arg4,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_ulong))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_ulong))
return -1;
break;
case RECORD_SHMCTL:
regcache_raw_read_unsigned (regcache, tdep->arg5,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_shmid_ds))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_shmid_ds))
return -1;
break;
default:
@@ -1230,8 +1236,8 @@ Do you want to stop the program?"),
case gdb_sys_newuname:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_new_utsname))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_new_utsname))
return -1;
break;
@@ -1243,14 +1249,15 @@ Do you want to stop the program?"),
regcache_raw_read_unsigned (regcache, tdep->arg2, &ptr);
regcache_raw_read_unsigned (regcache, tdep->arg3, &bytecount);
- if (record_arch_list_add_mem ((CORE_ADDR) ptr, (int) bytecount))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) ptr, (int) bytecount))
return -1;
}
break;
case gdb_sys_adjtimex:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_timex))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_timex))
return -1;
break;
@@ -1259,8 +1266,8 @@ Do you want to stop the program?"),
case gdb_sys_sigprocmask:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_sigset_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_sigset_t))
return -1;
break;
@@ -1278,29 +1285,29 @@ Do you want to stop the program?"),
regcache_raw_read_unsigned (regcache, tdep->arg4,
&tmpulongest);
/* __u32 */
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, 4))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest, 4))
return -1;
break;
case RECORD_Q_GETINFO:
regcache_raw_read_unsigned (regcache, tdep->arg4,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_mem_dqinfo))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_mem_dqinfo))
return -1;
break;
case RECORD_Q_GETQUOTA:
regcache_raw_read_unsigned (regcache, tdep->arg4,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_if_dqblk))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_if_dqblk))
return -1;
break;
case RECORD_Q_XGETQSTAT:
case RECORD_Q_XGETQUOTA:
regcache_raw_read_unsigned (regcache, tdep->arg4,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_fs_quota_stat))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_fs_quota_stat))
return -1;
break;
}
@@ -1318,7 +1325,7 @@ Do you want to stop the program?"),
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
/*XXX the size of memory is not very clear. */
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, 10))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest, 10))
return -1;
}
break;
@@ -1331,8 +1338,8 @@ Do you want to stop the program?"),
case gdb_sys_llseek:
regcache_raw_read_unsigned (regcache, tdep->arg4, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_loff_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_loff_t))
return -1;
break;
@@ -1343,28 +1350,28 @@ Do you want to stop the program?"),
regcache_raw_read_unsigned (regcache, tdep->arg2,
&tmpulongest);
regcache_raw_read_unsigned (regcache, tdep->arg3, &count);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_dirent * count))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_dirent * count))
return -1;
}
break;
case gdb_sys_select:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_fd_set))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_fd_set))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_fd_set))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_fd_set))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg4, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_fd_set))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_fd_set))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg5, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_timeval))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_timeval))
return -1;
break;
@@ -1403,7 +1410,7 @@ Do you want to stop the program?"),
= (int) extract_unsigned_integer (iov + tdep->size_pointer,
tdep->size_size_t,
byte_order);
- if (record_arch_list_add_mem (tmpaddr, tmpint))
+ if (record_full_arch_list_add_mem (tmpaddr, tmpint))
return -1;
vec += tdep->size_iovec;
}
@@ -1424,7 +1431,8 @@ Do you want to stop the program?"),
case gdb_sys_sched_getparam:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
break;
@@ -1438,8 +1446,8 @@ Do you want to stop the program?"),
case gdb_sys_sched_rr_get_interval:
case gdb_sys_nanosleep:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_timespec))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_timespec))
return -1;
break;
@@ -1449,16 +1457,16 @@ Do you want to stop the program?"),
case gdb_sys_getresuid16:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_uid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_uid_t))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_uid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_uid_t))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_uid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_uid_t))
return -1;
break;
@@ -1473,8 +1481,8 @@ Do you want to stop the program?"),
ULONGEST nfds;
regcache_raw_read_unsigned (regcache, tdep->arg2, &nfds);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_pollfd * nfds))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_pollfd * nfds))
return -1;
}
break;
@@ -1491,7 +1499,7 @@ Do you want to stop the program?"),
rsize = tdep->size_knfsd_fh;
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, rsize))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest, rsize))
return -1;
}
break;
@@ -1501,16 +1509,16 @@ Do you want to stop the program?"),
case gdb_sys_getresgid16:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_gid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_gid_t))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_gid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_gid_t))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_old_gid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_old_gid_t))
return -1;
break;
@@ -1521,15 +1529,15 @@ Do you want to stop the program?"),
case 2:
regcache_raw_read_unsigned (regcache, tdep->arg2,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
break;
case 16:
regcache_raw_read_unsigned (regcache, tdep->arg2,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_TASK_COMM_LEN))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_TASK_COMM_LEN))
return -1;
break;
}
@@ -1540,15 +1548,15 @@ Do you want to stop the program?"),
case gdb_sys_rt_sigaction:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_sigaction))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_sigaction))
return -1;
break;
case gdb_sys_rt_sigprocmask:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_sigset_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_sigset_t))
return -1;
break;
@@ -1559,16 +1567,16 @@ Do you want to stop the program?"),
ULONGEST sigsetsize;
regcache_raw_read_unsigned (regcache, tdep->arg2,&sigsetsize);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- (int) sigsetsize))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (int) sigsetsize))
return -1;
}
break;
case gdb_sys_rt_sigtimedwait:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_siginfo_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_siginfo_t))
return -1;
break;
@@ -1583,7 +1591,8 @@ Do you want to stop the program?"),
ULONGEST count;
regcache_raw_read_unsigned (regcache, tdep->arg3,&count);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, (int) count))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (int) count))
return -1;
}
break;
@@ -1599,15 +1608,16 @@ Do you want to stop the program?"),
ULONGEST size;
regcache_raw_read_unsigned (regcache, tdep->arg2, &size);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, (int) size))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (int) size))
return -1;
}
break;
case gdb_sys_capget:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_cap_user_data_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_cap_user_data_t))
return -1;
break;
@@ -1616,15 +1626,15 @@ Do you want to stop the program?"),
case gdb_sys_sigaltstack:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_stack_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_stack_t))
return -1;
break;
case gdb_sys_sendfile:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_off_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_off_t))
return -1;
break;
@@ -1635,8 +1645,8 @@ Do you want to stop the program?"),
case gdb_sys_getrlimit:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_rlimit))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_rlimit))
return -1;
break;
@@ -1651,8 +1661,8 @@ Do you want to stop the program?"),
case gdb_sys_lstat64:
case gdb_sys_fstat64:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_stat64))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_stat64))
return -1;
break;
@@ -1674,7 +1684,7 @@ Do you want to stop the program?"),
regcache_raw_read_unsigned (regcache, tdep->arg1,
&gidsetsize);
tmpint = tdep->size_gid_t * (int) gidsetsize;
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tmpint))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest, tmpint))
return -1;
}
break;
@@ -1686,13 +1696,16 @@ Do you want to stop the program?"),
case gdb_sys_getresuid:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_uid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_uid_t))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_uid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_uid_t))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_uid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_uid_t))
return -1;
break;
@@ -1701,13 +1714,16 @@ Do you want to stop the program?"),
case gdb_sys_getresgid:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_gid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_gid_t))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_gid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_gid_t))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_gid_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_gid_t))
return -1;
break;
@@ -1721,8 +1737,8 @@ Do you want to stop the program?"),
case gdb_sys_mincore:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_PAGE_SIZE))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_PAGE_SIZE))
return -1;
break;
@@ -1736,8 +1752,8 @@ Do you want to stop the program?"),
regcache_raw_read_unsigned (regcache, tdep->arg2,
&tmpulongest);
regcache_raw_read_unsigned (regcache, tdep->arg3, &count);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_dirent64 * count))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_dirent64 * count))
return -1;
}
break;
@@ -1748,8 +1764,8 @@ Do you want to stop the program?"),
{
regcache_raw_read_unsigned (regcache, tdep->arg3,
&tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_flock64))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_flock64))
return -1;
}
else if (tmpulongest != tdep->fcntl_F_SETLK64
@@ -1777,7 +1793,8 @@ Do you want to stop the program?"),
ULONGEST size;
regcache_raw_read_unsigned (regcache, tdep->arg4, &size);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, (int) size))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (int) size))
return -1;
}
break;
@@ -1791,7 +1808,8 @@ Do you want to stop the program?"),
ULONGEST size;
regcache_raw_read_unsigned (regcache, tdep->arg3, &size);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, (int) size))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (int) size))
return -1;
}
break;
@@ -1804,8 +1822,8 @@ Do you want to stop the program?"),
case gdb_sys_sendfile64:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_loff_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_loff_t))
return -1;
break;
@@ -1820,27 +1838,30 @@ Do you want to stop the program?"),
ULONGEST len;
regcache_raw_read_unsigned (regcache, tdep->arg2, &len);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, (int) len))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (int) len))
return -1;
}
break;
case gdb_sys_set_thread_area:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
break;
case gdb_sys_get_thread_area:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_user_desc))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_user_desc))
return -1;
break;
case gdb_sys_io_setup:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_long))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_long))
return -1;
break;
@@ -1854,8 +1875,8 @@ Do you want to stop the program?"),
ULONGEST nr;
regcache_raw_read_unsigned (regcache, tdep->arg3, &nr);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- nr * tdep->size_io_event))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ nr * tdep->size_io_event))
return -1;
}
break;
@@ -1886,7 +1907,7 @@ Do you want to stop the program?"),
= (CORE_ADDR) extract_unsigned_integer (iocbp,
tdep->size_pointer,
byte_order);
- if (record_arch_list_add_mem (tmpaddr, tdep->size_iocb))
+ if (record_full_arch_list_add_mem (tmpaddr, tdep->size_iocb))
return -1;
iocbp += tdep->size_pointer;
}
@@ -1895,8 +1916,8 @@ Do you want to stop the program?"),
case gdb_sys_io_cancel:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_io_event))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_io_event))
return -1;
break;
@@ -1925,7 +1946,8 @@ Do you want to stop the program?"),
ULONGEST len;
regcache_raw_read_unsigned (regcache, tdep->arg3, &len);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, (int) len))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (int) len))
return -1;
}
break;
@@ -1941,8 +1963,9 @@ Do you want to stop the program?"),
ULONGEST maxevents;
regcache_raw_read_unsigned (regcache, tdep->arg3, &maxevents);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- maxevents * tdep->size_epoll_event))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (maxevents
+ * tdep->size_epoll_event)))
return -1;
}
break;
@@ -1953,21 +1976,22 @@ Do you want to stop the program?"),
case gdb_sys_timer_create:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
break;
case gdb_sys_timer_settime:
regcache_raw_read_unsigned (regcache, tdep->arg4, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_itimerspec))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_itimerspec))
return -1;
break;
case gdb_sys_timer_gettime:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_itimerspec))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_itimerspec))
return -1;
break;
@@ -1978,30 +2002,30 @@ Do you want to stop the program?"),
case gdb_sys_clock_gettime:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_timespec))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_timespec))
return -1;
break;
case gdb_sys_clock_getres:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_timespec))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_timespec))
return -1;
break;
case gdb_sys_clock_nanosleep:
regcache_raw_read_unsigned (regcache, tdep->arg4, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_timespec))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_timespec))
return -1;
break;
case gdb_sys_statfs64:
case gdb_sys_fstatfs64:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_statfs64))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_statfs64))
return -1;
break;
@@ -2014,7 +2038,8 @@ Do you want to stop the program?"),
case gdb_sys_get_mempolicy:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
if (tmpulongest)
@@ -2022,8 +2047,8 @@ Do you want to stop the program?"),
ULONGEST maxnode;
regcache_raw_read_unsigned (regcache, tdep->arg3, &maxnode);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- maxnode * tdep->size_long))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ maxnode * tdep->size_long))
return -1;
}
break;
@@ -2041,12 +2066,13 @@ Do you want to stop the program?"),
ULONGEST msg_len;
regcache_raw_read_unsigned (regcache, tdep->arg3, &msg_len);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- (int) msg_len))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (int) msg_len))
return -1;
}
regcache_raw_read_unsigned (regcache, tdep->arg4, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
break;
@@ -2055,8 +2081,8 @@ Do you want to stop the program?"),
case gdb_sys_mq_getsetattr:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_mq_attr))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_mq_attr))
return -1;
break;
@@ -2065,12 +2091,12 @@ Do you want to stop the program?"),
case gdb_sys_waitid:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_siginfo))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_siginfo))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg5, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_rusage))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_rusage))
return -1;
break;
@@ -2090,8 +2116,8 @@ Do you want to stop the program?"),
ULONGEST buflen;
regcache_raw_read_unsigned (regcache, tdep->arg4, &buflen);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- (int) buflen))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (int) buflen))
return -1;
}
}
@@ -2112,8 +2138,8 @@ Do you want to stop the program?"),
case gdb_sys_fstatat64:
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_stat64))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_stat64))
return -1;
break;
@@ -2130,7 +2156,8 @@ Do you want to stop the program?"),
ULONGEST bufsiz;
regcache_raw_read_unsigned (regcache, tdep->arg4, &bufsiz);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, (int) bufsiz))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ (int) bufsiz))
return -1;
}
break;
@@ -2141,20 +2168,20 @@ Do you want to stop the program?"),
case gdb_sys_pselect6:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_fd_set))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_fd_set))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_fd_set))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_fd_set))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg4, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_fd_set))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_fd_set))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg5, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_timespec))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_timespec))
return -1;
break;
@@ -2165,13 +2192,13 @@ Do you want to stop the program?"),
ULONGEST nfds;
regcache_raw_read_unsigned (regcache, tdep->arg2, &nfds);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_pollfd * nfds))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_pollfd * nfds))
return -1;
}
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_timespec))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_timespec))
return -1;
break;
@@ -2181,21 +2208,23 @@ Do you want to stop the program?"),
case gdb_sys_get_robust_list:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
break;
case gdb_sys_splice:
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_loff_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_loff_t))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg4, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_loff_t))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_loff_t))
return -1;
break;
@@ -2211,22 +2240,24 @@ Do you want to stop the program?"),
ULONGEST nr_pages;
regcache_raw_read_unsigned (regcache, tdep->arg2, &nr_pages);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- nr_pages * tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ nr_pages * tdep->size_int))
return -1;
}
break;
case gdb_sys_getcpu:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg2, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tdep->size_int))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_int))
return -1;
regcache_raw_read_unsigned (regcache, tdep->arg3, &tmpulongest);
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
- tdep->size_ulong * 2))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest,
+ tdep->size_ulong * 2))
return -1;
break;
@@ -2238,7 +2269,7 @@ Do you want to stop the program?"),
regcache_raw_read_unsigned (regcache, tdep->arg3, &maxevents);
tmpint = (int) maxevents * tdep->size_epoll_event;
- if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest, tmpint))
+ if (record_full_arch_list_add_mem ((CORE_ADDR) tmpulongest, tmpint))
return -1;
}
break;
diff --git a/gdb/moxie-tdep.c b/gdb/moxie-tdep.c
index fc0f85c..1676a9b 100644
--- a/gdb/moxie-tdep.c
+++ b/gdb/moxie-tdep.c
@@ -573,7 +573,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
case 0x02: /* gsr */
{
int reg = (inst >> 8) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -603,7 +603,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
case 0x02: /* mov (register-to-register) */
{
int reg = (inst >> 4) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -613,25 +613,25 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
MOXIE_SP_REGNUM, (gdb_byte *) & tmpu32);
tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
4, byte_order);
- if (record_arch_list_add_reg (regcache, MOXIE_FP_REGNUM)
- || (record_arch_list_add_reg (regcache,
- MOXIE_SP_REGNUM))
- || record_arch_list_add_mem (tmpu32 - 12, 12))
+ if (record_full_arch_list_add_reg (regcache, MOXIE_FP_REGNUM)
+ || (record_full_arch_list_add_reg (regcache,
+ MOXIE_SP_REGNUM))
+ || record_full_arch_list_add_mem (tmpu32 - 12, 12))
return -1;
}
break;
case 0x04: /* ret */
{
- if (record_arch_list_add_reg (regcache, MOXIE_FP_REGNUM)
- || (record_arch_list_add_reg (regcache,
- MOXIE_SP_REGNUM)))
+ if (record_full_arch_list_add_reg (regcache, MOXIE_FP_REGNUM)
+ || (record_full_arch_list_add_reg (regcache,
+ MOXIE_SP_REGNUM)))
return -1;
}
break;
case 0x05: /* add.l */
{
int reg = (inst >> 4) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -641,8 +641,8 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
4, byte_order);
- if (record_arch_list_add_reg (regcache, reg)
- || record_arch_list_add_mem (tmpu32 - 4, 4))
+ if (record_full_arch_list_add_reg (regcache, reg)
+ || record_full_arch_list_add_mem (tmpu32 - 4, 4))
return -1;
}
break;
@@ -650,15 +650,15 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
{
int a = (inst >> 4) & 0xf;
int b = inst & 0xf;
- if (record_arch_list_add_reg (regcache, a)
- || record_arch_list_add_reg (regcache, b))
+ if (record_full_arch_list_add_reg (regcache, a)
+ || record_full_arch_list_add_reg (regcache, b))
return -1;
}
break;
case 0x08: /* lda.l */
{
int reg = (inst >> 4) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -666,14 +666,14 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
{
tmpu32 = (uint32_t) moxie_process_readu (addr+2, buf,
4, byte_order);
- if (record_arch_list_add_mem (tmpu32, 4))
+ if (record_full_arch_list_add_mem (tmpu32, 4))
return -1;
}
break;
case 0x0a: /* ld.l (register indirect) */
{
int reg = (inst >> 4) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -683,14 +683,14 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
4, byte_order);
- if (record_arch_list_add_mem (tmpu32, 4))
+ if (record_full_arch_list_add_mem (tmpu32, 4))
return -1;
}
break;
case 0x0c: /* ldo.l */
{
int reg = (inst >> 4) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -703,13 +703,13 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
4, byte_order);
tmpu32 += offset;
- if (record_arch_list_add_mem (tmpu32, 4))
+ if (record_full_arch_list_add_mem (tmpu32, 4))
return -1;
}
break;
case 0x0e: /* cmp */
{
- if (record_arch_list_add_reg (regcache, MOXIE_CC_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, MOXIE_CC_REGNUM))
return -1;
}
break;
@@ -733,10 +733,10 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
MOXIE_SP_REGNUM, (gdb_byte *) & tmpu32);
tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
4, byte_order);
- if (record_arch_list_add_reg (regcache, MOXIE_FP_REGNUM)
- || (record_arch_list_add_reg (regcache,
- MOXIE_SP_REGNUM))
- || record_arch_list_add_mem (tmpu32 - 12, 12))
+ if (record_full_arch_list_add_reg (regcache, MOXIE_FP_REGNUM)
+ || (record_full_arch_list_add_reg (regcache,
+ MOXIE_SP_REGNUM))
+ || record_full_arch_list_add_mem (tmpu32 - 12, 12))
return -1;
}
break;
@@ -750,7 +750,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
case 0x1d: /* lda.b */
{
int reg = (inst >> 4) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -760,7 +760,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
4, byte_order);
- if (record_arch_list_add_mem (tmpu32, 1))
+ if (record_full_arch_list_add_mem (tmpu32, 1))
return -1;
}
break;
@@ -768,7 +768,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
{
tmpu32 = moxie_process_readu (addr+2, (char *) buf,
4, byte_order);
- if (record_arch_list_add_mem (tmpu32, 1))
+ if (record_full_arch_list_add_mem (tmpu32, 1))
return -1;
}
break;
@@ -777,7 +777,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
case 0x22: /* lda.s */
{
int reg = (inst >> 4) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -787,7 +787,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
regcache_raw_read (regcache, reg, (gdb_byte *) & tmpu32);
tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
4, byte_order);
- if (record_arch_list_add_mem (tmpu32, 2))
+ if (record_full_arch_list_add_mem (tmpu32, 2))
return -1;
}
break;
@@ -795,7 +795,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
{
tmpu32 = moxie_process_readu (addr+2, (char *) buf,
4, byte_order);
- if (record_arch_list_add_mem (tmpu32, 2))
+ if (record_full_arch_list_add_mem (tmpu32, 2))
return -1;
}
break;
@@ -816,7 +816,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
case 0x2f: /* mul.l */
{
int reg = (inst >> 4) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -837,7 +837,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
break;
case 0x2: /* SYS_open */
{
- if (record_arch_list_add_reg (regcache, RET1_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, RET1_REGNUM))
return -1;
}
break;
@@ -858,13 +858,13 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
length = moxie_process_readu (tmpu32+20, (char *) buf,
4, byte_order);
- if (record_arch_list_add_mem (ptr, length))
+ if (record_full_arch_list_add_mem (ptr, length))
return -1;
}
break;
case 0x5: /* SYS_write */
{
- if (record_arch_list_add_reg (regcache, RET1_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, RET1_REGNUM))
return -1;
}
break;
@@ -879,7 +879,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
case 0x34: /* umod.l */
{
int reg = (inst >> 4) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -889,7 +889,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
case 0x36: /* ldo.b */
{
int reg = (inst >> 4) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -902,14 +902,14 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
4, byte_order);
tmpu32 += offset;
- if (record_arch_list_add_mem (tmpu32, 1))
+ if (record_full_arch_list_add_mem (tmpu32, 1))
return -1;
}
break;
case 0x38: /* ldo.s */
{
int reg = (inst >> 4) & 0xf;
- if (record_arch_list_add_reg (regcache, reg))
+ if (record_full_arch_list_add_reg (regcache, reg))
return -1;
}
break;
@@ -922,7 +922,7 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
4, byte_order);
tmpu32 += offset;
- if (record_arch_list_add_mem (tmpu32, 2))
+ if (record_full_arch_list_add_mem (tmpu32, 2))
return -1;
}
break;
@@ -932,9 +932,9 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
}
}
- if (record_arch_list_add_reg (regcache, MOXIE_PC_REGNUM))
+ if (record_full_arch_list_add_reg (regcache, MOXIE_PC_REGNUM))
return -1;
- if (record_arch_list_add_end ())
+ if (record_full_arch_list_add_end ())
return -1;
return 0;
}
diff --git a/gdb/record-full.c b/gdb/record-full.c
index 14f4400..5ffa6b7 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -156,7 +156,7 @@ struct record_full_entry
/* If true, query if PREC cannot record memory
change of next instruction. */
-int record_memory_query = 0;
+int record_full_memory_query = 0;
struct record_full_core_buf_entry
{
@@ -483,7 +483,7 @@ record_full_get_loc (struct record_full_entry *rec)
/* Record the value of a register NUM to record_full_arch_list. */
int
-record_arch_list_add_reg (struct regcache *regcache, int regnum)
+record_full_arch_list_add_reg (struct regcache *regcache, int regnum)
{
struct record_full_entry *rec;
@@ -506,7 +506,7 @@ record_arch_list_add_reg (struct regcache *regcache, int regnum)
length is LEN to record_full_arch_list. */
int
-record_arch_list_add_mem (CORE_ADDR addr, int len)
+record_full_arch_list_add_mem (CORE_ADDR addr, int len)
{
struct record_full_entry *rec;
@@ -537,7 +537,7 @@ record_arch_list_add_mem (CORE_ADDR addr, int len)
record_full_arch_list. */
int
-record_arch_list_add_end (void)
+record_full_arch_list_add_end (void)
{
struct record_full_entry *rec;
@@ -701,7 +701,7 @@ record_full_message_wrapper_safe (struct regcache *regcache,
static int record_full_gdb_operation_disable = 0;
struct cleanup *
-record_gdb_operation_disable_set (void)
+record_full_gdb_operation_disable_set (void)
{
struct cleanup *old_cleanups = NULL;
@@ -1189,7 +1189,7 @@ record_full_wait_1 (struct target_ops *ops,
ptid_t ptid, struct target_waitstatus *status,
int options)
{
- struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
+ struct cleanup *set_cleanups = record_full_gdb_operation_disable_set ();
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
@@ -1599,7 +1599,7 @@ record_full_registers_change (struct regcache *regcache, int regnum)
for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
{
- if (record_arch_list_add_reg (regcache, i))
+ if (record_full_arch_list_add_reg (regcache, i))
{
record_full_list_release (record_full_arch_list_tail);
error (_("Process record: failed to record execution log."));
@@ -1608,13 +1608,13 @@ record_full_registers_change (struct regcache *regcache, int regnum)
}
else
{
- if (record_arch_list_add_reg (regcache, regnum))
+ if (record_full_arch_list_add_reg (regcache, regnum))
{
record_full_list_release (record_full_arch_list_tail);
error (_("Process record: failed to record execution log."));
}
}
- if (record_arch_list_add_end ())
+ if (record_full_arch_list_add_end ())
{
record_full_list_release (record_full_arch_list_tail);
error (_("Process record: failed to record execution log."));
@@ -1721,7 +1721,7 @@ record_full_xfer_partial (struct target_ops *ops, enum target_object object,
/* Record registers change to list as an instruction. */
record_full_arch_list_head = NULL;
record_full_arch_list_tail = NULL;
- if (record_arch_list_add_mem (offset, len))
+ if (record_full_arch_list_add_mem (offset, len))
{
record_full_list_release (record_full_arch_list_tail);
if (record_debug)
@@ -1730,7 +1730,7 @@ record_full_xfer_partial (struct target_ops *ops, enum target_object object,
"execution log.");
return -1;
}
- if (record_arch_list_add_end ())
+ if (record_full_arch_list_add_end ())
{
record_full_list_release (record_full_arch_list_tail);
if (record_debug)
@@ -1831,7 +1831,7 @@ record_full_insert_breakpoint (struct gdbarch *gdbarch,
struct cleanup *old_cleanups;
int ret;
- old_cleanups = record_gdb_operation_disable_set ();
+ old_cleanups = record_full_gdb_operation_disable_set ();
ret = record_full_beneath_to_insert_breakpoint (gdbarch, bp_tgt);
do_cleanups (old_cleanups);
@@ -1871,7 +1871,7 @@ record_full_remove_breakpoint (struct gdbarch *gdbarch,
struct cleanup *old_cleanups;
int ret;
- old_cleanups = record_gdb_operation_disable_set ();
+ old_cleanups = record_full_gdb_operation_disable_set ();
ret = record_full_beneath_to_remove_breakpoint (gdbarch, bp_tgt);
do_cleanups (old_cleanups);
@@ -2717,7 +2717,7 @@ record_full_save (char *recfilename)
gdbarch = get_regcache_arch (regcache);
/* Disable the GDB operation record. */
- set_cleanups = record_gdb_operation_disable_set ();
+ set_cleanups = record_full_gdb_operation_disable_set ();
/* Reverse execute to the begin of record list. */
while (1)
@@ -2897,7 +2897,7 @@ static void
record_full_goto_insn (struct record_full_entry *entry,
enum exec_direction_kind dir)
{
- struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
+ struct cleanup *set_cleanups = record_full_gdb_operation_disable_set ();
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = get_regcache_arch (regcache);
@@ -3043,7 +3043,7 @@ record/replay buffer. Zero means unlimited. Default is 200000."),
deprecate_cmd (c, "show record full insn-number-max");
add_setshow_boolean_cmd ("memory-query", no_class,
- &record_memory_query, _("\
+ &record_full_memory_query, _("\
Set whether query if PREC cannot record memory change of next instruction."),
_("\
Show whether query if PREC cannot record memory change of next instruction."),
diff --git a/gdb/record-full.h b/gdb/record-full.h
index 46da3a2..b5d5b31 100644
--- a/gdb/record-full.h
+++ b/gdb/record-full.h
@@ -20,11 +20,11 @@
#ifndef RECORD_FULL_H
#define RECORD_FULL_H
-extern int record_memory_query;
+extern int record_full_memory_query;
-extern int record_arch_list_add_reg (struct regcache *regcache, int num);
-extern int record_arch_list_add_mem (CORE_ADDR addr, int len);
-extern int record_arch_list_add_end (void);
-extern struct cleanup *record_gdb_operation_disable_set (void);
+extern int record_full_arch_list_add_reg (struct regcache *regcache, int num);
+extern int record_full_arch_list_add_mem (CORE_ADDR addr, int len);
+extern int record_full_arch_list_add_end (void);
+extern struct cleanup *record_full_gdb_operation_disable_set (void);
#endif /* RECORD_FULL_H */
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 19/21] doc, record: document record changes
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (14 preceding siblings ...)
2013-03-08 9:19 ` [patch v10 13/21] record-full.h: rename record_ into record_full_ Markus Metzger
@ 2013-03-08 9:19 ` Markus Metzger
2013-03-08 9:19 ` [patch v10 03/21] linux, i386, amd64: enable btrace for 32bit and 64bit linux native Markus Metzger
` (6 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:19 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Document changes to the record target resulting from the renaming into
record-full.
Document two new record sub-commands "record instruction-history" and
"record function-call-history" and two associated set/show commands
"set record instruction-history-size" and "set record
function-call-history-size".
Add this to NEWS.
Doc approved by Eli Zaretskii.
I modified the NEWS changes to incorporate feedback from Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* NEWS: Add record changes.
doc/
* gdb.texinfo (Process Record and Replay): Document record
changes.
---
gdb/NEWS | 30 +++++++
gdb/doc/gdb.texinfo | 215 +++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 211 insertions(+), 34 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 05fa498..a46e9c0 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,36 @@
*** Changes since GDB 7.5
+* Target record has been renamed to record-full.
+ Record/replay is now enabled with the "record full" command.
+ This also affects settings that are associated with full record/replay
+ that have been moved from "set/show record" to "set/show record full":
+
+set|show record full insn-number-max
+set|show record full stop-at-limit
+set|show record full memory-query
+
+* A new record target "record-btrace" has been added. The new target
+ uses hardware support to record the control-flow of a process. It
+ does not support replaying the execution, but it implements the
+ below new commands for investigating the recorded execution log.
+ This new recording method can be enabled using:
+
+record btrace
+
+ The "record-btrace" target is only available on Intel Atom processors
+ and requires a Linux kernel 2.6.32 or later.
+
+* Two new commands have been added for record/replay to give information
+ about the recorded execution without having to replay the execution.
+ The commands are only supported by "record btrace".
+
+record instruction-history prints the execution history at
+ instruction granularity
+
+record function-call-history prints the execution history at
+ function granularity
+
* New native configurations
ARM AArch64 GNU/Linux aarch64*-*-linux-gnu
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5c6859f..b2462a9 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6117,16 +6117,40 @@ For architecture environments that support process record and replay,
@table @code
@kindex target record
+@kindex target record-full
+@kindex target record-btrace
@kindex record
+@kindex record full
+@kindex record btrace
@kindex rec
-@item target record
-This command starts the process record and replay target. The process
-record and replay target can only debug a process that is already
-running. Therefore, you need first to start the process with the
-@kbd{run} or @kbd{start} commands, and then start the recording with
-the @kbd{target record} command.
+@kindex rec full
+@kindex rec btrace
+@item record @var{method}
+This command starts the process record and replay target. The
+recording method can be specified as parameter. Without a parameter
+the command uses the @code{full} recording method. The following
+recording methods are available:
-Both @code{record} and @code{rec} are aliases of @code{target record}.
+@table @code
+@item full
+Full record/replay recording using @value{GDBN}'s software record and
+replay implementation. This method allows replaying and reverse
+execution.
+
+@item btrace
+Hardware-supported instruction recording. This method does not allow
+replaying and reverse execution.
+
+This recording method may not be available on all processors.
+@end table
+
+The process record and replay target can only debug a process that is
+already running. Therefore, you need first to start the process with
+the @kbd{run} or @kbd{start} commands, and then start the recording
+with the @kbd{record @var{method}} command.
+
+Both @code{record @var{method}} and @code{rec @var{method}} are
+aliases of @code{target record-@var{method}}.
@cindex displaced stepping, and process record and replay
Displaced stepping (@pxref{Maintenance Commands,, displaced stepping})
@@ -6137,9 +6161,9 @@ doesn't support displaced stepping.
@cindex non-stop mode, and process record and replay
@cindex asynchronous execution, and process record and replay
If the inferior is in the non-stop mode (@pxref{Non-Stop Mode}) or in
-the asynchronous execution mode (@pxref{Background Execution}), the
-process record and replay target cannot be started because it doesn't
-support these two modes.
+the asynchronous execution mode (@pxref{Background Execution}), not
+all recording methods are available. The @code{full} recording method
+does not support these two modes.
@kindex record stop
@kindex rec s
@@ -6169,14 +6193,17 @@ Save the execution log to a file @file{@var{filename}}.
Default filename is @file{gdb_record.@var{process_id}}, where
@var{process_id} is the process ID of the inferior.
+This command may not be available for all recording methods.
+
@kindex record restore
@item record restore @var{filename}
Restore the execution log from a file @file{@var{filename}}.
File must have been created with @code{record save}.
-@kindex set record insn-number-max
-@item set record insn-number-max @var{limit}
-Set the limit of instructions to be recorded. Default value is 200000.
+@kindex set record full
+@item set record full insn-number-max @var{limit}
+Set the limit of instructions to be recorded for the @code{full}
+recording method. Default value is 200000.
If @var{limit} is a positive number, then @value{GDBN} will start
deleting instructions from the log once the number of the record
@@ -6191,31 +6218,31 @@ If @var{limit} is zero, @value{GDBN} will never delete recorded
instructions from the execution log. The number of recorded
instructions is unlimited in this case.
-@kindex show record insn-number-max
-@item show record insn-number-max
-Show the limit of instructions to be recorded.
+@kindex show record full
+@item show record full insn-number-max
+Show the limit of instructions to be recorded with the @code{full}
+recording method.
-@kindex set record stop-at-limit
-@item set record stop-at-limit
-Control the behavior when the number of recorded instructions reaches
-the limit. If ON (the default), @value{GDBN} will stop when the limit
-is reached for the first time and ask you whether you want to stop the
-inferior or continue running it and recording the execution log. If
-you decide to continue recording, each new recorded instruction will
-cause the oldest one to be deleted.
+@item set record full stop-at-limit
+Control the behavior of the @code{full} recording method when the
+number of recorded instructions reaches the limit. If ON (the
+default), @value{GDBN} will stop when the limit is reached for the
+first time and ask you whether you want to stop the inferior or
+continue running it and recording the execution log. If you decide
+to continue recording, each new recorded instruction will cause the
+oldest one to be deleted.
If this option is OFF, @value{GDBN} will automatically delete the
oldest record to make room for each new one, without asking.
-@kindex show record stop-at-limit
-@item show record stop-at-limit
+@item show record full stop-at-limit
Show the current setting of @code{stop-at-limit}.
-@kindex set record memory-query
-@item set record memory-query
+@item set record full memory-query
Control the behavior when @value{GDBN} is unable to record memory
-changes caused by an instruction. If ON, @value{GDBN} will query
-whether to stop the inferior in that case.
+changes caused by an instruction for the @code{full} recording method.
+If ON, @value{GDBN} will query whether to stop the inferior in that
+case.
If this option is OFF (the default), @value{GDBN} will automatically
ignore the effect of such instructions on memory. Later, when
@@ -6223,14 +6250,18 @@ ignore the effect of such instructions on memory. Later, when
instruction as not accessible, and it will not affect the replay
results.
-@kindex show record memory-query
-@item show record memory-query
+@item show record full memory-query
Show the current setting of @code{memory-query}.
@kindex info record
@item info record
-Show various statistics about the state of process record and its
-in-memory execution log buffer, including:
+Show various statistics about the recording depending on the recording
+method:
+
+@table @code
+@item full
+For the @code{full} recording method, it shows the state of process
+record and its in-memory execution log buffer, including:
@itemize @bullet
@item
@@ -6247,6 +6278,12 @@ Number of instructions contained in the execution log.
Maximum number of instructions that may be contained in the execution log.
@end itemize
+@item btrace
+For the @code{btrace} recording method, it shows the number of
+instructions that have been recorded and the number of blocks of
+sequential control-flow that is formed by the recorded instructions.
+@end table
+
@kindex record delete
@kindex rec del
@item record delete
@@ -6254,6 +6291,116 @@ When record target runs in replay mode (``in the past''), delete the
subsequent execution log and begin to record a new execution log starting
from the current address. This means you will abandon the previously
recorded ``future'' and begin recording a new ``future''.
+
+@kindex record instruction-history
+@kindex rec instruction-history
+@item record instruction-history
+Disassembles instructions from the recorded execution log. By
+default, ten instructions are disassembled. This can be changed using
+the @code{set record instruction-history-size} command. Instructions
+are printed in execution order. There are several ways to specify
+what part of the execution log to disassemble:
+
+@table @code
+@item record instruction-history @var{insn}
+Disassembles ten instructions starting from instruction number
+@var{insn}.
+
+@item record instruction-history @var{insn}, +/-@var{n}
+Disassembles @var{n} instructions around instruction number
+@var{insn}. If @var{n} is preceded with @code{+}, disassembles
+@var{n} instructions after instruction number @var{insn}. If
+@var{n} is preceded with @code{-}, disassembles @var{n}
+instructions before instruction number @var{insn}.
+
+@item record instruction-history
+Disassembles ten more instructions after the last disassembly.
+
+@item record instruction-history -
+Disassembles ten more instructions before the last disassembly.
+
+@item record instruction-history @var{begin} @var{end}
+Disassembles instructions beginning with instruction number
+@var{begin} until instruction number @var{end}. The instruction
+number @var{end} is not included.
+@end table
+
+This command may not be available for all recording methods.
+
+@kindex set record
+@item set record instruction-history-size
+Define how many instructions to disassemble in the @code{record
+instruction-history} command. The default value is 10.
+
+@kindex show record
+@item show record instruction-history-size
+Show how many instructions to disassemble in the @code{record
+instruction-history} command.
+
+@kindex record function-call-history
+@kindex rec function-call-history
+@item record function-call-history
+Prints the execution history at function granularity. It prints one
+line for each sequence of instructions that belong to the same
+function giving the name of that function, the source lines
+for this instruction sequence (if the @code{/l} modifier is
+specified), and the instructions numbers that form the sequence (if
+the @code{/i} modifier is specified).
+
+@smallexample
+(@value{GDBP}) @b{list 1, 10}
+1 void foo (void)
+2 @{
+3 @}
+4
+5 void bar (void)
+6 @{
+7 ...
+8 foo ();
+9 ...
+10 @}
+(@value{GDBP}) @b{record function-call-history /l}
+1 foo.c:6-8 bar
+2 foo.c:2-3 foo
+3 foo.c:9-10 bar
+@end smallexample
+
+By default, ten lines are printed. This can be changed using the
+@code{set record function-call-history-size} command. Functions are
+printed in execution order. There are several ways to specify what
+to print:
+
+@table @code
+@item record function-call-history @var{func}
+Prints ten functions starting from function number @var{func}.
+
+@item record function-call-history @var{func}, +/-@var{n}
+Prints @var{n} functions around function number @var{func}. If
+@var{n} is preceded with @code{+}, prints @var{n} functions after
+function number @var{func}. If @var{n} is preceded with @code{-},
+prints @var{n} functions before function number @var{func}.
+
+@item record function-call-history
+Prints ten more functions after the last ten-line print.
+
+@item record function-call-history -
+Prints ten more functions before the last ten-line print.
+
+@item record function-call-history @var{begin} @var{end}
+Prints functions beginning with function number @var{begin} until
+function number @var{end}. The function number @var{end} is not
+included.
+@end table
+
+This command may not be available for all recording methods.
+
+@item set record function-call-history-size
+Define how many lines to print in the
+@code{record function-call-history} command. The default value is 10.
+
+@item show record function-call-history-size
+Show how many lines to print in the
+@code{record function-call-history} command.
@end table
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 03/21] linux, i386, amd64: enable btrace for 32bit and 64bit linux native
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (15 preceding siblings ...)
2013-03-08 9:19 ` [patch v10 19/21] doc, record: document record changes Markus Metzger
@ 2013-03-08 9:19 ` Markus Metzger
2013-03-08 9:19 ` [patch v10 10/21] record: split record Markus Metzger
` (5 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:19 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Install the btrace target ops for i386-linux-nat and amd64-linux-nat.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* amd64-linux-nat.c: Include btrace.h and linux-btrace.h.
(amd64_linux_enable_btrace): New.
(amd64_linux_disable_btrace): New.
(_initialize_amd64_linux_nat): Initialize btrace ops.
* i386-linux.nat.c: Include btrace.h and linux-btrace.h.
(i386_linux_enable_btrace): New.
(i386_linux_disable_btrace): New.
(_initialize_i386_linux_nat): Initialize btrace ops.
* config/i386/linux.mh: Add linux-btrace.o.
* config/i386/linux64.mh: Add linux-btrace.o.
---
gdb/amd64-linux-nat.c | 41 +++++++++++++++++++++++++++++++++++++++++
gdb/config/i386/linux.mh | 3 ++-
gdb/config/i386/linux64.mh | 2 +-
gdb/i386-linux-nat.c | 41 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 85 insertions(+), 2 deletions(-)
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index 3d1983b..6f13fca 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -25,6 +25,8 @@
#include "regset.h"
#include "linux-nat.h"
#include "amd64-linux-tdep.h"
+#include "linux-btrace.h"
+#include "btrace.h"
#include "gdb_assert.h"
#include "gdb_string.h"
@@ -1119,6 +1121,39 @@ amd64_linux_read_description (struct target_ops *ops)
}
}
+/* Enable branch tracing. */
+
+static struct btrace_target_info *
+amd64_linux_enable_btrace (ptid_t ptid)
+{
+ struct btrace_target_info *tinfo;
+ struct gdbarch *gdbarch;
+
+ errno = 0;
+ tinfo = linux_enable_btrace (ptid);
+
+ if (tinfo == NULL)
+ error (_("Could not enable branch tracing for %s: %s."),
+ target_pid_to_str (ptid), safe_strerror (errno));
+
+ /* Fill in the size of a pointer in bits. */
+ gdbarch = target_thread_architecture (ptid);
+ tinfo->ptr_bits = gdbarch_ptr_bit (gdbarch);
+
+ return tinfo;
+}
+
+/* Disable branch tracing. */
+
+static void
+amd64_linux_disable_btrace (struct btrace_target_info *tinfo)
+{
+ int errcode = linux_disable_btrace (tinfo);
+
+ if (errcode != 0)
+ error (_("Could not disable branch tracing: %s."), safe_strerror (errcode));
+}
+
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_amd64_linux_nat (void);
@@ -1157,6 +1192,12 @@ _initialize_amd64_linux_nat (void)
t->to_read_description = amd64_linux_read_description;
+ /* Add btrace methods. */
+ t->to_supports_btrace = linux_supports_btrace;
+ t->to_enable_btrace = amd64_linux_enable_btrace;
+ t->to_disable_btrace = amd64_linux_disable_btrace;
+ t->to_read_btrace = linux_read_btrace;
+
/* Register the target. */
linux_nat_add_target (t);
linux_nat_set_new_thread (t, amd64_linux_new_thread);
diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh
index 8316d87..7c64e83 100644
--- a/gdb/config/i386/linux.mh
+++ b/gdb/config/i386/linux.mh
@@ -4,7 +4,8 @@ NAT_FILE= config/nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o \
i386-nat.o i386-linux-nat.o \
proc-service.o linux-thread-db.o \
- linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o
+ linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
+ linux-btrace.o
NAT_CDEPS = $(srcdir)/proc-service.list
# The dynamically loaded libthread_db needs access to symbols in the
diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh
index d2b95fd..8d782c1 100644
--- a/gdb/config/i386/linux64.mh
+++ b/gdb/config/i386/linux64.mh
@@ -3,7 +3,7 @@ NATDEPFILES= inf-ptrace.o fork-child.o \
i386-nat.o amd64-nat.o amd64-linux-nat.o \
linux-nat.o linux-osdata.o \
proc-service.o linux-thread-db.o linux-fork.o \
- linux-procfs.o linux-ptrace.o
+ linux-procfs.o linux-ptrace.o linux-btrace.o
NAT_FILE= config/nm-linux.h
NAT_CDEPS = $(srcdir)/proc-service.list
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 11b510d..715c6d4 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -25,6 +25,8 @@
#include "regset.h"
#include "target.h"
#include "linux-nat.h"
+#include "linux-btrace.h"
+#include "btrace.h"
#include "gdb_assert.h"
#include "gdb_string.h"
@@ -1046,6 +1048,39 @@ i386_linux_read_description (struct target_ops *ops)
return tdesc_i386_linux;
}
+/* Enable branch tracing. */
+
+static struct btrace_target_info *
+i386_linux_enable_btrace (ptid_t ptid)
+{
+ struct btrace_target_info *tinfo;
+ struct gdbarch *gdbarch;
+
+ errno = 0;
+ tinfo = linux_enable_btrace (ptid);
+
+ if (tinfo == NULL)
+ error (_("Could not enable branch tracing for %s: %s."),
+ target_pid_to_str (ptid), safe_strerror (errno));
+
+ /* Fill in the size of a pointer in bits. */
+ gdbarch = target_thread_architecture (ptid);
+ tinfo->ptr_bits = gdbarch_ptr_bit (gdbarch);
+
+ return tinfo;
+}
+
+/* Disable branch tracing. */
+
+static void
+i386_linux_disable_btrace (struct btrace_target_info *tinfo)
+{
+ int errcode = linux_disable_btrace (tinfo);
+
+ if (errcode != 0)
+ error (_("Could not disable branch tracing: %s."), safe_strerror (errcode));
+}
+
/* -Wmissing-prototypes */
extern initialize_file_ftype _initialize_i386_linux_nat;
@@ -1079,6 +1114,12 @@ _initialize_i386_linux_nat (void)
t->to_read_description = i386_linux_read_description;
+ /* Add btrace methods. */
+ t->to_supports_btrace = linux_supports_btrace;
+ t->to_enable_btrace = i386_linux_enable_btrace;
+ t->to_disable_btrace = i386_linux_disable_btrace;
+ t->to_read_btrace = linux_read_btrace;
+
/* Register the target. */
linux_nat_add_target (t);
linux_nat_set_new_thread (t, i386_linux_new_thread);
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 10/21] record: split record
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (16 preceding siblings ...)
2013-03-08 9:19 ` [patch v10 03/21] linux, i386, amd64: enable btrace for 32bit and 64bit linux native Markus Metzger
@ 2013-03-08 9:19 ` Markus Metzger
2013-03-08 9:19 ` [patch v10 15/21] record: add "record instruction-history" command Markus Metzger
` (4 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:19 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Split record.h into record.h and record-full.h.
Split record.c into record.c and record-full.c.
The split leaves the command part in record.c and moves the target part into
record-full.c.
The result does not build!
This patch will be merged with the next patch before committing.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* record.h: Split into this and ...
* record-full.h: ... this.
* record.c: Split into this and ...
* record-full.c: ... this.
---
gdb/record-full.c | 2738 +++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/record-full.h | 30 +
gdb/record.c | 2704 +----------------------------------------------------
gdb/record.h | 6 -
4 files changed, 2771 insertions(+), 2707 deletions(-)
create mode 100644 gdb/record-full.c
create mode 100644 gdb/record-full.h
diff --git a/gdb/record-full.c b/gdb/record-full.c
new file mode 100644
index 0000000..ff22b95
--- /dev/null
+++ b/gdb/record-full.c
@@ -0,0 +1,2738 @@
+/* Process record and replay target for GDB, the GNU debugger.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "regcache.h"
+#include "gdbthread.h"
+#include "event-top.h"
+#include "exceptions.h"
+#include "completer.h"
+#include "arch-utils.h"
+#include "gdbcore.h"
+#include "exec.h"
+#include "record.h"
+#include "elf-bfd.h"
+#include "gcore.h"
+#include "event-loop.h"
+#include "inf-loop.h"
+#include "gdb_bfd.h"
+#include "observer.h"
+
+#include <signal.h>
+
+/* This module implements "target record", also known as "process
+ record and replay". This target sits on top of a "normal" target
+ (a target that "has execution"), and provides a record and replay
+ functionality, including reverse debugging.
+
+ Target record has two modes: recording, and replaying.
+
+ In record mode, we intercept the to_resume and to_wait methods.
+ Whenever gdb resumes the target, we run the target in single step
+ mode, and we build up an execution log in which, for each executed
+ instruction, we record all changes in memory and register state.
+ This is invisible to the user, to whom it just looks like an
+ ordinary debugging session (except for performance degredation).
+
+ In replay mode, instead of actually letting the inferior run as a
+ process, we simulate its execution by playing back the recorded
+ execution log. For each instruction in the log, we simulate the
+ instruction's side effects by duplicating the changes that it would
+ have made on memory and registers. */
+
+#define DEFAULT_RECORD_INSN_MAX_NUM 200000
+
+#define RECORD_IS_REPLAY \
+ (record_list->next || execution_direction == EXEC_REVERSE)
+
+#define RECORD_FILE_MAGIC netorder32(0x20091016)
+
+/* These are the core structs of the process record functionality.
+
+ A record_entry is a record of the value change of a register
+ ("record_reg") or a part of memory ("record_mem"). And each
+ instruction must have a struct record_entry ("record_end") that
+ indicates that this is the last struct record_entry of this
+ instruction.
+
+ Each struct record_entry is linked to "record_list" by "prev" and
+ "next" pointers. */
+
+struct record_mem_entry
+{
+ CORE_ADDR addr;
+ int len;
+ /* Set this flag if target memory for this entry
+ can no longer be accessed. */
+ int mem_entry_not_accessible;
+ union
+ {
+ gdb_byte *ptr;
+ gdb_byte buf[sizeof (gdb_byte *)];
+ } u;
+};
+
+struct record_reg_entry
+{
+ unsigned short num;
+ unsigned short len;
+ union
+ {
+ gdb_byte *ptr;
+ gdb_byte buf[2 * sizeof (gdb_byte *)];
+ } u;
+};
+
+struct record_end_entry
+{
+ enum gdb_signal sigval;
+ ULONGEST insn_num;
+};
+
+enum record_type
+{
+ record_end = 0,
+ record_reg,
+ record_mem
+};
+
+/* This is the data structure that makes up the execution log.
+
+ The execution log consists of a single linked list of entries
+ of type "struct record_entry". It is doubly linked so that it
+ can be traversed in either direction.
+
+ The start of the list is anchored by a struct called
+ "record_first". The pointer "record_list" either points to the
+ last entry that was added to the list (in record mode), or to the
+ next entry in the list that will be executed (in replay mode).
+
+ Each list element (struct record_entry), in addition to next and
+ prev pointers, consists of a union of three entry types: mem, reg,
+ and end. A field called "type" determines which entry type is
+ represented by a given list element.
+
+ Each instruction that is added to the execution log is represented
+ by a variable number of list elements ('entries'). The instruction
+ will have one "reg" entry for each register that is changed by
+ executing the instruction (including the PC in every case). It
+ will also have one "mem" entry for each memory change. Finally,
+ each instruction will have an "end" entry that separates it from
+ the changes associated with the next instruction. */
+
+struct record_entry
+{
+ struct record_entry *prev;
+ struct record_entry *next;
+ enum record_type type;
+ union
+ {
+ /* reg */
+ struct record_reg_entry reg;
+ /* mem */
+ struct record_mem_entry mem;
+ /* end */
+ struct record_end_entry end;
+ } u;
+};
+
+/* If true, query if PREC cannot record memory
+ change of next instruction. */
+int record_memory_query = 0;
+
+struct record_core_buf_entry
+{
+ struct record_core_buf_entry *prev;
+ struct target_section *p;
+ bfd_byte *buf;
+};
+
+/* Record buf with core target. */
+static gdb_byte *record_core_regbuf = NULL;
+static struct target_section *record_core_start;
+static struct target_section *record_core_end;
+static struct record_core_buf_entry *record_core_buf_list = NULL;
+
+/* The following variables are used for managing the linked list that
+ represents the execution log.
+
+ record_first is the anchor that holds down the beginning of the list.
+
+ record_list serves two functions:
+ 1) In record mode, it anchors the end of the list.
+ 2) In replay mode, it traverses the list and points to
+ the next instruction that must be emulated.
+
+ record_arch_list_head and record_arch_list_tail are used to manage
+ a separate list, which is used to build up the change elements of
+ the currently executing instruction during record mode. When this
+ instruction has been completely annotated in the "arch list", it
+ will be appended to the main execution log. */
+
+static struct record_entry record_first;
+static struct record_entry *record_list = &record_first;
+static struct record_entry *record_arch_list_head = NULL;
+static struct record_entry *record_arch_list_tail = NULL;
+
+/* 1 ask user. 0 auto delete the last struct record_entry. */
+static int record_stop_at_limit = 1;
+/* Maximum allowed number of insns in execution log. */
+static unsigned int record_insn_max_num = DEFAULT_RECORD_INSN_MAX_NUM;
+/* Actual count of insns presently in execution log. */
+static int record_insn_num = 0;
+/* Count of insns logged so far (may be larger
+ than count of insns presently in execution log). */
+static ULONGEST record_insn_count;
+
+/* The target_ops of process record. */
+static struct target_ops record_ops;
+static struct target_ops record_core_ops;
+
+/* The beneath function pointers. */
+static struct target_ops *record_beneath_to_resume_ops;
+static void (*record_beneath_to_resume) (struct target_ops *, ptid_t, int,
+ enum gdb_signal);
+static struct target_ops *record_beneath_to_wait_ops;
+static ptid_t (*record_beneath_to_wait) (struct target_ops *, ptid_t,
+ struct target_waitstatus *,
+ int);
+static struct target_ops *record_beneath_to_store_registers_ops;
+static void (*record_beneath_to_store_registers) (struct target_ops *,
+ struct regcache *,
+ int regno);
+static struct target_ops *record_beneath_to_xfer_partial_ops;
+static LONGEST (*record_beneath_to_xfer_partial) (struct target_ops *ops,
+ enum target_object object,
+ const char *annex,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset,
+ LONGEST len);
+static int (*record_beneath_to_insert_breakpoint) (struct gdbarch *,
+ struct bp_target_info *);
+static int (*record_beneath_to_remove_breakpoint) (struct gdbarch *,
+ struct bp_target_info *);
+static int (*record_beneath_to_stopped_by_watchpoint) (void);
+static int (*record_beneath_to_stopped_data_address) (struct target_ops *,
+ CORE_ADDR *);
+static void (*record_beneath_to_async) (void (*) (enum inferior_event_type, void *), void *);
+
+/* Alloc and free functions for record_reg, record_mem, and record_end
+ entries. */
+
+/* Alloc a record_reg record entry. */
+
+static inline struct record_entry *
+record_reg_alloc (struct regcache *regcache, int regnum)
+{
+ struct record_entry *rec;
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
+ rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry));
+ rec->type = record_reg;
+ rec->u.reg.num = regnum;
+ rec->u.reg.len = register_size (gdbarch, regnum);
+ if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
+ rec->u.reg.u.ptr = (gdb_byte *) xmalloc (rec->u.reg.len);
+
+ return rec;
+}
+
+/* Free a record_reg record entry. */
+
+static inline void
+record_reg_release (struct record_entry *rec)
+{
+ gdb_assert (rec->type == record_reg);
+ if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
+ xfree (rec->u.reg.u.ptr);
+ xfree (rec);
+}
+
+/* Alloc a record_mem record entry. */
+
+static inline struct record_entry *
+record_mem_alloc (CORE_ADDR addr, int len)
+{
+ struct record_entry *rec;
+
+ rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry));
+ rec->type = record_mem;
+ rec->u.mem.addr = addr;
+ rec->u.mem.len = len;
+ if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
+ rec->u.mem.u.ptr = (gdb_byte *) xmalloc (len);
+
+ return rec;
+}
+
+/* Free a record_mem record entry. */
+
+static inline void
+record_mem_release (struct record_entry *rec)
+{
+ gdb_assert (rec->type == record_mem);
+ if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
+ xfree (rec->u.mem.u.ptr);
+ xfree (rec);
+}
+
+/* Alloc a record_end record entry. */
+
+static inline struct record_entry *
+record_end_alloc (void)
+{
+ struct record_entry *rec;
+
+ rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry));
+ rec->type = record_end;
+
+ return rec;
+}
+
+/* Free a record_end record entry. */
+
+static inline void
+record_end_release (struct record_entry *rec)
+{
+ xfree (rec);
+}
+
+/* Free one record entry, any type.
+ Return entry->type, in case caller wants to know. */
+
+static inline enum record_type
+record_entry_release (struct record_entry *rec)
+{
+ enum record_type type = rec->type;
+
+ switch (type) {
+ case record_reg:
+ record_reg_release (rec);
+ break;
+ case record_mem:
+ record_mem_release (rec);
+ break;
+ case record_end:
+ record_end_release (rec);
+ break;
+ }
+ return type;
+}
+
+/* Free all record entries in list pointed to by REC. */
+
+static void
+record_list_release (struct record_entry *rec)
+{
+ if (!rec)
+ return;
+
+ while (rec->next)
+ rec = rec->next;
+
+ while (rec->prev)
+ {
+ rec = rec->prev;
+ record_entry_release (rec->next);
+ }
+
+ if (rec == &record_first)
+ {
+ record_insn_num = 0;
+ record_first.next = NULL;
+ }
+ else
+ record_entry_release (rec);
+}
+
+/* Free all record entries forward of the given list position. */
+
+static void
+record_list_release_following (struct record_entry *rec)
+{
+ struct record_entry *tmp = rec->next;
+
+ rec->next = NULL;
+ while (tmp)
+ {
+ rec = tmp->next;
+ if (record_entry_release (tmp) == record_end)
+ {
+ record_insn_num--;
+ record_insn_count--;
+ }
+ tmp = rec;
+ }
+}
+
+/* Delete the first instruction from the beginning of the log, to make
+ room for adding a new instruction at the end of the log.
+
+ Note -- this function does not modify record_insn_num. */
+
+static void
+record_list_release_first (void)
+{
+ struct record_entry *tmp;
+
+ if (!record_first.next)
+ return;
+
+ /* Loop until a record_end. */
+ while (1)
+ {
+ /* Cut record_first.next out of the linked list. */
+ tmp = record_first.next;
+ record_first.next = tmp->next;
+ tmp->next->prev = &record_first;
+
+ /* tmp is now isolated, and can be deleted. */
+ if (record_entry_release (tmp) == record_end)
+ break; /* End loop at first record_end. */
+
+ if (!record_first.next)
+ {
+ gdb_assert (record_insn_num == 1);
+ break; /* End loop when list is empty. */
+ }
+ }
+}
+
+/* Add a struct record_entry to record_arch_list. */
+
+static void
+record_arch_list_add (struct record_entry *rec)
+{
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_arch_list_add %s.\n",
+ host_address_to_string (rec));
+
+ if (record_arch_list_tail)
+ {
+ record_arch_list_tail->next = rec;
+ rec->prev = record_arch_list_tail;
+ record_arch_list_tail = rec;
+ }
+ else
+ {
+ record_arch_list_head = rec;
+ record_arch_list_tail = rec;
+ }
+}
+
+/* Return the value storage location of a record entry. */
+static inline gdb_byte *
+record_get_loc (struct record_entry *rec)
+{
+ switch (rec->type) {
+ case record_mem:
+ if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
+ return rec->u.mem.u.ptr;
+ else
+ return rec->u.mem.u.buf;
+ case record_reg:
+ if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
+ return rec->u.reg.u.ptr;
+ else
+ return rec->u.reg.u.buf;
+ case record_end:
+ default:
+ gdb_assert_not_reached ("unexpected record_entry type");
+ return NULL;
+ }
+}
+
+/* Record the value of a register NUM to record_arch_list. */
+
+int
+record_arch_list_add_reg (struct regcache *regcache, int regnum)
+{
+ struct record_entry *rec;
+
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: add register num = %d to "
+ "record list.\n",
+ regnum);
+
+ rec = record_reg_alloc (regcache, regnum);
+
+ regcache_raw_read (regcache, regnum, record_get_loc (rec));
+
+ record_arch_list_add (rec);
+
+ return 0;
+}
+
+/* Record the value of a region of memory whose address is ADDR and
+ length is LEN to record_arch_list. */
+
+int
+record_arch_list_add_mem (CORE_ADDR addr, int len)
+{
+ struct record_entry *rec;
+
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: add mem addr = %s len = %d to "
+ "record list.\n",
+ paddress (target_gdbarch (), addr), len);
+
+ if (!addr) /* FIXME: Why? Some arch must permit it... */
+ return 0;
+
+ rec = record_mem_alloc (addr, len);
+
+ if (record_read_memory (target_gdbarch (), addr, record_get_loc (rec), len))
+ {
+ record_mem_release (rec);
+ return -1;
+ }
+
+ record_arch_list_add (rec);
+
+ return 0;
+}
+
+/* Add a record_end type struct record_entry to record_arch_list. */
+
+int
+record_arch_list_add_end (void)
+{
+ struct record_entry *rec;
+
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: add end to arch list.\n");
+
+ rec = record_end_alloc ();
+ rec->u.end.sigval = GDB_SIGNAL_0;
+ rec->u.end.insn_num = ++record_insn_count;
+
+ record_arch_list_add (rec);
+
+ return 0;
+}
+
+static void
+record_check_insn_num (int set_terminal)
+{
+ if (record_insn_max_num)
+ {
+ gdb_assert (record_insn_num <= record_insn_max_num);
+ if (record_insn_num == record_insn_max_num)
+ {
+ /* Ask user what to do. */
+ if (record_stop_at_limit)
+ {
+ int q;
+
+ if (set_terminal)
+ target_terminal_ours ();
+ q = yquery (_("Do you want to auto delete previous execution "
+ "log entries when record/replay buffer becomes "
+ "full (record stop-at-limit)?"));
+ if (set_terminal)
+ target_terminal_inferior ();
+ if (q)
+ record_stop_at_limit = 0;
+ else
+ error (_("Process record: stopped by user."));
+ }
+ }
+ }
+}
+
+static void
+record_arch_list_cleanups (void *ignore)
+{
+ record_list_release (record_arch_list_tail);
+}
+
+/* Before inferior step (when GDB record the running message, inferior
+ only can step), GDB will call this function to record the values to
+ record_list. This function will call gdbarch_process_record to
+ record the running message of inferior and set them to
+ record_arch_list, and add it to record_list. */
+
+static int
+record_message (struct regcache *regcache, enum gdb_signal signal)
+{
+ int ret;
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct cleanup *old_cleanups = make_cleanup (record_arch_list_cleanups, 0);
+
+ record_arch_list_head = NULL;
+ record_arch_list_tail = NULL;
+
+ /* Check record_insn_num. */
+ record_check_insn_num (1);
+
+ /* If gdb sends a signal value to target_resume,
+ save it in the 'end' field of the previous instruction.
+
+ Maybe process record should record what really happened,
+ rather than what gdb pretends has happened.
+
+ So if Linux delivered the signal to the child process during
+ the record mode, we will record it and deliver it again in
+ the replay mode.
+
+ If user says "ignore this signal" during the record mode, then
+ it will be ignored again during the replay mode (no matter if
+ the user says something different, like "deliver this signal"
+ during the replay mode).
+
+ User should understand that nothing he does during the replay
+ mode will change the behavior of the child. If he tries,
+ then that is a user error.
+
+ But we should still deliver the signal to gdb during the replay,
+ if we delivered it during the recording. Therefore we should
+ record the signal during record_wait, not record_resume. */
+ if (record_list != &record_first) /* FIXME better way to check */
+ {
+ gdb_assert (record_list->type == record_end);
+ record_list->u.end.sigval = signal;
+ }
+
+ if (signal == GDB_SIGNAL_0
+ || !gdbarch_process_record_signal_p (gdbarch))
+ ret = gdbarch_process_record (gdbarch,
+ regcache,
+ regcache_read_pc (regcache));
+ else
+ ret = gdbarch_process_record_signal (gdbarch,
+ regcache,
+ signal);
+
+ if (ret > 0)
+ error (_("Process record: inferior program stopped."));
+ if (ret < 0)
+ error (_("Process record: failed to record execution log."));
+
+ discard_cleanups (old_cleanups);
+
+ record_list->next = record_arch_list_head;
+ record_arch_list_head->prev = record_list;
+ record_list = record_arch_list_tail;
+
+ if (record_insn_num == record_insn_max_num && record_insn_max_num)
+ record_list_release_first ();
+ else
+ record_insn_num++;
+
+ return 1;
+}
+
+struct record_message_args {
+ struct regcache *regcache;
+ enum gdb_signal signal;
+};
+
+static int
+record_message_wrapper (void *args)
+{
+ struct record_message_args *record_args = args;
+
+ return record_message (record_args->regcache, record_args->signal);
+}
+
+static int
+record_message_wrapper_safe (struct regcache *regcache,
+ enum gdb_signal signal)
+{
+ struct record_message_args args;
+
+ args.regcache = regcache;
+ args.signal = signal;
+
+ return catch_errors (record_message_wrapper, &args, NULL, RETURN_MASK_ALL);
+}
+
+/* Set to 1 if record_store_registers and record_xfer_partial
+ doesn't need record. */
+
+static int record_gdb_operation_disable = 0;
+
+struct cleanup *
+record_gdb_operation_disable_set (void)
+{
+ struct cleanup *old_cleanups = NULL;
+
+ old_cleanups =
+ make_cleanup_restore_integer (&record_gdb_operation_disable);
+ record_gdb_operation_disable = 1;
+
+ return old_cleanups;
+}
+
+/* Flag set to TRUE for target_stopped_by_watchpoint. */
+static int record_hw_watchpoint = 0;
+
+/* Execute one instruction from the record log. Each instruction in
+ the log will be represented by an arbitrary sequence of register
+ entries and memory entries, followed by an 'end' entry. */
+
+static inline void
+record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
+ struct record_entry *entry)
+{
+ switch (entry->type)
+ {
+ case record_reg: /* reg */
+ {
+ gdb_byte reg[MAX_REGISTER_SIZE];
+
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_reg %s to "
+ "inferior num = %d.\n",
+ host_address_to_string (entry),
+ entry->u.reg.num);
+
+ regcache_cooked_read (regcache, entry->u.reg.num, reg);
+ regcache_cooked_write (regcache, entry->u.reg.num,
+ record_get_loc (entry));
+ memcpy (record_get_loc (entry), reg, entry->u.reg.len);
+ }
+ break;
+
+ case record_mem: /* mem */
+ {
+ /* Nothing to do if the entry is flagged not_accessible. */
+ if (!entry->u.mem.mem_entry_not_accessible)
+ {
+ gdb_byte *mem = alloca (entry->u.mem.len);
+
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_mem %s to "
+ "inferior addr = %s len = %d.\n",
+ host_address_to_string (entry),
+ paddress (gdbarch, entry->u.mem.addr),
+ entry->u.mem.len);
+
+ if (record_read_memory (gdbarch,
+ entry->u.mem.addr, mem, entry->u.mem.len))
+ entry->u.mem.mem_entry_not_accessible = 1;
+ else
+ {
+ if (target_write_memory (entry->u.mem.addr,
+ record_get_loc (entry),
+ entry->u.mem.len))
+ {
+ entry->u.mem.mem_entry_not_accessible = 1;
+ if (record_debug)
+ warning (_("Process record: error writing memory at "
+ "addr = %s len = %d."),
+ paddress (gdbarch, entry->u.mem.addr),
+ entry->u.mem.len);
+ }
+ else
+ {
+ memcpy (record_get_loc (entry), mem, entry->u.mem.len);
+
+ /* We've changed memory --- check if a hardware
+ watchpoint should trap. Note that this
+ presently assumes the target beneath supports
+ continuable watchpoints. On non-continuable
+ watchpoints target, we'll want to check this
+ _before_ actually doing the memory change, and
+ not doing the change at all if the watchpoint
+ traps. */
+ if (hardware_watchpoint_inserted_in_range
+ (get_regcache_aspace (regcache),
+ entry->u.mem.addr, entry->u.mem.len))
+ record_hw_watchpoint = 1;
+ }
+ }
+ }
+ }
+ break;
+ }
+}
+
+static struct target_ops *tmp_to_resume_ops;
+static void (*tmp_to_resume) (struct target_ops *, ptid_t, int,
+ enum gdb_signal);
+static struct target_ops *tmp_to_wait_ops;
+static ptid_t (*tmp_to_wait) (struct target_ops *, ptid_t,
+ struct target_waitstatus *,
+ int);
+static struct target_ops *tmp_to_store_registers_ops;
+static void (*tmp_to_store_registers) (struct target_ops *,
+ struct regcache *,
+ int regno);
+static struct target_ops *tmp_to_xfer_partial_ops;
+static LONGEST (*tmp_to_xfer_partial) (struct target_ops *ops,
+ enum target_object object,
+ const char *annex,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset,
+ LONGEST len);
+static int (*tmp_to_insert_breakpoint) (struct gdbarch *,
+ struct bp_target_info *);
+static int (*tmp_to_remove_breakpoint) (struct gdbarch *,
+ struct bp_target_info *);
+static int (*tmp_to_stopped_by_watchpoint) (void);
+static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
+static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
+static void (*tmp_to_async) (void (*) (enum inferior_event_type, void *), void *);
+
+static void record_restore (void);
+
+/* Asynchronous signal handle registered as event loop source for when
+ we have pending events ready to be passed to the core. */
+
+static struct async_event_handler *record_async_inferior_event_token;
+
+static void
+record_async_inferior_event_handler (gdb_client_data data)
+{
+ inferior_event_handler (INF_REG_EVENT, NULL);
+}
+
+/* Open the process record target. */
+
+static void
+record_core_open_1 (char *name, int from_tty)
+{
+ struct regcache *regcache = get_current_regcache ();
+ int regnum = gdbarch_num_regs (get_regcache_arch (regcache));
+ int i;
+
+ /* Get record_core_regbuf. */
+ target_fetch_registers (regcache, -1);
+ record_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum);
+ for (i = 0; i < regnum; i ++)
+ regcache_raw_collect (regcache, i,
+ record_core_regbuf + MAX_REGISTER_SIZE * i);
+
+ /* Get record_core_start and record_core_end. */
+ if (build_section_table (core_bfd, &record_core_start, &record_core_end))
+ {
+ xfree (record_core_regbuf);
+ record_core_regbuf = NULL;
+ error (_("\"%s\": Can't find sections: %s"),
+ bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ()));
+ }
+
+ push_target (&record_core_ops);
+ record_restore ();
+}
+
+/* "to_open" target method for 'live' processes. */
+
+static void
+record_open_1 (char *name, int from_tty)
+{
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
+
+ /* check exec */
+ if (!target_has_execution)
+ error (_("Process record: the program is not being run."));
+ if (non_stop)
+ error (_("Process record target can't debug inferior in non-stop mode "
+ "(non-stop)."));
+
+ if (!gdbarch_process_record_p (target_gdbarch ()))
+ error (_("Process record: the current architecture doesn't support "
+ "record function."));
+
+ if (!tmp_to_resume)
+ error (_("Could not find 'to_resume' method on the target stack."));
+ if (!tmp_to_wait)
+ error (_("Could not find 'to_wait' method on the target stack."));
+ if (!tmp_to_store_registers)
+ error (_("Could not find 'to_store_registers' "
+ "method on the target stack."));
+ if (!tmp_to_insert_breakpoint)
+ error (_("Could not find 'to_insert_breakpoint' "
+ "method on the target stack."));
+ if (!tmp_to_remove_breakpoint)
+ error (_("Could not find 'to_remove_breakpoint' "
+ "method on the target stack."));
+ if (!tmp_to_stopped_by_watchpoint)
+ error (_("Could not find 'to_stopped_by_watchpoint' "
+ "method on the target stack."));
+ if (!tmp_to_stopped_data_address)
+ error (_("Could not find 'to_stopped_data_address' "
+ "method on the target stack."));
+
+ push_target (&record_ops);
+}
+
+static void record_init_record_breakpoints (void);
+
+/* "to_open" target method. Open the process record target. */
+
+static void
+record_open (char *name, int from_tty)
+{
+ struct target_ops *t;
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
+
+ /* Check if record target is already running. */
+ if (current_target.to_stratum == record_stratum)
+ error (_("Process record target already running. Use \"record stop\" to "
+ "stop record target first."));
+
+ /* Reset the tmp beneath pointers. */
+ tmp_to_resume_ops = NULL;
+ tmp_to_resume = NULL;
+ tmp_to_wait_ops = NULL;
+ tmp_to_wait = NULL;
+ tmp_to_store_registers_ops = NULL;
+ tmp_to_store_registers = NULL;
+ tmp_to_xfer_partial_ops = NULL;
+ tmp_to_xfer_partial = NULL;
+ tmp_to_insert_breakpoint = NULL;
+ tmp_to_remove_breakpoint = NULL;
+ tmp_to_stopped_by_watchpoint = NULL;
+ tmp_to_stopped_data_address = NULL;
+ tmp_to_async = NULL;
+
+ /* Set the beneath function pointers. */
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ {
+ if (!tmp_to_resume)
+ {
+ tmp_to_resume = t->to_resume;
+ tmp_to_resume_ops = t;
+ }
+ if (!tmp_to_wait)
+ {
+ tmp_to_wait = t->to_wait;
+ tmp_to_wait_ops = t;
+ }
+ if (!tmp_to_store_registers)
+ {
+ tmp_to_store_registers = t->to_store_registers;
+ tmp_to_store_registers_ops = t;
+ }
+ if (!tmp_to_xfer_partial)
+ {
+ tmp_to_xfer_partial = t->to_xfer_partial;
+ tmp_to_xfer_partial_ops = t;
+ }
+ if (!tmp_to_insert_breakpoint)
+ tmp_to_insert_breakpoint = t->to_insert_breakpoint;
+ if (!tmp_to_remove_breakpoint)
+ tmp_to_remove_breakpoint = t->to_remove_breakpoint;
+ if (!tmp_to_stopped_by_watchpoint)
+ tmp_to_stopped_by_watchpoint = t->to_stopped_by_watchpoint;
+ if (!tmp_to_stopped_data_address)
+ tmp_to_stopped_data_address = t->to_stopped_data_address;
+ if (!tmp_to_async)
+ tmp_to_async = t->to_async;
+ }
+ if (!tmp_to_xfer_partial)
+ error (_("Could not find 'to_xfer_partial' method on the target stack."));
+
+ /* Reset */
+ record_insn_num = 0;
+ record_insn_count = 0;
+ record_list = &record_first;
+ record_list->next = NULL;
+
+ /* Set the tmp beneath pointers to beneath pointers. */
+ record_beneath_to_resume_ops = tmp_to_resume_ops;
+ record_beneath_to_resume = tmp_to_resume;
+ record_beneath_to_wait_ops = tmp_to_wait_ops;
+ record_beneath_to_wait = tmp_to_wait;
+ record_beneath_to_store_registers_ops = tmp_to_store_registers_ops;
+ record_beneath_to_store_registers = tmp_to_store_registers;
+ record_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops;
+ record_beneath_to_xfer_partial = tmp_to_xfer_partial;
+ record_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint;
+ record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
+ record_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint;
+ record_beneath_to_stopped_data_address = tmp_to_stopped_data_address;
+ record_beneath_to_async = tmp_to_async;
+
+ if (core_bfd)
+ record_core_open_1 (name, from_tty);
+ else
+ record_open_1 (name, from_tty);
+
+ /* Register extra event sources in the event loop. */
+ record_async_inferior_event_token
+ = create_async_event_handler (record_async_inferior_event_handler,
+ NULL);
+
+ record_init_record_breakpoints ();
+
+ observer_notify_record_changed (current_inferior (), 1);
+}
+
+/* "to_close" target method. Close the process record target. */
+
+static void
+record_close (int quitting)
+{
+ struct record_core_buf_entry *entry;
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n");
+
+ record_list_release (record_list);
+
+ /* Release record_core_regbuf. */
+ if (record_core_regbuf)
+ {
+ xfree (record_core_regbuf);
+ record_core_regbuf = NULL;
+ }
+
+ /* Release record_core_buf_list. */
+ if (record_core_buf_list)
+ {
+ for (entry = record_core_buf_list->prev; entry; entry = entry->prev)
+ {
+ xfree (record_core_buf_list);
+ record_core_buf_list = entry;
+ }
+ record_core_buf_list = NULL;
+ }
+
+ if (record_async_inferior_event_token)
+ delete_async_event_handler (&record_async_inferior_event_token);
+}
+
+static int record_resume_step = 0;
+
+/* True if we've been resumed, and so each record_wait call should
+ advance execution. If this is false, record_wait will return a
+ TARGET_WAITKIND_IGNORE. */
+static int record_resumed = 0;
+
+/* The execution direction of the last resume we got. This is
+ necessary for async mode. Vis (order is not strictly accurate):
+
+ 1. user has the global execution direction set to forward
+ 2. user does a reverse-step command
+ 3. record_resume is called with global execution direction
+ temporarily switched to reverse
+ 4. GDB's execution direction is reverted back to forward
+ 5. target record notifies event loop there's an event to handle
+ 6. infrun asks the target which direction was it going, and switches
+ the global execution direction accordingly (to reverse)
+ 7. infrun polls an event out of the record target, and handles it
+ 8. GDB goes back to the event loop, and goto #4.
+*/
+static enum exec_direction_kind record_execution_dir = EXEC_FORWARD;
+
+/* "to_resume" target method. Resume the process record target. */
+
+static void
+record_resume (struct target_ops *ops, ptid_t ptid, int step,
+ enum gdb_signal signal)
+{
+ record_resume_step = step;
+ record_resumed = 1;
+ record_execution_dir = execution_direction;
+
+ if (!RECORD_IS_REPLAY)
+ {
+ struct gdbarch *gdbarch = target_thread_architecture (ptid);
+
+ record_message (get_current_regcache (), signal);
+
+ if (!step)
+ {
+ /* This is not hard single step. */
+ if (!gdbarch_software_single_step_p (gdbarch))
+ {
+ /* This is a normal continue. */
+ step = 1;
+ }
+ else
+ {
+ /* This arch support soft sigle step. */
+ if (single_step_breakpoints_inserted ())
+ {
+ /* This is a soft single step. */
+ record_resume_step = 1;
+ }
+ else
+ {
+ /* This is a continue.
+ Try to insert a soft single step breakpoint. */
+ if (!gdbarch_software_single_step (gdbarch,
+ get_current_frame ()))
+ {
+ /* This system don't want use soft single step.
+ Use hard sigle step. */
+ step = 1;
+ }
+ }
+ }
+ }
+
+ /* Make sure the target beneath reports all signals. */
+ target_pass_signals (0, NULL);
+
+ record_beneath_to_resume (record_beneath_to_resume_ops,
+ ptid, step, signal);
+ }
+
+ /* We are about to start executing the inferior (or simulate it),
+ let's register it with the event loop. */
+ if (target_can_async_p ())
+ {
+ target_async (inferior_event_handler, 0);
+ /* Notify the event loop there's an event to wait for. We do
+ most of the work in record_wait. */
+ mark_async_event_handler (record_async_inferior_event_token);
+ }
+}
+
+static int record_get_sig = 0;
+
+/* SIGINT signal handler, registered by "to_wait" method. */
+
+static void
+record_sig_handler (int signo)
+{
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Process record: get a signal\n");
+
+ /* It will break the running inferior in replay mode. */
+ record_resume_step = 1;
+
+ /* It will let record_wait set inferior status to get the signal
+ SIGINT. */
+ record_get_sig = 1;
+}
+
+static void
+record_wait_cleanups (void *ignore)
+{
+ if (execution_direction == EXEC_REVERSE)
+ {
+ if (record_list->next)
+ record_list = record_list->next;
+ }
+ else
+ record_list = record_list->prev;
+}
+
+/* "to_wait" target method for process record target.
+
+ In record mode, the target is always run in singlestep mode
+ (even when gdb says to continue). The to_wait method intercepts
+ the stop events and determines which ones are to be passed on to
+ gdb. Most stop events are just singlestep events that gdb is not
+ to know about, so the to_wait method just records them and keeps
+ singlestepping.
+
+ In replay mode, this function emulates the recorded execution log,
+ one instruction at a time (forward or backward), and determines
+ where to stop. */
+
+static ptid_t
+record_wait_1 (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *status,
+ int options)
+{
+ struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_wait "
+ "record_resume_step = %d, record_resumed = %d, direction=%s\n",
+ record_resume_step, record_resumed,
+ record_execution_dir == EXEC_FORWARD ? "forward" : "reverse");
+
+ if (!record_resumed)
+ {
+ gdb_assert ((options & TARGET_WNOHANG) != 0);
+
+ /* No interesting event. */
+ status->kind = TARGET_WAITKIND_IGNORE;
+ return minus_one_ptid;
+ }
+
+ record_get_sig = 0;
+ signal (SIGINT, record_sig_handler);
+
+ if (!RECORD_IS_REPLAY && ops != &record_core_ops)
+ {
+ if (record_resume_step)
+ {
+ /* This is a single step. */
+ return record_beneath_to_wait (record_beneath_to_wait_ops,
+ ptid, status, options);
+ }
+ else
+ {
+ /* This is not a single step. */
+ ptid_t ret;
+ CORE_ADDR tmp_pc;
+ struct gdbarch *gdbarch = target_thread_architecture (inferior_ptid);
+
+ while (1)
+ {
+ ret = record_beneath_to_wait (record_beneath_to_wait_ops,
+ ptid, status, options);
+ if (status->kind == TARGET_WAITKIND_IGNORE)
+ {
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_wait "
+ "target beneath not done yet\n");
+ return ret;
+ }
+
+ if (single_step_breakpoints_inserted ())
+ remove_single_step_breakpoints ();
+
+ if (record_resume_step)
+ return ret;
+
+ /* Is this a SIGTRAP? */
+ if (status->kind == TARGET_WAITKIND_STOPPED
+ && status->value.sig == GDB_SIGNAL_TRAP)
+ {
+ struct regcache *regcache;
+ struct address_space *aspace;
+
+ /* Yes -- this is likely our single-step finishing,
+ but check if there's any reason the core would be
+ interested in the event. */
+
+ registers_changed ();
+ regcache = get_current_regcache ();
+ tmp_pc = regcache_read_pc (regcache);
+ aspace = get_regcache_aspace (regcache);
+
+ if (target_stopped_by_watchpoint ())
+ {
+ /* Always interested in watchpoints. */
+ }
+ else if (breakpoint_inserted_here_p (aspace, tmp_pc))
+ {
+ /* There is a breakpoint here. Let the core
+ handle it. */
+ if (software_breakpoint_inserted_here_p (aspace, tmp_pc))
+ {
+ struct gdbarch *gdbarch
+ = get_regcache_arch (regcache);
+ CORE_ADDR decr_pc_after_break
+ = gdbarch_decr_pc_after_break (gdbarch);
+ if (decr_pc_after_break)
+ regcache_write_pc (regcache,
+ tmp_pc + decr_pc_after_break);
+ }
+ }
+ else
+ {
+ /* This is a single-step trap. Record the
+ insn and issue another step.
+ FIXME: this part can be a random SIGTRAP too.
+ But GDB cannot handle it. */
+ int step = 1;
+
+ if (!record_message_wrapper_safe (regcache,
+ GDB_SIGNAL_0))
+ {
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = GDB_SIGNAL_0;
+ break;
+ }
+
+ if (gdbarch_software_single_step_p (gdbarch))
+ {
+ /* Try to insert the software single step breakpoint.
+ If insert success, set step to 0. */
+ set_executing (inferior_ptid, 0);
+ reinit_frame_cache ();
+ if (gdbarch_software_single_step (gdbarch,
+ get_current_frame ()))
+ step = 0;
+ set_executing (inferior_ptid, 1);
+ }
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_wait "
+ "issuing one more step in the target beneath\n");
+ record_beneath_to_resume (record_beneath_to_resume_ops,
+ ptid, step,
+ GDB_SIGNAL_0);
+ continue;
+ }
+ }
+
+ /* The inferior is broken by a breakpoint or a signal. */
+ break;
+ }
+
+ return ret;
+ }
+ }
+ else
+ {
+ struct regcache *regcache = get_current_regcache ();
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct address_space *aspace = get_regcache_aspace (regcache);
+ int continue_flag = 1;
+ int first_record_end = 1;
+ struct cleanup *old_cleanups = make_cleanup (record_wait_cleanups, 0);
+ CORE_ADDR tmp_pc;
+
+ record_hw_watchpoint = 0;
+ status->kind = TARGET_WAITKIND_STOPPED;
+
+ /* Check breakpoint when forward execute. */
+ if (execution_direction == EXEC_FORWARD)
+ {
+ tmp_pc = regcache_read_pc (regcache);
+ if (breakpoint_inserted_here_p (aspace, tmp_pc))
+ {
+ int decr_pc_after_break = gdbarch_decr_pc_after_break (gdbarch);
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: break at %s.\n",
+ paddress (gdbarch, tmp_pc));
+
+ if (decr_pc_after_break
+ && !record_resume_step
+ && software_breakpoint_inserted_here_p (aspace, tmp_pc))
+ regcache_write_pc (regcache,
+ tmp_pc + decr_pc_after_break);
+ goto replay_out;
+ }
+ }
+
+ /* If GDB is in terminal_inferior mode, it will not get the signal.
+ And in GDB replay mode, GDB doesn't need to be in terminal_inferior
+ mode, because inferior will not executed.
+ Then set it to terminal_ours to make GDB get the signal. */
+ target_terminal_ours ();
+
+ /* In EXEC_FORWARD mode, record_list points to the tail of prev
+ instruction. */
+ if (execution_direction == EXEC_FORWARD && record_list->next)
+ record_list = record_list->next;
+
+ /* Loop over the record_list, looking for the next place to
+ stop. */
+ do
+ {
+ /* Check for beginning and end of log. */
+ if (execution_direction == EXEC_REVERSE
+ && record_list == &record_first)
+ {
+ /* Hit beginning of record log in reverse. */
+ status->kind = TARGET_WAITKIND_NO_HISTORY;
+ break;
+ }
+ if (execution_direction != EXEC_REVERSE && !record_list->next)
+ {
+ /* Hit end of record log going forward. */
+ status->kind = TARGET_WAITKIND_NO_HISTORY;
+ break;
+ }
+
+ record_exec_insn (regcache, gdbarch, record_list);
+
+ if (record_list->type == record_end)
+ {
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_end %s to "
+ "inferior.\n",
+ host_address_to_string (record_list));
+
+ if (first_record_end && execution_direction == EXEC_REVERSE)
+ {
+ /* When reverse excute, the first record_end is the part of
+ current instruction. */
+ first_record_end = 0;
+ }
+ else
+ {
+ /* In EXEC_REVERSE mode, this is the record_end of prev
+ instruction.
+ In EXEC_FORWARD mode, this is the record_end of current
+ instruction. */
+ /* step */
+ if (record_resume_step)
+ {
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: step.\n");
+ continue_flag = 0;
+ }
+
+ /* check breakpoint */
+ tmp_pc = regcache_read_pc (regcache);
+ if (breakpoint_inserted_here_p (aspace, tmp_pc))
+ {
+ int decr_pc_after_break
+ = gdbarch_decr_pc_after_break (gdbarch);
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: break "
+ "at %s.\n",
+ paddress (gdbarch, tmp_pc));
+ if (decr_pc_after_break
+ && execution_direction == EXEC_FORWARD
+ && !record_resume_step
+ && software_breakpoint_inserted_here_p (aspace,
+ tmp_pc))
+ regcache_write_pc (regcache,
+ tmp_pc + decr_pc_after_break);
+ continue_flag = 0;
+ }
+
+ if (record_hw_watchpoint)
+ {
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: hit hw "
+ "watchpoint.\n");
+ continue_flag = 0;
+ }
+ /* Check target signal */
+ if (record_list->u.end.sigval != GDB_SIGNAL_0)
+ /* FIXME: better way to check */
+ continue_flag = 0;
+ }
+ }
+
+ if (continue_flag)
+ {
+ if (execution_direction == EXEC_REVERSE)
+ {
+ if (record_list->prev)
+ record_list = record_list->prev;
+ }
+ else
+ {
+ if (record_list->next)
+ record_list = record_list->next;
+ }
+ }
+ }
+ while (continue_flag);
+
+replay_out:
+ if (record_get_sig)
+ status->value.sig = GDB_SIGNAL_INT;
+ else if (record_list->u.end.sigval != GDB_SIGNAL_0)
+ /* FIXME: better way to check */
+ status->value.sig = record_list->u.end.sigval;
+ else
+ status->value.sig = GDB_SIGNAL_TRAP;
+
+ discard_cleanups (old_cleanups);
+ }
+
+ signal (SIGINT, handle_sigint);
+
+ do_cleanups (set_cleanups);
+ return inferior_ptid;
+}
+
+static ptid_t
+record_wait (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *status,
+ int options)
+{
+ ptid_t return_ptid;
+
+ return_ptid = record_wait_1 (ops, ptid, status, options);
+ if (status->kind != TARGET_WAITKIND_IGNORE)
+ {
+ /* We're reporting a stop. Make sure any spurious
+ target_wait(WNOHANG) doesn't advance the target until the
+ core wants us resumed again. */
+ record_resumed = 0;
+ }
+ return return_ptid;
+}
+
+static int
+record_stopped_by_watchpoint (void)
+{
+ if (RECORD_IS_REPLAY)
+ return record_hw_watchpoint;
+ else
+ return record_beneath_to_stopped_by_watchpoint ();
+}
+
+/* "to_disconnect" method for process record target. */
+
+static void
+record_disconnect (struct target_ops *target, char *args, int from_tty)
+{
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_disconnect\n");
+
+ unpush_target (&record_ops);
+ target_disconnect (args, from_tty);
+}
+
+/* "to_detach" method for process record target. */
+
+static void
+record_detach (struct target_ops *ops, char *args, int from_tty)
+{
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_detach\n");
+
+ unpush_target (&record_ops);
+ target_detach (args, from_tty);
+}
+
+/* "to_mourn_inferior" method for process record target. */
+
+static void
+record_mourn_inferior (struct target_ops *ops)
+{
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Process record: "
+ "record_mourn_inferior\n");
+
+ unpush_target (&record_ops);
+ target_mourn_inferior ();
+}
+
+/* Close process record target before killing the inferior process. */
+
+static void
+record_kill (struct target_ops *ops)
+{
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_kill\n");
+
+ unpush_target (&record_ops);
+ target_kill ();
+}
+
+static int
+record_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
+{
+ if (RECORD_IS_REPLAY)
+ return 0;
+ else
+ return record_beneath_to_stopped_data_address (ops, addr_p);
+}
+
+/* Record registers change (by user or by GDB) to list as an instruction. */
+
+static void
+record_registers_change (struct regcache *regcache, int regnum)
+{
+ /* Check record_insn_num. */
+ record_check_insn_num (0);
+
+ record_arch_list_head = NULL;
+ record_arch_list_tail = NULL;
+
+ if (regnum < 0)
+ {
+ int i;
+
+ for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
+ {
+ if (record_arch_list_add_reg (regcache, i))
+ {
+ record_list_release (record_arch_list_tail);
+ error (_("Process record: failed to record execution log."));
+ }
+ }
+ }
+ else
+ {
+ if (record_arch_list_add_reg (regcache, regnum))
+ {
+ record_list_release (record_arch_list_tail);
+ error (_("Process record: failed to record execution log."));
+ }
+ }
+ if (record_arch_list_add_end ())
+ {
+ record_list_release (record_arch_list_tail);
+ error (_("Process record: failed to record execution log."));
+ }
+ record_list->next = record_arch_list_head;
+ record_arch_list_head->prev = record_list;
+ record_list = record_arch_list_tail;
+
+ if (record_insn_num == record_insn_max_num && record_insn_max_num)
+ record_list_release_first ();
+ else
+ record_insn_num++;
+}
+
+/* "to_store_registers" method for process record target. */
+
+static void
+record_store_registers (struct target_ops *ops, struct regcache *regcache,
+ int regno)
+{
+ if (!record_gdb_operation_disable)
+ {
+ if (RECORD_IS_REPLAY)
+ {
+ int n;
+
+ /* Let user choose if he wants to write register or not. */
+ if (regno < 0)
+ n =
+ query (_("Because GDB is in replay mode, changing the "
+ "value of a register will make the execution "
+ "log unusable from this point onward. "
+ "Change all registers?"));
+ else
+ n =
+ query (_("Because GDB is in replay mode, changing the value "
+ "of a register will make the execution log unusable "
+ "from this point onward. Change register %s?"),
+ gdbarch_register_name (get_regcache_arch (regcache),
+ regno));
+
+ if (!n)
+ {
+ /* Invalidate the value of regcache that was set in function
+ "regcache_raw_write". */
+ if (regno < 0)
+ {
+ int i;
+
+ for (i = 0;
+ i < gdbarch_num_regs (get_regcache_arch (regcache));
+ i++)
+ regcache_invalidate (regcache, i);
+ }
+ else
+ regcache_invalidate (regcache, regno);
+
+ error (_("Process record canceled the operation."));
+ }
+
+ /* Destroy the record from here forward. */
+ record_list_release_following (record_list);
+ }
+
+ record_registers_change (regcache, regno);
+ }
+ record_beneath_to_store_registers (record_beneath_to_store_registers_ops,
+ regcache, regno);
+}
+
+/* "to_xfer_partial" method. Behavior is conditional on RECORD_IS_REPLAY.
+ In replay mode, we cannot write memory unles we are willing to
+ invalidate the record/replay log from this point forward. */
+
+static LONGEST
+record_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+ if (!record_gdb_operation_disable
+ && (object == TARGET_OBJECT_MEMORY
+ || object == TARGET_OBJECT_RAW_MEMORY) && writebuf)
+ {
+ if (RECORD_IS_REPLAY)
+ {
+ /* Let user choose if he wants to write memory or not. */
+ if (!query (_("Because GDB is in replay mode, writing to memory "
+ "will make the execution log unusable from this "
+ "point onward. Write memory at address %s?"),
+ paddress (target_gdbarch (), offset)))
+ error (_("Process record canceled the operation."));
+
+ /* Destroy the record from here forward. */
+ record_list_release_following (record_list);
+ }
+
+ /* Check record_insn_num */
+ record_check_insn_num (0);
+
+ /* Record registers change to list as an instruction. */
+ record_arch_list_head = NULL;
+ record_arch_list_tail = NULL;
+ if (record_arch_list_add_mem (offset, len))
+ {
+ record_list_release (record_arch_list_tail);
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: failed to record "
+ "execution log.");
+ return -1;
+ }
+ if (record_arch_list_add_end ())
+ {
+ record_list_release (record_arch_list_tail);
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: failed to record "
+ "execution log.");
+ return -1;
+ }
+ record_list->next = record_arch_list_head;
+ record_arch_list_head->prev = record_list;
+ record_list = record_arch_list_tail;
+
+ if (record_insn_num == record_insn_max_num && record_insn_max_num)
+ record_list_release_first ();
+ else
+ record_insn_num++;
+ }
+
+ return record_beneath_to_xfer_partial (record_beneath_to_xfer_partial_ops,
+ object, annex, readbuf, writebuf,
+ offset, len);
+}
+
+/* This structure represents a breakpoint inserted while the record
+ target is active. We use this to know when to install/remove
+ breakpoints in/from the target beneath. For example, a breakpoint
+ may be inserted while recording, but removed when not replaying nor
+ recording. In that case, the breakpoint had not been inserted on
+ the target beneath, so we should not try to remove it there. */
+
+struct record_breakpoint
+{
+ /* The address and address space the breakpoint was set at. */
+ struct address_space *address_space;
+ CORE_ADDR addr;
+
+ /* True when the breakpoint has been also installed in the target
+ beneath. This will be false for breakpoints set during replay or
+ when recording. */
+ int in_target_beneath;
+};
+
+typedef struct record_breakpoint *record_breakpoint_p;
+DEF_VEC_P(record_breakpoint_p);
+
+/* The list of breakpoints inserted while the record target is
+ active. */
+VEC(record_breakpoint_p) *record_breakpoints = NULL;
+
+static void
+record_sync_record_breakpoints (struct bp_location *loc, void *data)
+{
+ if (loc->loc_type != bp_loc_software_breakpoint)
+ return;
+
+ if (loc->inserted)
+ {
+ struct record_breakpoint *bp = XNEW (struct record_breakpoint);
+
+ bp->addr = loc->target_info.placed_address;
+ bp->address_space = loc->target_info.placed_address_space;
+
+ bp->in_target_beneath = 1;
+
+ VEC_safe_push (record_breakpoint_p, record_breakpoints, bp);
+ }
+}
+
+/* Sync existing breakpoints to record_breakpoints. */
+
+static void
+record_init_record_breakpoints (void)
+{
+ VEC_free (record_breakpoint_p, record_breakpoints);
+
+ iterate_over_bp_locations (record_sync_record_breakpoints);
+}
+
+/* Behavior is conditional on RECORD_IS_REPLAY. We will not actually
+ insert or remove breakpoints in the real target when replaying, nor
+ when recording. */
+
+static int
+record_insert_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
+{
+ struct record_breakpoint *bp;
+ int in_target_beneath = 0;
+
+ if (!RECORD_IS_REPLAY)
+ {
+ /* When recording, we currently always single-step, so we don't
+ really need to install regular breakpoints in the inferior.
+ However, we do have to insert software single-step
+ breakpoints, in case the target can't hardware step. To keep
+ things single, we always insert. */
+ struct cleanup *old_cleanups;
+ int ret;
+
+ old_cleanups = record_gdb_operation_disable_set ();
+ ret = record_beneath_to_insert_breakpoint (gdbarch, bp_tgt);
+ do_cleanups (old_cleanups);
+
+ if (ret != 0)
+ return ret;
+
+ in_target_beneath = 1;
+ }
+
+ bp = XNEW (struct record_breakpoint);
+ bp->addr = bp_tgt->placed_address;
+ bp->address_space = bp_tgt->placed_address_space;
+ bp->in_target_beneath = in_target_beneath;
+ VEC_safe_push (record_breakpoint_p, record_breakpoints, bp);
+ return 0;
+}
+
+/* "to_remove_breakpoint" method for process record target. */
+
+static int
+record_remove_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
+{
+ struct record_breakpoint *bp;
+ int ix;
+
+ for (ix = 0;
+ VEC_iterate (record_breakpoint_p, record_breakpoints, ix, bp);
+ ++ix)
+ {
+ if (bp->addr == bp_tgt->placed_address
+ && bp->address_space == bp_tgt->placed_address_space)
+ {
+ if (bp->in_target_beneath)
+ {
+ struct cleanup *old_cleanups;
+ int ret;
+
+ old_cleanups = record_gdb_operation_disable_set ();
+ ret = record_beneath_to_remove_breakpoint (gdbarch, bp_tgt);
+ do_cleanups (old_cleanups);
+
+ if (ret != 0)
+ return ret;
+ }
+
+ VEC_unordered_remove (record_breakpoint_p, record_breakpoints, ix);
+ return 0;
+ }
+ }
+
+ gdb_assert_not_reached ("removing unknown breakpoint");
+}
+
+/* "to_can_execute_reverse" method for process record target. */
+
+static int
+record_can_execute_reverse (void)
+{
+ return 1;
+}
+
+/* "to_get_bookmark" method for process record and prec over core. */
+
+static gdb_byte *
+record_get_bookmark (char *args, int from_tty)
+{
+ gdb_byte *ret = NULL;
+
+ /* Return stringified form of instruction count. */
+ if (record_list && record_list->type == record_end)
+ ret = xstrdup (pulongest (record_list->u.end.insn_num));
+
+ if (record_debug)
+ {
+ if (ret)
+ fprintf_unfiltered (gdb_stdlog,
+ "record_get_bookmark returns %s\n", ret);
+ else
+ fprintf_unfiltered (gdb_stdlog,
+ "record_get_bookmark returns NULL\n");
+ }
+ return ret;
+}
+
+/* "to_goto_bookmark" method for process record and prec over core. */
+
+static void
+record_goto_bookmark (gdb_byte *bookmark, int from_tty)
+{
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "record_goto_bookmark receives %s\n", bookmark);
+
+ if (bookmark[0] == '\'' || bookmark[0] == '\"')
+ {
+ if (bookmark[strlen (bookmark) - 1] != bookmark[0])
+ error (_("Unbalanced quotes: %s"), bookmark);
+
+ /* Strip trailing quote. */
+ bookmark[strlen (bookmark) - 1] = '\0';
+ /* Strip leading quote. */
+ bookmark++;
+ /* Pass along to cmd_record_goto. */
+ }
+
+ cmd_record_goto ((char *) bookmark, from_tty);
+ return;
+}
+
+static void
+record_async (void (*callback) (enum inferior_event_type event_type,
+ void *context), void *context)
+{
+ /* If we're on top of a line target (e.g., linux-nat, remote), then
+ set it to async mode as well. Will be NULL if we're sitting on
+ top of the core target, for "record restore". */
+ if (record_beneath_to_async != NULL)
+ record_beneath_to_async (callback, context);
+}
+
+static int
+record_can_async_p (void)
+{
+ /* We only enable async when the user specifically asks for it. */
+ return target_async_permitted;
+}
+
+static int
+record_is_async_p (void)
+{
+ /* We only enable async when the user specifically asks for it. */
+ return target_async_permitted;
+}
+
+static enum exec_direction_kind
+record_execution_direction (void)
+{
+ return record_execution_dir;
+}
+
+static void
+init_record_ops (void)
+{
+ record_ops.to_shortname = "record";
+ record_ops.to_longname = "Process record and replay target";
+ record_ops.to_doc =
+ "Log program while executing and replay execution from log.";
+ record_ops.to_open = record_open;
+ record_ops.to_close = record_close;
+ record_ops.to_resume = record_resume;
+ record_ops.to_wait = record_wait;
+ record_ops.to_disconnect = record_disconnect;
+ record_ops.to_detach = record_detach;
+ record_ops.to_mourn_inferior = record_mourn_inferior;
+ record_ops.to_kill = record_kill;
+ record_ops.to_create_inferior = find_default_create_inferior;
+ record_ops.to_store_registers = record_store_registers;
+ record_ops.to_xfer_partial = record_xfer_partial;
+ record_ops.to_insert_breakpoint = record_insert_breakpoint;
+ record_ops.to_remove_breakpoint = record_remove_breakpoint;
+ record_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint;
+ record_ops.to_stopped_data_address = record_stopped_data_address;
+ record_ops.to_can_execute_reverse = record_can_execute_reverse;
+ record_ops.to_stratum = record_stratum;
+ /* Add bookmark target methods. */
+ record_ops.to_get_bookmark = record_get_bookmark;
+ record_ops.to_goto_bookmark = record_goto_bookmark;
+ record_ops.to_async = record_async;
+ record_ops.to_can_async_p = record_can_async_p;
+ record_ops.to_is_async_p = record_is_async_p;
+ record_ops.to_execution_direction = record_execution_direction;
+ record_ops.to_magic = OPS_MAGIC;
+}
+
+/* "to_resume" method for prec over corefile. */
+
+static void
+record_core_resume (struct target_ops *ops, ptid_t ptid, int step,
+ enum gdb_signal signal)
+{
+ record_resume_step = step;
+ record_resumed = 1;
+ record_execution_dir = execution_direction;
+
+ /* We are about to start executing the inferior (or simulate it),
+ let's register it with the event loop. */
+ if (target_can_async_p ())
+ {
+ target_async (inferior_event_handler, 0);
+
+ /* Notify the event loop there's an event to wait for. */
+ mark_async_event_handler (record_async_inferior_event_token);
+ }
+}
+
+/* "to_kill" method for prec over corefile. */
+
+static void
+record_core_kill (struct target_ops *ops)
+{
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Process record: record_core_kill\n");
+
+ unpush_target (&record_core_ops);
+}
+
+/* "to_fetch_registers" method for prec over corefile. */
+
+static void
+record_core_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache,
+ int regno)
+{
+ if (regno < 0)
+ {
+ int num = gdbarch_num_regs (get_regcache_arch (regcache));
+ int i;
+
+ for (i = 0; i < num; i ++)
+ regcache_raw_supply (regcache, i,
+ record_core_regbuf + MAX_REGISTER_SIZE * i);
+ }
+ else
+ regcache_raw_supply (regcache, regno,
+ record_core_regbuf + MAX_REGISTER_SIZE * regno);
+}
+
+/* "to_prepare_to_store" method for prec over corefile. */
+
+static void
+record_core_prepare_to_store (struct regcache *regcache)
+{
+}
+
+/* "to_store_registers" method for prec over corefile. */
+
+static void
+record_core_store_registers (struct target_ops *ops,
+ struct regcache *regcache,
+ int regno)
+{
+ if (record_gdb_operation_disable)
+ regcache_raw_collect (regcache, regno,
+ record_core_regbuf + MAX_REGISTER_SIZE * regno);
+ else
+ error (_("You can't do that without a process to debug."));
+}
+
+/* "to_xfer_partial" method for prec over corefile. */
+
+static LONGEST
+record_core_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset,
+ LONGEST len)
+{
+ if (object == TARGET_OBJECT_MEMORY)
+ {
+ if (record_gdb_operation_disable || !writebuf)
+ {
+ struct target_section *p;
+
+ for (p = record_core_start; p < record_core_end; p++)
+ {
+ if (offset >= p->addr)
+ {
+ struct record_core_buf_entry *entry;
+ ULONGEST sec_offset;
+
+ if (offset >= p->endaddr)
+ continue;
+
+ if (offset + len > p->endaddr)
+ len = p->endaddr - offset;
+
+ sec_offset = offset - p->addr;
+
+ /* Read readbuf or write writebuf p, offset, len. */
+ /* Check flags. */
+ if (p->the_bfd_section->flags & SEC_CONSTRUCTOR
+ || (p->the_bfd_section->flags & SEC_HAS_CONTENTS) == 0)
+ {
+ if (readbuf)
+ memset (readbuf, 0, len);
+ return len;
+ }
+ /* Get record_core_buf_entry. */
+ for (entry = record_core_buf_list; entry;
+ entry = entry->prev)
+ if (entry->p == p)
+ break;
+ if (writebuf)
+ {
+ if (!entry)
+ {
+ /* Add a new entry. */
+ entry = (struct record_core_buf_entry *)
+ xmalloc (sizeof (struct record_core_buf_entry));
+ entry->p = p;
+ if (!bfd_malloc_and_get_section (p->bfd,
+ p->the_bfd_section,
+ &entry->buf))
+ {
+ xfree (entry);
+ return 0;
+ }
+ entry->prev = record_core_buf_list;
+ record_core_buf_list = entry;
+ }
+
+ memcpy (entry->buf + sec_offset, writebuf,
+ (size_t) len);
+ }
+ else
+ {
+ if (!entry)
+ return record_beneath_to_xfer_partial
+ (record_beneath_to_xfer_partial_ops,
+ object, annex, readbuf, writebuf,
+ offset, len);
+
+ memcpy (readbuf, entry->buf + sec_offset,
+ (size_t) len);
+ }
+
+ return len;
+ }
+ }
+
+ return -1;
+ }
+ else
+ error (_("You can't do that without a process to debug."));
+ }
+
+ return record_beneath_to_xfer_partial (record_beneath_to_xfer_partial_ops,
+ object, annex, readbuf, writebuf,
+ offset, len);
+}
+
+/* "to_insert_breakpoint" method for prec over corefile. */
+
+static int
+record_core_insert_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
+{
+ return 0;
+}
+
+/* "to_remove_breakpoint" method for prec over corefile. */
+
+static int
+record_core_remove_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
+{
+ return 0;
+}
+
+/* "to_has_execution" method for prec over corefile. */
+
+static int
+record_core_has_execution (struct target_ops *ops, ptid_t the_ptid)
+{
+ return 1;
+}
+
+static void
+init_record_core_ops (void)
+{
+ record_core_ops.to_shortname = "record-core";
+ record_core_ops.to_longname = "Process record and replay target";
+ record_core_ops.to_doc =
+ "Log program while executing and replay execution from log.";
+ record_core_ops.to_open = record_open;
+ record_core_ops.to_close = record_close;
+ record_core_ops.to_resume = record_core_resume;
+ record_core_ops.to_wait = record_wait;
+ record_core_ops.to_kill = record_core_kill;
+ record_core_ops.to_fetch_registers = record_core_fetch_registers;
+ record_core_ops.to_prepare_to_store = record_core_prepare_to_store;
+ record_core_ops.to_store_registers = record_core_store_registers;
+ record_core_ops.to_xfer_partial = record_core_xfer_partial;
+ record_core_ops.to_insert_breakpoint = record_core_insert_breakpoint;
+ record_core_ops.to_remove_breakpoint = record_core_remove_breakpoint;
+ record_core_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint;
+ record_core_ops.to_stopped_data_address = record_stopped_data_address;
+ record_core_ops.to_can_execute_reverse = record_can_execute_reverse;
+ record_core_ops.to_has_execution = record_core_has_execution;
+ record_core_ops.to_stratum = record_stratum;
+ /* Add bookmark target methods. */
+ record_core_ops.to_get_bookmark = record_get_bookmark;
+ record_core_ops.to_goto_bookmark = record_goto_bookmark;
+ record_core_ops.to_async = record_async;
+ record_core_ops.to_can_async_p = record_can_async_p;
+ record_core_ops.to_is_async_p = record_is_async_p;
+ record_core_ops.to_execution_direction = record_execution_direction;
+ record_core_ops.to_magic = OPS_MAGIC;
+}
+
+/* Record log save-file format
+ Version 1 (never released)
+
+ Header:
+ 4 bytes: magic number htonl(0x20090829).
+ NOTE: be sure to change whenever this file format changes!
+
+ Records:
+ record_end:
+ 1 byte: record type (record_end, see enum record_type).
+ record_reg:
+ 1 byte: record type (record_reg, see enum record_type).
+ 8 bytes: register id (network byte order).
+ MAX_REGISTER_SIZE bytes: register value.
+ record_mem:
+ 1 byte: record type (record_mem, see enum record_type).
+ 8 bytes: memory length (network byte order).
+ 8 bytes: memory address (network byte order).
+ n bytes: memory value (n == memory length).
+
+ Version 2
+ 4 bytes: magic number netorder32(0x20091016).
+ NOTE: be sure to change whenever this file format changes!
+
+ Records:
+ record_end:
+ 1 byte: record type (record_end, see enum record_type).
+ 4 bytes: signal
+ 4 bytes: instruction count
+ record_reg:
+ 1 byte: record type (record_reg, see enum record_type).
+ 4 bytes: register id (network byte order).
+ n bytes: register value (n == actual register size).
+ (eg. 4 bytes for x86 general registers).
+ record_mem:
+ 1 byte: record type (record_mem, see enum record_type).
+ 4 bytes: memory length (network byte order).
+ 8 bytes: memory address (network byte order).
+ n bytes: memory value (n == memory length).
+
+*/
+
+/* bfdcore_read -- read bytes from a core file section. */
+
+static inline void
+bfdcore_read (bfd *obfd, asection *osec, void *buf, int len, int *offset)
+{
+ int ret = bfd_get_section_contents (obfd, osec, buf, *offset, len);
+
+ if (ret)
+ *offset += len;
+ else
+ error (_("Failed to read %d bytes from core file %s ('%s')."),
+ len, bfd_get_filename (obfd),
+ bfd_errmsg (bfd_get_error ()));
+}
+
+static inline uint64_t
+netorder64 (uint64_t input)
+{
+ uint64_t ret;
+
+ store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret),
+ BFD_ENDIAN_BIG, input);
+ return ret;
+}
+
+static inline uint32_t
+netorder32 (uint32_t input)
+{
+ uint32_t ret;
+
+ store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret),
+ BFD_ENDIAN_BIG, input);
+ return ret;
+}
+
+static inline uint16_t
+netorder16 (uint16_t input)
+{
+ uint16_t ret;
+
+ store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret),
+ BFD_ENDIAN_BIG, input);
+ return ret;
+}
+
+/* Restore the execution log from a core_bfd file. */
+static void
+record_restore (void)
+{
+ uint32_t magic;
+ struct cleanup *old_cleanups;
+ struct record_entry *rec;
+ asection *osec;
+ uint32_t osec_size;
+ int bfd_offset = 0;
+ struct regcache *regcache;
+
+ /* We restore the execution log from the open core bfd,
+ if there is one. */
+ if (core_bfd == NULL)
+ return;
+
+ /* "record_restore" can only be called when record list is empty. */
+ gdb_assert (record_first.next == NULL);
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Restoring recording from core file.\n");
+
+ /* Now need to find our special note section. */
+ osec = bfd_get_section_by_name (core_bfd, "null0");
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Find precord section %s.\n",
+ osec ? "succeeded" : "failed");
+ if (osec == NULL)
+ return;
+ osec_size = bfd_section_size (core_bfd, osec);
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "%s", bfd_section_name (core_bfd, osec));
+
+ /* Check the magic code. */
+ bfdcore_read (core_bfd, osec, &magic, sizeof (magic), &bfd_offset);
+ if (magic != RECORD_FILE_MAGIC)
+ error (_("Version mis-match or file format error in core file %s."),
+ bfd_get_filename (core_bfd));
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ " Reading 4-byte magic cookie "
+ "RECORD_FILE_MAGIC (0x%s)\n",
+ phex_nz (netorder32 (magic), 4));
+
+ /* Restore the entries in recfd into record_arch_list_head and
+ record_arch_list_tail. */
+ record_arch_list_head = NULL;
+ record_arch_list_tail = NULL;
+ record_insn_num = 0;
+ old_cleanups = make_cleanup (record_arch_list_cleanups, 0);
+ regcache = get_current_regcache ();
+
+ while (1)
+ {
+ uint8_t rectype;
+ uint32_t regnum, len, signal, count;
+ uint64_t addr;
+
+ /* We are finished when offset reaches osec_size. */
+ if (bfd_offset >= osec_size)
+ break;
+ bfdcore_read (core_bfd, osec, &rectype, sizeof (rectype), &bfd_offset);
+
+ switch (rectype)
+ {
+ case record_reg: /* reg */
+ /* Get register number to regnum. */
+ bfdcore_read (core_bfd, osec, ®num,
+ sizeof (regnum), &bfd_offset);
+ regnum = netorder32 (regnum);
+
+ rec = record_reg_alloc (regcache, regnum);
+
+ /* Get val. */
+ bfdcore_read (core_bfd, osec, record_get_loc (rec),
+ rec->u.reg.len, &bfd_offset);
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ " Reading register %d (1 "
+ "plus %lu plus %d bytes)\n",
+ rec->u.reg.num,
+ (unsigned long) sizeof (regnum),
+ rec->u.reg.len);
+ break;
+
+ case record_mem: /* mem */
+ /* Get len. */
+ bfdcore_read (core_bfd, osec, &len,
+ sizeof (len), &bfd_offset);
+ len = netorder32 (len);
+
+ /* Get addr. */
+ bfdcore_read (core_bfd, osec, &addr,
+ sizeof (addr), &bfd_offset);
+ addr = netorder64 (addr);
+
+ rec = record_mem_alloc (addr, len);
+
+ /* Get val. */
+ bfdcore_read (core_bfd, osec, record_get_loc (rec),
+ rec->u.mem.len, &bfd_offset);
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ " Reading memory %s (1 plus "
+ "%lu plus %lu plus %d bytes)\n",
+ paddress (get_current_arch (),
+ rec->u.mem.addr),
+ (unsigned long) sizeof (addr),
+ (unsigned long) sizeof (len),
+ rec->u.mem.len);
+ break;
+
+ case record_end: /* end */
+ rec = record_end_alloc ();
+ record_insn_num ++;
+
+ /* Get signal value. */
+ bfdcore_read (core_bfd, osec, &signal,
+ sizeof (signal), &bfd_offset);
+ signal = netorder32 (signal);
+ rec->u.end.sigval = signal;
+
+ /* Get insn count. */
+ bfdcore_read (core_bfd, osec, &count,
+ sizeof (count), &bfd_offset);
+ count = netorder32 (count);
+ rec->u.end.insn_num = count;
+ record_insn_count = count + 1;
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ " Reading record_end (1 + "
+ "%lu + %lu bytes), offset == %s\n",
+ (unsigned long) sizeof (signal),
+ (unsigned long) sizeof (count),
+ paddress (get_current_arch (),
+ bfd_offset));
+ break;
+
+ default:
+ error (_("Bad entry type in core file %s."),
+ bfd_get_filename (core_bfd));
+ break;
+ }
+
+ /* Add rec to record arch list. */
+ record_arch_list_add (rec);
+ }
+
+ discard_cleanups (old_cleanups);
+
+ /* Add record_arch_list_head to the end of record list. */
+ record_first.next = record_arch_list_head;
+ record_arch_list_head->prev = &record_first;
+ record_arch_list_tail->next = NULL;
+ record_list = &record_first;
+
+ /* Update record_insn_max_num. */
+ if (record_insn_num > record_insn_max_num)
+ {
+ record_insn_max_num = record_insn_num;
+ warning (_("Auto increase record/replay buffer limit to %d."),
+ record_insn_max_num);
+ }
+
+ /* Succeeded. */
+ printf_filtered (_("Restored records from core file %s.\n"),
+ bfd_get_filename (core_bfd));
+
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+}
+
+/* bfdcore_write -- write bytes into a core file section. */
+
+static inline void
+bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offset)
+{
+ int ret = bfd_set_section_contents (obfd, osec, buf, *offset, len);
+
+ if (ret)
+ *offset += len;
+ else
+ error (_("Failed to write %d bytes to core file %s ('%s')."),
+ len, bfd_get_filename (obfd),
+ bfd_errmsg (bfd_get_error ()));
+}
+
+/* Restore the execution log from a file. We use a modified elf
+ corefile format, with an extra section for our data. */
+
+static void
+cmd_record_restore (char *args, int from_tty)
+{
+ core_file_command (args, from_tty);
+ record_open (args, from_tty);
+}
+
+static void
+record_save_cleanups (void *data)
+{
+ bfd *obfd = data;
+ char *pathname = xstrdup (bfd_get_filename (obfd));
+
+ gdb_bfd_unref (obfd);
+ unlink (pathname);
+ xfree (pathname);
+}
+
+/* Save the execution log to a file. We use a modified elf corefile
+ format, with an extra section for our data. */
+
+static void
+cmd_record_save (char *args, int from_tty)
+{
+ char *recfilename, recfilename_buffer[40];
+ struct record_entry *cur_record_list;
+ uint32_t magic;
+ struct regcache *regcache;
+ struct gdbarch *gdbarch;
+ struct cleanup *old_cleanups;
+ struct cleanup *set_cleanups;
+ bfd *obfd;
+ int save_size = 0;
+ asection *osec = NULL;
+ int bfd_offset = 0;
+
+ if (strcmp (current_target.to_shortname, "record") != 0)
+ error (_("This command can only be used with target 'record'.\n"
+ "Use 'target record' first.\n"));
+
+ if (args && *args)
+ recfilename = args;
+ else
+ {
+ /* Default recfile name is "gdb_record.PID". */
+ snprintf (recfilename_buffer, sizeof (recfilename_buffer),
+ "gdb_record.%d", PIDGET (inferior_ptid));
+ recfilename = recfilename_buffer;
+ }
+
+ /* Open the save file. */
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "Saving execution log to core file '%s'\n",
+ recfilename);
+
+ /* Open the output file. */
+ obfd = create_gcore_bfd (recfilename);
+ old_cleanups = make_cleanup (record_save_cleanups, obfd);
+
+ /* Save the current record entry to "cur_record_list". */
+ cur_record_list = record_list;
+
+ /* Get the values of regcache and gdbarch. */
+ regcache = get_current_regcache ();
+ gdbarch = get_regcache_arch (regcache);
+
+ /* Disable the GDB operation record. */
+ set_cleanups = record_gdb_operation_disable_set ();
+
+ /* Reverse execute to the begin of record list. */
+ while (1)
+ {
+ /* Check for beginning and end of log. */
+ if (record_list == &record_first)
+ break;
+
+ record_exec_insn (regcache, gdbarch, record_list);
+
+ if (record_list->prev)
+ record_list = record_list->prev;
+ }
+
+ /* Compute the size needed for the extra bfd section. */
+ save_size = 4; /* magic cookie */
+ for (record_list = record_first.next; record_list;
+ record_list = record_list->next)
+ switch (record_list->type)
+ {
+ case record_end:
+ save_size += 1 + 4 + 4;
+ break;
+ case record_reg:
+ save_size += 1 + 4 + record_list->u.reg.len;
+ break;
+ case record_mem:
+ save_size += 1 + 4 + 8 + record_list->u.mem.len;
+ break;
+ }
+
+ /* Make the new bfd section. */
+ osec = bfd_make_section_anyway_with_flags (obfd, "precord",
+ SEC_HAS_CONTENTS
+ | SEC_READONLY);
+ if (osec == NULL)
+ error (_("Failed to create 'precord' section for corefile %s: %s"),
+ recfilename,
+ bfd_errmsg (bfd_get_error ()));
+ bfd_set_section_size (obfd, osec, save_size);
+ bfd_set_section_vma (obfd, osec, 0);
+ bfd_set_section_alignment (obfd, osec, 0);
+ bfd_section_lma (obfd, osec) = 0;
+
+ /* Save corefile state. */
+ write_gcore_file (obfd);
+
+ /* Write out the record log. */
+ /* Write the magic code. */
+ magic = RECORD_FILE_MAGIC;
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ " Writing 4-byte magic cookie "
+ "RECORD_FILE_MAGIC (0x%s)\n",
+ phex_nz (magic, 4));
+ bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset);
+
+ /* Save the entries to recfd and forward execute to the end of
+ record list. */
+ record_list = &record_first;
+ while (1)
+ {
+ /* Save entry. */
+ if (record_list != &record_first)
+ {
+ uint8_t type;
+ uint32_t regnum, len, signal, count;
+ uint64_t addr;
+
+ type = record_list->type;
+ bfdcore_write (obfd, osec, &type, sizeof (type), &bfd_offset);
+
+ switch (record_list->type)
+ {
+ case record_reg: /* reg */
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ " Writing register %d (1 "
+ "plus %lu plus %d bytes)\n",
+ record_list->u.reg.num,
+ (unsigned long) sizeof (regnum),
+ record_list->u.reg.len);
+
+ /* Write regnum. */
+ regnum = netorder32 (record_list->u.reg.num);
+ bfdcore_write (obfd, osec, ®num,
+ sizeof (regnum), &bfd_offset);
+
+ /* Write regval. */
+ bfdcore_write (obfd, osec, record_get_loc (record_list),
+ record_list->u.reg.len, &bfd_offset);
+ break;
+
+ case record_mem: /* mem */
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ " Writing memory %s (1 plus "
+ "%lu plus %lu plus %d bytes)\n",
+ paddress (gdbarch,
+ record_list->u.mem.addr),
+ (unsigned long) sizeof (addr),
+ (unsigned long) sizeof (len),
+ record_list->u.mem.len);
+
+ /* Write memlen. */
+ len = netorder32 (record_list->u.mem.len);
+ bfdcore_write (obfd, osec, &len, sizeof (len), &bfd_offset);
+
+ /* Write memaddr. */
+ addr = netorder64 (record_list->u.mem.addr);
+ bfdcore_write (obfd, osec, &addr,
+ sizeof (addr), &bfd_offset);
+
+ /* Write memval. */
+ bfdcore_write (obfd, osec, record_get_loc (record_list),
+ record_list->u.mem.len, &bfd_offset);
+ break;
+
+ case record_end:
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ " Writing record_end (1 + "
+ "%lu + %lu bytes)\n",
+ (unsigned long) sizeof (signal),
+ (unsigned long) sizeof (count));
+ /* Write signal value. */
+ signal = netorder32 (record_list->u.end.sigval);
+ bfdcore_write (obfd, osec, &signal,
+ sizeof (signal), &bfd_offset);
+
+ /* Write insn count. */
+ count = netorder32 (record_list->u.end.insn_num);
+ bfdcore_write (obfd, osec, &count,
+ sizeof (count), &bfd_offset);
+ break;
+ }
+ }
+
+ /* Execute entry. */
+ record_exec_insn (regcache, gdbarch, record_list);
+
+ if (record_list->next)
+ record_list = record_list->next;
+ else
+ break;
+ }
+
+ /* Reverse execute to cur_record_list. */
+ while (1)
+ {
+ /* Check for beginning and end of log. */
+ if (record_list == cur_record_list)
+ break;
+
+ record_exec_insn (regcache, gdbarch, record_list);
+
+ if (record_list->prev)
+ record_list = record_list->prev;
+ }
+
+ do_cleanups (set_cleanups);
+ gdb_bfd_unref (obfd);
+ discard_cleanups (old_cleanups);
+
+ /* Succeeded. */
+ printf_filtered (_("Saved core file %s with execution log.\n"),
+ recfilename);
+}
+
+/* record_goto_insn -- rewind the record log (forward or backward,
+ depending on DIR) to the given entry, changing the program state
+ correspondingly. */
+
+static void
+record_goto_insn (struct record_entry *entry,
+ enum exec_direction_kind dir)
+{
+ struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
+ struct regcache *regcache = get_current_regcache ();
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
+ /* Assume everything is valid: we will hit the entry,
+ and we will not hit the end of the recording. */
+
+ if (dir == EXEC_FORWARD)
+ record_list = record_list->next;
+
+ do
+ {
+ record_exec_insn (regcache, gdbarch, record_list);
+ if (dir == EXEC_REVERSE)
+ record_list = record_list->prev;
+ else
+ record_list = record_list->next;
+ } while (record_list != entry);
+ do_cleanups (set_cleanups);
+}
diff --git a/gdb/record-full.h b/gdb/record-full.h
new file mode 100644
index 0000000..46da3a2
--- /dev/null
+++ b/gdb/record-full.h
@@ -0,0 +1,30 @@
+/* Process record and replay target for GDB, the GNU debugger.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifndef RECORD_FULL_H
+#define RECORD_FULL_H
+
+extern int record_memory_query;
+
+extern int record_arch_list_add_reg (struct regcache *regcache, int num);
+extern int record_arch_list_add_mem (CORE_ADDR addr, int len);
+extern int record_arch_list_add_end (void);
+extern struct cleanup *record_gdb_operation_disable_set (void);
+
+#endif /* RECORD_FULL_H */
diff --git a/gdb/record.c b/gdb/record.c
index 1a68738..c06bcae 100644
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -37,454 +37,13 @@
#include <signal.h>
-/* This module implements "target record", also known as "process
- record and replay". This target sits on top of a "normal" target
- (a target that "has execution"), and provides a record and replay
- functionality, including reverse debugging.
-
- Target record has two modes: recording, and replaying.
-
- In record mode, we intercept the to_resume and to_wait methods.
- Whenever gdb resumes the target, we run the target in single step
- mode, and we build up an execution log in which, for each executed
- instruction, we record all changes in memory and register state.
- This is invisible to the user, to whom it just looks like an
- ordinary debugging session (except for performance degredation).
-
- In replay mode, instead of actually letting the inferior run as a
- process, we simulate its execution by playing back the recorded
- execution log. For each instruction in the log, we simulate the
- instruction's side effects by duplicating the changes that it would
- have made on memory and registers. */
-
-#define DEFAULT_RECORD_INSN_MAX_NUM 200000
-
-#define RECORD_IS_REPLAY \
- (record_list->next || execution_direction == EXEC_REVERSE)
-
-#define RECORD_FILE_MAGIC netorder32(0x20091016)
-
-/* These are the core structs of the process record functionality.
-
- A record_entry is a record of the value change of a register
- ("record_reg") or a part of memory ("record_mem"). And each
- instruction must have a struct record_entry ("record_end") that
- indicates that this is the last struct record_entry of this
- instruction.
-
- Each struct record_entry is linked to "record_list" by "prev" and
- "next" pointers. */
-
-struct record_mem_entry
-{
- CORE_ADDR addr;
- int len;
- /* Set this flag if target memory for this entry
- can no longer be accessed. */
- int mem_entry_not_accessible;
- union
- {
- gdb_byte *ptr;
- gdb_byte buf[sizeof (gdb_byte *)];
- } u;
-};
-
-struct record_reg_entry
-{
- unsigned short num;
- unsigned short len;
- union
- {
- gdb_byte *ptr;
- gdb_byte buf[2 * sizeof (gdb_byte *)];
- } u;
-};
-
-struct record_end_entry
-{
- enum gdb_signal sigval;
- ULONGEST insn_num;
-};
-
-enum record_type
-{
- record_end = 0,
- record_reg,
- record_mem
-};
-
-/* This is the data structure that makes up the execution log.
-
- The execution log consists of a single linked list of entries
- of type "struct record_entry". It is doubly linked so that it
- can be traversed in either direction.
-
- The start of the list is anchored by a struct called
- "record_first". The pointer "record_list" either points to the
- last entry that was added to the list (in record mode), or to the
- next entry in the list that will be executed (in replay mode).
-
- Each list element (struct record_entry), in addition to next and
- prev pointers, consists of a union of three entry types: mem, reg,
- and end. A field called "type" determines which entry type is
- represented by a given list element.
-
- Each instruction that is added to the execution log is represented
- by a variable number of list elements ('entries'). The instruction
- will have one "reg" entry for each register that is changed by
- executing the instruction (including the PC in every case). It
- will also have one "mem" entry for each memory change. Finally,
- each instruction will have an "end" entry that separates it from
- the changes associated with the next instruction. */
-
-struct record_entry
-{
- struct record_entry *prev;
- struct record_entry *next;
- enum record_type type;
- union
- {
- /* reg */
- struct record_reg_entry reg;
- /* mem */
- struct record_mem_entry mem;
- /* end */
- struct record_end_entry end;
- } u;
-};
-
/* This is the debug switch for process record. */
unsigned int record_debug = 0;
-/* If true, query if PREC cannot record memory
- change of next instruction. */
-int record_memory_query = 0;
-
-struct record_core_buf_entry
-{
- struct record_core_buf_entry *prev;
- struct target_section *p;
- bfd_byte *buf;
-};
-
-/* Record buf with core target. */
-static gdb_byte *record_core_regbuf = NULL;
-static struct target_section *record_core_start;
-static struct target_section *record_core_end;
-static struct record_core_buf_entry *record_core_buf_list = NULL;
-
-/* The following variables are used for managing the linked list that
- represents the execution log.
-
- record_first is the anchor that holds down the beginning of the list.
-
- record_list serves two functions:
- 1) In record mode, it anchors the end of the list.
- 2) In replay mode, it traverses the list and points to
- the next instruction that must be emulated.
-
- record_arch_list_head and record_arch_list_tail are used to manage
- a separate list, which is used to build up the change elements of
- the currently executing instruction during record mode. When this
- instruction has been completely annotated in the "arch list", it
- will be appended to the main execution log. */
-
-static struct record_entry record_first;
-static struct record_entry *record_list = &record_first;
-static struct record_entry *record_arch_list_head = NULL;
-static struct record_entry *record_arch_list_tail = NULL;
-
-/* 1 ask user. 0 auto delete the last struct record_entry. */
-static int record_stop_at_limit = 1;
-/* Maximum allowed number of insns in execution log. */
-static unsigned int record_insn_max_num = DEFAULT_RECORD_INSN_MAX_NUM;
-/* Actual count of insns presently in execution log. */
-static int record_insn_num = 0;
-/* Count of insns logged so far (may be larger
- than count of insns presently in execution log). */
-static ULONGEST record_insn_count;
-
-/* The target_ops of process record. */
-static struct target_ops record_ops;
-static struct target_ops record_core_ops;
-
-/* The beneath function pointers. */
-static struct target_ops *record_beneath_to_resume_ops;
-static void (*record_beneath_to_resume) (struct target_ops *, ptid_t, int,
- enum gdb_signal);
-static struct target_ops *record_beneath_to_wait_ops;
-static ptid_t (*record_beneath_to_wait) (struct target_ops *, ptid_t,
- struct target_waitstatus *,
- int);
-static struct target_ops *record_beneath_to_store_registers_ops;
-static void (*record_beneath_to_store_registers) (struct target_ops *,
- struct regcache *,
- int regno);
-static struct target_ops *record_beneath_to_xfer_partial_ops;
-static LONGEST (*record_beneath_to_xfer_partial) (struct target_ops *ops,
- enum target_object object,
- const char *annex,
- gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset,
- LONGEST len);
-static int (*record_beneath_to_insert_breakpoint) (struct gdbarch *,
- struct bp_target_info *);
-static int (*record_beneath_to_remove_breakpoint) (struct gdbarch *,
- struct bp_target_info *);
-static int (*record_beneath_to_stopped_by_watchpoint) (void);
-static int (*record_beneath_to_stopped_data_address) (struct target_ops *,
- CORE_ADDR *);
-static void (*record_beneath_to_async) (void (*) (enum inferior_event_type, void *), void *);
-
-/* Alloc and free functions for record_reg, record_mem, and record_end
- entries. */
-
-/* Alloc a record_reg record entry. */
-
-static inline struct record_entry *
-record_reg_alloc (struct regcache *regcache, int regnum)
-{
- struct record_entry *rec;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
-
- rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry));
- rec->type = record_reg;
- rec->u.reg.num = regnum;
- rec->u.reg.len = register_size (gdbarch, regnum);
- if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
- rec->u.reg.u.ptr = (gdb_byte *) xmalloc (rec->u.reg.len);
-
- return rec;
-}
-
-/* Free a record_reg record entry. */
-
-static inline void
-record_reg_release (struct record_entry *rec)
-{
- gdb_assert (rec->type == record_reg);
- if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
- xfree (rec->u.reg.u.ptr);
- xfree (rec);
-}
-
-/* Alloc a record_mem record entry. */
-
-static inline struct record_entry *
-record_mem_alloc (CORE_ADDR addr, int len)
-{
- struct record_entry *rec;
-
- rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry));
- rec->type = record_mem;
- rec->u.mem.addr = addr;
- rec->u.mem.len = len;
- if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
- rec->u.mem.u.ptr = (gdb_byte *) xmalloc (len);
-
- return rec;
-}
-
-/* Free a record_mem record entry. */
-
-static inline void
-record_mem_release (struct record_entry *rec)
-{
- gdb_assert (rec->type == record_mem);
- if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
- xfree (rec->u.mem.u.ptr);
- xfree (rec);
-}
-
-/* Alloc a record_end record entry. */
-
-static inline struct record_entry *
-record_end_alloc (void)
-{
- struct record_entry *rec;
-
- rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry));
- rec->type = record_end;
-
- return rec;
-}
-
-/* Free a record_end record entry. */
-
-static inline void
-record_end_release (struct record_entry *rec)
-{
- xfree (rec);
-}
-
-/* Free one record entry, any type.
- Return entry->type, in case caller wants to know. */
-
-static inline enum record_type
-record_entry_release (struct record_entry *rec)
-{
- enum record_type type = rec->type;
-
- switch (type) {
- case record_reg:
- record_reg_release (rec);
- break;
- case record_mem:
- record_mem_release (rec);
- break;
- case record_end:
- record_end_release (rec);
- break;
- }
- return type;
-}
-
-/* Free all record entries in list pointed to by REC. */
-
-static void
-record_list_release (struct record_entry *rec)
-{
- if (!rec)
- return;
-
- while (rec->next)
- rec = rec->next;
-
- while (rec->prev)
- {
- rec = rec->prev;
- record_entry_release (rec->next);
- }
-
- if (rec == &record_first)
- {
- record_insn_num = 0;
- record_first.next = NULL;
- }
- else
- record_entry_release (rec);
-}
-
-/* Free all record entries forward of the given list position. */
-
-static void
-record_list_release_following (struct record_entry *rec)
-{
- struct record_entry *tmp = rec->next;
-
- rec->next = NULL;
- while (tmp)
- {
- rec = tmp->next;
- if (record_entry_release (tmp) == record_end)
- {
- record_insn_num--;
- record_insn_count--;
- }
- tmp = rec;
- }
-}
-
-/* Delete the first instruction from the beginning of the log, to make
- room for adding a new instruction at the end of the log.
-
- Note -- this function does not modify record_insn_num. */
-
-static void
-record_list_release_first (void)
-{
- struct record_entry *tmp;
-
- if (!record_first.next)
- return;
-
- /* Loop until a record_end. */
- while (1)
- {
- /* Cut record_first.next out of the linked list. */
- tmp = record_first.next;
- record_first.next = tmp->next;
- tmp->next->prev = &record_first;
-
- /* tmp is now isolated, and can be deleted. */
- if (record_entry_release (tmp) == record_end)
- break; /* End loop at first record_end. */
-
- if (!record_first.next)
- {
- gdb_assert (record_insn_num == 1);
- break; /* End loop when list is empty. */
- }
- }
-}
-
-/* Add a struct record_entry to record_arch_list. */
-
-static void
-record_arch_list_add (struct record_entry *rec)
-{
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_arch_list_add %s.\n",
- host_address_to_string (rec));
-
- if (record_arch_list_tail)
- {
- record_arch_list_tail->next = rec;
- rec->prev = record_arch_list_tail;
- record_arch_list_tail = rec;
- }
- else
- {
- record_arch_list_head = rec;
- record_arch_list_tail = rec;
- }
-}
-
-/* Return the value storage location of a record entry. */
-static inline gdb_byte *
-record_get_loc (struct record_entry *rec)
-{
- switch (rec->type) {
- case record_mem:
- if (rec->u.mem.len > sizeof (rec->u.mem.u.buf))
- return rec->u.mem.u.ptr;
- else
- return rec->u.mem.u.buf;
- case record_reg:
- if (rec->u.reg.len > sizeof (rec->u.reg.u.buf))
- return rec->u.reg.u.ptr;
- else
- return rec->u.reg.u.buf;
- case record_end:
- default:
- gdb_assert_not_reached ("unexpected record_entry type");
- return NULL;
- }
-}
-
-/* Record the value of a register NUM to record_arch_list. */
-
-int
-record_arch_list_add_reg (struct regcache *regcache, int regnum)
-{
- struct record_entry *rec;
-
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: add register num = %d to "
- "record list.\n",
- regnum);
-
- rec = record_reg_alloc (regcache, regnum);
-
- regcache_raw_read (regcache, regnum, record_get_loc (rec));
-
- record_arch_list_add (rec);
+/* The implementation of the command "record goto". */
+static void cmd_record_goto (char *, int);
- return 0;
-}
+/* See record.h. */
int
record_read_memory (struct gdbarch *gdbarch,
@@ -500,1718 +59,6 @@ record_read_memory (struct gdbarch *gdbarch,
return ret;
}
-/* Record the value of a region of memory whose address is ADDR and
- length is LEN to record_arch_list. */
-
-int
-record_arch_list_add_mem (CORE_ADDR addr, int len)
-{
- struct record_entry *rec;
-
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: add mem addr = %s len = %d to "
- "record list.\n",
- paddress (target_gdbarch (), addr), len);
-
- if (!addr) /* FIXME: Why? Some arch must permit it... */
- return 0;
-
- rec = record_mem_alloc (addr, len);
-
- if (record_read_memory (target_gdbarch (), addr, record_get_loc (rec), len))
- {
- record_mem_release (rec);
- return -1;
- }
-
- record_arch_list_add (rec);
-
- return 0;
-}
-
-/* Add a record_end type struct record_entry to record_arch_list. */
-
-int
-record_arch_list_add_end (void)
-{
- struct record_entry *rec;
-
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: add end to arch list.\n");
-
- rec = record_end_alloc ();
- rec->u.end.sigval = GDB_SIGNAL_0;
- rec->u.end.insn_num = ++record_insn_count;
-
- record_arch_list_add (rec);
-
- return 0;
-}
-
-static void
-record_check_insn_num (int set_terminal)
-{
- if (record_insn_max_num)
- {
- gdb_assert (record_insn_num <= record_insn_max_num);
- if (record_insn_num == record_insn_max_num)
- {
- /* Ask user what to do. */
- if (record_stop_at_limit)
- {
- int q;
-
- if (set_terminal)
- target_terminal_ours ();
- q = yquery (_("Do you want to auto delete previous execution "
- "log entries when record/replay buffer becomes "
- "full (record stop-at-limit)?"));
- if (set_terminal)
- target_terminal_inferior ();
- if (q)
- record_stop_at_limit = 0;
- else
- error (_("Process record: stopped by user."));
- }
- }
- }
-}
-
-static void
-record_arch_list_cleanups (void *ignore)
-{
- record_list_release (record_arch_list_tail);
-}
-
-/* Before inferior step (when GDB record the running message, inferior
- only can step), GDB will call this function to record the values to
- record_list. This function will call gdbarch_process_record to
- record the running message of inferior and set them to
- record_arch_list, and add it to record_list. */
-
-static int
-record_message (struct regcache *regcache, enum gdb_signal signal)
-{
- int ret;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct cleanup *old_cleanups = make_cleanup (record_arch_list_cleanups, 0);
-
- record_arch_list_head = NULL;
- record_arch_list_tail = NULL;
-
- /* Check record_insn_num. */
- record_check_insn_num (1);
-
- /* If gdb sends a signal value to target_resume,
- save it in the 'end' field of the previous instruction.
-
- Maybe process record should record what really happened,
- rather than what gdb pretends has happened.
-
- So if Linux delivered the signal to the child process during
- the record mode, we will record it and deliver it again in
- the replay mode.
-
- If user says "ignore this signal" during the record mode, then
- it will be ignored again during the replay mode (no matter if
- the user says something different, like "deliver this signal"
- during the replay mode).
-
- User should understand that nothing he does during the replay
- mode will change the behavior of the child. If he tries,
- then that is a user error.
-
- But we should still deliver the signal to gdb during the replay,
- if we delivered it during the recording. Therefore we should
- record the signal during record_wait, not record_resume. */
- if (record_list != &record_first) /* FIXME better way to check */
- {
- gdb_assert (record_list->type == record_end);
- record_list->u.end.sigval = signal;
- }
-
- if (signal == GDB_SIGNAL_0
- || !gdbarch_process_record_signal_p (gdbarch))
- ret = gdbarch_process_record (gdbarch,
- regcache,
- regcache_read_pc (regcache));
- else
- ret = gdbarch_process_record_signal (gdbarch,
- regcache,
- signal);
-
- if (ret > 0)
- error (_("Process record: inferior program stopped."));
- if (ret < 0)
- error (_("Process record: failed to record execution log."));
-
- discard_cleanups (old_cleanups);
-
- record_list->next = record_arch_list_head;
- record_arch_list_head->prev = record_list;
- record_list = record_arch_list_tail;
-
- if (record_insn_num == record_insn_max_num && record_insn_max_num)
- record_list_release_first ();
- else
- record_insn_num++;
-
- return 1;
-}
-
-struct record_message_args {
- struct regcache *regcache;
- enum gdb_signal signal;
-};
-
-static int
-record_message_wrapper (void *args)
-{
- struct record_message_args *record_args = args;
-
- return record_message (record_args->regcache, record_args->signal);
-}
-
-static int
-record_message_wrapper_safe (struct regcache *regcache,
- enum gdb_signal signal)
-{
- struct record_message_args args;
-
- args.regcache = regcache;
- args.signal = signal;
-
- return catch_errors (record_message_wrapper, &args, NULL, RETURN_MASK_ALL);
-}
-
-/* Set to 1 if record_store_registers and record_xfer_partial
- doesn't need record. */
-
-static int record_gdb_operation_disable = 0;
-
-struct cleanup *
-record_gdb_operation_disable_set (void)
-{
- struct cleanup *old_cleanups = NULL;
-
- old_cleanups =
- make_cleanup_restore_integer (&record_gdb_operation_disable);
- record_gdb_operation_disable = 1;
-
- return old_cleanups;
-}
-
-/* Flag set to TRUE for target_stopped_by_watchpoint. */
-static int record_hw_watchpoint = 0;
-
-/* Execute one instruction from the record log. Each instruction in
- the log will be represented by an arbitrary sequence of register
- entries and memory entries, followed by an 'end' entry. */
-
-static inline void
-record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
- struct record_entry *entry)
-{
- switch (entry->type)
- {
- case record_reg: /* reg */
- {
- gdb_byte reg[MAX_REGISTER_SIZE];
-
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_reg %s to "
- "inferior num = %d.\n",
- host_address_to_string (entry),
- entry->u.reg.num);
-
- regcache_cooked_read (regcache, entry->u.reg.num, reg);
- regcache_cooked_write (regcache, entry->u.reg.num,
- record_get_loc (entry));
- memcpy (record_get_loc (entry), reg, entry->u.reg.len);
- }
- break;
-
- case record_mem: /* mem */
- {
- /* Nothing to do if the entry is flagged not_accessible. */
- if (!entry->u.mem.mem_entry_not_accessible)
- {
- gdb_byte *mem = alloca (entry->u.mem.len);
-
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_mem %s to "
- "inferior addr = %s len = %d.\n",
- host_address_to_string (entry),
- paddress (gdbarch, entry->u.mem.addr),
- entry->u.mem.len);
-
- if (record_read_memory (gdbarch,
- entry->u.mem.addr, mem, entry->u.mem.len))
- entry->u.mem.mem_entry_not_accessible = 1;
- else
- {
- if (target_write_memory (entry->u.mem.addr,
- record_get_loc (entry),
- entry->u.mem.len))
- {
- entry->u.mem.mem_entry_not_accessible = 1;
- if (record_debug)
- warning (_("Process record: error writing memory at "
- "addr = %s len = %d."),
- paddress (gdbarch, entry->u.mem.addr),
- entry->u.mem.len);
- }
- else
- {
- memcpy (record_get_loc (entry), mem, entry->u.mem.len);
-
- /* We've changed memory --- check if a hardware
- watchpoint should trap. Note that this
- presently assumes the target beneath supports
- continuable watchpoints. On non-continuable
- watchpoints target, we'll want to check this
- _before_ actually doing the memory change, and
- not doing the change at all if the watchpoint
- traps. */
- if (hardware_watchpoint_inserted_in_range
- (get_regcache_aspace (regcache),
- entry->u.mem.addr, entry->u.mem.len))
- record_hw_watchpoint = 1;
- }
- }
- }
- }
- break;
- }
-}
-
-static struct target_ops *tmp_to_resume_ops;
-static void (*tmp_to_resume) (struct target_ops *, ptid_t, int,
- enum gdb_signal);
-static struct target_ops *tmp_to_wait_ops;
-static ptid_t (*tmp_to_wait) (struct target_ops *, ptid_t,
- struct target_waitstatus *,
- int);
-static struct target_ops *tmp_to_store_registers_ops;
-static void (*tmp_to_store_registers) (struct target_ops *,
- struct regcache *,
- int regno);
-static struct target_ops *tmp_to_xfer_partial_ops;
-static LONGEST (*tmp_to_xfer_partial) (struct target_ops *ops,
- enum target_object object,
- const char *annex,
- gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset,
- LONGEST len);
-static int (*tmp_to_insert_breakpoint) (struct gdbarch *,
- struct bp_target_info *);
-static int (*tmp_to_remove_breakpoint) (struct gdbarch *,
- struct bp_target_info *);
-static int (*tmp_to_stopped_by_watchpoint) (void);
-static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
-static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
-static void (*tmp_to_async) (void (*) (enum inferior_event_type, void *), void *);
-
-static void record_restore (void);
-
-/* Asynchronous signal handle registered as event loop source for when
- we have pending events ready to be passed to the core. */
-
-static struct async_event_handler *record_async_inferior_event_token;
-
-static void
-record_async_inferior_event_handler (gdb_client_data data)
-{
- inferior_event_handler (INF_REG_EVENT, NULL);
-}
-
-/* Open the process record target. */
-
-static void
-record_core_open_1 (char *name, int from_tty)
-{
- struct regcache *regcache = get_current_regcache ();
- int regnum = gdbarch_num_regs (get_regcache_arch (regcache));
- int i;
-
- /* Get record_core_regbuf. */
- target_fetch_registers (regcache, -1);
- record_core_regbuf = xmalloc (MAX_REGISTER_SIZE * regnum);
- for (i = 0; i < regnum; i ++)
- regcache_raw_collect (regcache, i,
- record_core_regbuf + MAX_REGISTER_SIZE * i);
-
- /* Get record_core_start and record_core_end. */
- if (build_section_table (core_bfd, &record_core_start, &record_core_end))
- {
- xfree (record_core_regbuf);
- record_core_regbuf = NULL;
- error (_("\"%s\": Can't find sections: %s"),
- bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ()));
- }
-
- push_target (&record_core_ops);
- record_restore ();
-}
-
-/* "to_open" target method for 'live' processes. */
-
-static void
-record_open_1 (char *name, int from_tty)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
-
- /* check exec */
- if (!target_has_execution)
- error (_("Process record: the program is not being run."));
- if (non_stop)
- error (_("Process record target can't debug inferior in non-stop mode "
- "(non-stop)."));
-
- if (!gdbarch_process_record_p (target_gdbarch ()))
- error (_("Process record: the current architecture doesn't support "
- "record function."));
-
- if (!tmp_to_resume)
- error (_("Could not find 'to_resume' method on the target stack."));
- if (!tmp_to_wait)
- error (_("Could not find 'to_wait' method on the target stack."));
- if (!tmp_to_store_registers)
- error (_("Could not find 'to_store_registers' "
- "method on the target stack."));
- if (!tmp_to_insert_breakpoint)
- error (_("Could not find 'to_insert_breakpoint' "
- "method on the target stack."));
- if (!tmp_to_remove_breakpoint)
- error (_("Could not find 'to_remove_breakpoint' "
- "method on the target stack."));
- if (!tmp_to_stopped_by_watchpoint)
- error (_("Could not find 'to_stopped_by_watchpoint' "
- "method on the target stack."));
- if (!tmp_to_stopped_data_address)
- error (_("Could not find 'to_stopped_data_address' "
- "method on the target stack."));
-
- push_target (&record_ops);
-}
-
-static void record_init_record_breakpoints (void);
-
-/* "to_open" target method. Open the process record target. */
-
-static void
-record_open (char *name, int from_tty)
-{
- struct target_ops *t;
-
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
-
- /* Check if record target is already running. */
- if (current_target.to_stratum == record_stratum)
- error (_("Process record target already running. Use \"record stop\" to "
- "stop record target first."));
-
- /* Reset the tmp beneath pointers. */
- tmp_to_resume_ops = NULL;
- tmp_to_resume = NULL;
- tmp_to_wait_ops = NULL;
- tmp_to_wait = NULL;
- tmp_to_store_registers_ops = NULL;
- tmp_to_store_registers = NULL;
- tmp_to_xfer_partial_ops = NULL;
- tmp_to_xfer_partial = NULL;
- tmp_to_insert_breakpoint = NULL;
- tmp_to_remove_breakpoint = NULL;
- tmp_to_stopped_by_watchpoint = NULL;
- tmp_to_stopped_data_address = NULL;
- tmp_to_async = NULL;
-
- /* Set the beneath function pointers. */
- for (t = current_target.beneath; t != NULL; t = t->beneath)
- {
- if (!tmp_to_resume)
- {
- tmp_to_resume = t->to_resume;
- tmp_to_resume_ops = t;
- }
- if (!tmp_to_wait)
- {
- tmp_to_wait = t->to_wait;
- tmp_to_wait_ops = t;
- }
- if (!tmp_to_store_registers)
- {
- tmp_to_store_registers = t->to_store_registers;
- tmp_to_store_registers_ops = t;
- }
- if (!tmp_to_xfer_partial)
- {
- tmp_to_xfer_partial = t->to_xfer_partial;
- tmp_to_xfer_partial_ops = t;
- }
- if (!tmp_to_insert_breakpoint)
- tmp_to_insert_breakpoint = t->to_insert_breakpoint;
- if (!tmp_to_remove_breakpoint)
- tmp_to_remove_breakpoint = t->to_remove_breakpoint;
- if (!tmp_to_stopped_by_watchpoint)
- tmp_to_stopped_by_watchpoint = t->to_stopped_by_watchpoint;
- if (!tmp_to_stopped_data_address)
- tmp_to_stopped_data_address = t->to_stopped_data_address;
- if (!tmp_to_async)
- tmp_to_async = t->to_async;
- }
- if (!tmp_to_xfer_partial)
- error (_("Could not find 'to_xfer_partial' method on the target stack."));
-
- /* Reset */
- record_insn_num = 0;
- record_insn_count = 0;
- record_list = &record_first;
- record_list->next = NULL;
-
- /* Set the tmp beneath pointers to beneath pointers. */
- record_beneath_to_resume_ops = tmp_to_resume_ops;
- record_beneath_to_resume = tmp_to_resume;
- record_beneath_to_wait_ops = tmp_to_wait_ops;
- record_beneath_to_wait = tmp_to_wait;
- record_beneath_to_store_registers_ops = tmp_to_store_registers_ops;
- record_beneath_to_store_registers = tmp_to_store_registers;
- record_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops;
- record_beneath_to_xfer_partial = tmp_to_xfer_partial;
- record_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint;
- record_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint;
- record_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint;
- record_beneath_to_stopped_data_address = tmp_to_stopped_data_address;
- record_beneath_to_async = tmp_to_async;
-
- if (core_bfd)
- record_core_open_1 (name, from_tty);
- else
- record_open_1 (name, from_tty);
-
- /* Register extra event sources in the event loop. */
- record_async_inferior_event_token
- = create_async_event_handler (record_async_inferior_event_handler,
- NULL);
-
- record_init_record_breakpoints ();
-
- observer_notify_record_changed (current_inferior (), 1);
-}
-
-/* "to_close" target method. Close the process record target. */
-
-static void
-record_close (int quitting)
-{
- struct record_core_buf_entry *entry;
-
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n");
-
- record_list_release (record_list);
-
- /* Release record_core_regbuf. */
- if (record_core_regbuf)
- {
- xfree (record_core_regbuf);
- record_core_regbuf = NULL;
- }
-
- /* Release record_core_buf_list. */
- if (record_core_buf_list)
- {
- for (entry = record_core_buf_list->prev; entry; entry = entry->prev)
- {
- xfree (record_core_buf_list);
- record_core_buf_list = entry;
- }
- record_core_buf_list = NULL;
- }
-
- if (record_async_inferior_event_token)
- delete_async_event_handler (&record_async_inferior_event_token);
-}
-
-static int record_resume_step = 0;
-
-/* True if we've been resumed, and so each record_wait call should
- advance execution. If this is false, record_wait will return a
- TARGET_WAITKIND_IGNORE. */
-static int record_resumed = 0;
-
-/* The execution direction of the last resume we got. This is
- necessary for async mode. Vis (order is not strictly accurate):
-
- 1. user has the global execution direction set to forward
- 2. user does a reverse-step command
- 3. record_resume is called with global execution direction
- temporarily switched to reverse
- 4. GDB's execution direction is reverted back to forward
- 5. target record notifies event loop there's an event to handle
- 6. infrun asks the target which direction was it going, and switches
- the global execution direction accordingly (to reverse)
- 7. infrun polls an event out of the record target, and handles it
- 8. GDB goes back to the event loop, and goto #4.
-*/
-static enum exec_direction_kind record_execution_dir = EXEC_FORWARD;
-
-/* "to_resume" target method. Resume the process record target. */
-
-static void
-record_resume (struct target_ops *ops, ptid_t ptid, int step,
- enum gdb_signal signal)
-{
- record_resume_step = step;
- record_resumed = 1;
- record_execution_dir = execution_direction;
-
- if (!RECORD_IS_REPLAY)
- {
- struct gdbarch *gdbarch = target_thread_architecture (ptid);
-
- record_message (get_current_regcache (), signal);
-
- if (!step)
- {
- /* This is not hard single step. */
- if (!gdbarch_software_single_step_p (gdbarch))
- {
- /* This is a normal continue. */
- step = 1;
- }
- else
- {
- /* This arch support soft sigle step. */
- if (single_step_breakpoints_inserted ())
- {
- /* This is a soft single step. */
- record_resume_step = 1;
- }
- else
- {
- /* This is a continue.
- Try to insert a soft single step breakpoint. */
- if (!gdbarch_software_single_step (gdbarch,
- get_current_frame ()))
- {
- /* This system don't want use soft single step.
- Use hard sigle step. */
- step = 1;
- }
- }
- }
- }
-
- /* Make sure the target beneath reports all signals. */
- target_pass_signals (0, NULL);
-
- record_beneath_to_resume (record_beneath_to_resume_ops,
- ptid, step, signal);
- }
-
- /* We are about to start executing the inferior (or simulate it),
- let's register it with the event loop. */
- if (target_can_async_p ())
- {
- target_async (inferior_event_handler, 0);
- /* Notify the event loop there's an event to wait for. We do
- most of the work in record_wait. */
- mark_async_event_handler (record_async_inferior_event_token);
- }
-}
-
-static int record_get_sig = 0;
-
-/* SIGINT signal handler, registered by "to_wait" method. */
-
-static void
-record_sig_handler (int signo)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: get a signal\n");
-
- /* It will break the running inferior in replay mode. */
- record_resume_step = 1;
-
- /* It will let record_wait set inferior status to get the signal
- SIGINT. */
- record_get_sig = 1;
-}
-
-static void
-record_wait_cleanups (void *ignore)
-{
- if (execution_direction == EXEC_REVERSE)
- {
- if (record_list->next)
- record_list = record_list->next;
- }
- else
- record_list = record_list->prev;
-}
-
-/* "to_wait" target method for process record target.
-
- In record mode, the target is always run in singlestep mode
- (even when gdb says to continue). The to_wait method intercepts
- the stop events and determines which ones are to be passed on to
- gdb. Most stop events are just singlestep events that gdb is not
- to know about, so the to_wait method just records them and keeps
- singlestepping.
-
- In replay mode, this function emulates the recorded execution log,
- one instruction at a time (forward or backward), and determines
- where to stop. */
-
-static ptid_t
-record_wait_1 (struct target_ops *ops,
- ptid_t ptid, struct target_waitstatus *status,
- int options)
-{
- struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
-
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_wait "
- "record_resume_step = %d, record_resumed = %d, direction=%s\n",
- record_resume_step, record_resumed,
- record_execution_dir == EXEC_FORWARD ? "forward" : "reverse");
-
- if (!record_resumed)
- {
- gdb_assert ((options & TARGET_WNOHANG) != 0);
-
- /* No interesting event. */
- status->kind = TARGET_WAITKIND_IGNORE;
- return minus_one_ptid;
- }
-
- record_get_sig = 0;
- signal (SIGINT, record_sig_handler);
-
- if (!RECORD_IS_REPLAY && ops != &record_core_ops)
- {
- if (record_resume_step)
- {
- /* This is a single step. */
- return record_beneath_to_wait (record_beneath_to_wait_ops,
- ptid, status, options);
- }
- else
- {
- /* This is not a single step. */
- ptid_t ret;
- CORE_ADDR tmp_pc;
- struct gdbarch *gdbarch = target_thread_architecture (inferior_ptid);
-
- while (1)
- {
- ret = record_beneath_to_wait (record_beneath_to_wait_ops,
- ptid, status, options);
- if (status->kind == TARGET_WAITKIND_IGNORE)
- {
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_wait "
- "target beneath not done yet\n");
- return ret;
- }
-
- if (single_step_breakpoints_inserted ())
- remove_single_step_breakpoints ();
-
- if (record_resume_step)
- return ret;
-
- /* Is this a SIGTRAP? */
- if (status->kind == TARGET_WAITKIND_STOPPED
- && status->value.sig == GDB_SIGNAL_TRAP)
- {
- struct regcache *regcache;
- struct address_space *aspace;
-
- /* Yes -- this is likely our single-step finishing,
- but check if there's any reason the core would be
- interested in the event. */
-
- registers_changed ();
- regcache = get_current_regcache ();
- tmp_pc = regcache_read_pc (regcache);
- aspace = get_regcache_aspace (regcache);
-
- if (target_stopped_by_watchpoint ())
- {
- /* Always interested in watchpoints. */
- }
- else if (breakpoint_inserted_here_p (aspace, tmp_pc))
- {
- /* There is a breakpoint here. Let the core
- handle it. */
- if (software_breakpoint_inserted_here_p (aspace, tmp_pc))
- {
- struct gdbarch *gdbarch
- = get_regcache_arch (regcache);
- CORE_ADDR decr_pc_after_break
- = gdbarch_decr_pc_after_break (gdbarch);
- if (decr_pc_after_break)
- regcache_write_pc (regcache,
- tmp_pc + decr_pc_after_break);
- }
- }
- else
- {
- /* This is a single-step trap. Record the
- insn and issue another step.
- FIXME: this part can be a random SIGTRAP too.
- But GDB cannot handle it. */
- int step = 1;
-
- if (!record_message_wrapper_safe (regcache,
- GDB_SIGNAL_0))
- {
- status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = GDB_SIGNAL_0;
- break;
- }
-
- if (gdbarch_software_single_step_p (gdbarch))
- {
- /* Try to insert the software single step breakpoint.
- If insert success, set step to 0. */
- set_executing (inferior_ptid, 0);
- reinit_frame_cache ();
- if (gdbarch_software_single_step (gdbarch,
- get_current_frame ()))
- step = 0;
- set_executing (inferior_ptid, 1);
- }
-
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_wait "
- "issuing one more step in the target beneath\n");
- record_beneath_to_resume (record_beneath_to_resume_ops,
- ptid, step,
- GDB_SIGNAL_0);
- continue;
- }
- }
-
- /* The inferior is broken by a breakpoint or a signal. */
- break;
- }
-
- return ret;
- }
- }
- else
- {
- struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct address_space *aspace = get_regcache_aspace (regcache);
- int continue_flag = 1;
- int first_record_end = 1;
- struct cleanup *old_cleanups = make_cleanup (record_wait_cleanups, 0);
- CORE_ADDR tmp_pc;
-
- record_hw_watchpoint = 0;
- status->kind = TARGET_WAITKIND_STOPPED;
-
- /* Check breakpoint when forward execute. */
- if (execution_direction == EXEC_FORWARD)
- {
- tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (aspace, tmp_pc))
- {
- int decr_pc_after_break = gdbarch_decr_pc_after_break (gdbarch);
-
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: break at %s.\n",
- paddress (gdbarch, tmp_pc));
-
- if (decr_pc_after_break
- && !record_resume_step
- && software_breakpoint_inserted_here_p (aspace, tmp_pc))
- regcache_write_pc (regcache,
- tmp_pc + decr_pc_after_break);
- goto replay_out;
- }
- }
-
- /* If GDB is in terminal_inferior mode, it will not get the signal.
- And in GDB replay mode, GDB doesn't need to be in terminal_inferior
- mode, because inferior will not executed.
- Then set it to terminal_ours to make GDB get the signal. */
- target_terminal_ours ();
-
- /* In EXEC_FORWARD mode, record_list points to the tail of prev
- instruction. */
- if (execution_direction == EXEC_FORWARD && record_list->next)
- record_list = record_list->next;
-
- /* Loop over the record_list, looking for the next place to
- stop. */
- do
- {
- /* Check for beginning and end of log. */
- if (execution_direction == EXEC_REVERSE
- && record_list == &record_first)
- {
- /* Hit beginning of record log in reverse. */
- status->kind = TARGET_WAITKIND_NO_HISTORY;
- break;
- }
- if (execution_direction != EXEC_REVERSE && !record_list->next)
- {
- /* Hit end of record log going forward. */
- status->kind = TARGET_WAITKIND_NO_HISTORY;
- break;
- }
-
- record_exec_insn (regcache, gdbarch, record_list);
-
- if (record_list->type == record_end)
- {
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: record_end %s to "
- "inferior.\n",
- host_address_to_string (record_list));
-
- if (first_record_end && execution_direction == EXEC_REVERSE)
- {
- /* When reverse excute, the first record_end is the part of
- current instruction. */
- first_record_end = 0;
- }
- else
- {
- /* In EXEC_REVERSE mode, this is the record_end of prev
- instruction.
- In EXEC_FORWARD mode, this is the record_end of current
- instruction. */
- /* step */
- if (record_resume_step)
- {
- if (record_debug > 1)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: step.\n");
- continue_flag = 0;
- }
-
- /* check breakpoint */
- tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (aspace, tmp_pc))
- {
- int decr_pc_after_break
- = gdbarch_decr_pc_after_break (gdbarch);
-
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: break "
- "at %s.\n",
- paddress (gdbarch, tmp_pc));
- if (decr_pc_after_break
- && execution_direction == EXEC_FORWARD
- && !record_resume_step
- && software_breakpoint_inserted_here_p (aspace,
- tmp_pc))
- regcache_write_pc (regcache,
- tmp_pc + decr_pc_after_break);
- continue_flag = 0;
- }
-
- if (record_hw_watchpoint)
- {
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: hit hw "
- "watchpoint.\n");
- continue_flag = 0;
- }
- /* Check target signal */
- if (record_list->u.end.sigval != GDB_SIGNAL_0)
- /* FIXME: better way to check */
- continue_flag = 0;
- }
- }
-
- if (continue_flag)
- {
- if (execution_direction == EXEC_REVERSE)
- {
- if (record_list->prev)
- record_list = record_list->prev;
- }
- else
- {
- if (record_list->next)
- record_list = record_list->next;
- }
- }
- }
- while (continue_flag);
-
-replay_out:
- if (record_get_sig)
- status->value.sig = GDB_SIGNAL_INT;
- else if (record_list->u.end.sigval != GDB_SIGNAL_0)
- /* FIXME: better way to check */
- status->value.sig = record_list->u.end.sigval;
- else
- status->value.sig = GDB_SIGNAL_TRAP;
-
- discard_cleanups (old_cleanups);
- }
-
- signal (SIGINT, handle_sigint);
-
- do_cleanups (set_cleanups);
- return inferior_ptid;
-}
-
-static ptid_t
-record_wait (struct target_ops *ops,
- ptid_t ptid, struct target_waitstatus *status,
- int options)
-{
- ptid_t return_ptid;
-
- return_ptid = record_wait_1 (ops, ptid, status, options);
- if (status->kind != TARGET_WAITKIND_IGNORE)
- {
- /* We're reporting a stop. Make sure any spurious
- target_wait(WNOHANG) doesn't advance the target until the
- core wants us resumed again. */
- record_resumed = 0;
- }
- return return_ptid;
-}
-
-static int
-record_stopped_by_watchpoint (void)
-{
- if (RECORD_IS_REPLAY)
- return record_hw_watchpoint;
- else
- return record_beneath_to_stopped_by_watchpoint ();
-}
-
-static int
-record_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
-{
- if (RECORD_IS_REPLAY)
- return 0;
- else
- return record_beneath_to_stopped_data_address (ops, addr_p);
-}
-
-/* "to_disconnect" method for process record target. */
-
-static void
-record_disconnect (struct target_ops *target, char *args, int from_tty)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_disconnect\n");
-
- unpush_target (&record_ops);
- target_disconnect (args, from_tty);
-}
-
-/* "to_detach" method for process record target. */
-
-static void
-record_detach (struct target_ops *ops, char *args, int from_tty)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_detach\n");
-
- unpush_target (&record_ops);
- target_detach (args, from_tty);
-}
-
-/* "to_mourn_inferior" method for process record target. */
-
-static void
-record_mourn_inferior (struct target_ops *ops)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: "
- "record_mourn_inferior\n");
-
- unpush_target (&record_ops);
- target_mourn_inferior ();
-}
-
-/* Close process record target before killing the inferior process. */
-
-static void
-record_kill (struct target_ops *ops)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_kill\n");
-
- unpush_target (&record_ops);
- target_kill ();
-}
-
-/* Record registers change (by user or by GDB) to list as an instruction. */
-
-static void
-record_registers_change (struct regcache *regcache, int regnum)
-{
- /* Check record_insn_num. */
- record_check_insn_num (0);
-
- record_arch_list_head = NULL;
- record_arch_list_tail = NULL;
-
- if (regnum < 0)
- {
- int i;
-
- for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
- {
- if (record_arch_list_add_reg (regcache, i))
- {
- record_list_release (record_arch_list_tail);
- error (_("Process record: failed to record execution log."));
- }
- }
- }
- else
- {
- if (record_arch_list_add_reg (regcache, regnum))
- {
- record_list_release (record_arch_list_tail);
- error (_("Process record: failed to record execution log."));
- }
- }
- if (record_arch_list_add_end ())
- {
- record_list_release (record_arch_list_tail);
- error (_("Process record: failed to record execution log."));
- }
- record_list->next = record_arch_list_head;
- record_arch_list_head->prev = record_list;
- record_list = record_arch_list_tail;
-
- if (record_insn_num == record_insn_max_num && record_insn_max_num)
- record_list_release_first ();
- else
- record_insn_num++;
-}
-
-/* "to_store_registers" method for process record target. */
-
-static void
-record_store_registers (struct target_ops *ops, struct regcache *regcache,
- int regno)
-{
- if (!record_gdb_operation_disable)
- {
- if (RECORD_IS_REPLAY)
- {
- int n;
-
- /* Let user choose if he wants to write register or not. */
- if (regno < 0)
- n =
- query (_("Because GDB is in replay mode, changing the "
- "value of a register will make the execution "
- "log unusable from this point onward. "
- "Change all registers?"));
- else
- n =
- query (_("Because GDB is in replay mode, changing the value "
- "of a register will make the execution log unusable "
- "from this point onward. Change register %s?"),
- gdbarch_register_name (get_regcache_arch (regcache),
- regno));
-
- if (!n)
- {
- /* Invalidate the value of regcache that was set in function
- "regcache_raw_write". */
- if (regno < 0)
- {
- int i;
-
- for (i = 0;
- i < gdbarch_num_regs (get_regcache_arch (regcache));
- i++)
- regcache_invalidate (regcache, i);
- }
- else
- regcache_invalidate (regcache, regno);
-
- error (_("Process record canceled the operation."));
- }
-
- /* Destroy the record from here forward. */
- record_list_release_following (record_list);
- }
-
- record_registers_change (regcache, regno);
- }
- record_beneath_to_store_registers (record_beneath_to_store_registers_ops,
- regcache, regno);
-}
-
-/* "to_xfer_partial" method. Behavior is conditional on RECORD_IS_REPLAY.
- In replay mode, we cannot write memory unles we are willing to
- invalidate the record/replay log from this point forward. */
-
-static LONGEST
-record_xfer_partial (struct target_ops *ops, enum target_object object,
- const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
-{
- if (!record_gdb_operation_disable
- && (object == TARGET_OBJECT_MEMORY
- || object == TARGET_OBJECT_RAW_MEMORY) && writebuf)
- {
- if (RECORD_IS_REPLAY)
- {
- /* Let user choose if he wants to write memory or not. */
- if (!query (_("Because GDB is in replay mode, writing to memory "
- "will make the execution log unusable from this "
- "point onward. Write memory at address %s?"),
- paddress (target_gdbarch (), offset)))
- error (_("Process record canceled the operation."));
-
- /* Destroy the record from here forward. */
- record_list_release_following (record_list);
- }
-
- /* Check record_insn_num */
- record_check_insn_num (0);
-
- /* Record registers change to list as an instruction. */
- record_arch_list_head = NULL;
- record_arch_list_tail = NULL;
- if (record_arch_list_add_mem (offset, len))
- {
- record_list_release (record_arch_list_tail);
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: failed to record "
- "execution log.");
- return -1;
- }
- if (record_arch_list_add_end ())
- {
- record_list_release (record_arch_list_tail);
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "Process record: failed to record "
- "execution log.");
- return -1;
- }
- record_list->next = record_arch_list_head;
- record_arch_list_head->prev = record_list;
- record_list = record_arch_list_tail;
-
- if (record_insn_num == record_insn_max_num && record_insn_max_num)
- record_list_release_first ();
- else
- record_insn_num++;
- }
-
- return record_beneath_to_xfer_partial (record_beneath_to_xfer_partial_ops,
- object, annex, readbuf, writebuf,
- offset, len);
-}
-
-/* This structure represents a breakpoint inserted while the record
- target is active. We use this to know when to install/remove
- breakpoints in/from the target beneath. For example, a breakpoint
- may be inserted while recording, but removed when not replaying nor
- recording. In that case, the breakpoint had not been inserted on
- the target beneath, so we should not try to remove it there. */
-
-struct record_breakpoint
-{
- /* The address and address space the breakpoint was set at. */
- struct address_space *address_space;
- CORE_ADDR addr;
-
- /* True when the breakpoint has been also installed in the target
- beneath. This will be false for breakpoints set during replay or
- when recording. */
- int in_target_beneath;
-};
-
-typedef struct record_breakpoint *record_breakpoint_p;
-DEF_VEC_P(record_breakpoint_p);
-
-/* The list of breakpoints inserted while the record target is
- active. */
-VEC(record_breakpoint_p) *record_breakpoints = NULL;
-
-static void
-record_sync_record_breakpoints (struct bp_location *loc, void *data)
-{
- if (loc->loc_type != bp_loc_software_breakpoint)
- return;
-
- if (loc->inserted)
- {
- struct record_breakpoint *bp = XNEW (struct record_breakpoint);
-
- bp->addr = loc->target_info.placed_address;
- bp->address_space = loc->target_info.placed_address_space;
-
- bp->in_target_beneath = 1;
-
- VEC_safe_push (record_breakpoint_p, record_breakpoints, bp);
- }
-}
-
-/* Sync existing breakpoints to record_breakpoints. */
-
-static void
-record_init_record_breakpoints (void)
-{
- VEC_free (record_breakpoint_p, record_breakpoints);
-
- iterate_over_bp_locations (record_sync_record_breakpoints);
-}
-
-/* Behavior is conditional on RECORD_IS_REPLAY. We will not actually
- insert or remove breakpoints in the real target when replaying, nor
- when recording. */
-
-static int
-record_insert_breakpoint (struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
-{
- struct record_breakpoint *bp;
- int in_target_beneath = 0;
-
- if (!RECORD_IS_REPLAY)
- {
- /* When recording, we currently always single-step, so we don't
- really need to install regular breakpoints in the inferior.
- However, we do have to insert software single-step
- breakpoints, in case the target can't hardware step. To keep
- things single, we always insert. */
- struct cleanup *old_cleanups;
- int ret;
-
- old_cleanups = record_gdb_operation_disable_set ();
- ret = record_beneath_to_insert_breakpoint (gdbarch, bp_tgt);
- do_cleanups (old_cleanups);
-
- if (ret != 0)
- return ret;
-
- in_target_beneath = 1;
- }
-
- bp = XNEW (struct record_breakpoint);
- bp->addr = bp_tgt->placed_address;
- bp->address_space = bp_tgt->placed_address_space;
- bp->in_target_beneath = in_target_beneath;
- VEC_safe_push (record_breakpoint_p, record_breakpoints, bp);
- return 0;
-}
-
-/* "to_remove_breakpoint" method for process record target. */
-
-static int
-record_remove_breakpoint (struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
-{
- struct record_breakpoint *bp;
- int ix;
-
- for (ix = 0;
- VEC_iterate (record_breakpoint_p, record_breakpoints, ix, bp);
- ++ix)
- {
- if (bp->addr == bp_tgt->placed_address
- && bp->address_space == bp_tgt->placed_address_space)
- {
- if (bp->in_target_beneath)
- {
- struct cleanup *old_cleanups;
- int ret;
-
- old_cleanups = record_gdb_operation_disable_set ();
- ret = record_beneath_to_remove_breakpoint (gdbarch, bp_tgt);
- do_cleanups (old_cleanups);
-
- if (ret != 0)
- return ret;
- }
-
- VEC_unordered_remove (record_breakpoint_p, record_breakpoints, ix);
- return 0;
- }
- }
-
- gdb_assert_not_reached ("removing unknown breakpoint");
-}
-
-/* "to_can_execute_reverse" method for process record target. */
-
-static int
-record_can_execute_reverse (void)
-{
- return 1;
-}
-
-/* "to_get_bookmark" method for process record and prec over core. */
-
-static gdb_byte *
-record_get_bookmark (char *args, int from_tty)
-{
- gdb_byte *ret = NULL;
-
- /* Return stringified form of instruction count. */
- if (record_list && record_list->type == record_end)
- ret = xstrdup (pulongest (record_list->u.end.insn_num));
-
- if (record_debug)
- {
- if (ret)
- fprintf_unfiltered (gdb_stdlog,
- "record_get_bookmark returns %s\n", ret);
- else
- fprintf_unfiltered (gdb_stdlog,
- "record_get_bookmark returns NULL\n");
- }
- return ret;
-}
-
-/* The implementation of the command "record goto". */
-static void cmd_record_goto (char *, int);
-
-/* "to_goto_bookmark" method for process record and prec over core. */
-
-static void
-record_goto_bookmark (gdb_byte *bookmark, int from_tty)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- "record_goto_bookmark receives %s\n", bookmark);
-
- if (bookmark[0] == '\'' || bookmark[0] == '\"')
- {
- if (bookmark[strlen (bookmark) - 1] != bookmark[0])
- error (_("Unbalanced quotes: %s"), bookmark);
-
- /* Strip trailing quote. */
- bookmark[strlen (bookmark) - 1] = '\0';
- /* Strip leading quote. */
- bookmark++;
- /* Pass along to cmd_record_goto. */
- }
-
- cmd_record_goto ((char *) bookmark, from_tty);
- return;
-}
-
-static void
-record_async (void (*callback) (enum inferior_event_type event_type,
- void *context), void *context)
-{
- /* If we're on top of a line target (e.g., linux-nat, remote), then
- set it to async mode as well. Will be NULL if we're sitting on
- top of the core target, for "record restore". */
- if (record_beneath_to_async != NULL)
- record_beneath_to_async (callback, context);
-}
-
-static int
-record_can_async_p (void)
-{
- /* We only enable async when the user specifically asks for it. */
- return target_async_permitted;
-}
-
-static int
-record_is_async_p (void)
-{
- /* We only enable async when the user specifically asks for it. */
- return target_async_permitted;
-}
-
-static enum exec_direction_kind
-record_execution_direction (void)
-{
- return record_execution_dir;
-}
-
-static void
-init_record_ops (void)
-{
- record_ops.to_shortname = "record";
- record_ops.to_longname = "Process record and replay target";
- record_ops.to_doc =
- "Log program while executing and replay execution from log.";
- record_ops.to_open = record_open;
- record_ops.to_close = record_close;
- record_ops.to_resume = record_resume;
- record_ops.to_wait = record_wait;
- record_ops.to_disconnect = record_disconnect;
- record_ops.to_detach = record_detach;
- record_ops.to_mourn_inferior = record_mourn_inferior;
- record_ops.to_kill = record_kill;
- record_ops.to_create_inferior = find_default_create_inferior;
- record_ops.to_store_registers = record_store_registers;
- record_ops.to_xfer_partial = record_xfer_partial;
- record_ops.to_insert_breakpoint = record_insert_breakpoint;
- record_ops.to_remove_breakpoint = record_remove_breakpoint;
- record_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint;
- record_ops.to_stopped_data_address = record_stopped_data_address;
- record_ops.to_can_execute_reverse = record_can_execute_reverse;
- record_ops.to_stratum = record_stratum;
- /* Add bookmark target methods. */
- record_ops.to_get_bookmark = record_get_bookmark;
- record_ops.to_goto_bookmark = record_goto_bookmark;
- record_ops.to_async = record_async;
- record_ops.to_can_async_p = record_can_async_p;
- record_ops.to_is_async_p = record_is_async_p;
- record_ops.to_execution_direction = record_execution_direction;
- record_ops.to_magic = OPS_MAGIC;
-}
-
-/* "to_resume" method for prec over corefile. */
-
-static void
-record_core_resume (struct target_ops *ops, ptid_t ptid, int step,
- enum gdb_signal signal)
-{
- record_resume_step = step;
- record_resumed = 1;
- record_execution_dir = execution_direction;
-
- /* We are about to start executing the inferior (or simulate it),
- let's register it with the event loop. */
- if (target_can_async_p ())
- {
- target_async (inferior_event_handler, 0);
-
- /* Notify the event loop there's an event to wait for. */
- mark_async_event_handler (record_async_inferior_event_token);
- }
-}
-
-/* "to_kill" method for prec over corefile. */
-
-static void
-record_core_kill (struct target_ops *ops)
-{
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Process record: record_core_kill\n");
-
- unpush_target (&record_core_ops);
-}
-
-/* "to_fetch_registers" method for prec over corefile. */
-
-static void
-record_core_fetch_registers (struct target_ops *ops,
- struct regcache *regcache,
- int regno)
-{
- if (regno < 0)
- {
- int num = gdbarch_num_regs (get_regcache_arch (regcache));
- int i;
-
- for (i = 0; i < num; i ++)
- regcache_raw_supply (regcache, i,
- record_core_regbuf + MAX_REGISTER_SIZE * i);
- }
- else
- regcache_raw_supply (regcache, regno,
- record_core_regbuf + MAX_REGISTER_SIZE * regno);
-}
-
-/* "to_prepare_to_store" method for prec over corefile. */
-
-static void
-record_core_prepare_to_store (struct regcache *regcache)
-{
-}
-
-/* "to_store_registers" method for prec over corefile. */
-
-static void
-record_core_store_registers (struct target_ops *ops,
- struct regcache *regcache,
- int regno)
-{
- if (record_gdb_operation_disable)
- regcache_raw_collect (regcache, regno,
- record_core_regbuf + MAX_REGISTER_SIZE * regno);
- else
- error (_("You can't do that without a process to debug."));
-}
-
-/* "to_xfer_partial" method for prec over corefile. */
-
-static LONGEST
-record_core_xfer_partial (struct target_ops *ops, enum target_object object,
- const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf, ULONGEST offset,
- LONGEST len)
-{
- if (object == TARGET_OBJECT_MEMORY)
- {
- if (record_gdb_operation_disable || !writebuf)
- {
- struct target_section *p;
-
- for (p = record_core_start; p < record_core_end; p++)
- {
- if (offset >= p->addr)
- {
- struct record_core_buf_entry *entry;
- ULONGEST sec_offset;
-
- if (offset >= p->endaddr)
- continue;
-
- if (offset + len > p->endaddr)
- len = p->endaddr - offset;
-
- sec_offset = offset - p->addr;
-
- /* Read readbuf or write writebuf p, offset, len. */
- /* Check flags. */
- if (p->the_bfd_section->flags & SEC_CONSTRUCTOR
- || (p->the_bfd_section->flags & SEC_HAS_CONTENTS) == 0)
- {
- if (readbuf)
- memset (readbuf, 0, len);
- return len;
- }
- /* Get record_core_buf_entry. */
- for (entry = record_core_buf_list; entry;
- entry = entry->prev)
- if (entry->p == p)
- break;
- if (writebuf)
- {
- if (!entry)
- {
- /* Add a new entry. */
- entry = (struct record_core_buf_entry *)
- xmalloc (sizeof (struct record_core_buf_entry));
- entry->p = p;
- if (!bfd_malloc_and_get_section (p->bfd,
- p->the_bfd_section,
- &entry->buf))
- {
- xfree (entry);
- return 0;
- }
- entry->prev = record_core_buf_list;
- record_core_buf_list = entry;
- }
-
- memcpy (entry->buf + sec_offset, writebuf,
- (size_t) len);
- }
- else
- {
- if (!entry)
- return record_beneath_to_xfer_partial
- (record_beneath_to_xfer_partial_ops,
- object, annex, readbuf, writebuf,
- offset, len);
-
- memcpy (readbuf, entry->buf + sec_offset,
- (size_t) len);
- }
-
- return len;
- }
- }
-
- return -1;
- }
- else
- error (_("You can't do that without a process to debug."));
- }
-
- return record_beneath_to_xfer_partial (record_beneath_to_xfer_partial_ops,
- object, annex, readbuf, writebuf,
- offset, len);
-}
-
-/* "to_insert_breakpoint" method for prec over corefile. */
-
-static int
-record_core_insert_breakpoint (struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
-{
- return 0;
-}
-
-/* "to_remove_breakpoint" method for prec over corefile. */
-
-static int
-record_core_remove_breakpoint (struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
-{
- return 0;
-}
-
-/* "to_has_execution" method for prec over corefile. */
-
-static int
-record_core_has_execution (struct target_ops *ops, ptid_t the_ptid)
-{
- return 1;
-}
-
-static void
-init_record_core_ops (void)
-{
- record_core_ops.to_shortname = "record-core";
- record_core_ops.to_longname = "Process record and replay target";
- record_core_ops.to_doc =
- "Log program while executing and replay execution from log.";
- record_core_ops.to_open = record_open;
- record_core_ops.to_close = record_close;
- record_core_ops.to_resume = record_core_resume;
- record_core_ops.to_wait = record_wait;
- record_core_ops.to_kill = record_core_kill;
- record_core_ops.to_fetch_registers = record_core_fetch_registers;
- record_core_ops.to_prepare_to_store = record_core_prepare_to_store;
- record_core_ops.to_store_registers = record_core_store_registers;
- record_core_ops.to_xfer_partial = record_core_xfer_partial;
- record_core_ops.to_insert_breakpoint = record_core_insert_breakpoint;
- record_core_ops.to_remove_breakpoint = record_core_remove_breakpoint;
- record_core_ops.to_stopped_by_watchpoint = record_stopped_by_watchpoint;
- record_core_ops.to_stopped_data_address = record_stopped_data_address;
- record_core_ops.to_can_execute_reverse = record_can_execute_reverse;
- record_core_ops.to_has_execution = record_core_has_execution;
- record_core_ops.to_stratum = record_stratum;
- /* Add bookmark target methods. */
- record_core_ops.to_get_bookmark = record_get_bookmark;
- record_core_ops.to_goto_bookmark = record_goto_bookmark;
- record_core_ops.to_async = record_async;
- record_core_ops.to_can_async_p = record_can_async_p;
- record_core_ops.to_is_async_p = record_is_async_p;
- record_core_ops.to_execution_direction = record_execution_direction;
- record_core_ops.to_magic = OPS_MAGIC;
-}
-
/* Implement "show record debug" command. */
static void
@@ -2358,551 +205,6 @@ info_record_command (char *args, int from_tty)
record_insn_max_num);
}
-/* Record log save-file format
- Version 1 (never released)
-
- Header:
- 4 bytes: magic number htonl(0x20090829).
- NOTE: be sure to change whenever this file format changes!
-
- Records:
- record_end:
- 1 byte: record type (record_end, see enum record_type).
- record_reg:
- 1 byte: record type (record_reg, see enum record_type).
- 8 bytes: register id (network byte order).
- MAX_REGISTER_SIZE bytes: register value.
- record_mem:
- 1 byte: record type (record_mem, see enum record_type).
- 8 bytes: memory length (network byte order).
- 8 bytes: memory address (network byte order).
- n bytes: memory value (n == memory length).
-
- Version 2
- 4 bytes: magic number netorder32(0x20091016).
- NOTE: be sure to change whenever this file format changes!
-
- Records:
- record_end:
- 1 byte: record type (record_end, see enum record_type).
- 4 bytes: signal
- 4 bytes: instruction count
- record_reg:
- 1 byte: record type (record_reg, see enum record_type).
- 4 bytes: register id (network byte order).
- n bytes: register value (n == actual register size).
- (eg. 4 bytes for x86 general registers).
- record_mem:
- 1 byte: record type (record_mem, see enum record_type).
- 4 bytes: memory length (network byte order).
- 8 bytes: memory address (network byte order).
- n bytes: memory value (n == memory length).
-
-*/
-
-/* bfdcore_read -- read bytes from a core file section. */
-
-static inline void
-bfdcore_read (bfd *obfd, asection *osec, void *buf, int len, int *offset)
-{
- int ret = bfd_get_section_contents (obfd, osec, buf, *offset, len);
-
- if (ret)
- *offset += len;
- else
- error (_("Failed to read %d bytes from core file %s ('%s')."),
- len, bfd_get_filename (obfd),
- bfd_errmsg (bfd_get_error ()));
-}
-
-static inline uint64_t
-netorder64 (uint64_t input)
-{
- uint64_t ret;
-
- store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret),
- BFD_ENDIAN_BIG, input);
- return ret;
-}
-
-static inline uint32_t
-netorder32 (uint32_t input)
-{
- uint32_t ret;
-
- store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret),
- BFD_ENDIAN_BIG, input);
- return ret;
-}
-
-static inline uint16_t
-netorder16 (uint16_t input)
-{
- uint16_t ret;
-
- store_unsigned_integer ((gdb_byte *) &ret, sizeof (ret),
- BFD_ENDIAN_BIG, input);
- return ret;
-}
-
-/* Restore the execution log from a core_bfd file. */
-static void
-record_restore (void)
-{
- uint32_t magic;
- struct cleanup *old_cleanups;
- struct record_entry *rec;
- asection *osec;
- uint32_t osec_size;
- int bfd_offset = 0;
- struct regcache *regcache;
-
- /* We restore the execution log from the open core bfd,
- if there is one. */
- if (core_bfd == NULL)
- return;
-
- /* "record_restore" can only be called when record list is empty. */
- gdb_assert (record_first.next == NULL);
-
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Restoring recording from core file.\n");
-
- /* Now need to find our special note section. */
- osec = bfd_get_section_by_name (core_bfd, "null0");
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Find precord section %s.\n",
- osec ? "succeeded" : "failed");
- if (osec == NULL)
- return;
- osec_size = bfd_section_size (core_bfd, osec);
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "%s", bfd_section_name (core_bfd, osec));
-
- /* Check the magic code. */
- bfdcore_read (core_bfd, osec, &magic, sizeof (magic), &bfd_offset);
- if (magic != RECORD_FILE_MAGIC)
- error (_("Version mis-match or file format error in core file %s."),
- bfd_get_filename (core_bfd));
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Reading 4-byte magic cookie "
- "RECORD_FILE_MAGIC (0x%s)\n",
- phex_nz (netorder32 (magic), 4));
-
- /* Restore the entries in recfd into record_arch_list_head and
- record_arch_list_tail. */
- record_arch_list_head = NULL;
- record_arch_list_tail = NULL;
- record_insn_num = 0;
- old_cleanups = make_cleanup (record_arch_list_cleanups, 0);
- regcache = get_current_regcache ();
-
- while (1)
- {
- uint8_t rectype;
- uint32_t regnum, len, signal, count;
- uint64_t addr;
-
- /* We are finished when offset reaches osec_size. */
- if (bfd_offset >= osec_size)
- break;
- bfdcore_read (core_bfd, osec, &rectype, sizeof (rectype), &bfd_offset);
-
- switch (rectype)
- {
- case record_reg: /* reg */
- /* Get register number to regnum. */
- bfdcore_read (core_bfd, osec, ®num,
- sizeof (regnum), &bfd_offset);
- regnum = netorder32 (regnum);
-
- rec = record_reg_alloc (regcache, regnum);
-
- /* Get val. */
- bfdcore_read (core_bfd, osec, record_get_loc (rec),
- rec->u.reg.len, &bfd_offset);
-
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Reading register %d (1 "
- "plus %lu plus %d bytes)\n",
- rec->u.reg.num,
- (unsigned long) sizeof (regnum),
- rec->u.reg.len);
- break;
-
- case record_mem: /* mem */
- /* Get len. */
- bfdcore_read (core_bfd, osec, &len,
- sizeof (len), &bfd_offset);
- len = netorder32 (len);
-
- /* Get addr. */
- bfdcore_read (core_bfd, osec, &addr,
- sizeof (addr), &bfd_offset);
- addr = netorder64 (addr);
-
- rec = record_mem_alloc (addr, len);
-
- /* Get val. */
- bfdcore_read (core_bfd, osec, record_get_loc (rec),
- rec->u.mem.len, &bfd_offset);
-
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Reading memory %s (1 plus "
- "%lu plus %lu plus %d bytes)\n",
- paddress (get_current_arch (),
- rec->u.mem.addr),
- (unsigned long) sizeof (addr),
- (unsigned long) sizeof (len),
- rec->u.mem.len);
- break;
-
- case record_end: /* end */
- rec = record_end_alloc ();
- record_insn_num ++;
-
- /* Get signal value. */
- bfdcore_read (core_bfd, osec, &signal,
- sizeof (signal), &bfd_offset);
- signal = netorder32 (signal);
- rec->u.end.sigval = signal;
-
- /* Get insn count. */
- bfdcore_read (core_bfd, osec, &count,
- sizeof (count), &bfd_offset);
- count = netorder32 (count);
- rec->u.end.insn_num = count;
- record_insn_count = count + 1;
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Reading record_end (1 + "
- "%lu + %lu bytes), offset == %s\n",
- (unsigned long) sizeof (signal),
- (unsigned long) sizeof (count),
- paddress (get_current_arch (),
- bfd_offset));
- break;
-
- default:
- error (_("Bad entry type in core file %s."),
- bfd_get_filename (core_bfd));
- break;
- }
-
- /* Add rec to record arch list. */
- record_arch_list_add (rec);
- }
-
- discard_cleanups (old_cleanups);
-
- /* Add record_arch_list_head to the end of record list. */
- record_first.next = record_arch_list_head;
- record_arch_list_head->prev = &record_first;
- record_arch_list_tail->next = NULL;
- record_list = &record_first;
-
- /* Update record_insn_max_num. */
- if (record_insn_num > record_insn_max_num)
- {
- record_insn_max_num = record_insn_num;
- warning (_("Auto increase record/replay buffer limit to %d."),
- record_insn_max_num);
- }
-
- /* Succeeded. */
- printf_filtered (_("Restored records from core file %s.\n"),
- bfd_get_filename (core_bfd));
-
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
-}
-
-/* bfdcore_write -- write bytes into a core file section. */
-
-static inline void
-bfdcore_write (bfd *obfd, asection *osec, void *buf, int len, int *offset)
-{
- int ret = bfd_set_section_contents (obfd, osec, buf, *offset, len);
-
- if (ret)
- *offset += len;
- else
- error (_("Failed to write %d bytes to core file %s ('%s')."),
- len, bfd_get_filename (obfd),
- bfd_errmsg (bfd_get_error ()));
-}
-
-/* Restore the execution log from a file. We use a modified elf
- corefile format, with an extra section for our data. */
-
-static void
-cmd_record_restore (char *args, int from_tty)
-{
- core_file_command (args, from_tty);
- record_open (args, from_tty);
-}
-
-static void
-record_save_cleanups (void *data)
-{
- bfd *obfd = data;
- char *pathname = xstrdup (bfd_get_filename (obfd));
-
- gdb_bfd_unref (obfd);
- unlink (pathname);
- xfree (pathname);
-}
-
-/* Save the execution log to a file. We use a modified elf corefile
- format, with an extra section for our data. */
-
-static void
-cmd_record_save (char *args, int from_tty)
-{
- char *recfilename, recfilename_buffer[40];
- struct record_entry *cur_record_list;
- uint32_t magic;
- struct regcache *regcache;
- struct gdbarch *gdbarch;
- struct cleanup *old_cleanups;
- struct cleanup *set_cleanups;
- bfd *obfd;
- int save_size = 0;
- asection *osec = NULL;
- int bfd_offset = 0;
-
- if (strcmp (current_target.to_shortname, "record") != 0)
- error (_("This command can only be used with target 'record'.\n"
- "Use 'target record' first.\n"));
-
- if (args && *args)
- recfilename = args;
- else
- {
- /* Default recfile name is "gdb_record.PID". */
- snprintf (recfilename_buffer, sizeof (recfilename_buffer),
- "gdb_record.%d", PIDGET (inferior_ptid));
- recfilename = recfilename_buffer;
- }
-
- /* Open the save file. */
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog, "Saving execution log to core file '%s'\n",
- recfilename);
-
- /* Open the output file. */
- obfd = create_gcore_bfd (recfilename);
- old_cleanups = make_cleanup (record_save_cleanups, obfd);
-
- /* Save the current record entry to "cur_record_list". */
- cur_record_list = record_list;
-
- /* Get the values of regcache and gdbarch. */
- regcache = get_current_regcache ();
- gdbarch = get_regcache_arch (regcache);
-
- /* Disable the GDB operation record. */
- set_cleanups = record_gdb_operation_disable_set ();
-
- /* Reverse execute to the begin of record list. */
- while (1)
- {
- /* Check for beginning and end of log. */
- if (record_list == &record_first)
- break;
-
- record_exec_insn (regcache, gdbarch, record_list);
-
- if (record_list->prev)
- record_list = record_list->prev;
- }
-
- /* Compute the size needed for the extra bfd section. */
- save_size = 4; /* magic cookie */
- for (record_list = record_first.next; record_list;
- record_list = record_list->next)
- switch (record_list->type)
- {
- case record_end:
- save_size += 1 + 4 + 4;
- break;
- case record_reg:
- save_size += 1 + 4 + record_list->u.reg.len;
- break;
- case record_mem:
- save_size += 1 + 4 + 8 + record_list->u.mem.len;
- break;
- }
-
- /* Make the new bfd section. */
- osec = bfd_make_section_anyway_with_flags (obfd, "precord",
- SEC_HAS_CONTENTS
- | SEC_READONLY);
- if (osec == NULL)
- error (_("Failed to create 'precord' section for corefile %s: %s"),
- recfilename,
- bfd_errmsg (bfd_get_error ()));
- bfd_set_section_size (obfd, osec, save_size);
- bfd_set_section_vma (obfd, osec, 0);
- bfd_set_section_alignment (obfd, osec, 0);
- bfd_section_lma (obfd, osec) = 0;
-
- /* Save corefile state. */
- write_gcore_file (obfd);
-
- /* Write out the record log. */
- /* Write the magic code. */
- magic = RECORD_FILE_MAGIC;
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Writing 4-byte magic cookie "
- "RECORD_FILE_MAGIC (0x%s)\n",
- phex_nz (magic, 4));
- bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset);
-
- /* Save the entries to recfd and forward execute to the end of
- record list. */
- record_list = &record_first;
- while (1)
- {
- /* Save entry. */
- if (record_list != &record_first)
- {
- uint8_t type;
- uint32_t regnum, len, signal, count;
- uint64_t addr;
-
- type = record_list->type;
- bfdcore_write (obfd, osec, &type, sizeof (type), &bfd_offset);
-
- switch (record_list->type)
- {
- case record_reg: /* reg */
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Writing register %d (1 "
- "plus %lu plus %d bytes)\n",
- record_list->u.reg.num,
- (unsigned long) sizeof (regnum),
- record_list->u.reg.len);
-
- /* Write regnum. */
- regnum = netorder32 (record_list->u.reg.num);
- bfdcore_write (obfd, osec, ®num,
- sizeof (regnum), &bfd_offset);
-
- /* Write regval. */
- bfdcore_write (obfd, osec, record_get_loc (record_list),
- record_list->u.reg.len, &bfd_offset);
- break;
-
- case record_mem: /* mem */
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Writing memory %s (1 plus "
- "%lu plus %lu plus %d bytes)\n",
- paddress (gdbarch,
- record_list->u.mem.addr),
- (unsigned long) sizeof (addr),
- (unsigned long) sizeof (len),
- record_list->u.mem.len);
-
- /* Write memlen. */
- len = netorder32 (record_list->u.mem.len);
- bfdcore_write (obfd, osec, &len, sizeof (len), &bfd_offset);
-
- /* Write memaddr. */
- addr = netorder64 (record_list->u.mem.addr);
- bfdcore_write (obfd, osec, &addr,
- sizeof (addr), &bfd_offset);
-
- /* Write memval. */
- bfdcore_write (obfd, osec, record_get_loc (record_list),
- record_list->u.mem.len, &bfd_offset);
- break;
-
- case record_end:
- if (record_debug)
- fprintf_unfiltered (gdb_stdlog,
- " Writing record_end (1 + "
- "%lu + %lu bytes)\n",
- (unsigned long) sizeof (signal),
- (unsigned long) sizeof (count));
- /* Write signal value. */
- signal = netorder32 (record_list->u.end.sigval);
- bfdcore_write (obfd, osec, &signal,
- sizeof (signal), &bfd_offset);
-
- /* Write insn count. */
- count = netorder32 (record_list->u.end.insn_num);
- bfdcore_write (obfd, osec, &count,
- sizeof (count), &bfd_offset);
- break;
- }
- }
-
- /* Execute entry. */
- record_exec_insn (regcache, gdbarch, record_list);
-
- if (record_list->next)
- record_list = record_list->next;
- else
- break;
- }
-
- /* Reverse execute to cur_record_list. */
- while (1)
- {
- /* Check for beginning and end of log. */
- if (record_list == cur_record_list)
- break;
-
- record_exec_insn (regcache, gdbarch, record_list);
-
- if (record_list->prev)
- record_list = record_list->prev;
- }
-
- do_cleanups (set_cleanups);
- gdb_bfd_unref (obfd);
- discard_cleanups (old_cleanups);
-
- /* Succeeded. */
- printf_filtered (_("Saved core file %s with execution log.\n"),
- recfilename);
-}
-
-/* record_goto_insn -- rewind the record log (forward or backward,
- depending on DIR) to the given entry, changing the program state
- correspondingly. */
-
-static void
-record_goto_insn (struct record_entry *entry,
- enum exec_direction_kind dir)
-{
- struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
- struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
-
- /* Assume everything is valid: we will hit the entry,
- and we will not hit the end of the recording. */
-
- if (dir == EXEC_FORWARD)
- record_list = record_list->next;
-
- do
- {
- record_exec_insn (regcache, gdbarch, record_list);
- if (dir == EXEC_REVERSE)
- record_list = record_list->prev;
- else
- record_list = record_list->next;
- } while (record_list != entry);
- do_cleanups (set_cleanups);
-}
-
/* "record goto" command. Argument is an instruction number,
as given by "info record".
diff --git a/gdb/record.h b/gdb/record.h
index 9cf9223..88e59e2 100644
--- a/gdb/record.h
+++ b/gdb/record.h
@@ -23,12 +23,6 @@
#define RECORD_IS_USED (current_target.to_stratum == record_stratum)
extern unsigned int record_debug;
-extern int record_memory_query;
-
-extern int record_arch_list_add_reg (struct regcache *regcache, int num);
-extern int record_arch_list_add_mem (CORE_ADDR addr, int len);
-extern int record_arch_list_add_end (void);
-extern struct cleanup *record_gdb_operation_disable_set (void);
/* Wrapper for target_read_memory that prints a debug message if
reading memory fails. */
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 15/21] record: add "record instruction-history" command
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (17 preceding siblings ...)
2013-03-08 9:19 ` [patch v10 10/21] record: split record Markus Metzger
@ 2013-03-08 9:19 ` Markus Metzger
2013-03-08 9:19 ` [patch v10 17/21] record, btrace: add record-btrace target Markus Metzger
` (3 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:19 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Add a command to provide a disassembly of the execution trace log.
The command iterates over the execution trace log similar to the
"list" command.
Doc approved by Eli Zaretskii.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* target.h (target_ops) <to_insn_history, to_insn_history_from,
to_insn_history_range>: New fields.
(target_insn_history): New.
(target_insn_history_from): New.
(target_insn_history_range): New.
* target.c (target_insn_history): New.
(target_insn_history_from): New.
(target_insn_history_range): New.
* record.c: Include cli/cli-utils.h, disasm.h, ctype.h.
(record_insn_history_size): New.
(get_insn_number): New.
(get_context_size): New.
(no_chunk): New.
(get_insn_history_modifiers): New.
(cmd_record_insn_history): New.
(_initialize_record): Add "set/show record instruction-history-size"
command. Add "record instruction-history" command.
---
gdb/record.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/target.c | 51 +++++++++++++++
gdb/target.h | 25 +++++++
3 files changed, 279 insertions(+), 0 deletions(-)
diff --git a/gdb/record.c b/gdb/record.c
index abd8216..c71842f 100644
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -24,10 +24,17 @@
#include "observer.h"
#include "inferior.h"
#include "common/common-utils.h"
+#include "cli/cli-utils.h"
+#include "disasm.h"
+
+#include <ctype.h>
/* This is the debug switch for process record. */
unsigned int record_debug = 0;
+/* The number of instructions to print in "record instruction-history". */
+static unsigned int record_insn_history_size = 10;
+
struct cmd_list_element *record_cmdlist = NULL;
struct cmd_list_element *set_record_cmdlist = NULL;
struct cmd_list_element *show_record_cmdlist = NULL;
@@ -289,6 +296,176 @@ cmd_record_goto (char *arg, int from_tty)
}
}
+/* Read an instruction number from an argument string. */
+
+static ULONGEST
+get_insn_number (char **arg)
+{
+ ULONGEST number;
+ const char *begin, *end, *pos;
+
+ begin = *arg;
+ pos = skip_spaces_const (begin);
+
+ if (!isdigit (*pos))
+ error (_("Expected positive number, got: %s."), pos);
+
+ number = strtoulst (pos, &end, 10);
+
+ *arg += (end - begin);
+
+ return number;
+}
+
+/* Read a context size from an argument string. */
+
+static int
+get_context_size (char **arg)
+{
+ char *pos;
+ int number;
+
+ pos = skip_spaces (*arg);
+
+ if (!isdigit (*pos))
+ error (_("Expected positive number, got: %s."), pos);
+
+ return strtol (pos, arg, 10);
+}
+
+/* Complain about junk at the end of an argument string. */
+
+static void
+no_chunk (char *arg)
+{
+ if (*arg != 0)
+ error (_("Junk after argument: %s."), arg);
+}
+
+/* Read instruction-history modifiers from an argument string. */
+
+static int
+get_insn_history_modifiers (char **arg)
+{
+ int modifiers;
+ char *args;
+
+ modifiers = 0;
+ args = *arg;
+
+ if (args == NULL)
+ return modifiers;
+
+ while (*args == '/')
+ {
+ ++args;
+
+ if (*args == '\0')
+ error (_("Missing modifier."));
+
+ for (; *args; ++args)
+ {
+ if (isspace (*args))
+ break;
+
+ if (*args == '/')
+ continue;
+
+ switch (*args)
+ {
+ case 'm':
+ modifiers |= DISASSEMBLY_SOURCE;
+ modifiers |= DISASSEMBLY_FILENAME;
+ break;
+ case 'r':
+ modifiers |= DISASSEMBLY_RAW_INSN;
+ break;
+ case 'f':
+ modifiers |= DISASSEMBLY_OMIT_FNAME;
+ break;
+ default:
+ error (_("Invalid modifier: %c."), *args);
+ }
+ }
+
+ args = skip_spaces (args);
+ }
+
+ /* Update the argument string. */
+ *arg = args;
+
+ return modifiers;
+}
+
+/* The "record instruction-history" command. */
+
+static void
+cmd_record_insn_history (char *arg, int from_tty)
+{
+ int flags, size;
+
+ require_record_target ();
+
+ flags = get_insn_history_modifiers (&arg);
+
+ /* We use a signed size to also indicate the direction. Make sure that
+ unlimited remains unlimited. */
+ size = (int) record_insn_history_size;
+ if (size < 0)
+ size = INT_MAX;
+
+ if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0)
+ target_insn_history (size, flags);
+ else if (strcmp (arg, "-") == 0)
+ target_insn_history (-size, flags);
+ else
+ {
+ ULONGEST begin, end;
+
+ begin = get_insn_number (&arg);
+
+ if (*arg == ',')
+ {
+ arg = skip_spaces (++arg);
+
+ if (*arg == '+')
+ {
+ arg += 1;
+ size = get_context_size (&arg);
+
+ no_chunk (arg);
+
+ target_insn_history_from (begin, size, flags);
+ }
+ else if (*arg == '-')
+ {
+ arg += 1;
+ size = get_context_size (&arg);
+
+ no_chunk (arg);
+
+ target_insn_history_from (begin, -size, flags);
+ }
+ else
+ {
+ end = get_insn_number (&arg);
+
+ no_chunk (arg);
+
+ target_insn_history_range (begin, end, flags);
+ }
+ }
+ else
+ {
+ no_chunk (arg);
+
+ target_insn_history_from (begin, size, flags);
+ }
+
+ dont_repeat ();
+ }
+}
+
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_record;
@@ -305,6 +482,13 @@ _initialize_record (void)
NULL, show_record_debug, &setdebuglist,
&showdebuglist);
+ add_setshow_uinteger_cmd ("instruction-history-size", no_class,
+ &record_insn_history_size, _("\
+Set number of instructions to print in \"record instruction-history\"."), _("\
+Show number of instructions to print in \"record instruction-history\"."),
+ NULL, NULL, NULL, &set_record_cmdlist,
+ &show_record_cmdlist);
+
c = add_prefix_cmd ("record", class_obscure, cmd_record_start,
_("Start recording."),
&record_cmdlist, "record ", 0, &cmdlist);
@@ -346,4 +530,23 @@ Default filename is 'gdb_record.<process_id>'."),
Restore the program to its state at instruction number N.\n\
Argument is instruction number, as shown by 'info record'."),
&record_cmdlist);
+
+ add_cmd ("instruction-history", class_obscure, cmd_record_insn_history, _("\
+Print disassembled instructions stored in the execution log.\n\
+With a /m modifier, source lines are included (if available).\n\
+With a /r modifier, raw instructions in hex are included.\n\
+With a /f modifier, function names are omitted.\n\
+With no argument, disassembles ten more instructions after the previous \
+disassembly.\n\
+\"record instruction-history -\" disassembles ten instructions before a \
+previous disassembly.\n\
+One argument specifies an instruction number as shown by 'info record', and \
+ten instructions are disassembled after that instruction.\n\
+Two arguments with comma between them specify starting and ending instruction \
+numbers to disassemble.\n\
+If the second argument is preceded by '+' or '-', it specifies the distance \
+from the first argument.\n\
+The number of instructions to disassemble can be defined with \"set record \
+instruction-history-size\"."),
+ &record_cmdlist);
}
diff --git a/gdb/target.c b/gdb/target.c
index 78736ad..797163f 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4353,6 +4353,57 @@ target_goto_record (ULONGEST insn)
tcomplain ();
}
+/* See target.h. */
+
+void
+target_insn_history (int size, int flags)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_insn_history != NULL)
+ {
+ t->to_insn_history (size, flags);
+ return;
+ }
+
+ tcomplain ();
+}
+
+/* See target.h. */
+
+void
+target_insn_history_from (ULONGEST from, int size, int flags)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_insn_history_from != NULL)
+ {
+ t->to_insn_history_from (from, size, flags);
+ return;
+ }
+
+ tcomplain ();
+}
+
+/* See target.h. */
+
+void
+target_insn_history_range (ULONGEST begin, ULONGEST end, int flags)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_insn_history_range != NULL)
+ {
+ t->to_insn_history_range (begin, end, flags);
+ return;
+ }
+
+ tcomplain ();
+}
+
static void
debug_to_prepare_to_store (struct regcache *regcache)
{
diff --git a/gdb/target.h b/gdb/target.h
index 821085c..47fa6a3 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -895,6 +895,22 @@ struct target_ops
/* Go to a specific location in the recorded execution trace. */
void (*to_goto_record) (ULONGEST insn);
+ /* Disassemble SIZE instructions in the recorded execution trace from
+ the current position.
+ If SIZE < 0, disassemble abs (SIZE) preceding instructions; otherwise,
+ disassemble SIZE succeeding instructions. */
+ void (*to_insn_history) (int size, int flags);
+
+ /* Disassemble SIZE instructions in the recorded execution trace around
+ FROM.
+ If SIZE < 0, disassemble abs (SIZE) instructions before FROM; otherwise,
+ disassemble SIZE instructions after FROM. */
+ void (*to_insn_history_from) (ULONGEST from, int size, int flags);
+
+ /* Disassemble a section of the recorded execution trace from instruction
+ BEGIN (inclusive) to instruction END (exclusive). */
+ void (*to_insn_history_range) (ULONGEST begin, ULONGEST end, int flags);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -1979,4 +1995,13 @@ extern void target_goto_record_end (void);
/* See to_goto_record in struct target_ops. */
extern void target_goto_record (ULONGEST insn);
+/* See to_insn_history. */
+extern void target_insn_history (int size, int flags);
+
+/* See to_insn_history_from. */
+extern void target_insn_history_from (ULONGEST from, int size, int flags);
+
+/* See to_insn_history_range. */
+extern void target_insn_history_range (ULONGEST begin, ULONGEST end, int flags);
+
#endif /* !defined (TARGET_H) */
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 17/21] record, btrace: add record-btrace target
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (18 preceding siblings ...)
2013-03-08 9:19 ` [patch v10 15/21] record: add "record instruction-history" command Markus Metzger
@ 2013-03-08 9:19 ` Markus Metzger
2013-03-08 9:19 ` [patch v10 18/21] record-btrace, disas: omit pc prefix Markus Metzger
` (2 subsequent siblings)
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:19 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Add a target for branch trace recording. This will replace the btrace
commands added earlier in the patch series.
The target implements the new record sub-commands
"record instruction-history" and
"record function-call-history".
The target does not support reverse execution or navigation in the
recorded execution log.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* Makefile.in (SFILES): Add record-btrace.c
(COMMON_OBS): Add record-btrace.o
* record-btrace.c: New.
* objfiles.c: Include btrace.h.
(free_objfile): call btrace_free_objfile.
---
gdb/Makefile.in | 4 +-
gdb/objfiles.c | 2 +
gdb/record-btrace.c | 688 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 692 insertions(+), 2 deletions(-)
create mode 100644 gdb/record-btrace.c
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index a36d576..5366d9e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -760,7 +760,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
regset.c sol-thread.c windows-termcap.c \
common/gdb_vecs.c common/common-utils.c common/xml-utils.c \
common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c \
- common/format.c btrace.c
+ common/format.c btrace.c record-btrace.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -930,7 +930,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
inferior.o osdata.o gdb_usleep.o record.o record-full.o gcore.o \
gdb_vecs.o jit.o progspace.o skip.o probe.o \
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
- format.o registry.o btrace.o
+ format.o registry.o btrace.o record-btrace.o
TSOBS = inflow.o
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 8c17c14..3017fdf 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -53,6 +53,7 @@
#include "psymtab.h"
#include "solist.h"
#include "gdb_bfd.h"
+#include "btrace.h"
/* Keep a registry of per-objfile data-pointers required by other GDB
modules. */
@@ -567,6 +568,7 @@ free_objfile (struct objfile *objfile)
forget_cached_source_info_for_objfile (objfile);
breakpoint_free_objfile (objfile);
+ btrace_free_objfile (objfile);
/* First do any symbol file specific actions required when we are
finished with a particular symbol file. Note that if the objfile
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
new file mode 100644
index 0000000..66b4a3d
--- /dev/null
+++ b/gdb/record-btrace.c
@@ -0,0 +1,688 @@
+/* Branch trace support for GDB, the GNU debugger.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <markus.t.metzger@intel.com>
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "record.h"
+#include "gdbthread.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "disasm.h"
+#include "observer.h"
+#include "exceptions.h"
+#include "cli/cli-utils.h"
+#include "source.h"
+#include "ui-out.h"
+#include "symtab.h"
+#include "filenames.h"
+
+/* The target_ops of record-btrace. */
+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;
+
+/* Print a record-btrace debug message. Use do ... while (0) to avoid
+ ambiguities when used in if statements. */
+
+#define DEBUG(msg, args...) \
+ do \
+ { \
+ if (record_debug != 0) \
+ fprintf_unfiltered (gdb_stdlog, \
+ "[record-btrace] " msg "\n", ##args); \
+ } \
+ while (0)
+
+
+/* Update the branch trace for the current thread and return a pointer to its
+ branch trace information struct.
+
+ Throws an error if there is no thread or no trace. This function never
+ returns NULL. */
+
+static struct btrace_thread_info *
+require_btrace (void)
+{
+ struct thread_info *tp;
+ struct btrace_thread_info *btinfo;
+
+ DEBUG ("require");
+
+ tp = find_thread_ptid (inferior_ptid);
+ if (tp == NULL)
+ error (_("No thread."));
+
+ btrace_fetch (tp);
+
+ btinfo = &tp->btrace;
+
+ if (VEC_empty (btrace_inst_s, btinfo->itrace))
+ error (_("No trace."));
+
+ return btinfo;
+}
+
+/* Enable branch tracing for one thread. Warn on errors. */
+
+static void
+record_btrace_enable_warn (struct thread_info *tp)
+{
+ volatile struct gdb_exception error;
+
+ TRY_CATCH (error, RETURN_MASK_ERROR)
+ btrace_enable (tp);
+
+ if (error.message != NULL)
+ warning ("%s", error.message);
+}
+
+/* Callback function to disable branch tracing for one thread. */
+
+static void
+record_btrace_disable_callback (void *arg)
+{
+ volatile struct gdb_exception error;
+ struct thread_info *tp;
+
+ tp = arg;
+
+ TRY_CATCH (error, RETURN_MASK_ERROR)
+ btrace_disable (tp);
+
+ if (error.message != NULL)
+ warning ("%s", error.message);
+}
+
+/* Enable automatic tracing of new threads. */
+
+static void
+record_btrace_auto_enable (void)
+{
+ DEBUG ("attach thread observer");
+
+ record_btrace_thread_observer
+ = observer_attach_new_thread (record_btrace_enable_warn);
+}
+
+/* Disable automatic tracing of new threads. */
+
+static void
+record_btrace_auto_disable (void)
+{
+ /* The observer may have been detached, already. */
+ if (record_btrace_thread_observer == NULL)
+ return;
+
+ DEBUG ("detach thread observer");
+
+ observer_detach_new_thread (record_btrace_thread_observer);
+ record_btrace_thread_observer = NULL;
+}
+
+/* The to_open method of target record-btrace. */
+
+static void
+record_btrace_open (char *args, int from_tty)
+{
+ struct cleanup *disable_chain;
+ struct thread_info *tp;
+
+ DEBUG ("open");
+
+ if (RECORD_IS_USED)
+ error (_("The process is already being recorded."));
+
+ if (!target_has_execution)
+ error (_("The program is not being run."));
+
+ if (!target_supports_btrace ())
+ error (_("Target does not support branch tracing."));
+
+ gdb_assert (record_btrace_thread_observer == NULL);
+
+ disable_chain = make_cleanup (null_cleanup, NULL);
+ ALL_THREADS (tp)
+ if (args == NULL || *args == 0 || number_is_in_list (args, tp->num))
+ {
+ btrace_enable (tp);
+
+ make_cleanup (record_btrace_disable_callback, tp);
+ }
+
+ record_btrace_auto_enable ();
+
+ push_target (&record_btrace_ops);
+
+ observer_notify_record_changed (current_inferior (), 1);
+
+ discard_cleanups (disable_chain);
+}
+
+/* The to_close method of target record-btrace. */
+
+static void
+record_btrace_close (int quitting)
+{
+ struct thread_info *tp;
+
+ DEBUG ("close");
+
+ record_btrace_auto_disable ();
+
+ ALL_THREADS (tp)
+ if (tp->btrace.target != NULL)
+ btrace_disable (tp);
+}
+
+/* The to_info_record method of target record-btrace. */
+
+static void
+record_btrace_info (void)
+{
+ struct btrace_thread_info *btinfo;
+ struct thread_info *tp;
+ unsigned int insts, funcs;
+
+ DEBUG ("info");
+
+ tp = find_thread_ptid (inferior_ptid);
+ if (tp == NULL)
+ error (_("No thread."));
+
+ btrace_fetch (tp);
+
+ btinfo = &tp->btrace;
+ insts = VEC_length (btrace_inst_s, btinfo->itrace);
+ funcs = VEC_length (btrace_func_s, btinfo->ftrace);
+
+ printf_unfiltered (_("Recorded %u instructions in %u functions for thread "
+ "%d (%s).\n"), insts, funcs, tp->num,
+ target_pid_to_str (tp->ptid));
+}
+
+/* Print an unsigned int. */
+
+static void
+ui_out_field_uint (struct ui_out *uiout, const char *fld, unsigned int val)
+{
+ ui_out_field_fmt (uiout, fld, "%u", val);
+}
+
+/* Disassemble a section of the recorded instruction trace. */
+
+static void
+btrace_insn_history (struct btrace_thread_info *btinfo, struct ui_out *uiout,
+ unsigned int begin, unsigned int end, int flags)
+{
+ struct gdbarch *gdbarch;
+ struct btrace_inst *inst;
+ unsigned int idx;
+
+ DEBUG ("itrace (0x%x): [%u; %u[", flags, begin, end);
+
+ gdbarch = target_gdbarch ();
+
+ for (idx = begin; VEC_iterate (btrace_inst_s, btinfo->itrace, idx, inst)
+ && idx < end; ++idx)
+ {
+ /* Print the instruction index. */
+ ui_out_field_uint (uiout, "index", idx);
+ ui_out_text (uiout, "\t");
+
+ /* Disassembly with '/m' flag may not produce the expected result.
+ See PR gdb/11833. */
+ gdb_disassembly (gdbarch, uiout, NULL, flags, 1, inst->pc, inst->pc + 1);
+ }
+}
+
+/* The to_insn_history method of target record-btrace. */
+
+static void
+record_btrace_insn_history (int size, int flags)
+{
+ struct btrace_thread_info *btinfo;
+ struct cleanup *uiout_cleanup;
+ struct ui_out *uiout;
+ unsigned int context, last, begin, end;
+
+ uiout = current_uiout;
+ uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
+ "insn history");
+ btinfo = require_btrace ();
+ last = VEC_length (btrace_inst_s, btinfo->itrace);
+
+ context = abs (size);
+ begin = btinfo->insn_iterator.begin;
+ end = btinfo->insn_iterator.end;
+
+ DEBUG ("insn-history (0x%x): %d, prev: [%u; %u[", flags, size, begin, end);
+
+ if (context == 0)
+ error (_("Bad record instruction-history-size."));
+
+ /* We start at the end. */
+ if (end < begin)
+ {
+ /* Truncate the context, if necessary. */
+ context = min (context, last);
+
+ end = last;
+ begin = end - context;
+ }
+ else if (size < 0)
+ {
+ if (begin == 0)
+ {
+ printf_unfiltered (_("At the start of the branch trace record.\n"));
+
+ btinfo->insn_iterator.end = 0;
+ return;
+ }
+
+ /* Truncate the context, if necessary. */
+ context = min (context, begin);
+
+ end = begin;
+ begin -= context;
+ }
+ else
+ {
+ if (end == last)
+ {
+ printf_unfiltered (_("At the end of the branch trace record.\n"));
+
+ btinfo->insn_iterator.begin = last;
+ return;
+ }
+
+ /* Truncate the context, if necessary. */
+ context = min (context, last - end);
+
+ begin = end;
+ end += context;
+ }
+
+ btrace_insn_history (btinfo, uiout, begin, end, flags);
+
+ btinfo->insn_iterator.begin = begin;
+ btinfo->insn_iterator.end = end;
+
+ do_cleanups (uiout_cleanup);
+}
+
+/* The to_insn_history_range method of target record-btrace. */
+
+static void
+record_btrace_insn_history_range (ULONGEST from, ULONGEST to, int flags)
+{
+ struct btrace_thread_info *btinfo;
+ struct cleanup *uiout_cleanup;
+ struct ui_out *uiout;
+ unsigned int last, begin, end;
+
+ uiout = current_uiout;
+ uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
+ "insn history");
+ btinfo = require_btrace ();
+ last = VEC_length (btrace_inst_s, btinfo->itrace);
+
+ begin = (unsigned int) from;
+ end = (unsigned int) to;
+
+ DEBUG ("insn-history (0x%x): [%u; %u[", flags, begin, end);
+
+ /* Check for wrap-arounds. */
+ if (begin != from || end != to)
+ error (_("Bad range."));
+
+ if (end <= begin)
+ error (_("Bad range."));
+
+ if (last <= begin)
+ error (_("Range out of bounds."));
+
+ /* Truncate the range, if necessary. */
+ if (last < end)
+ end = last;
+
+ btrace_insn_history (btinfo, uiout, begin, end, flags);
+
+ btinfo->insn_iterator.begin = begin;
+ btinfo->insn_iterator.end = end;
+
+ do_cleanups (uiout_cleanup);
+}
+
+/* The to_insn_history_from method of target record-btrace. */
+
+static void
+record_btrace_insn_history_from (ULONGEST from, int size, int flags)
+{
+ ULONGEST begin, end, context;
+
+ context = abs (size);
+
+ if (size < 0)
+ {
+ end = from;
+
+ if (from < context)
+ begin = 0;
+ else
+ begin = from - context;
+ }
+ else
+ {
+ begin = from;
+ end = from + context;
+
+ /* Check for wrap-around. */
+ if (end < begin)
+ end = ULONGEST_MAX;
+ }
+
+ record_btrace_insn_history_range (begin, end, flags);
+}
+
+/* Print the instruction number range for a function call history line. */
+
+static void
+btrace_func_history_insn_range (struct ui_out *uiout, struct btrace_func *bfun)
+{
+ ui_out_field_uint (uiout, "insn begin", bfun->ibegin);
+
+ if (bfun->ibegin == bfun->iend)
+ return;
+
+ ui_out_text (uiout, "-");
+ ui_out_field_uint (uiout, "insn end", bfun->iend);
+}
+
+/* Print the source line information for a function call history line. */
+
+static void
+btrace_func_history_src_line (struct ui_out *uiout, struct btrace_func *bfun)
+{
+ struct symbol *sym;
+
+ sym = bfun->sym;
+ if (sym == NULL)
+ return;
+
+ ui_out_field_string (uiout, "file",
+ symtab_to_filename_for_display (sym->symtab));
+
+ if (bfun->lend == 0)
+ return;
+
+ ui_out_text (uiout, ":");
+ ui_out_field_int (uiout, "min line", bfun->lbegin);
+
+ if (bfun->lend == bfun->lbegin)
+ return;
+
+ ui_out_text (uiout, "-");
+ ui_out_field_int (uiout, "max line", bfun->lend);
+}
+
+/* Disassemble a section of the recorded function trace. */
+
+static void
+btrace_func_history (struct btrace_thread_info *btinfo, struct ui_out *uiout,
+ unsigned int begin, unsigned int end,
+ enum record_print_flag flags)
+{
+ struct btrace_func *bfun;
+ unsigned int idx;
+
+ DEBUG ("ftrace (0x%x): [%u; %u[", flags, begin, end);
+
+ for (idx = begin; VEC_iterate (btrace_func_s, btinfo->ftrace, idx, bfun)
+ && idx < end; ++idx)
+ {
+ /* Print the function index. */
+ ui_out_field_uint (uiout, "index", idx);
+ ui_out_text (uiout, "\t");
+
+ if ((flags & record_print_insn_range) != 0)
+ {
+ btrace_func_history_insn_range (uiout, bfun);
+ ui_out_text (uiout, "\t");
+ }
+
+ if ((flags & record_print_src_line) != 0)
+ {
+ btrace_func_history_src_line (uiout, bfun);
+ ui_out_text (uiout, "\t");
+ }
+
+ if (bfun->sym != NULL)
+ ui_out_field_string (uiout, "function", SYMBOL_PRINT_NAME (bfun->sym));
+ else if (bfun->msym != NULL)
+ ui_out_field_string (uiout, "function", SYMBOL_PRINT_NAME (bfun->msym));
+ ui_out_text (uiout, "\n");
+ }
+}
+
+/* The to_call_history method of target record-btrace. */
+
+static void
+record_btrace_call_history (int size, int flags)
+{
+ struct btrace_thread_info *btinfo;
+ struct cleanup *uiout_cleanup;
+ struct ui_out *uiout;
+ unsigned int context, last, begin, end;
+
+ uiout = current_uiout;
+ uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
+ "insn history");
+ btinfo = require_btrace ();
+ last = VEC_length (btrace_func_s, btinfo->ftrace);
+
+ context = abs (size);
+ begin = btinfo->func_iterator.begin;
+ end = btinfo->func_iterator.end;
+
+ DEBUG ("func-history (0x%x): %d, prev: [%u; %u[", flags, size, begin, end);
+
+ if (context == 0)
+ error (_("Bad record function-call-history-size."));
+
+ /* We start at the end. */
+ if (end < begin)
+ {
+ /* Truncate the context, if necessary. */
+ context = min (context, last);
+
+ end = last;
+ begin = end - context;
+ }
+ else if (size < 0)
+ {
+ if (begin == 0)
+ {
+ printf_unfiltered (_("At the start of the branch trace record.\n"));
+
+ btinfo->func_iterator.end = 0;
+ return;
+ }
+
+ /* Truncate the context, if necessary. */
+ context = min (context, begin);
+
+ end = begin;
+ begin -= context;
+ }
+ else
+ {
+ if (end == last)
+ {
+ printf_unfiltered (_("At the end of the branch trace record.\n"));
+
+ btinfo->func_iterator.begin = last;
+ return;
+ }
+
+ /* Truncate the context, if necessary. */
+ context = min (context, last - end);
+
+ begin = end;
+ end += context;
+ }
+
+ btrace_func_history (btinfo, uiout, begin, end, flags);
+
+ btinfo->func_iterator.begin = begin;
+ btinfo->func_iterator.end = end;
+
+ do_cleanups (uiout_cleanup);
+}
+
+/* The to_call_history_range method of target record-btrace. */
+
+static void
+record_btrace_call_history_range (ULONGEST from, ULONGEST to, int flags)
+{
+ struct btrace_thread_info *btinfo;
+ struct cleanup *uiout_cleanup;
+ struct ui_out *uiout;
+ unsigned int last, begin, end;
+
+ uiout = current_uiout;
+ uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout,
+ "func history");
+ btinfo = require_btrace ();
+ last = VEC_length (btrace_func_s, btinfo->ftrace);
+
+ begin = (unsigned int) from;
+ end = (unsigned int) to;
+
+ DEBUG ("func-history (0x%x): [%u; %u[", flags, begin, end);
+
+ /* Check for wrap-arounds. */
+ if (begin != from || end != to)
+ error (_("Bad range."));
+
+ if (end <= begin)
+ error (_("Bad range."));
+
+ if (last <= begin)
+ error (_("Range out of bounds."));
+
+ /* Truncate the range, if necessary. */
+ if (last < end)
+ end = last;
+
+ btrace_func_history (btinfo, uiout, begin, end, flags);
+
+ btinfo->func_iterator.begin = begin;
+ btinfo->func_iterator.end = end;
+
+ do_cleanups (uiout_cleanup);
+}
+
+/* The to_call_history_from method of target record-btrace. */
+
+static void
+record_btrace_call_history_from (ULONGEST from, int size, int flags)
+{
+ ULONGEST begin, end, context;
+
+ context = abs (size);
+
+ if (size < 0)
+ {
+ end = from;
+
+ if (from < context)
+ begin = 0;
+ else
+ begin = from - context;
+ }
+ else
+ {
+ begin = from;
+ end = from + context;
+
+ /* Check for wrap-around. */
+ if (end < begin)
+ end = ULONGEST_MAX;
+ }
+
+ record_btrace_call_history_range (begin, end, flags);
+}
+
+/* Initialize the record-btrace target ops. */
+
+static void
+init_record_btrace_ops (void)
+{
+ struct target_ops *ops;
+
+ ops = &record_btrace_ops;
+ ops->to_shortname = "record-btrace";
+ ops->to_longname = "Branch tracing target";
+ ops->to_doc = "Collect control-flow trace and provide the execution history.";
+ ops->to_open = record_btrace_open;
+ ops->to_close = record_btrace_close;
+ ops->to_detach = record_detach;
+ ops->to_disconnect = record_disconnect;
+ ops->to_mourn_inferior = record_mourn_inferior;
+ ops->to_kill = record_kill;
+ ops->to_create_inferior = find_default_create_inferior;
+ ops->to_info_record = record_btrace_info;
+ ops->to_insn_history = record_btrace_insn_history;
+ ops->to_insn_history_from = record_btrace_insn_history_from;
+ ops->to_insn_history_range = record_btrace_insn_history_range;
+ ops->to_call_history = record_btrace_call_history;
+ ops->to_call_history_from = record_btrace_call_history_from;
+ ops->to_call_history_range = record_btrace_call_history_range;
+ ops->to_stratum = record_stratum;
+ ops->to_magic = OPS_MAGIC;
+}
+
+/* Alias for "target record". */
+
+static void
+cmd_record_btrace_start (char *args, int from_tty)
+{
+ if (args != NULL && *args != 0)
+ error (_("Invalid argument."));
+
+ execute_command ("target record-btrace", from_tty);
+}
+
+void _initialize_record_btrace (void);
+
+/* Initialize btrace commands. */
+
+void
+_initialize_record_btrace (void)
+{
+ add_cmd ("btrace", class_obscure, cmd_record_btrace_start,
+ _("Start branch trace recording."),
+ &record_cmdlist);
+ add_alias_cmd ("b", "btrace", class_obscure, 1, &record_cmdlist);
+
+ init_record_btrace_ops ();
+ add_target (&record_btrace_ops);
+}
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* [patch v10 18/21] record-btrace, disas: omit pc prefix
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (19 preceding siblings ...)
2013-03-08 9:19 ` [patch v10 17/21] record, btrace: add record-btrace target Markus Metzger
@ 2013-03-08 9:19 ` Markus Metzger
2013-03-08 12:16 ` [patch v10 00/21] branch tracing for Atom Jan Kratochvil
2013-03-08 14:00 ` Jan Kratochvil
22 siblings, 0 replies; 34+ messages in thread
From: Markus Metzger @ 2013-03-08 9:19 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Add a disassembly flag to omit the pc prefix and use it in the "record
instruction-history" command of record-btrace.
The pc prefix would appear multiple times in the branch trace disassembly,
which is more confusing than helpful.
Approved by Jan Kratochvil.
2013-03-08 Markus Metzger <markus.t.metzger@intel.com>
* record-btrace.c (btrace_insn_history): Omit the pc prefix in
the instruction history disassembly.
* disasm.c (dump_insns): Omit the pc prefix, if requested.
* disasm.h (DISASSEMBLY_OMIT_PC): New.
---
gdb/disasm.c | 4 +++-
gdb/disasm.h | 1 +
gdb/record.c | 4 ++++
3 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 9d61379..e643c2d 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -122,7 +122,9 @@ dump_insns (struct gdbarch *gdbarch, struct ui_out *uiout,
num_displayed++;
}
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
- ui_out_text (uiout, pc_prefix (pc));
+
+ if ((flags & DISASSEMBLY_OMIT_PC) == 0)
+ ui_out_text (uiout, pc_prefix (pc));
ui_out_field_core_addr (uiout, "address", gdbarch, pc);
if (!build_address_symbolic (gdbarch, pc, 0, &name, &offset, &filename,
diff --git a/gdb/disasm.h b/gdb/disasm.h
index 20ceb2b..3743ccc 100644
--- a/gdb/disasm.h
+++ b/gdb/disasm.h
@@ -23,6 +23,7 @@
#define DISASSEMBLY_RAW_INSN (0x1 << 1)
#define DISASSEMBLY_OMIT_FNAME (0x1 << 2)
#define DISASSEMBLY_FILENAME (0x1 << 3)
+#define DISASSEMBLY_OMIT_PC (0x1 << 4)
struct ui_out;
struct ui_file;
diff --git a/gdb/record.c b/gdb/record.c
index 12ab179..83f4e1b 100644
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -386,6 +386,9 @@ get_insn_history_modifiers (char **arg)
case 'f':
modifiers |= DISASSEMBLY_OMIT_FNAME;
break;
+ case 'p':
+ modifiers |= DISASSEMBLY_OMIT_PC;
+ break;
default:
error (_("Invalid modifier: %c."), *args);
}
@@ -666,6 +669,7 @@ Print disassembled instructions stored in the execution log.\n\
With a /m modifier, source lines are included (if available).\n\
With a /r modifier, raw instructions in hex are included.\n\
With a /f modifier, function names are omitted.\n\
+With a /p modifier, current position markers are omitted.\n\
With no argument, disassembles ten more instructions after the previous \
disassembly.\n\
\"record instruction-history -\" disassembles ten instructions before a \
--
1.7.1
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [patch v10 00/21] branch tracing for Atom
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (20 preceding siblings ...)
2013-03-08 9:19 ` [patch v10 18/21] record-btrace, disas: omit pc prefix Markus Metzger
@ 2013-03-08 12:16 ` Jan Kratochvil
2013-03-08 12:32 ` Metzger, Markus T
2013-03-08 14:00 ` Jan Kratochvil
22 siblings, 1 reply; 34+ messages in thread
From: Jan Kratochvil @ 2013-03-08 12:16 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Fri, 08 Mar 2013 10:15:47 +0100, Markus Metzger wrote:
> The series has been committed into archer's mmetzger/btrace.
FYI on that branch I get:
infcmd.c: In function ‘detach_command’:
infcmd.c:2725:3: error: implicit declaration of function ‘disconnect_btrace’ [-Werror=implicit-function-declaration]
disconnect_btrace ();
mmetzger/btrace = b9726ca4867ba8cea4f945aebae4c3ad2e2e2889
But I can cleanly 'git am' your posted patchset on top of gdb/master
(61ea5d208bafd661f52b7db0d43cd2655741987f) so no problem with it.
Jan
^ permalink raw reply [flat|nested] 34+ messages in thread* RE: [patch v10 00/21] branch tracing for Atom
2013-03-08 12:16 ` [patch v10 00/21] branch tracing for Atom Jan Kratochvil
@ 2013-03-08 12:32 ` Metzger, Markus T
0 siblings, 0 replies; 34+ messages in thread
From: Metzger, Markus T @ 2013-03-08 12:32 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, markus.t.metzger
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Friday, March 08, 2013 1:16 PM
> To: Metzger, Markus T
> Cc: gdb-patches@sourceware.org; markus.t.metzger@gmail.com
> Subject: Re: [patch v10 00/21] branch tracing for Atom
>
> On Fri, 08 Mar 2013 10:15:47 +0100, Markus Metzger wrote:
> > The series has been committed into archer's mmetzger/btrace.
>
> FYI on that branch I get:
>
> infcmd.c: In function 'detach_command':
> infcmd.c:2725:3: error: implicit declaration of function 'disconnect_btrace' [-Werror=implicit-function-declaration]
> disconnect_btrace ();
Hmmm, I did "git merge --squash -s recursive -X theirs btrace" to update the
archer branch. When I do this again, I do not get any changes.
I force-pushed my local development branch to archer's mmetzger/btrace.
Regards,
Markus.
Intel GmbH
Dornacher Strasse 1
85622 Feldkirchen/Muenchen, Deutschland
Sitz der Gesellschaft: Feldkirchen bei Muenchen
Geschaeftsfuehrer: Christian Lamprechter, Hannes Schwaderer, Douglas Lusk
Registergericht: Muenchen HRB 47456
Ust.-IdNr./VAT Registration No.: DE129385895
Citibank Frankfurt a.M. (BLZ 502 109 00) 600119052
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [patch v10 00/21] branch tracing for Atom
2013-03-08 9:19 [patch v10 00/21] branch tracing for Atom Markus Metzger
` (21 preceding siblings ...)
2013-03-08 12:16 ` [patch v10 00/21] branch tracing for Atom Jan Kratochvil
@ 2013-03-08 14:00 ` Jan Kratochvil
2013-03-08 14:58 ` Jan Kratochvil
22 siblings, 1 reply; 34+ messages in thread
From: Jan Kratochvil @ 2013-03-08 14:00 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Fri, 08 Mar 2013 10:15:47 +0100, Markus Metzger wrote:
> I squashed the various remote/gdbserver patches and fixed a bug reported by
> Jan.
OK for the CVS check-in. I have filed new related PRs:
remote_read_qxfer hides remote errors
http://sourceware.org/bugzilla/show_bug.cgi?id=15255
+
remote.c uses pop_target
http://sourceware.org/bugzilla/show_bug.cgi?id=15256
Thanks,
Jan
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [patch v10 00/21] branch tracing for Atom
2013-03-08 14:00 ` Jan Kratochvil
@ 2013-03-08 14:58 ` Jan Kratochvil
2013-03-08 15:13 ` Metzger, Markus T
0 siblings, 1 reply; 34+ messages in thread
From: Jan Kratochvil @ 2013-03-08 14:58 UTC (permalink / raw)
To: Markus Metzger; +Cc: markus.t.metzger, gdb-patches
On Fri, 08 Mar 2013 14:59:37 +0100, Jan Kratochvil wrote:
> On Fri, 08 Mar 2013 10:15:47 +0100, Markus Metzger wrote:
> > I squashed the various remote/gdbserver patches and fixed a bug reported by
> > Jan.
>
> OK for the CVS check-in.
Except for that record split 3921a591df61f1b78468f060611e0afaa9870182 it all
looks check-in-able separately, great work. I did not verify if it does not
regress in some intermediate stage but I doubt so.
Thanks,
Jan
^ permalink raw reply [flat|nested] 34+ messages in thread
* RE: [patch v10 00/21] branch tracing for Atom
2013-03-08 14:58 ` Jan Kratochvil
@ 2013-03-08 15:13 ` Metzger, Markus T
2013-03-08 15:42 ` Jan Kratochvil
0 siblings, 1 reply; 34+ messages in thread
From: Metzger, Markus T @ 2013-03-08 15:13 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: markus.t.metzger, gdb-patches
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Friday, March 08, 2013 3:58 PM
> > OK for the CVS check-in.
>
> Except for that record split 3921a591df61f1b78468f060611e0afaa9870182 it all
> looks check-in-able separately, great work. I did not verify if it does not
> regress in some intermediate stage but I doubt so.
I checked that each patch builds, but I have not run any tests for each patch.
I am currently running the full test suite before and after the series. Do you
typically expect people to do this for each test in a series?
Btw, I noticed a broken build for --enable-targets=all. I'm currently only building
for the target I'm testing.
gdb/remote-m32-r-sdi.c:1233
while (*args != '\000')
{
char *arg;
args = skip_spaces (arg);
arg = args;
while ((*args != '\000') && !isspace (*args))
args++;
regards,
markus.
Intel GmbH
Dornacher Strasse 1
85622 Feldkirchen/Muenchen, Deutschland
Sitz der Gesellschaft: Feldkirchen bei Muenchen
Geschaeftsfuehrer: Christian Lamprechter, Hannes Schwaderer, Douglas Lusk
Registergericht: Muenchen HRB 47456
Ust.-IdNr./VAT Registration No.: DE129385895
Citibank Frankfurt a.M. (BLZ 502 109 00) 600119052
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [patch v10 00/21] branch tracing for Atom
2013-03-08 15:13 ` Metzger, Markus T
@ 2013-03-08 15:42 ` Jan Kratochvil
0 siblings, 0 replies; 34+ messages in thread
From: Jan Kratochvil @ 2013-03-08 15:42 UTC (permalink / raw)
To: Metzger, Markus T; +Cc: markus.t.metzger, gdb-patches
On Fri, 08 Mar 2013 16:13:36 +0100, Metzger, Markus T wrote:
> I checked that each patch builds, but I have not run any tests for each patch.
>
> I am currently running the full test suite before and after the series. Do you
> typically expect people to do this for each test in a series?
It is useful to do it when you do some modifications of existing code.
But this patchset is mostly just about adding new features and test for that
is added as the last patch so I do not expect regressions in between.
So I do ask for testing each of the patches.
> Btw, I noticed a broken build for --enable-targets=all. I'm currently only building
> for the target I'm testing.
Thanks, going to check it (I do not have/run the nightly testing these days
(nights)).
Jan
^ permalink raw reply [flat|nested] 34+ messages in thread