* [patch v9 10/23] remote, btrace: add branch tracing protocol to Qbtrace packet
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
@ 2013-03-04 17:07 ` Markus Metzger
2013-03-05 20:09 ` Jan Kratochvil
2013-03-04 17:07 ` [patch v9 07/23] gdbserver, btrace: add generic btrace support Markus Metzger
` (22 subsequent siblings)
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:07 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger, Pedro Alves
We might want to add support for LBR branch tracing in the future.
To prepare for this, I would specify the branch trace recording method
in the Qbtrace packet when requesting branch tracing.
Similar to qXfer, I am adding separate packets for each recording method plus
one packet to disable tracing. The currently supported packets are:
Qbtrace:off
Qbtrace:bts
CC: Pedro Alves <palves@redhat.com>
2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
---
gdb/doc/gdb.texinfo | 18 +++++++++---
gdb/gdbserver/server.c | 7 +++--
gdb/remote.c | 69 +++++++++++++++++++++++++----------------------
3 files changed, 54 insertions(+), 40 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5ac450c..337675c 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -37321,7 +37321,12 @@ These are the currently defined stub features and their properties:
@tab @samp{-}
@tab Yes
-@item @samp{Qbtrace}
+@item @samp{Qbtrace:off}
+@tab Yes
+@tab @samp{-}
+@tab Yes
+
+@item @samp{Qbtrace:bts}
@tab Yes
@tab @samp{-}
@tab Yes
@@ -37562,8 +37567,11 @@ rather than reporting the hit to @value{GDBN}.
@item qbtrace
The remote stub understands the @samp{qbtrace} packet.
-@item Qbtrace
-The remote stub understands the @samp{Qbtrace} packet.
+@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
@@ -37942,8 +37950,8 @@ No new branch trace data is available.
A badly formed request or an error was encountered.
@end table
-@item Qbtrace:on
-Enable branch tracing for the current thread.
+@item Qbtrace:bts
+Enable branch tracing for the current thread using bts tracing.
Reply:
@table @samp
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index e755ba0..00cac8e 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -463,12 +463,12 @@ handle_btrace_general_set (char *own_buf)
err = NULL;
- if (strcmp (op, "on") == 0)
+ 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 on or off.";
+ err = "E.Bad Qbtrace operation. Use bts or off.";
if (err != 0)
strcpy (own_buf, err);
@@ -1828,7 +1828,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_btrace ())
{
strcat (own_buf, ";qbtrace+");
- strcat (own_buf, ";Qbtrace+");
+ strcat (own_buf, ";Qbtrace:bts+");
+ strcat (own_buf, ";Qbtrace:off+");
strcat (own_buf, ";qXfer:btrace:read+");
}
diff --git a/gdb/remote.c b/gdb/remote.c
index 787c596..2365713 100755
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1286,7 +1286,8 @@ enum {
PACKET_QDisableRandomization,
PACKET_QAgent,
PACKET_qbtrace,
- PACKET_Qbtrace,
+ PACKET_Qbtrace_off,
+ PACKET_Qbtrace_bts,
PACKET_qXfer_btrace,
PACKET_MAX
};
@@ -4000,7 +4001,8 @@ static struct protocol_feature remote_protocol_features[] = {
{ "tracenz", PACKET_DISABLE,
remote_string_tracing_feature, -1 },
{ "qbtrace", PACKET_DISABLE, remote_supported_packet, PACKET_qbtrace },
- { "Qbtrace", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace },
+ { "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 }
};
@@ -11140,7 +11142,9 @@ remote_supports_btrace (void)
{
if (remote_protocol_packets[PACKET_qbtrace].support != PACKET_ENABLE)
return 0;
- if (remote_protocol_packets[PACKET_Qbtrace].support != PACKET_ENABLE)
+ 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;
@@ -11148,12 +11152,13 @@ remote_supports_btrace (void)
return 1;
}
-/* Send the Qbtrace packet and check the response. */
+/* Enable branch tracing. */
-static void
-send_Qbtrace (ptid_t ptid, int enable)
+static struct btrace_target_info *
+remote_enable_btrace (ptid_t ptid)
{
- struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace];
+ 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 ();
@@ -11163,31 +11168,13 @@ send_Qbtrace (ptid_t ptid, int enable)
set_general_thread (ptid);
- buf += xsnprintf (buf, endbuf - buf, "%s:", packet->name);
- buf += xsnprintf (buf, endbuf - buf, enable ? "on" : "off");
+ 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 (enable != 0)
- error (_("Could not enable branch tracing for %s: %s"),
- target_pid_to_str (ptid), rs->buf);
- else
- error (_("Could not disable branch tracing for %s: %s"),
- target_pid_to_str (ptid), rs->buf);
- }
-}
-
-/* Enable branch tracing. */
-
-static struct btrace_target_info *
-remote_enable_btrace (ptid_t ptid)
-{
- struct btrace_target_info *tinfo = NULL;
-
- /* This will throw an error if enabling failed. */
- send_Qbtrace (ptid, 1);
+ error (_("Could not enable branch tracing for %s: %s"),
+ target_pid_to_str (ptid), rs->buf);
tinfo = xzalloc (sizeof (*tinfo));
tinfo->ptid = ptid;
@@ -11200,8 +11187,23 @@ remote_enable_btrace (ptid_t ptid)
static void
remote_disable_btrace (struct btrace_target_info *tinfo)
{
- /* This will throw an error if disabling failed. */
- send_Qbtrace (tinfo->ptid, 0);
+ 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)
+ error (_("Could not disable branch tracing for %s: %s"),
+ target_pid_to_str (tinfo->ptid), rs->buf);
xfree (tinfo);
}
@@ -11927,8 +11929,11 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_qbtrace],
"qbtrace", "query-btrace", 0);
- add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace],
- "Qbtrace", "enable-btrace", 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);
--
1.7.1
^ permalink raw reply [flat|nested] 102+ messages in thread* Re: [patch v9 10/23] remote, btrace: add branch tracing protocol to Qbtrace packet
2013-03-04 17:07 ` [patch v9 10/23] remote, btrace: add branch tracing protocol to Qbtrace packet Markus Metzger
@ 2013-03-05 20:09 ` Jan Kratochvil
2013-03-06 9:19 ` Metzger, Markus T
0 siblings, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:09 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger, Pedro Alves
On Mon, 04 Mar 2013 18:05:57 +0100, Markus Metzger wrote:
> We might want to add support for LBR branch tracing in the future.
>
> To prepare for this, I would specify the branch trace recording method
> in the Qbtrace packet when requesting branch tracing.
>
> Similar to qXfer, I am adding separate packets for each recording method plus
> one packet to disable tracing. The currently supported packets are:
>
> Qbtrace:off
> Qbtrace:bts
As explained in a different mail the patch should be merged, so that no
intermediate unapproved features get into the FSF GDB repository history.
>
> CC: Pedro Alves <palves@redhat.com>
>
>
> 2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
> ---
> gdb/doc/gdb.texinfo | 18 +++++++++---
> gdb/gdbserver/server.c | 7 +++--
> gdb/remote.c | 69 +++++++++++++++++++++++++----------------------
> 3 files changed, 54 insertions(+), 40 deletions(-)
I do not see here FSF ChangeLog so I do not understand now if it was meant as
a separate CVS check-in or not.
The content is OK for check-in in the patchset.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* RE: [patch v9 10/23] remote, btrace: add branch tracing protocol to Qbtrace packet
2013-03-05 20:09 ` Jan Kratochvil
@ 2013-03-06 9:19 ` Metzger, Markus T
0 siblings, 0 replies; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 9:19 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, markus.t.metzger, Pedro Alves
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Tuesday, March 05, 2013 9:09 PM
> > Similar to qXfer, I am adding separate packets for each recording method plus
> > one packet to disable tracing. The currently supported packets are:
> >
> > Qbtrace:off
> > Qbtrace:bts
>
> As explained in a different mail the patch should be merged, so that no
> intermediate unapproved features get into the FSF GDB repository history.
OK. I'll merge the remote protocol changes and send out the updated series.
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] 102+ messages in thread
* [patch v9 07/23] gdbserver, btrace: add generic btrace support
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
2013-03-04 17:07 ` [patch v9 10/23] remote, btrace: add branch tracing protocol to Qbtrace packet Markus Metzger
@ 2013-03-04 17:07 ` Markus Metzger
2013-03-05 20:08 ` Jan Kratochvil
2013-03-06 13:22 ` Jan Kratochvil
2013-03-04 17:07 ` [patch v9 04/23] xml, btrace: define btrace xml document style Markus Metzger
` (21 subsequent siblings)
23 siblings, 2 replies; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:07 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Add support to gdbserver to understand branch trace related packages.
2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
gdbserver/
* target.h (struct target_ops): Add btrace ops.
(target_supports_btrace): New macro.
(target_btrace_has_changed): 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 (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.
(handle_btrace_query): New function.
(handle_query): Add btrace to supported query, call handle_btrace_query.
* inferiors.c (remove_thread): Disable btrace.
---
gdb/gdbserver/gdbthread.h | 5 +
gdb/gdbserver/inferiors.c | 3 +
gdb/gdbserver/server.c | 188 +++++++++++++++++++++++++++++++++++++++++++++
gdb/gdbserver/target.h | 33 ++++++++
4 files changed, 229 insertions(+), 0 deletions(-)
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/server.c b/gdb/gdbserver/server.c
index 768eae7..e755ba0 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -396,6 +396,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, "on") == 0)
+ err = handle_btrace_enable (thread);
+ else if (strcmp (op, "off") == 0)
+ err = handle_btrace_disable (thread);
+ else
+ err = "E.Bad Qbtrace operation. Use on 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 +634,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 +1336,66 @@ 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;
+
+ if (the_target->read_btrace == NULL || writebuf != NULL)
+ return -2;
+
+ if (!target_running () || annex[0] != '\0')
+ 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;
+ }
+
+ if (thread->btrace == NULL)
+ {
+ strcpy (own_buf, "E.Btrace not enabled.");
+ return -1;
+ }
+
+ if (offset == 0)
+ {
+ buffer_free (&cache);
+
+ target_read_btrace (thread->btrace, &cache);
+ }
+ else if (offset > cache.used_size)
+ {
+ buffer_free (&cache);
+ return -1;
+ }
+
+ 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 },
@@ -1418,6 +1560,42 @@ crc32 (CORE_ADDR base, int len, unsigned int crc)
return (unsigned long long) crc;
}
+/* Handle the "qbtrace" packet. */
+
+static int
+handle_btrace_query (char *own_buf)
+{
+ if (strncmp ("qbtrace", own_buf, strlen ("qbtrace")) == 0)
+ {
+ struct thread_info *thread;
+
+ 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;
+ }
+
+ if (thread->btrace == NULL)
+ {
+ strcpy (own_buf, "E.Btrace not enabled.");
+ return -1;
+ }
+
+ strcpy (own_buf,
+ (target_btrace_has_changed (thread->btrace) ? "yes" : "no"));
+ return 1;
+ }
+ return 0;
+}
+
/* Handle all of the extended 'q' packets. */
void
@@ -1647,6 +1825,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+");
+ strcat (own_buf, ";Qbtrace+");
+ strcat (own_buf, ";qXfer:btrace:read+");
+ }
+
return;
}
@@ -1837,6 +2022,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_tracepoints () && handle_tracepoint_query (own_buf))
return;
+ if (handle_btrace_query (own_buf))
+ return;
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index cc9a910..a597911 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,22 @@ 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);
+
+ /* Check whether branch trace changed on the target. */
+ int (*btrace_has_changed) (struct btrace_target_info *);
+
+ /* Read branch trace data into buffer. */
+ void (*read_btrace) (struct btrace_target_info *, struct buffer *);
};
extern struct target_ops *the_target;
@@ -520,6 +538,21 @@ 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_btrace_has_changed(tinfo) \
+ (*the_target->btrace_has_changed) (tinfo)
+
+#define target_read_btrace(tinfo, buffer) \
+ (*the_target->read_btrace) (tinfo, buffer)
+
/* Start non-stop mode, returns 0 on success, -1 on failure. */
int start_non_stop (int nonstop);
--
1.7.1
^ permalink raw reply [flat|nested] 102+ messages in thread* Re: [patch v9 07/23] gdbserver, btrace: add generic btrace support
2013-03-04 17:07 ` [patch v9 07/23] gdbserver, btrace: add generic btrace support Markus Metzger
@ 2013-03-05 20:08 ` Jan Kratochvil
2013-03-06 9:15 ` Metzger, Markus T
2013-03-06 13:22 ` Jan Kratochvil
1 sibling, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:08 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:05:54 +0100, Markus Metzger wrote:
> Add support to gdbserver to understand branch trace related packages.
>
> 2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
>
> gdbserver/
> * target.h (struct target_ops): Add btrace ops.
> (target_supports_btrace): New macro.
> (target_btrace_has_changed): 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 (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.
> (handle_btrace_query): New function.
> (handle_query): Add btrace to supported query, call handle_btrace_query.
> * inferiors.c (remove_thread): Disable btrace.
[...]
> +/* 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, "on") == 0)
> + err = handle_btrace_enable (thread);
Again not merged.
> + else if (strcmp (op, "off") == 0)
> + err = handle_btrace_disable (thread);
> + else
> + err = "E.Bad Qbtrace operation. Use on or off.";
> +
> + if (err != 0)
> + strcpy (own_buf, err);
> + else
> + write_ok (own_buf);
> +
> + return 1;
> +}
> +
Reviewed by Pedro.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread* RE: [patch v9 07/23] gdbserver, btrace: add generic btrace support
2013-03-05 20:08 ` Jan Kratochvil
@ 2013-03-06 9:15 ` Metzger, Markus T
0 siblings, 0 replies; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 9:15 UTC (permalink / raw)
To: Jan Kratochvil
Cc: gdb-patches, markus.t.metzger, Pedro Alves (palves@redhat.com)
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Tuesday, March 05, 2013 9:09 PM
> Reviewed by Pedro.
Pedro reviewed the original btrace series (without record changes) and I incorporated
his feedback. He has not reviewed the updated patches and he has not OK'ed them.
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] 102+ messages in thread
* Re: [patch v9 07/23] gdbserver, btrace: add generic btrace support
2013-03-04 17:07 ` [patch v9 07/23] gdbserver, btrace: add generic btrace support Markus Metzger
2013-03-05 20:08 ` Jan Kratochvil
@ 2013-03-06 13:22 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-06 13:22 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger, Pedro Alves
On Mon, 04 Mar 2013 18:05:54 +0100, Markus Metzger wrote:
> Add support to gdbserver to understand branch trace related packages.
>
> 2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
>
> gdbserver/
> * target.h (struct target_ops): Add btrace ops.
> (target_supports_btrace): New macro.
> (target_btrace_has_changed): 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 (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.
> (handle_btrace_query): New function.
> (handle_query): Add btrace to supported query, call handle_btrace_query.
> * inferiors.c (remove_thread): Disable btrace.
[...]
> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
[...]
> +/* 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;
> +
> + if (the_target->read_btrace == NULL || writebuf != NULL)
> + return -2;
> +
> + if (!target_running () || annex[0] != '\0')
> + 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.");
While Pedro suggested the "E.XXX" error codes in xfer function they do not
work as returning -1 will overwrite it by "E01" and any other return code also
cannot be used.
Maybe just add a new return value -3, describe it in the struct qxfer->qxfer
comment and handle it in handle_qxfer <"read"> and <"write">.
else if (n < 0)
write_enn (own_buf);
->
else if (n == -3)
{
/* Keep the error code in OWN_BUF. */
}
else if (n < 0)
write_enn (own_buf);
And BTW the error handling in remote.c is not correct:
if (packet_ok (rs->buf, packet) == PACKET_ERROR)
error (_("Could not enable branch tracing for %s: %s"),
target_pid_to_str (ptid), rs->buf);
Sending packet: $Qbtrace:bts#45...Packet received: E.Target does not support branch tracing.
->
Could not enable branch tracing for Thread 18498: E.Target does not support branch tracing.
There needs to be also some:
if (rs->buf[1] == '.')
and use
rs->buf + 2;
(rs->buf is 0-terminated).
> + return -1;
> + }
> +
> + thread = find_thread_ptid (general_thread);
> + if (thread == NULL)
> + {
> + strcpy (own_buf, "E.No such thread.");
> + return -1;
> + }
> +
> + if (thread->btrace == NULL)
> + {
> + strcpy (own_buf, "E.Btrace not enabled.");
> + return -1;
> + }
> +
> + if (offset == 0)
> + {
> + buffer_free (&cache);
> +
> + target_read_btrace (thread->btrace, &cache);
> + }
> + else if (offset > cache.used_size)
> + {
> + buffer_free (&cache);
> + return -1;
> + }
> +
> + if (len > cache.used_size - offset)
> + len = cache.used_size - offset;
> +
> + memcpy (readbuf, cache.buffer + offset, len);
> +
> + return len;
> +}
> +
Otherwise OK for the diff against Pedro's review.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 04/23] xml, btrace: define btrace xml document style
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
2013-03-04 17:07 ` [patch v9 10/23] remote, btrace: add branch tracing protocol to Qbtrace packet Markus Metzger
2013-03-04 17:07 ` [patch v9 07/23] gdbserver, btrace: add generic btrace support Markus Metzger
@ 2013-03-04 17:07 ` Markus Metzger
2013-03-05 20:07 ` Jan Kratochvil
2013-03-04 17:07 ` [patch v9 02/23] linux, btrace: perf_event based branch tracing Markus Metzger
` (20 subsequent siblings)
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:07 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.
2013-03-04 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 | 95 +++++++++++++++++++++++++++++++++++++++++++++++
gdb/btrace.h | 3 +
gdb/features/btrace.dtd | 12 ++++++
4 files changed, 112 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 b6cd1c8..406508d 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. */
@@ -465,3 +466,97 @@ 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);
+ errno = errcode;
+ return NULL;
+ }
+
+ /* Keep parse results. */
+ discard_cleanups (cleanup);
+
+#else /* !defined(HAVE_LIBEXPAT) */
+
+ error (_("Cannot process branch tracing result. XML parsing not supported."));
+
+#endif /* !defined(HAVE_LIBEXPAT) */
+
+ return btrace;
+}
diff --git a/gdb/btrace.h b/gdb/btrace.h
index a1b01c8..405bcff 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -132,4 +132,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..18c5b2a
--- /dev/null
+++ b/gdb/features/btrace.dtd
@@ -0,0 +1,12 @@
+<!-- Copyright (C) 2012 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] 102+ messages in thread* Re: [patch v9 04/23] xml, btrace: define btrace xml document style
2013-03-04 17:07 ` [patch v9 04/23] xml, btrace: define btrace xml document style Markus Metzger
@ 2013-03-05 20:07 ` Jan Kratochvil
0 siblings, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:07 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:05:51 +0100, Markus Metzger wrote:
> 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.
>
> 2013-03-04 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.
[...]
> --- 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. */
> @@ -465,3 +466,97 @@ btrace_free_objfile (struct objfile *objfile)
> ALL_THREADS (tp)
> btrace_clear (tp);
> }
> +
> +#if defined(HAVE_LIBEXPAT)
There should be space before '(' according to GNU Coding Standards.
It is 7 times in the whole patchet, ther other instances I have not commented.
Choose one:
#ifdef HAVE_LIBEXPAT
#if defined HAVE_LIBEXPAT
#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);
> + errno = errcode;
gdb_xml_parse_quick returns 0 or -1, -1 is not valid errno code. Also I do
not see errno used by the caller of parse_xml_btrace.
Remove that errno setting, returning NULL is enough.
> + return NULL;
> + }
> +
> + /* Keep parse results. */
> + discard_cleanups (cleanup);
> +
> +#else /* !defined(HAVE_LIBEXPAT) */
> +
> + error (_("Cannot process branch tracing result. XML parsing not supported."));
Two spaces after dot ('.'). Maybe also s/not/is not/.
> +
> +#endif /* !defined(HAVE_LIBEXPAT) */
> +
> + return btrace;
> +}
> diff --git a/gdb/btrace.h b/gdb/btrace.h
> index a1b01c8..405bcff 100644
> --- a/gdb/btrace.h
> +++ b/gdb/btrace.h
> @@ -132,4 +132,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..18c5b2a
> --- /dev/null
> +++ b/gdb/features/btrace.dtd
> @@ -0,0 +1,12 @@
> +<!-- Copyright (C) 2012 Free Software Foundation, Inc.
Besides all the .c/.h sources files here chould be also 2013.
> +
> + 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
OK for check in with those few small changes.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 02/23] linux, btrace: perf_event based branch tracing
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (2 preceding siblings ...)
2013-03-04 17:07 ` [patch v9 04/23] xml, btrace: define btrace xml document style Markus Metzger
@ 2013-03-04 17:07 ` Markus Metzger
2013-03-05 20:06 ` Jan Kratochvil
2013-03-06 10:11 ` Mark Kettenis
2013-03-04 17:07 ` [patch v9 05/23] remote, btrace: add branch trace remote ops Markus Metzger
` (19 subsequent siblings)
23 siblings, 2 replies; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:07 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.
2013-03-04 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 | 437 +++++++++++++++++++++++++++++++++++++++++++++
gdb/common/linux-btrace.h | 79 ++++++++
gdb/gdbserver/Makefile.in | 7 +-
4 files changed, 527 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..44eb6dc
--- /dev/null
+++ b/gdb/common/linux-btrace.c
@@ -0,0 +1,437 @@
+/* Linux-dependent part of branch trace support for GDB, and GDBserver.
+
+ Copyright (C) 2012 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>
+
+#if defined(__GNUC__)
+# define memory_barrier() asm volatile ("" : : : "memory")
+#else
+# define memory_barrier() do {} while (0)
+#endif
+
+/* 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. */
+
+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. */
+
+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;
+}
+
+/* See linux-btrace.h. */
+
+VEC (btrace_block_s) *
+linux_read_btrace (struct btrace_target_info *tinfo)
+{
+ 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;
+
+ 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;
+
+ /* Make sure the trace data is up-to-date. */
+ memory_barrier ();
+
+ /* 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. */
+
+int
+linux_btrace_has_changed (struct btrace_target_info *tinfo)
+{
+ 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)
+{
+ 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..b382e49
--- /dev/null
+++ b/gdb/common/linux-btrace.h
@@ -0,0 +1,79 @@
+/* Linux-dependent part of branch trace support for GDB, and GDBserver.
+
+ Copyright (C) 2012 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);
+
+/* Check whether there is new trace data available. */
+extern int linux_btrace_has_changed (struct btrace_target_info *);
+
+/* Read branch trace data. */
+extern VEC (btrace_block_s) *linux_read_btrace (struct btrace_target_info *);
+
+#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] 102+ messages in thread* Re: [patch v9 02/23] linux, btrace: perf_event based branch tracing
2013-03-04 17:07 ` [patch v9 02/23] linux, btrace: perf_event based branch tracing Markus Metzger
@ 2013-03-05 20:06 ` Jan Kratochvil
2013-03-06 10:11 ` Mark Kettenis
1 sibling, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:06 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:05:49 +0100, Markus Metzger wrote:
> 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.
>
> 2013-03-04 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.
[...]
> --- /dev/null
> +++ b/gdb/common/linux-btrace.c
[...]
> +/* 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:
Labels should be indented by one space so they do not clash with function
names, like:
err_file:
> + close (tinfo->file);
> +
> +err:
> + xfree (tinfo);
> + return NULL;
> +}
OK for check-in.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread* Re: [patch v9 02/23] linux, btrace: perf_event based branch tracing
2013-03-04 17:07 ` [patch v9 02/23] linux, btrace: perf_event based branch tracing Markus Metzger
2013-03-05 20:06 ` Jan Kratochvil
@ 2013-03-06 10:11 ` Mark Kettenis
2013-03-06 10:29 ` Metzger, Markus T
1 sibling, 1 reply; 102+ messages in thread
From: Mark Kettenis @ 2013-03-06 10:11 UTC (permalink / raw)
To: markus.t.metzger; +Cc: gdb-patches, markus.t.metzger
> From: Markus Metzger <markus.t.metzger@intel.com>
> Date: Mon, 4 Mar 2013 18:05:49 +0100
>
> 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.
>
> 2013-03-04 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.
> +/* See linux-btrace.h. */
> +
> +VEC (btrace_block_s) *
> +linux_read_btrace (struct btrace_target_info *tinfo)
> +{
> + 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;
> +
> + 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;
> +
> + /* Make sure the trace data is up-to-date. */
> + memory_barrier ();
The barrier here makes absolutely no sense to me. It's only a
compiler barrier and declaring header as volatile should be enough to
force the compiler to fetch HEADER->data_head from memory.
> +
> + /* 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;
> + }
^ permalink raw reply [flat|nested] 102+ messages in thread* RE: [patch v9 02/23] linux, btrace: perf_event based branch tracing
2013-03-06 10:11 ` Mark Kettenis
@ 2013-03-06 10:29 ` Metzger, Markus T
0 siblings, 0 replies; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 10:29 UTC (permalink / raw)
To: Mark Kettenis; +Cc: gdb-patches, markus.t.metzger
> -----Original Message-----
> From: gdb-patches-owner@sourceware.org [mailto:gdb-patches-owner@sourceware.org] On Behalf Of Mark Kettenis
> Sent: Wednesday, March 06, 2013 11:12 AM
> > + /* Make sure the trace data is up-to-date. */
> > + memory_barrier ();
>
> The barrier here makes absolutely no sense to me. It's only a
> compiler barrier and declaring header as volatile should be enough to
> force the compiler to fetch HEADER->data_head from memory.
Removed.
Thanks,
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] 102+ messages in thread
* [patch v9 05/23] remote, btrace: add branch trace remote ops
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (3 preceding siblings ...)
2013-03-04 17:07 ` [patch v9 02/23] linux, btrace: perf_event based branch tracing Markus Metzger
@ 2013-03-04 17:07 ` Markus Metzger
2013-03-05 20:07 ` Jan Kratochvil
2013-03-04 17:07 ` [patch v9 08/23] gdbserver, linux, btrace: add btrace support for linux-low Markus Metzger
` (18 subsequent siblings)
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:07 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Add the gdb remote target operations for branch tracing. We define the following
packets:
qbtrace query the current thread if new trace data is available
returns "yes" or "no" or "Enn"
Qbtrace:on 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
2013-03-04 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_btrace_has_changed): 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.
---
gdb/remote.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/target.h | 4 +-
2 files changed, 181 insertions(+), 1 deletions(-)
mode change 100644 => 100755 gdb/remote.c
diff --git a/gdb/remote.c b/gdb/remote.c
old mode 100644
new mode 100755
index 88a57c8..787c596
--- 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;
@@ -1284,6 +1285,9 @@ enum {
PACKET_qXfer_fdpic,
PACKET_QDisableRandomization,
PACKET_QAgent,
+ PACKET_qbtrace,
+ PACKET_Qbtrace,
+ PACKET_qXfer_btrace,
PACKET_MAX
};
@@ -3995,6 +3999,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", PACKET_DISABLE, remote_supported_packet, PACKET_qbtrace },
+ { "Qbtrace", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace },
+ { "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_btrace }
};
static char *remote_support_xml;
@@ -8796,6 +8804,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;
}
@@ -11115,6 +11127,158 @@ 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].support != PACKET_ENABLE)
+ return 0;
+ if (remote_protocol_packets[PACKET_Qbtrace].support != PACKET_ENABLE)
+ return 0;
+ if (remote_protocol_packets[PACKET_qXfer_btrace].support != PACKET_ENABLE)
+ return 0;
+
+ return 1;
+}
+
+/* Send the Qbtrace packet and check the response. */
+
+static void
+send_Qbtrace (ptid_t ptid, int enable)
+{
+ struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace];
+ 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);
+ buf += xsnprintf (buf, endbuf - buf, enable ? "on" : "off");
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (packet_ok (rs->buf, packet) == PACKET_ERROR)
+ {
+ if (enable != 0)
+ error (_("Could not enable branch tracing for %s: %s"),
+ target_pid_to_str (ptid), rs->buf);
+ else
+ error (_("Could not disable branch tracing for %s: %s"),
+ target_pid_to_str (ptid), rs->buf);
+ }
+}
+
+/* Enable branch tracing. */
+
+static struct btrace_target_info *
+remote_enable_btrace (ptid_t ptid)
+{
+ struct btrace_target_info *tinfo = NULL;
+
+ /* This will throw an error if enabling failed. */
+ send_Qbtrace (ptid, 1);
+
+ tinfo = xzalloc (sizeof (*tinfo));
+ tinfo->ptid = ptid;
+
+ return tinfo;
+}
+
+/* Disable branch tracing. */
+
+static void
+remote_disable_btrace (struct btrace_target_info *tinfo)
+{
+ /* This will throw an error if disabling failed. */
+ send_Qbtrace (tinfo->ptid, 0);
+
+ xfree (tinfo);
+}
+
+/* Check whether branch trace data has changed. */
+
+static int
+remote_btrace_has_changed (struct btrace_target_info *tinfo)
+{
+ struct packet_config *packet = &remote_protocol_packets[PACKET_qbtrace];
+ 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);
+
+ switch (packet_ok (rs->buf, packet))
+ {
+ case PACKET_OK:
+ break;
+
+ case PACKET_UNKNOWN:
+ return 0;
+
+ case PACKET_ERROR:
+ error (_("Failed to check for branch trace data for %s: %s."),
+ target_pid_to_str (tinfo->ptid), rs->buf);
+ }
+
+ if (strcmp (rs->buf, "yes") == 0)
+ return 1;
+
+ if (strcmp (rs->buf, "no") == 0)
+ return 0;
+
+ error (_("Bad remote reply: %s."), rs->buf);
+
+ return 0;
+}
+
+/* Read the branch trace. */
+
+static VEC (btrace_block_s) *
+remote_read_btrace (struct btrace_target_info *tinfo)
+{
+ struct packet_config *packet = &remote_protocol_packets[PACKET_qXfer_btrace];
+ struct remote_state *rs = get_remote_state ();
+ VEC (btrace_block_s) *btrace = NULL;
+ 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
+
+ xml = target_read_stralloc (¤t_target,
+ TARGET_OBJECT_BTRACE, NULL);
+ 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)
{
@@ -11231,6 +11395,11 @@ 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_btrace_has_changed = remote_btrace_has_changed;
+ remote_ops.to_read_btrace = remote_read_btrace;
}
/* Set up the extended remote vector by making a copy of the standard
@@ -11755,6 +11924,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],
+ "qbtrace", "query-btrace", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace],
+ "Qbtrace", "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 628c108..c543118 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -287,7 +287,9 @@ 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,
+ /* Branch trace data, in XML format. */
+ TARGET_OBJECT_BTRACE
/* Possible future objects: TARGET_OBJECT_FILE, ... */
};
--
1.7.1
^ permalink raw reply [flat|nested] 102+ messages in thread* Re: [patch v9 05/23] remote, btrace: add branch trace remote ops
2013-03-04 17:07 ` [patch v9 05/23] remote, btrace: add branch trace remote ops Markus Metzger
@ 2013-03-05 20:07 ` Jan Kratochvil
2013-03-06 9:00 ` Metzger, Markus T
0 siblings, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:07 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:05:52 +0100, Markus Metzger wrote:
> Add the gdb remote target operations for branch tracing. We define the following
> packets:
>
> qbtrace query the current thread if new trace data is available
> returns "yes" or "no" or "Enn"
>
> Qbtrace:on enable branch tracing for the current thread
> returns "OK" or "Enn"
This is not right as you changed it to Qbtrace:bts.
>
> 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
>
> 2013-03-04 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_btrace_has_changed): 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.
This was already reviewed before and OK for check-in.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* RE: [patch v9 05/23] remote, btrace: add branch trace remote ops
2013-03-05 20:07 ` Jan Kratochvil
@ 2013-03-06 9:00 ` Metzger, Markus T
0 siblings, 0 replies; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 9:00 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, markus.t.metzger
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Tuesday, March 05, 2013 9:07 PM
> > qbtrace query the current thread if new trace data is available
> > returns "yes" or "no" or "Enn"
> >
> > Qbtrace:on enable branch tracing for the current thread
> > returns "OK" or "Enn"
>
> This is not right as you changed it to Qbtrace:bts.
I changed this in a later patch on top of this. I have not merged that change
into this patch since I wanted separate feedback on the :bts change.
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] 102+ messages in thread
* [patch v9 08/23] gdbserver, linux, btrace: add btrace support for linux-low
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (4 preceding siblings ...)
2013-03-04 17:07 ` [patch v9 05/23] remote, btrace: add branch trace remote ops Markus Metzger
@ 2013-03-04 17:07 ` Markus Metzger
2013-03-05 20:09 ` Jan Kratochvil
2013-03-06 13:33 ` Jan Kratochvil
2013-03-04 17:07 ` [patch v9 03/23] linux, i386, amd64: enable btrace for 32bit and 64bit linux native Markus Metzger
` (17 subsequent siblings)
23 siblings, 2 replies; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:07 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger
Implement btrace target ops in target linux-low using the common linux-btrace
functions.
2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
gdbserver/
* 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/linux-low.c | 57 +++++++++++++++++++++++++++++++++++++++++++
5 files changed, 75 insertions(+), 2 deletions(-)
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 b9a99d0..9ab38b5 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/linux-low.c b/gdb/gdbserver/linux-low.c
index c52cd2e..c4507c8 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
@@ -5815,6 +5819,46 @@ 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)
+{
+ VEC (btrace_block_s) *btrace;
+ struct btrace_block *block;
+ int i;
+
+ btrace = linux_read_btrace (tinfo);
+
+ 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,
@@ -5879,6 +5923,19 @@ 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_btrace_has_changed,
+ linux_low_read_btrace,
+#else
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+#endif
};
static void
--
1.7.1
^ permalink raw reply [flat|nested] 102+ messages in thread* Re: [patch v9 08/23] gdbserver, linux, btrace: add btrace support for linux-low
2013-03-04 17:07 ` [patch v9 08/23] gdbserver, linux, btrace: add btrace support for linux-low Markus Metzger
@ 2013-03-05 20:09 ` Jan Kratochvil
2013-03-06 9:17 ` Metzger, Markus T
2013-03-06 13:33 ` Jan Kratochvil
1 sibling, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:09 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:05:55 +0100, Markus Metzger wrote:
> Implement btrace target ops in target linux-low using the common linux-btrace
> functions.
>
> 2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
>
> gdbserver/
> * 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.
[...]
> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
> index c52cd2e..c4507c8 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"
Indentation (as it is inside #if*):
# include "linux-btrace.h"
> +#endif
> +
> #ifndef HAVE_ELF32_AUXV_T
> /* Copied from glibc's elf.h. */
> typedef struct
Reviewed by Pedro IIRC.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* RE: [patch v9 08/23] gdbserver, linux, btrace: add btrace support for linux-low
2013-03-05 20:09 ` Jan Kratochvil
@ 2013-03-06 9:17 ` Metzger, Markus T
0 siblings, 0 replies; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 9:17 UTC (permalink / raw)
To: Jan Kratochvil
Cc: gdb-patches, markus.t.metzger, Pedro Alves (palves@redhat.com)
> -----Original Message-----
> From: gdb-patches-owner@sourceware.org [mailto:gdb-patches-owner@sourceware.org] On Behalf Of Jan Kratochvil
> Sent: Tuesday, March 05, 2013 9:09 PM
> Reviewed by Pedro IIRC.
Same here.
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] 102+ messages in thread
* Re: [patch v9 08/23] gdbserver, linux, btrace: add btrace support for linux-low
2013-03-04 17:07 ` [patch v9 08/23] gdbserver, linux, btrace: add btrace support for linux-low Markus Metzger
2013-03-05 20:09 ` Jan Kratochvil
@ 2013-03-06 13:33 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-06 13:33 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger, Pedro Alves
On Mon, 04 Mar 2013 18:05:55 +0100, Markus Metzger wrote:
> + if (tinfo != NULL)
> + tinfo->ptr_bits = register_size (0) * 8;
The diff against Pedro's review is OK; except for the Pedro's complaint on
PTR_BITS; but I see it is an abstraction as it is used in gdb/common/ while in
gdb/ one needs to use gdbarch_ptr_bit (gdbarch) and in gdbserver/ one needs to
use register_size (0).
There could be some more general abstraction put in gdb/common/ but I find it
acceptable as is for this patch.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 03/23] linux, i386, amd64: enable btrace for 32bit and 64bit linux native
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (5 preceding siblings ...)
2013-03-04 17:07 ` [patch v9 08/23] gdbserver, linux, btrace: add btrace support for linux-low Markus Metzger
@ 2013-03-04 17:07 ` Markus Metzger
2013-03-05 20:06 ` Jan Kratochvil
2013-03-04 17:07 ` [patch v9 01/23] thread, btrace: add generic branch trace support Markus Metzger
` (16 subsequent siblings)
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:07 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.
2013-03-04 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 | 42 ++++++++++++++++++++++++++++++++++++++++++
gdb/config/i386/linux.mh | 3 ++-
gdb/config/i386/linux64.mh | 2 +-
gdb/i386-linux-nat.c | 42 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index 3d1983b..c82edda 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,13 @@ _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_btrace_has_changed = linux_btrace_has_changed;
+ 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..d439133 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,13 @@ _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_btrace_has_changed = linux_btrace_has_changed;
+ 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] 102+ messages in thread* Re: [patch v9 03/23] linux, i386, amd64: enable btrace for 32bit and 64bit linux native
2013-03-04 17:07 ` [patch v9 03/23] linux, i386, amd64: enable btrace for 32bit and 64bit linux native Markus Metzger
@ 2013-03-05 20:06 ` Jan Kratochvil
0 siblings, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:06 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:05:50 +0100, Markus Metzger wrote:
> 2013-03-04 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.
OK.
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 01/23] thread, btrace: add generic branch trace support
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (6 preceding siblings ...)
2013-03-04 17:07 ` [patch v9 03/23] linux, i386, amd64: enable btrace for 32bit and 64bit linux native Markus Metzger
@ 2013-03-04 17:07 ` Markus Metzger
2013-03-05 20:06 ` Jan Kratochvil
2013-03-06 21:11 ` Doug Evans
2013-03-04 17:07 ` [patch v9 16/23] record: default target methods Markus Metzger
` (15 subsequent siblings)
23 siblings, 2 replies; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:07 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.
2013-03-04 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.
(target_btrace_has_changed): 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.
* infcmd.c: Include btrace.h.
(detach_command): Call btrace_disconnect.
* common/btrace-common.h: New file.
---
gdb/Makefile.in | 4 +-
gdb/btrace.c | 467 ++++++++++++++++++++++++++++++++++++++++++++
gdb/btrace.h | 135 +++++++++++++
gdb/common/btrace-common.h | 62 ++++++
gdb/gdbthread.h | 4 +
gdb/infcmd.c | 2 +
gdb/target.c | 69 +++++++
gdb/target.h | 35 ++++
gdb/thread.c | 3 +
9 files changed, 779 insertions(+), 2 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..b6cd1c8
--- /dev/null
+++ b/gdb/btrace.c
@@ -0,0 +1,467 @@
+/* Branch trace support for GDB, the GNU debugger.
+
+ Copyright (C) 2012 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 minimal_symbol *msym;
+ struct symbol *sym;
+ const char *filename;
+
+ msym = bfun->msym;
+ sym = bfun->sym;
+
+ if (sym != NULL)
+ filename = symtab_to_filename_for_display (sym->symtab);
+ else if (msym != NULL)
+ {
+ filename = msym->filename;
+ if (filename == NULL || *filename == 0)
+ filename = "<unknown>";
+ }
+ 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)
+ {
+ const char *bfname, *fname;
+
+ /* Check the function name. */
+ if (strcmp_iw (SYMBOL_PRINT_NAME (mfun),
+ SYMBOL_PRINT_NAME (msym)) != 0)
+ return 1;
+
+ /* Check the location of those functions, as well. */
+ bfname = msym->filename;
+ fname = mfun->filename;
+ if (fname != NULL && bfname != NULL
+ && filename_cmp (fname, bfname) != 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_iw (SYMBOL_PRINT_NAME (fun),
+ SYMBOL_PRINT_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 minimal_symbol *msym;
+ struct symbol *sym;
+ const char *bfile;
+
+ msym = bfun->msym;
+ sym = bfun->sym;
+
+ if (sym != NULL)
+ bfile = symtab_to_fullname (sym->symtab);
+ else if (msym != NULL && msym->filename != NULL)
+ bfile = msym->filename;
+ 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_disconnect (void)
+{
+ struct thread_info *tp;
+
+ DEBUG ("disconnect");
+
+ ALL_THREADS (tp)
+ btrace_disable (tp);
+}
+
+/* See btrace.h. */
+
+void
+btrace_fetch (struct thread_info *tp)
+{
+ struct btrace_thread_info *btinfo;
+
+ DEBUG ("fetch thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+
+ btinfo = &tp->btrace;
+ if (btinfo->target == NULL)
+ return;
+
+ if (!target_btrace_has_changed (btinfo->target))
+ return;
+
+ btrace_clear (tp);
+
+ btinfo->btrace = target_read_btrace (btinfo->target);
+ 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..a1b01c8
--- /dev/null
+++ b/gdb/btrace.h
@@ -0,0 +1,135 @@
+/* Branch trace support for GDB, the GNU debugger.
+
+ Copyright (C) 2012 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. */
+ 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 [begin; end[ 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 [begin; end[ 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 *);
+
+/* Disconnect branch tracing on detach. */
+extern void btrace_disconnect (void);
+
+/* 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..90372ba
--- /dev/null
+++ b/gdb/common/btrace-common.h
@@ -0,0 +1,62 @@
+/* Branch trace support for GDB, the GNU debugger.
+
+ Copyright (C) 2012 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 instruction in the block. */
+ CORE_ADDR begin;
+
+ /* The address 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;
+
+#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/infcmd.c b/gdb/infcmd.c
index 1ef3b48..d808e92 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -56,6 +56,7 @@
#include "inf-loop.h"
#include "continuations.h"
#include "linespec.h"
+#include "btrace.h"
/* Local functions: */
@@ -2725,6 +2726,7 @@ detach_command (char *args, int from_tty)
error (_("The program is not being run."));
disconnect_tracing (from_tty);
+ btrace_disconnect ();
target_detach (args, from_tty);
diff --git a/gdb/target.c b/gdb/target.c
index ecb1325..9dfbe08 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4147,6 +4147,75 @@ 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. */
+int
+target_btrace_has_changed (struct btrace_target_info *btinfo)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_btrace_has_changed != NULL)
+ return t->to_btrace_has_changed (btinfo);
+
+ tcomplain ();
+ return 0;
+}
+
+/* See target.h. */
+VEC (btrace_block_s) *
+target_read_btrace (struct btrace_target_info *btinfo)
+{
+ 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);
+
+ 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..628c108 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
{
@@ -857,6 +858,22 @@ 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);
+
+ /* Check whether branch trace changed on the target. */
+ int (*to_btrace_has_changed) (struct btrace_target_info *);
+
+ /* Read branch trace data. */
+ VEC (btrace_block_s) *(*to_read_btrace) (struct btrace_target_info *);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -1897,4 +1914,22 @@ 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);
+
+/* Check whether there is no branch tracing data available. */
+extern int target_btrace_has_changed (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 *);
+
+
#endif /* !defined (TARGET_H) */
diff --git a/gdb/thread.c b/gdb/thread.c
index 6b53c7a..cffaa42 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] 102+ messages in thread* Re: [patch v9 01/23] thread, btrace: add generic branch trace support
2013-03-04 17:07 ` [patch v9 01/23] thread, btrace: add generic branch trace support Markus Metzger
@ 2013-03-05 20:06 ` Jan Kratochvil
2013-03-05 22:02 ` Tom Tromey
2013-03-06 21:11 ` Doug Evans
1 sibling, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:06 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:05:48 +0100, Markus Metzger wrote:
> 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.
>
> 2013-03-04 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.
> (target_btrace_has_changed): 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.
> * infcmd.c: Include btrace.h.
> (detach_command): Call btrace_disconnect.
> * common/btrace-common.h: New file.
[...]
> --- /dev/null
> +++ b/gdb/btrace.c
> @@ -0,0 +1,467 @@
> +/* Branch trace support for GDB, the GNU debugger.
> +
> + Copyright (C) 2012 Free Software Foundation, Inc.
Please grep all files so that only 2013 is present in new files.
[...]
> +/* 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 minimal_symbol *msym;
> + struct symbol *sym;
> + const char *filename;
> +
> + msym = bfun->msym;
> + sym = bfun->sym;
> +
> + if (sym != NULL)
> + filename = symtab_to_filename_for_display (sym->symtab);
> + else if (msym != NULL)
> + {
> + filename = msym->filename;
> + if (filename == NULL || *filename == 0)
> + filename = "<unknown>";
Please never use minimal_symbol->filename (as I already asked for). It is
there only for some STABS compatibility, it works only for static (not global)
ELF symbols, during a small test it reports for main.c file 'crtstuff.c'
(where it really is not from).
GDB does not currently try to print any filenames for minimal symbols:
Temporary breakpoint 1, 0x00000000004004fa in main ()
vs.
Temporary breakpoint 1, main () at msym.c:3
If you have some reason to start printing filenames for minimal symbols it
needs to be a GDB global effort and it is a completely separate patchset.
And last but not least in general minimal_symbol->filename is never useful.
It is present only for file static symbols, not for global symbols. Therefore
the binary must not be stripped to have such file static ELF symbol at all.
But if it is not stripped there will be (in most cases) full DWARF.
If you want to make an excuse it is used only for DEBUG_FTRACE then this
function needs to be called as a debug function, like
ftrace_print_filename_for_debug. But even inthis case I do not
minimal_symbol->filename printing acceptable for reasons above.
> + }
> + 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)
> + {
> + const char *bfname, *fname;
> +
> + /* Check the function name. */
> + if (strcmp_iw (SYMBOL_PRINT_NAME (mfun),
> + SYMBOL_PRINT_NAME (msym)) != 0)
In fact I suggested it wrongly before, not realizing/seeing it whole.
Here could be rather SYMBOL_LINKAGE_NAME. For example various ctor/dtors
kinds like gnu_v3_base_object_ctor are not visible in SYMBOL_PRINT_NAME (nor
SYMBOL_SEARCH_NAME) but they are visible in SYMBOL_LINKAGE_NAME. But for
SYMBOL_LINKAGE_NAME one should use strcmp (not strcmp_iw).
If you would like to compare demangled names then strcmp_iw would be OK but
then rather SYMBOL_SEARCH_NAME.
But still rather strcmp and SYMBOL_LINKAGE_NAME.
> + return 1;
> +
> + /* Check the location of those functions, as well. */
> + bfname = msym->filename;
> + fname = mfun->filename;
> + if (fname != NULL && bfname != NULL
> + && filename_cmp (fname, bfname) != 0)
> + return 1;
This block should be deleted, minimal_symbol->filename is unsupported.
> + }
> +
> + /* If the symbol changed, we certainly switched functions. */
> + if (fun != NULL && sym != NULL)
> + {
> + const char *bfname, *fname;
> +
> + /* Check the function name. */
> + if (strcmp_iw (SYMBOL_PRINT_NAME (fun),
> + SYMBOL_PRINT_NAME (sym)) != 0)
Change like above.
> + 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 minimal_symbol *msym;
> + struct symbol *sym;
> + const char *bfile;
> +
> + msym = bfun->msym;
> + sym = bfun->sym;
> +
> + if (sym != NULL)
> + bfile = symtab_to_fullname (sym->symtab);
> + else if (msym != NULL && msym->filename != NULL)
> + bfile = msym->filename;
This block should be removed, minimal_symbol->filename is unsupported, present
AFAIK only for STABS compatibility.
[...]
> diff --git a/gdb/target.c b/gdb/target.c
> index ecb1325..9dfbe08 100644
> --- a/gdb/target.c
> +++ b/gdb/target.c
> @@ -4147,6 +4147,75 @@ target_ranged_break_num_registers (void)
> return -1;
> }
>
> +/* See target.h. */
BTW empty line here and in all the function definition cases below, see:
http://sourceware.org/gdb/wiki/JoelsCodingStyleCheatSheet#Empty_line_between_subprogram_description_and_the_subprogram_implementation
> +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;
> +}
[...]
OK to check it in with the requested changes, those are straight to implement.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread* Re: [patch v9 01/23] thread, btrace: add generic branch trace support
2013-03-05 20:06 ` Jan Kratochvil
@ 2013-03-05 22:02 ` Tom Tromey
0 siblings, 0 replies; 102+ messages in thread
From: Tom Tromey @ 2013-03-05 22:02 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Markus Metzger, gdb-patches, markus.t.metzger
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> And last but not least in general minimal_symbol->filename is never
Jan> useful.
I think sometimes we should remove it; or find a way to make so that
only stabs users pay the price for it.
Tom
^ permalink raw reply [flat|nested] 102+ messages in thread
* Re: [patch v9 01/23] thread, btrace: add generic branch trace support
2013-03-04 17:07 ` [patch v9 01/23] thread, btrace: add generic branch trace support Markus Metzger
2013-03-05 20:06 ` Jan Kratochvil
@ 2013-03-06 21:11 ` Doug Evans
2013-03-07 7:50 ` Metzger, Markus T
1 sibling, 1 reply; 102+ messages in thread
From: Doug Evans @ 2013-03-06 21:11 UTC (permalink / raw)
To: Markus Metzger; +Cc: jan.kratochvil, gdb-patches, markus.t.metzger
Markus Metzger writes:
> 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.
>
> 2013-03-04 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.
> (target_btrace_has_changed): 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.
> * infcmd.c: Include btrace.h.
> (detach_command): Call btrace_disconnect.
> * common/btrace-common.h: New file.
Hi. Just some nits.
> +/* Branch trace iteration state for "record function-call-history". */
> +struct btrace_func_iterator
> +{
> + /* The function index range [begin; end[ that has been covered last time.
Typo: end]
> +/* 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 instruction in the block. */
> + CORE_ADDR begin;
> +
> + /* The address of the last instruction in the block. */
> + CORE_ADDR end;
> +};
Can you elaborate in the docs for "end" what it is?
E.g., on an ISA with only 4 byte instructions, and the block contains
two instructions, is end == begin+4 or begin+7 or begin+8?
I'd guess that it's begin+4, but IWBN if the comment
removed all doubt.
> +/* See target.h. */
Blank line between function comment and definition.
[Here and elsewhere.]
> +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;
> +}
^ permalink raw reply [flat|nested] 102+ messages in thread* RE: [patch v9 01/23] thread, btrace: add generic branch trace support
2013-03-06 21:11 ` Doug Evans
@ 2013-03-07 7:50 ` Metzger, Markus T
2013-03-07 22:57 ` Doug Evans
0 siblings, 1 reply; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-07 7:50 UTC (permalink / raw)
To: Doug Evans; +Cc: jan.kratochvil, gdb-patches, markus.t.metzger
> -----Original Message-----
> From: Doug Evans [mailto:dje@google.com]
> Sent: Wednesday, March 06, 2013 10:12 PM
Thanks for your review.
> > + /* The function index range [begin; end[ that has been covered last time.
>
> Typo: end]
That's intended to indicate that begin is included in the range whereas end isn't.
I see that this has not been clear enough. I'll reword it.
> > +/* 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 instruction in the block. */
> > + CORE_ADDR begin;
> > +
> > + /* The address of the last instruction in the block. */
> > + CORE_ADDR end;
> > +};
>
> Can you elaborate in the docs for "end" what it is?
> E.g., on an ISA with only 4 byte instructions, and the block contains
> two instructions, is end == begin+4 or begin+7 or begin+8?
> I'd guess that it's begin+4, but IWBN if the comment
> removed all doubt.
I changed both comments to say "the first byte of ...".
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] 102+ messages in thread* Re: [patch v9 01/23] thread, btrace: add generic branch trace support
2013-03-07 7:50 ` Metzger, Markus T
@ 2013-03-07 22:57 ` Doug Evans
0 siblings, 0 replies; 102+ messages in thread
From: Doug Evans @ 2013-03-07 22:57 UTC (permalink / raw)
To: Metzger, Markus T; +Cc: jan.kratochvil, gdb-patches, markus.t.metzger
On Wed, Mar 6, 2013 at 11:49 PM, Metzger, Markus T
<markus.t.metzger@intel.com> wrote:
>> -----Original Message-----
>> From: Doug Evans [mailto:dje@google.com]
>> Sent: Wednesday, March 06, 2013 10:12 PM
>
> Thanks for your review.
>
>
>> > + /* The function index range [begin; end[ that has been covered last time.
>>
>> Typo: end]
>
> That's intended to indicate that begin is included in the range whereas end isn't.
> I see that this has not been clear enough. I'll reword it.
For that use [begin,end).
ref: http://en.wikipedia.org/wiki/Interval_(mathematics)
>> > +/* 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 instruction in the block. */
>> > + CORE_ADDR begin;
>> > +
>> > + /* The address of the last instruction in the block. */
>> > + CORE_ADDR end;
>> > +};
>>
>> Can you elaborate in the docs for "end" what it is?
>> E.g., on an ISA with only 4 byte instructions, and the block contains
>> two instructions, is end == begin+4 or begin+7 or begin+8?
>> I'd guess that it's begin+4, but IWBN if the comment
>> removed all doubt.
>
> I changed both comments to say "the first byte of ...".
Thanks.
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 16/23] record: default target methods.
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (7 preceding siblings ...)
2013-03-04 17:07 ` [patch v9 01/23] thread, btrace: add generic branch trace support Markus Metzger
@ 2013-03-04 17:07 ` Markus Metzger
2013-03-05 20:10 ` Jan Kratochvil
2013-03-04 17:08 ` [patch v9 06/23] btrace, doc: document remote serial protocol Markus Metzger
` (14 subsequent siblings)
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:07 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-04 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] 102+ messages in thread* Re: [patch v9 16/23] record: default target methods.
2013-03-04 17:07 ` [patch v9 16/23] record: default target methods Markus Metzger
@ 2013-03-05 20:10 ` Jan Kratochvil
0 siblings, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:10 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:06:03 +0100, Markus Metzger wrote:
> Provide default target methods for record targets that are likely to be shared
> between different record targets.
>
> Approved by Jan Kratochvil.
>
> 2013-03-04 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.
OK.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 06/23] btrace, doc: document remote serial protocol
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (8 preceding siblings ...)
2013-03-04 17:07 ` [patch v9 16/23] record: default target methods Markus Metzger
@ 2013-03-04 17:08 ` Markus Metzger
2013-03-04 18:08 ` Eli Zaretskii
2013-03-05 20:08 ` Jan Kratochvil
2013-03-04 17:08 ` [patch v9 22/23] testsuite, gdb.btrace: add btrace tests Markus Metzger
` (13 subsequent siblings)
23 siblings, 2 replies; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:08 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger, Eli Zaretskii
Document the extensions to the remote serial protocol for supporting branch tracing.
CC: Eli Zaretskii <eliz@gnu.org>
2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
doc/
* gdb.texinfo (Requirements): List qXfer:btrace:read requiring expat.
(General Query Packets): Describe qbtrace, Qbtrace, and qXfer:btrace:read.
---
gdb/doc/gdb.texinfo | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 123 insertions(+), 0 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5f39d2e..5ac450c 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
@@ -37243,11 +37246,21 @@ These are the currently defined stub features and their properties:
@tab @samp{-}
@tab No
+@item @samp{qbtrace}
+@tab No
+@tab @samp{-}
+@tab Yes
+
@item @samp{qXfer:auxv:read}
@tab No
@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 +37321,11 @@ These are the currently defined stub features and their properties:
@tab @samp{-}
@tab Yes
+@item @samp{Qbtrace}
+@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
+The remote stub understands the @samp{qbtrace} packet.
+
+@item Qbtrace
+The remote stub understands the @samp{Qbtrace} packet.
+
@end table
@item qSymbol::
@@ -37655,6 +37683,16 @@ 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 is 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:features:read:@var{annex}:@var{offset},@var{length}
@anchor{qXfer target description read}
Access the @dfn{target description}. @xref{Target Descriptions}. The
@@ -37891,6 +37929,41 @@ The remote server created a new process.
A badly formed request or an error was encountered.
@end table
+@item qbtrace
+Return whether new branch trace data is available for the current thread.
+
+Reply:
+@table @samp
+@item yes
+New branch trace data is available.
+@item no
+No new branch trace data is available.
+@item E.errtext
+A badly formed request or an error was encountered.
+@end table
+
+@item Qbtrace:on
+Enable branch tracing for the current thread.
+
+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 +40415,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] 102+ messages in thread* Re: [patch v9 06/23] btrace, doc: document remote serial protocol
2013-03-04 17:08 ` [patch v9 06/23] btrace, doc: document remote serial protocol Markus Metzger
@ 2013-03-04 18:08 ` Eli Zaretskii
2013-03-05 20:08 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Eli Zaretskii @ 2013-03-04 18:08 UTC (permalink / raw)
To: Markus Metzger; +Cc: jan.kratochvil, gdb-patches, markus.t.metzger
> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org, markus.t.metzger@gmail.com,
> Eli Zaretskii <eliz@gnu.org>
> Date: Mon, 4 Mar 2013 18:05:53 +0100
>
> Document the extensions to the remote serial protocol for supporting branch tracing.
>
> CC: Eli Zaretskii <eliz@gnu.org>
>
> 2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
>
> doc/
> * gdb.texinfo (Requirements): List qXfer:btrace:read requiring expat.
> (General Query Packets): Describe qbtrace, Qbtrace, and qXfer:btrace:read.
OK, thanks.
^ permalink raw reply [flat|nested] 102+ messages in thread
* Re: [patch v9 06/23] btrace, doc: document remote serial protocol
2013-03-04 17:08 ` [patch v9 06/23] btrace, doc: document remote serial protocol Markus Metzger
2013-03-04 18:08 ` Eli Zaretskii
@ 2013-03-05 20:08 ` Jan Kratochvil
2013-03-06 9:06 ` Metzger, Markus T
1 sibling, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:08 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger, Eli Zaretskii
On Mon, 04 Mar 2013 18:05:53 +0100, Markus Metzger wrote:
> Document the extensions to the remote serial protocol for supporting branch tracing.
>
> CC: Eli Zaretskii <eliz@gnu.org>
>
> 2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
>
> doc/
> * gdb.texinfo (Requirements): List qXfer:btrace:read requiring expat.
> (General Query Packets): Describe qbtrace, Qbtrace, and qXfer:btrace:read.
[...]
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
[...]
>
> +@item qbtrace
> +Return whether new branch trace data is available for the current thread.
> +
> +Reply:
> +@table @samp
> +@item yes
> +New branch trace data is available.
> +@item no
> +No new branch trace data is available.
> +@item E.errtext
> +A badly formed request or an error was encountered.
> +@end table
> +
> +@item Qbtrace:on
Again it should be merged.
> +Enable branch tracing for the current thread.
> +
> +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.
[...]
Reviewed by Eli and probably also Pedro etc.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* RE: [patch v9 06/23] btrace, doc: document remote serial protocol
2013-03-05 20:08 ` Jan Kratochvil
@ 2013-03-06 9:06 ` Metzger, Markus T
2013-03-06 9:50 ` Jan Kratochvil
0 siblings, 1 reply; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 9:06 UTC (permalink / raw)
To: Jan Kratochvil
Cc: gdb-patches, markus.t.metzger, Eli Zaretskii,
Pedro Alves (palves@redhat.com)
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Tuesday, March 05, 2013 9:08 PM
> > +@item Qbtrace:on
>
> Again it should be merged.
I would just leave the patches separate. The series will go in as a whole, anyway.
> Reviewed by Eli and probably also Pedro etc.
This has been OK'ed by Eli. Since this is doc only, I assume that this suffices. Correct?
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] 102+ messages in thread
* Re: [patch v9 06/23] btrace, doc: document remote serial protocol
2013-03-06 9:06 ` Metzger, Markus T
@ 2013-03-06 9:50 ` Jan Kratochvil
2013-03-06 10:01 ` Metzger, Markus T
0 siblings, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-06 9:50 UTC (permalink / raw)
To: Metzger, Markus T
Cc: gdb-patches, markus.t.metzger, Eli Zaretskii,
Pedro Alves (palves@redhat.com)
On Wed, 06 Mar 2013 10:06:12 +0100, Metzger, Markus T wrote:
> I would just leave the patches separate. The series will go in as a whole, anyway.
OK when it gets checked in as a single commit; in fact the patches are
probably not buildable incrementally anyway, I did not realize that yesterday.
> > Reviewed by Eli and probably also Pedro etc.
>
> This has been OK'ed by Eli. Since this is doc only, I assume that this
> suffices. Correct?
Yes.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* RE: [patch v9 06/23] btrace, doc: document remote serial protocol
2013-03-06 9:50 ` Jan Kratochvil
@ 2013-03-06 10:01 ` Metzger, Markus T
2013-03-06 12:07 ` Jan Kratochvil
0 siblings, 1 reply; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 10:01 UTC (permalink / raw)
To: Jan Kratochvil
Cc: gdb-patches, markus.t.metzger, Eli Zaretskii,
Pedro Alves (palves@redhat.com)
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Wednesday, March 06, 2013 10:50 AM
> On Wed, 06 Mar 2013 10:06:12 +0100, Metzger, Markus T wrote:
> > I would just leave the patches separate. The series will go in as a whole, anyway.
>
> OK when it gets checked in as a single commit; in fact the patches are
> probably not buildable incrementally anyway, I did not realize that yesterday.
I intended to commit the patches separately. There is a single patch that does not
build - the one where we split record.c.
I could also squash the entire series, if that's preferred, but the resulting patch
will be huge.
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] 102+ messages in thread
* Re: [patch v9 06/23] btrace, doc: document remote serial protocol
2013-03-06 10:01 ` Metzger, Markus T
@ 2013-03-06 12:07 ` Jan Kratochvil
2013-03-06 12:13 ` Metzger, Markus T
0 siblings, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-06 12:07 UTC (permalink / raw)
To: Metzger, Markus T
Cc: gdb-patches, markus.t.metzger, Eli Zaretskii,
Pedro Alves (palves@redhat.com)
On Wed, 06 Mar 2013 11:01:29 +0100, Metzger, Markus T wrote:
> I intended to commit the patches separately. There is a single patch that does not
> build - the one where we split record.c.
>
> I could also squash the entire series, if that's preferred, but the resulting patch
> will be huge.
As long as each commit is buildable and not regressing (and not introducing
unapproved code/functionality which just gets deleted by a later patch) it is
preferred to check it in separately.
(Reason: For example if one git bisect-s a regression it is easier to
investigate a smaller commit.)
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* RE: [patch v9 06/23] btrace, doc: document remote serial protocol
2013-03-06 12:07 ` Jan Kratochvil
@ 2013-03-06 12:13 ` Metzger, Markus T
2013-03-06 12:17 ` Jan Kratochvil
0 siblings, 1 reply; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 12:13 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, markus.t.metzger
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Wednesday, March 06, 2013 1:08 PM
> As long as each commit is buildable and not regressing (and not introducing
> unapproved code/functionality which just gets deleted by a later patch) it is
> preferred to check it in separately.
I squashed the gdbserver/remote changes and I'll also squash the record
refactoring.
Regarding PRs, is it OK to log a PR for the recursive function known fail before
the series has actually been committed?
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] 102+ messages in thread
* Re: [patch v9 06/23] btrace, doc: document remote serial protocol
2013-03-06 12:13 ` Metzger, Markus T
@ 2013-03-06 12:17 ` Jan Kratochvil
0 siblings, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-06 12:17 UTC (permalink / raw)
To: Metzger, Markus T; +Cc: gdb-patches, markus.t.metzger
On Wed, 06 Mar 2013 13:11:25 +0100, Metzger, Markus T wrote:
> Regarding PRs, is it OK to log a PR for the recursive function known fail before
> the series has actually been committed?
In general BZ is very free, one could even file it for an unreviewed patch and
later just close the PR if it gets resolved some other way etc.
And yes, otherwise apparently you cannot check in the filed PR number...
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 22/23] testsuite, gdb.btrace: add btrace tests
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (9 preceding siblings ...)
2013-03-04 17:08 ` [patch v9 06/23] btrace, doc: document remote serial protocol Markus Metzger
@ 2013-03-04 17:08 ` Markus Metzger
2013-03-04 19:47 ` Jan Kratochvil
2013-03-05 20:14 ` Jan Kratochvil
2013-03-04 17:08 ` [patch v9 11/23] target: add add_deprecated_target_alias Markus Metzger
` (12 subsequent siblings)
23 siblings, 2 replies; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:08 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 an XFAIL.
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 | 83 ++++++++
gdb/testsuite/gdb.btrace/function_call_history.c | 45 ++++
gdb/testsuite/gdb.btrace/function_call_history.exp | 211 ++++++++++++++++++++
gdb/testsuite/gdb.btrace/instruction_history.c | 26 +++
gdb/testsuite/gdb.btrace/instruction_history.exp | 190 ++++++++++++++++++
gdb/testsuite/gdb.btrace/x86-instruction_history.S | 32 +++
gdb/testsuite/lib/gdb.exp | 69 +++++++
12 files changed, 702 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.c
create mode 100644 gdb/testsuite/gdb.btrace/instruction_history.exp
create mode 100644 gdb/testsuite/gdb.btrace/x86-instruction_history.S
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..6cdd40a
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/enable.exp
@@ -0,0 +1,83 @@
+# 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
+}
+runto_main
+
+# 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"
+
+# rerun
+send_gdb "run\n"
+gdb_expect {
+ -re "The program .* has been started already.*y or n. $" {
+ send_gdb "y\n"
+ exp_continue
+ }
+ -re "Starting program.*$gdb_prompt $" {
+ pass "rerun to main"
+ }
+ -re "$gdb_prompt $" {
+ fail "rerun to main"
+ }
+ timeout {
+ fail "(timeout) rerun to main"
+ }
+}
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..711dd20
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/function_call_history.exp
@@ -0,0 +1,211 @@
+# 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
+}
+runto_main
+
+# 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 main\r
+1 inc\r
+2 main\r
+3 inc\r
+4 main\r
+5 inc\r
+6 main\r
+7 inc\r
+8 main\r
+9 inc\r
+10 main\r
+11 inc\r
+12 main\r
+13 inc\r
+14 main\r
+15 inc\r
+16 main\r
+17 inc\r
+18 main\r
+19 inc\r
+20 main\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 main\r
+1 inc\r
+2 main\r
+3 inc\r
+4 main\r
+5 inc\r
+6 main\r
+7 inc\r
+8 main\r
+9 inc\r
+10 main\r
+11 inc\r
+12 main\r
+13 inc\r
+14 main\r
+15 inc\r
+16 main\r
+17 inc\r
+18 main\r
+19 inc\r
+20 main\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 main\r
+1 inc\r
+2 main\r
+3 inc\r
+4 main\r
+5 inc\r
+6 main\r
+7 inc\r
+8 main\r
+9 inc\r
+10 main\r
+11 inc\r
+12 main\r
+13 inc\r
+14 main\r" "record function-call-history - show first 15 entries"
+
+# show last 6 entries
+gdb_test "record function-call-history +" "15 inc\r
+16 main\r
+17 inc\r
+18 main\r
+19 inc\r
+20 main\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 main\r
+7 inc\r
+8 main\r
+9 inc\r
+10 main\r
+11 inc\r
+12 main\r
+13 inc\r
+14 main\r
+15 inc\r
+16 main\r
+17 inc\r
+18 main\r
+19 inc\r
+20 main\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 main\r
+1 inc\r
+2 main\r
+3 inc\r
+4 main\r
+5 inc\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 main\r
+.*$srcfile:22-24 inc\r
+.*$srcfile:40-41 main\r
+.*$srcfile:22-24 inc\r
+.*$srcfile:40-41 main\r
+.*$srcfile:22-24 inc\r
+.*$srcfile:40-41 main\r
+.*$srcfile:22-24 inc\r
+.*$srcfile:40-41 main\r
+.*$srcfile:22-24 inc\r
+.*$srcfile:40-41 main\r
+.*$srcfile:22-24 inc\r
+.*$srcfile:40-41 main\r
+.*$srcfile:22-24 inc\r
+.*$srcfile:40-41 main\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 inc\r
+.*$srcfile:40-41 main\r
+.*$srcfile:22-24 inc\r
+.*$srcfile:40-41 main\r
+.*$srcfile:22-24 inc\r
+.*$srcfile:40-43 main\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 inc\r
+4 main\r
+5 inc\r
+6 main\r
+7 inc\r
+8 main\r
+9 inc\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 main\r\n14 fib\r\n15 fib\r\n16 fib\r\n17 fib\r\n18 fib\r\n19 fib\r\n20 fib\r\n21 fib\r\n22 main\r\n$gdb_prompt " {
+ pass $message
+ }
+ -re "13 inc\r\n14 main\r\n15 inc\r\n16 main\r\n17 inc\r\n18 main\r\n19 inc\r\n20 main\r\n21 fib\r\n22 main\r\n$gdb_prompt " {
+ # recursive function calls appear only as 1 call
+ xfail $message
+ }
+}
diff --git a/gdb/testsuite/gdb.btrace/instruction_history.c b/gdb/testsuite/gdb.btrace/instruction_history.c
new file mode 100644
index 0000000..2dc3c6b
--- /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..92288eb
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/instruction_history.exp
@@ -0,0 +1,190 @@
+# 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
+if [prepare_for_testing instruction_history.exp $testfile "$testfile.c x86-$testfile.S" {debug}] {
+ return -1
+}
+
+runto_main
+
+# set bp before loop and continue
+set bp_location [gdb_get_line_number "bp.1" x86-$testfile.S]
+gdb_breakpoint x86-$testfile.S:$bp_location
+gdb_continue_to_breakpoint "cont to $bp_location" ".*x86-$testfile.S:$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" x86-$testfile.S]
+gdb_breakpoint x86-$testfile.S:$bp_location
+gdb_continue_to_breakpoint "cont to $bp_location" ".*x86-$testfile.S:$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\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 /pf 1,6" "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"
+
+# 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/gdb.btrace/x86-instruction_history.S b/gdb/testsuite/gdb.btrace/x86-instruction_history.S
new file mode 100644
index 0000000..5c74b46
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/x86-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/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 8b16b38..1393455 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -2097,6 +2097,75 @@ 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 btrace[pid].c
+ set exe btrace[pid].x
+
+ set f [open $src "w"]
+ puts $f "int main() { 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.
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load "$exe"
+ runto_main
+ # 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 "$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] 102+ messages in thread* Re: [patch v9 22/23] testsuite, gdb.btrace: add btrace tests
2013-03-04 17:08 ` [patch v9 22/23] testsuite, gdb.btrace: add btrace tests Markus Metzger
@ 2013-03-04 19:47 ` Jan Kratochvil
2013-03-05 6:39 ` Metzger, Markus T
2013-03-05 20:14 ` Jan Kratochvil
1 sibling, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-04 19:47 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger, Christian Himpel
On Mon, 04 Mar 2013 18:06:09 +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 an XFAIL.
That is a known defect of GDB, not a defect of system component we cannot fix.
Therefore it should be KFAIL and the problem should be described (copy/pasted)
to GDB Bugzilla to get a PR number for the 'kfail' command.
Thanks,
Jan
[...]
> +# 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 main\r\n14 fib\r\n15 fib\r\n16 fib\r\n17 fib\r\n18 fib\r\n19 fib\r\n20 fib\r\n21 fib\r\n22 main\r\n$gdb_prompt " {
> + pass $message
> + }
> + -re "13 inc\r\n14 main\r\n15 inc\r\n16 main\r\n17 inc\r\n18 main\r\n19 inc\r\n20 main\r\n21 fib\r\n22 main\r\n$gdb_prompt " {
> + # recursive function calls appear only as 1 call
> + xfail $message
> + }
> +}
^ permalink raw reply [flat|nested] 102+ messages in thread* RE: [patch v9 22/23] testsuite, gdb.btrace: add btrace tests
2013-03-04 19:47 ` Jan Kratochvil
@ 2013-03-05 6:39 ` Metzger, Markus T
0 siblings, 0 replies; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-05 6:39 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, markus.t.metzger, Himpel, Christian
> -----Original Message-----
> From: gdb-patches-owner@sourceware.org [mailto:gdb-patches-owner@sourceware.org] On Behalf Of Jan Kratochvil
> Sent: Monday, March 04, 2013 8:47 PM
> > Recursive function calls are listed as only one function call. This is
> > marked as an XFAIL.
>
> That is a known defect of GDB, not a defect of system component we cannot fix.
> Therefore it should be KFAIL and the problem should be described (copy/pasted)
> to GDB Bugzilla to get a PR number for the 'kfail' command.
Agreed. I just didn't want to log an issue for a patch that's not yet in.
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] 102+ messages in thread
* Re: [patch v9 22/23] testsuite, gdb.btrace: add btrace tests
2013-03-04 17:08 ` [patch v9 22/23] testsuite, gdb.btrace: add btrace tests Markus Metzger
2013-03-04 19:47 ` Jan Kratochvil
@ 2013-03-05 20:14 ` Jan Kratochvil
2013-03-06 15:32 ` christian.himpel
1 sibling, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:14 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger, Christian Himpel
On Mon, 04 Mar 2013 18:06:09 +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 an XFAIL.
>
> 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.
[...]
> --- /dev/null
> +++ b/gdb/testsuite/gdb.btrace/enable.exp
> @@ -0,0 +1,83 @@
> +# 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"
\ -> \\
First processing is by TCL, second processing is by regex.
This is regex backslash. This way it acts the same as:
gdb_test "record stop" "No record target is currently active..*" "record stop without target"
One can also use {...} instead of "..." which avoids the Tcl processing, it
would be then:
gdb_test "record stop" {No record target is currently active\.} "record stop without target"
And that trailing .* is not needed there, gdb_test automatically matches
trailing "\r\n$gdb_prompt $".
> +
> +# btrace cannot be enabled without a running inferior
> +gdb_test "record btrace" "The program is not being run\." "record btrace without running program"
Again \ -> \\ .
> +
> +# 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
standard_testfile should be at the top of file; it does not start/contol GDB
any way.
> +if [prepare_for_testing $testfile.exp $testfile {} {debug}] {
> + return -1
> +}
> +runto_main
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"
\. -> \\.
twice
> +
> +# 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"
\. -> \\.
Many times below again and in the other *.exp files.
> +
> +# 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"
> +
> +# rerun
> +send_gdb "run\n"
> +gdb_expect {
> + -re "The program .* has been started already.*y or n. $" {
> + send_gdb "y\n"
> + exp_continue
> + }
> + -re "Starting program.*$gdb_prompt $" {
> + pass "rerun to main"
> + }
> + -re "$gdb_prompt $" {
> + fail "rerun to main"
> + }
> + timeout {
> + fail "(timeout) rerun to main"
> + }
> +}
In general one should never use gdb_expect. And send_gdb is used only
exceptionally. For complicated cases there is gdb_test_multiple. But in this
case why there isn't just another runto_main?
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..711dd20
> --- /dev/null
> +++ b/gdb/testsuite/gdb.btrace/function_call_history.exp
> @@ -0,0 +1,211 @@
> +# 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
> +}
> +runto_main
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 main\r
> +1 inc\r
> +2 main\r
> +3 inc\r
> +4 main\r
> +5 inc\r
> +6 main\r
> +7 inc\r
> +8 main\r
> +9 inc\r
> +10 main\r
> +11 inc\r
> +12 main\r
> +13 inc\r
> +14 main\r
> +15 inc\r
> +16 main\r
> +17 inc\r
> +18 main\r
> +19 inc\r
> +20 main\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 main\r
> +1 inc\r
> +2 main\r
> +3 inc\r
> +4 main\r
> +5 inc\r
> +6 main\r
> +7 inc\r
> +8 main\r
> +9 inc\r
> +10 main\r
> +11 inc\r
> +12 main\r
> +13 inc\r
> +14 main\r
> +15 inc\r
> +16 main\r
> +17 inc\r
> +18 main\r
> +19 inc\r
> +20 main\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 main\r
> +1 inc\r
> +2 main\r
> +3 inc\r
> +4 main\r
> +5 inc\r
> +6 main\r
> +7 inc\r
> +8 main\r
> +9 inc\r
> +10 main\r
> +11 inc\r
> +12 main\r
> +13 inc\r
> +14 main\r" "record function-call-history - show first 15 entries"
> +
> +# show last 6 entries
> +gdb_test "record function-call-history +" "15 inc\r
> +16 main\r
> +17 inc\r
> +18 main\r
> +19 inc\r
> +20 main\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 main\r
> +7 inc\r
> +8 main\r
> +9 inc\r
> +10 main\r
> +11 inc\r
> +12 main\r
> +13 inc\r
> +14 main\r
> +15 inc\r
> +16 main\r
> +17 inc\r
> +18 main\r
> +19 inc\r
> +20 main\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 main\r
> +1 inc\r
> +2 main\r
> +3 inc\r
> +4 main\r
> +5 inc\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 main\r
> +.*$srcfile:22-24 inc\r
> +.*$srcfile:40-41 main\r
> +.*$srcfile:22-24 inc\r
> +.*$srcfile:40-41 main\r
> +.*$srcfile:22-24 inc\r
> +.*$srcfile:40-41 main\r
> +.*$srcfile:22-24 inc\r
> +.*$srcfile:40-41 main\r
> +.*$srcfile:22-24 inc\r
> +.*$srcfile:40-41 main\r
> +.*$srcfile:22-24 inc\r
> +.*$srcfile:40-41 main\r
> +.*$srcfile:22-24 inc\r
> +.*$srcfile:40-41 main\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 inc\r
> +.*$srcfile:40-41 main\r
> +.*$srcfile:22-24 inc\r
> +.*$srcfile:40-41 main\r
> +.*$srcfile:22-24 inc\r
> +.*$srcfile:40-43 main\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 inc\r
> +4 main\r
> +5 inc\r
> +6 main\r
> +7 inc\r
> +8 main\r
> +9 inc\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 main\r\n14 fib\r\n15 fib\r\n16 fib\r\n17 fib\r\n18 fib\r\n19 fib\r\n20 fib\r\n21 fib\r\n22 main\r\n$gdb_prompt " {
> + pass $message
> + }
> + -re "13 inc\r\n14 main\r\n15 inc\r\n16 main\r\n17 inc\r\n18 main\r\n19 inc\r\n20 main\r\n21 fib\r\n22 main\r\n$gdb_prompt " {
> + # recursive function calls appear only as 1 call
> + xfail $message
kfail, as already discussed before.
A nitpick but there can (and therefore should) be trailing $ match so that no
more accidental input is accepted there, therefore in both cases:
main\r\n$gdb_prompt " {
->
main\r\n$gdb_prompt $" {
> + }
> +}
> diff --git a/gdb/testsuite/gdb.btrace/instruction_history.c b/gdb/testsuite/gdb.btrace/instruction_history.c
> new file mode 100644
> index 0000000..2dc3c6b
> --- /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
Rather /* comments */ ; although one will probably never use such new feature
with old compilers not supporting // for .c .
> + 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..92288eb
> --- /dev/null
> +++ b/gdb/testsuite/gdb.btrace/instruction_history.exp
> @@ -0,0 +1,190 @@
> +# 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
> +if [prepare_for_testing instruction_history.exp $testfile "$testfile.c x86-$testfile.S" {debug}] {
standard_testfile has parameters for this purpose:
standard_testfile .c x86-instruction_history.S
if [prepare_for_testing $testfile.exp $testfile "$srcfile $srcfile2" {debug}] {
And please rename x86-instruction_history.S to instruction_history-x86.S so
that completion works for all the files belonging to a testcase.
> + return -1
> +}
> +
> +runto_main
if ![runto_main] {
return -1
}
> +
> +# set bp before loop and continue
> +set bp_location [gdb_get_line_number "bp.1" x86-$testfile.S]
> +gdb_breakpoint x86-$testfile.S:$bp_location
> +gdb_continue_to_breakpoint "cont to $bp_location" ".*x86-$testfile.S:$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" x86-$testfile.S]
> +gdb_breakpoint x86-$testfile.S:$bp_location
> +gdb_continue_to_breakpoint "cont to $bp_location" ".*x86-$testfile.S:$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 " {
Again trailing $gdb_prompt $" like in the other file.
> + 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
It is OK as is but FYI one can do the escaping automatically at runtime for any
string using 'string_to_regexp' function.
> +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\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 /pf 1,6" "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"
> +
> +# 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 " {
trailing $ again.
> + 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/gdb.btrace/x86-instruction_history.S b/gdb/testsuite/gdb.btrace/x86-instruction_history.S
> new file mode 100644
> index 0000000..5c74b46
> --- /dev/null
> +++ b/gdb/testsuite/gdb.btrace/x86-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/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 8b16b38..1393455 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -2097,6 +2097,75 @@ 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 btrace[pid].c
> + set exe btrace[pid].x
Use:
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() { return 0; }"
For C there should be:
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.
> +
> + gdb_exit
> + gdb_start
> + gdb_reinitialize_dir $srcdir/$subdir
> + gdb_load "$exe"
This can be replaced by:
clean_restart btrace[pid].x
Unfortunately one cannot use $exe as that one has standard_output_file already
applied which must not be done for clean_restart.
> + runto_main
if ![runto_main] {
return [...]
}
> + # 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 "$gdb_prompt $" {
To test no output has been produced (instead of any output has been produced):
-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
If you follow the advices there shold not be an issue but it would be probably
worth another review.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread* RE: [patch v9 22/23] testsuite, gdb.btrace: add btrace tests
2013-03-05 20:14 ` Jan Kratochvil
@ 2013-03-06 15:32 ` christian.himpel
2013-03-06 16:35 ` Jan Kratochvil
0 siblings, 1 reply; 102+ messages in thread
From: christian.himpel @ 2013-03-06 15:32 UTC (permalink / raw)
To: Jan Kratochvil, Metzger, Markus T; +Cc: gdb-patches, markus.t.metzger
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Tuesday, March 05, 2013 9:14 PM
> To: Metzger, Markus T
> Cc: gdb-patches@sourceware.org; markus.t.metzger@gmail.com; Himpel, Christian
> Subject: Re: [patch v9 22/23] testsuite, gdb.btrace: add btrace tests
>
> On Mon, 04 Mar 2013 18:06:09 +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 an XFAIL.
> >
> > 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.
> [...]
> > --- /dev/null
> > +++ b/gdb/testsuite/gdb.btrace/enable.exp
> > @@ -0,0 +1,83 @@
> > +# 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"
>
> \ -> \\
> First processing is by TCL, second processing is by regex.
> This is regex backslash. This way it acts the same as:
> gdb_test "record stop" "No record target is currently active..*" "record stop without target"
>
> One can also use {...} instead of "..." which avoids the Tcl processing, it
> would be then:
> gdb_test "record stop" {No record target is currently active\.} "record stop without target"
Thanks, I'll address the \. issue in all files.
> And that trailing .* is not needed there, gdb_test automatically matches
> trailing "\r\n$gdb_prompt $".
Yes, but the output is actually 2 lines:
No record target is currently active.
Use one of the "target record-<tab><tab>" commands first.
> > +
> > +# btrace cannot be enabled without a running inferior
> > +gdb_test "record btrace" "The program is not being run\." "record btrace without running program"
>
> Again \ -> \\ .
>
>
>
>
> > +
> > +# 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
>
> standard_testfile should be at the top of file; it does not start/contol GDB
> any way.
>
>
> > +if [prepare_for_testing $testfile.exp $testfile {} {debug}] {
> > + return -1
> > +}
>
> > +runto_main
>
> if ![runto_main] {
> return -1
> }
Done.
> > +
> > +# 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"
>
> \. -> \\.
> twice
>
>
> > +
> > +# 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"
>
> \. -> \\.
>
>
> Many times below again and in the other *.exp files.
>
>
> > +
> > +# 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"
> > +
>
>
> > +# rerun
> > +send_gdb "run\n"
> > +gdb_expect {
> > + -re "The program .* has been started already.*y or n. $" {
> > + send_gdb "y\n"
> > + exp_continue
> > + }
> > + -re "Starting program.*$gdb_prompt $" {
> > + pass "rerun to main"
> > + }
> > + -re "$gdb_prompt $" {
> > + fail "rerun to main"
> > + }
> > + timeout {
> > + fail "(timeout) rerun to main"
> > + }
> > +}
>
> In general one should never use gdb_expect. And send_gdb is used only
> exceptionally. For complicated cases there is gdb_test_multiple. But in this
> case why there isn't just another runto_main?
>
> if ![runto_main] {
> return -1
> }
I had an xfail here before, but that was fixed meanwhile. I'll just use runto_main
instead as you suggested.
> > 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..711dd20
> > --- /dev/null
> > +++ b/gdb/testsuite/gdb.btrace/function_call_history.exp
> > @@ -0,0 +1,211 @@
> > +# 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
> > +}
>
>
> > +runto_main
>
> if ![runto_main] {
> return -1
> }
Done.
> > +
> > +# 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 main\r
> > +1 inc\r
> > +2 main\r
> > +3 inc\r
> > +4 main\r
> > +5 inc\r
> > +6 main\r
> > +7 inc\r
> > +8 main\r
> > +9 inc\r
> > +10 main\r
> > +11 inc\r
> > +12 main\r
> > +13 inc\r
> > +14 main\r
> > +15 inc\r
> > +16 main\r
> > +17 inc\r
> > +18 main\r
> > +19 inc\r
> > +20 main\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 main\r
> > +1 inc\r
> > +2 main\r
> > +3 inc\r
> > +4 main\r
> > +5 inc\r
> > +6 main\r
> > +7 inc\r
> > +8 main\r
> > +9 inc\r
> > +10 main\r
> > +11 inc\r
> > +12 main\r
> > +13 inc\r
> > +14 main\r
> > +15 inc\r
> > +16 main\r
> > +17 inc\r
> > +18 main\r
> > +19 inc\r
> > +20 main\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 main\r
> > +1 inc\r
> > +2 main\r
> > +3 inc\r
> > +4 main\r
> > +5 inc\r
> > +6 main\r
> > +7 inc\r
> > +8 main\r
> > +9 inc\r
> > +10 main\r
> > +11 inc\r
> > +12 main\r
> > +13 inc\r
> > +14 main\r" "record function-call-history - show first 15 entries"
> > +
> > +# show last 6 entries
> > +gdb_test "record function-call-history +" "15 inc\r
> > +16 main\r
> > +17 inc\r
> > +18 main\r
> > +19 inc\r
> > +20 main\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 main\r
> > +7 inc\r
> > +8 main\r
> > +9 inc\r
> > +10 main\r
> > +11 inc\r
> > +12 main\r
> > +13 inc\r
> > +14 main\r
> > +15 inc\r
> > +16 main\r
> > +17 inc\r
> > +18 main\r
> > +19 inc\r
> > +20 main\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 main\r
> > +1 inc\r
> > +2 main\r
> > +3 inc\r
> > +4 main\r
> > +5 inc\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 main\r
> > +.*$srcfile:22-24 inc\r
> > +.*$srcfile:40-41 main\r
> > +.*$srcfile:22-24 inc\r
> > +.*$srcfile:40-41 main\r
> > +.*$srcfile:22-24 inc\r
> > +.*$srcfile:40-41 main\r
> > +.*$srcfile:22-24 inc\r
> > +.*$srcfile:40-41 main\r
> > +.*$srcfile:22-24 inc\r
> > +.*$srcfile:40-41 main\r
> > +.*$srcfile:22-24 inc\r
> > +.*$srcfile:40-41 main\r
> > +.*$srcfile:22-24 inc\r
> > +.*$srcfile:40-41 main\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 inc\r
> > +.*$srcfile:40-41 main\r
> > +.*$srcfile:22-24 inc\r
> > +.*$srcfile:40-41 main\r
> > +.*$srcfile:22-24 inc\r
> > +.*$srcfile:40-43 main\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 inc\r
> > +4 main\r
> > +5 inc\r
> > +6 main\r
> > +7 inc\r
> > +8 main\r
> > +9 inc\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 main\r\n14 fib\r\n15 fib\r\n16 fib\r\n17 fib\r\n18 fib\r\n19 fib\r\n20
> fib\r\n21 fib\r\n22 main\r\n$gdb_prompt " {
> > + pass $message
> > + }
> > + -re "13 inc\r\n14 main\r\n15 inc\r\n16 main\r\n17 inc\r\n18 main\r\n19 inc\r\n20
> main\r\n21 fib\r\n22 main\r\n$gdb_prompt " {
> > + # recursive function calls appear only as 1 call
> > + xfail $message
>
> kfail, as already discussed before.
>
>
> A nitpick but there can (and therefore should) be trailing $ match so that no
> more accidental input is accepted there, therefore in both cases:
> main\r\n$gdb_prompt " {
> ->
> main\r\n$gdb_prompt $" {
>
>
>
> > + }
> > +}
> > diff --git a/gdb/testsuite/gdb.btrace/instruction_history.c
> b/gdb/testsuite/gdb.btrace/instruction_history.c
> > new file mode 100644
> > index 0000000..2dc3c6b
> > --- /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
>
> Rather /* comments */ ; although one will probably never use such new feature
> with old compilers not supporting // for .c .
>
>
> > + 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..92288eb
> > --- /dev/null
> > +++ b/gdb/testsuite/gdb.btrace/instruction_history.exp
> > @@ -0,0 +1,190 @@
> > +# 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
> > +if [prepare_for_testing instruction_history.exp $testfile "$testfile.c x86-$testfile.S" {debug}] {
>
> standard_testfile has parameters for this purpose:
> standard_testfile .c x86-instruction_history.S
> if [prepare_for_testing $testfile.exp $testfile "$srcfile $srcfile2" {debug}] {
>
> And please rename x86-instruction_history.S to instruction_history-x86.S so
> that completion works for all the files belonging to a testcase.
>
>
> > + return -1
> > +}
> > +
>
> > +runto_main
>
> if ![runto_main] {
> return -1
> }
>
>
> > +
> > +# set bp before loop and continue
> > +set bp_location [gdb_get_line_number "bp.1" x86-$testfile.S]
> > +gdb_breakpoint x86-$testfile.S:$bp_location
> > +gdb_continue_to_breakpoint "cont to $bp_location" ".*x86-$testfile.S:$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" x86-$testfile.S]
> > +gdb_breakpoint x86-$testfile.S:$bp_location
> > +gdb_continue_to_breakpoint "cont to $bp_location" ".*x86-$testfile.S:$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 " {
>
> Again trailing $gdb_prompt $" like in the other file.
>
>
> > + 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
>
> It is OK as is but FYI one can do the escaping automatically at runtime for any
> string using 'string_to_regexp' function.
>
>
> > +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\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 /pf 1,6" "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"
> > +
> > +# 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 " {
>
> trailing $ again.
>
>
> > + 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/gdb.btrace/x86-instruction_history.S b/gdb/testsuite/gdb.btrace/x86-
> instruction_history.S
> > new file mode 100644
> > index 0000000..5c74b46
> > --- /dev/null
> > +++ b/gdb/testsuite/gdb.btrace/x86-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/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> > index 8b16b38..1393455 100644
> > --- a/gdb/testsuite/lib/gdb.exp
> > +++ b/gdb/testsuite/lib/gdb.exp
> > @@ -2097,6 +2097,75 @@ 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 btrace[pid].c
> > + set exe btrace[pid].x
>
> Use:
> 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() { return 0; }"
>
> For C there should be:
> 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.
> > +
> > + gdb_exit
> > + gdb_start
> > + gdb_reinitialize_dir $srcdir/$subdir
> > + gdb_load "$exe"
>
> This can be replaced by:
> clean_restart btrace[pid].x
>
> Unfortunately one cannot use $exe as that one has standard_output_file already
> applied which must not be done for clean_restart.
>
>
> > + runto_main
>
> if ![runto_main] {
> return [...]
> }
>
>
> > + # 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 "$gdb_prompt $" {
>
> To test no output has been produced (instead of any output has been produced):
> -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
>
> If you follow the advices there shold not be an issue but it would be probably
> worth another review.
Jan, thanks for the feedback. The updated version of the patch will be
submitted by Markus.
Thanks,
christian
>
> Thanks,
> Jan
^ permalink raw reply [flat|nested] 102+ messages in thread* Re: [patch v9 22/23] testsuite, gdb.btrace: add btrace tests
2013-03-06 15:32 ` christian.himpel
@ 2013-03-06 16:35 ` Jan Kratochvil
0 siblings, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-06 16:35 UTC (permalink / raw)
To: christian.himpel; +Cc: Metzger, Markus T, gdb-patches, markus.t.metzger
On Wed, 06 Mar 2013 16:31:44 +0100, christian.himpel wrote:
> > And that trailing .* is not needed there, gdb_test automatically matches
> > trailing "\r\n$gdb_prompt $".
>
> Yes, but the output is actually 2 lines:
> No record target is currently active.
> Use one of the "target record-<tab><tab>" commands first.
Sorry, then .* was sure OK.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 11/23] target: add add_deprecated_target_alias
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (10 preceding siblings ...)
2013-03-04 17:08 ` [patch v9 22/23] testsuite, gdb.btrace: add btrace tests Markus Metzger
@ 2013-03-04 17:08 ` Markus Metzger
2013-03-05 20:09 ` Jan Kratochvil
2013-03-04 17:08 ` [patch v9 19/23] record, btrace: add record-btrace target Markus Metzger
` (11 subsequent siblings)
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:08 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-04 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 9dfbe08..1771d3a 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 c543118..1d73336 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1779,6 +1779,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] 102+ messages in thread* Re: [patch v9 11/23] target: add add_deprecated_target_alias
2013-03-04 17:08 ` [patch v9 11/23] target: add add_deprecated_target_alias Markus Metzger
@ 2013-03-05 20:09 ` Jan Kratochvil
0 siblings, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:09 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:05:58 +0100, Markus Metzger wrote:
> 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-04 Markus Metzger <markus.t.metzger@intel.com>
>
> * target.h (add_deprecated_target_alias): New.
> * target.c (add_deprecated_target_alias): New.
Yes, OK for check-in.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 19/23] record, btrace: add record-btrace target
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (11 preceding siblings ...)
2013-03-04 17:08 ` [patch v9 11/23] target: add add_deprecated_target_alias Markus Metzger
@ 2013-03-04 17:08 ` Markus Metzger
2013-03-05 20:13 ` Jan Kratochvil
2013-03-06 16:28 ` Jan Kratochvil
2013-03-04 17:08 ` [patch v9 09/23] btrace, x86: disable on some processors Markus Metzger
` (10 subsequent siblings)
23 siblings, 2 replies; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:08 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.
2013-03-04 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 | 699 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 703 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..c1a7905
--- /dev/null
+++ b/gdb/record-btrace.c
@@ -0,0 +1,699 @@
+/* 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 enable 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);
+
+ (void) 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");
+
+ /* Disable tracing for traced threads. We use the ~_callback variant to
+ turn errors into warnings since we cannot afford to throw an error. */
+ ALL_THREADS (tp)
+ if (tp->btrace.target != NULL)
+ record_btrace_disable_callback (tp);
+
+ record_btrace_auto_disable ();
+}
+
+/* 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 minimal_symbol *msym;
+ struct symbol *sym;
+ const char *filename;
+
+ msym = bfun->msym;
+ sym = bfun->sym;
+
+ filename = NULL;
+ if (sym != NULL)
+ filename = symtab_to_filename_for_display (sym->symtab);
+ else if (msym != NULL)
+ filename = msym->filename;
+
+ if (filename == NULL || *filename == 0)
+ return;
+
+ ui_out_field_string (uiout, "file", filename);
+
+ 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] 102+ messages in thread* Re: [patch v9 19/23] record, btrace: add record-btrace target
2013-03-04 17:08 ` [patch v9 19/23] record, btrace: add record-btrace target Markus Metzger
@ 2013-03-05 20:13 ` Jan Kratochvil
2013-03-06 9:57 ` Metzger, Markus T
2013-03-06 16:28 ` Jan Kratochvil
1 sibling, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:13 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:06:06 +0100, Markus Metzger wrote:
> 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.
>
> 2013-03-04 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.
[...]
> --- /dev/null
> +++ b/gdb/record-btrace.c
[...]
> +/* 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);
> +
> + (void) make_cleanup (record_btrace_disable_callback, tp);
Needless cast. If it is required by your GCC warnings compatible with current
GDB codebase where it makes sense please propose them.
> + }
> +
> + record_btrace_auto_enable ();
> +
> + push_target (&record_btrace_ops);
> +
> + observer_notify_record_changed (current_inferior (), 1);
> +
> + discard_cleanups (disable_chain);
> +}
[...]
> +/* 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 minimal_symbol *msym;
> + struct symbol *sym;
> + const char *filename;
> +
> + msym = bfun->msym;
> + sym = bfun->sym;
> +
> + filename = NULL;
> + if (sym != NULL)
> + filename = symtab_to_filename_for_display (sym->symtab);
> + else if (msym != NULL)
> + filename = msym->filename;
No filename from minimal_symbol.
It prints for me bogus 'interp.c' there:
0 genops.c:456-486 __GI__IO_default_xsputn
1 vfprintf.c:1635-1662 _IO_vfprintf_internal
2 interp.c strchrnul
3 vfprintf.c:1662-1666 _IO_vfprintf_internal
One can always find line number information two ways.
here you use the symbol's line. But sometimes it is not available:
(gdb) p strchrnul
$3 = {<text variable, no debug info>} 0x7ffff6311480 <strchrnul>
On the other hand line number information (sal - source-and-line) may be
available even for such symbol:
(gdb) info line strchrnul
Line 26 of "/usr/src/debug/glibc-2.17-c758a686/sysdeps/x86_64/strchrnul.S" starts at address 0x7ffff6311480 <strchrnul> and ends at 0x7ffff6311484 <strchrnul+4>.
When you display ranges of lines I would find more natural to use the sal's
filename, it would also provide more rich info for the .S files.
It can be also filed as a PR so it does not block gdb-7.6; I wanted to get the
user interface final for the release.
> +
> + if (filename == NULL || *filename == 0)
> + return;
> +
> + ui_out_field_string (uiout, "file", filename);
> +
> + 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 ");
Why here
> +
> + 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 ");
and here is trailing space (' ')?
BTW maybe you could also align the columns by auto-sizing them, GDB does
auto-sizing (each place on its own, no utility for it) of various text tables
output.
0 ./common/common-utils.c:124 xstrprintf
1 ./cli/cli-decode.c:450-451 add_setshow_cmd_full
2 ./common/common-utils.c:116-121 xstrprintf
3 ./common/common-utils.c:128-130 xstrvprintf
4 vasprintf@plt
5 vasprintf.c:39-50 _IO_vasprintf
6 memmove@plt
7 malloc.c:2849-2875 __GI___libc_malloc
8 mcheck.c:206-223 mallochook
9 memmove@plt
This is just a future RFE.
> + }
> +
> + 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");
> + }
> +}
[...]
Thanks; those issues could be also left as future PRs/RFEs.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread* RE: [patch v9 19/23] record, btrace: add record-btrace target
2013-03-05 20:13 ` Jan Kratochvil
@ 2013-03-06 9:57 ` Metzger, Markus T
2013-03-06 13:35 ` Jan Kratochvil
0 siblings, 1 reply; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 9:57 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, markus.t.metzger
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Tuesday, March 05, 2013 9:13 PM
> > + else if (msym != NULL)
> > + filename = msym->filename;
>
> No filename from minimal_symbol.
>
> It prints for me bogus 'interp.c' there:
>
> 0 genops.c:456-486 __GI__IO_default_xsputn
> 1 vfprintf.c:1635-1662 _IO_vfprintf_internal
> 2 interp.c strchrnul
> 3 vfprintf.c:1662-1666 _IO_vfprintf_internal
OK. I'm printing nothing, in this case, now.
> One can always find line number information two ways.
>
> here you use the symbol's line. But sometimes it is not available:
> (gdb) p strchrnul
> $3 = {<text variable, no debug info>} 0x7ffff6311480 <strchrnul>
>
> On the other hand line number information (sal - source-and-line) may be
> available even for such symbol:
> (gdb) info line strchrnul
> Line 26 of "/usr/src/debug/glibc-2.17-c758a686/sysdeps/x86_64/strchrnul.S" starts at address 0x7ffff6311480 <strchrnul> and
> ends at 0x7ffff6311484 <strchrnul+4>.
>
> When you display ranges of lines I would find more natural to use the sal's
> filename, it would also provide more rich info for the .S files.
>
> It can be also filed as a PR so it does not block gdb-7.6; I wanted to get the
> user interface final for the release.
OK. I'll prepare a separate patch for that while I'm waiting for a decision
on the gdbserver changes. I'll file a PR if the gdbserver approval is faster.
> > + /* Print the function index. */
> > + ui_out_field_uint (uiout, "index", idx);
> > + ui_out_text (uiout, "\t ");
>
> Why here
So the other functions only print one of the fields and leave the
formatting to this function.
> BTW maybe you could also align the columns by auto-sizing them, GDB does
> auto-sizing (each place on its own, no utility for it) of various text tables
> output.
>
> 0 ./common/common-utils.c:124 xstrprintf
> 1 ./cli/cli-decode.c:450-451 add_setshow_cmd_full
> 2 ./common/common-utils.c:116-121 xstrprintf
> 3 ./common/common-utils.c:128-130 xstrvprintf
> 4 vasprintf@plt
> 5 vasprintf.c:39-50 _IO_vasprintf
> 6 memmove@plt
> 7 malloc.c:2849-2875 __GI___libc_malloc
> 8 mcheck.c:206-223 mallochook
> 9 memmove@plt
>
> This is just a future RFE.
OK.
> > + }
> > +
> > + 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");
> > + }
> > +}
> [...]
>
>
> Thanks; those issues could be also left as future PRs/RFEs.
I read this as OK. Nevertheless, since I'm resending the series with the merged
gdbserver changes, you may object if I got this wrong.
Thanks,
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] 102+ messages in thread* Re: [patch v9 19/23] record, btrace: add record-btrace target
2013-03-06 9:57 ` Metzger, Markus T
@ 2013-03-06 13:35 ` Jan Kratochvil
2013-03-06 14:01 ` Metzger, Markus T
0 siblings, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-06 13:35 UTC (permalink / raw)
To: Metzger, Markus T; +Cc: gdb-patches, markus.t.metzger
On Wed, 06 Mar 2013 10:57:20 +0100, Metzger, Markus T wrote:
> > > + /* Print the function index. */
> > > + ui_out_field_uint (uiout, "index", idx);
> > > + ui_out_text (uiout, "\t ");
> >
> > Why here
>
> So the other functions only print one of the fields and leave the
> formatting to this function.
I was pointing out why there is
ui_out_text (uiout, "\t ");
and not
ui_out_text (uiout, "\t");
. I do not much understand your reply. But it sure does not matter much.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread* RE: [patch v9 19/23] record, btrace: add record-btrace target
2013-03-06 13:35 ` Jan Kratochvil
@ 2013-03-06 14:01 ` Metzger, Markus T
0 siblings, 0 replies; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 14:01 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, markus.t.metzger
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Wednesday, March 06, 2013 2:35 PM
> On Wed, 06 Mar 2013 10:57:20 +0100, Metzger, Markus T wrote:
> > > > + /* Print the function index. */
> > > > + ui_out_field_uint (uiout, "index", idx);
> > > > + ui_out_text (uiout, "\t ");
> > >
> > > Why here
> >
> > So the other functions only print one of the fields and leave the
> > formatting to this function.
>
> I was pointing out why there is
> ui_out_text (uiout, "\t ");
> and not
> ui_out_text (uiout, "\t");
> . I do not much understand your reply. But it sure does not matter much.
I understood you wrong, then. I removed the extra space everywhere.
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] 102+ messages in thread
* Re: [patch v9 19/23] record, btrace: add record-btrace target
2013-03-04 17:08 ` [patch v9 19/23] record, btrace: add record-btrace target Markus Metzger
2013-03-05 20:13 ` Jan Kratochvil
@ 2013-03-06 16:28 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-06 16:28 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:06:06 +0100, Markus Metzger wrote:
> --- /dev/null
> +++ b/gdb/record-btrace.c
[...]
> +/* Callback function to enable branch tracing for one thread. */
> +
> +static void
> +record_btrace_disable_callback (void *arg)
enable vs. disable
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 09/23] btrace, x86: disable on some processors
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (12 preceding siblings ...)
2013-03-04 17:08 ` [patch v9 19/23] record, btrace: add record-btrace target Markus Metzger
@ 2013-03-04 17:08 ` Markus Metzger
2013-03-05 20:09 ` Jan Kratochvil
2013-03-04 17:08 ` [patch v9 20/23] record-btrace, disas: omit pc prefix Markus Metzger
` (9 subsequent siblings)
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:08 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-04 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 44eb6dc..238d7ba 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>
#if defined(__GNUC__)
# define memory_barrier() asm volatile ("" : : : "memory")
@@ -253,12 +257,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] 102+ messages in thread* Re: [patch v9 09/23] btrace, x86: disable on some processors
2013-03-04 17:08 ` [patch v9 09/23] btrace, x86: disable on some processors Markus Metzger
@ 2013-03-05 20:09 ` Jan Kratochvil
0 siblings, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:09 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:05:56 +0100, Markus Metzger wrote:
> Approved by Jan Kratochvil.
> Approved by Mark Kettenis.
>
> 2013-03-04 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.
Yes, changes are OK.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 20/23] record-btrace, disas: omit pc prefix
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (13 preceding siblings ...)
2013-03-04 17:08 ` [patch v9 09/23] btrace, x86: disable on some processors Markus Metzger
@ 2013-03-04 17:08 ` Markus Metzger
2013-03-05 20:13 ` Jan Kratochvil
2013-03-04 17:09 ` [patch v9 17/23] record: add "record instruction-history" command Markus Metzger
` (8 subsequent siblings)
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:08 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.
2013-03-04 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 8bbd057..43fb990 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);
}
@@ -660,6 +663,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] 102+ messages in thread* Re: [patch v9 20/23] record-btrace, disas: omit pc prefix
2013-03-04 17:08 ` [patch v9 20/23] record-btrace, disas: omit pc prefix Markus Metzger
@ 2013-03-05 20:13 ` Jan Kratochvil
0 siblings, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:13 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:06:07 +0100, Markus Metzger wrote:
> 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.
>
> 2013-03-04 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.
OK.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 17/23] record: add "record instruction-history" command
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (14 preceding siblings ...)
2013-03-04 17:08 ` [patch v9 20/23] record-btrace, disas: omit pc prefix Markus Metzger
@ 2013-03-04 17:09 ` Markus Metzger
2013-03-04 18:14 ` Eli Zaretskii
2013-03-05 20:11 ` Jan Kratochvil
2013-03-04 17:09 ` [patch v9 13/23] record: make it build again Markus Metzger
` (7 subsequent siblings)
23 siblings, 2 replies; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:09 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger, Eli Zaretskii
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.
CC: Eli Zaretskii <eliz@gnu.org>
2013-03-04 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 | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/target.c | 51 +++++++++++++++
gdb/target.h | 20 ++++++
3 files changed, 271 insertions(+), 0 deletions(-)
diff --git a/gdb/record.c b/gdb/record.c
index abd8216..4c5f3f0 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,173 @@ 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);
+ 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 +479,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 +527,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 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 8512ae5..e9d70b7 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4360,6 +4360,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 d416193..4ecb6e2 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -897,6 +897,17 @@ 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. */
+ void (*to_insn_history) (int size, int flags);
+
+ /* Disassemble SIZE instructions in the recorded execution trace around
+ FROM. */
+ void (*to_insn_history_from) (ULONGEST FROM, int size, int flags);
+
+ /* Disassemble a section of the recorded execution trace. */
+ 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?
*/
@@ -1983,4 +1994,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] 102+ messages in thread* Re: [patch v9 17/23] record: add "record instruction-history" command
2013-03-04 17:09 ` [patch v9 17/23] record: add "record instruction-history" command Markus Metzger
@ 2013-03-04 18:14 ` Eli Zaretskii
2013-03-05 20:11 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Eli Zaretskii @ 2013-03-04 18:14 UTC (permalink / raw)
To: Markus Metzger; +Cc: jan.kratochvil, gdb-patches, markus.t.metzger
> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org, markus.t.metzger@gmail.com,
> Eli Zaretskii <eliz@gnu.org>
> Date: Mon, 4 Mar 2013 18:06:04 +0100
>
> +Two arguments with comma between specify starting and ending instruction \
^^^^^^^^^^^^^
"between them"
OK with this change. Thanks.
^ permalink raw reply [flat|nested] 102+ messages in thread* Re: [patch v9 17/23] record: add "record instruction-history" command
2013-03-04 17:09 ` [patch v9 17/23] record: add "record instruction-history" command Markus Metzger
2013-03-04 18:14 ` Eli Zaretskii
@ 2013-03-05 20:11 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:11 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger, Eli Zaretskii
On Mon, 04 Mar 2013 18:06:04 +0100, Markus Metzger wrote:
> 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.
>
> CC: Eli Zaretskii <eliz@gnu.org>
>
> 2013-03-04 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.
[...]
> --- a/gdb/record.c
> +++ b/gdb/record.c
[...]
> +/* 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);
> + size = (int) record_insn_history_size;
> + if (size < 0)
> + size = INT_MAX;
Could you make some comment what is the goal of casting unsigned
record_insn_history_size here and comparing it to < 0 etc.?
> +
> + 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;
>
[...]
> --- a/gdb/target.h
> +++ b/gdb/target.h
> @@ -897,6 +897,17 @@ 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. */
> + void (*to_insn_history) (int size, int flags);
> +
> + /* Disassemble SIZE instructions in the recorded execution trace around
> + FROM. */
> + void (*to_insn_history_from) (ULONGEST FROM, int size, int flags);
FROM should be lowercased here in the code.
Please comment here the rules about FROM and SIZE, one needs to look at
record_btrace_insn_history_from to find out what it should do.
> +
> + /* Disassemble a section of the recorded execution trace. */
> + 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?
> */
> @@ -1983,4 +1994,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
OK for check-in with those changes.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 13/23] record: make it build again
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (15 preceding siblings ...)
2013-03-04 17:09 ` [patch v9 17/23] record: add "record instruction-history" command Markus Metzger
@ 2013-03-04 17:09 ` Markus Metzger
2013-03-05 20:10 ` Jan Kratochvil
2013-03-04 17:09 ` [patch v9 15/23] record-full.h: rename record_ into record_full_ Markus Metzger
` (6 subsequent siblings)
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:09 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.
Approved by Jan Kratochvil.
2013-03-04 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 | 129 +++++++++++++++++++
gdb/target.h | 44 +++++++
13 files changed, 591 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 5a9ec99..b8c7a4e 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 1771d3a..8512ae5 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4230,6 +4230,135 @@ 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 1d73336..d416193 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -876,6 +876,27 @@ struct target_ops
/* Read branch trace data. */
VEC (btrace_block_s) *(*to_read_btrace) (struct btrace_target_info *);
+ /* 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?
*/
@@ -1938,5 +1959,28 @@ extern int target_btrace_has_changed (struct btrace_target_info *btinfo);
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 *);
+/* 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] 102+ messages in thread* Re: [patch v9 13/23] record: make it build again
2013-03-04 17:09 ` [patch v9 13/23] record: make it build again Markus Metzger
@ 2013-03-05 20:10 ` Jan Kratochvil
0 siblings, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:10 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:06:00 +0100, Markus Metzger wrote:
> 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.
>
> Approved by Jan Kratochvil.
>
> 2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
>
> * target.h (target_ops): Add new fields to_info_record,
[...]
> (_initialize_record_full): New.
OK.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 15/23] record-full.h: rename record_ into record_full_
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (16 preceding siblings ...)
2013-03-04 17:09 ` [patch v9 13/23] record: make it build again Markus Metzger
@ 2013-03-04 17:09 ` Markus Metzger
2013-03-05 20:10 ` Jan Kratochvil
2013-03-04 17:09 ` [patch v9 14/23] record-full.c: rename record_ in record_full_ Markus Metzger
` (5 subsequent siblings)
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:09 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-04 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 b8c7a4e..e4c1f96 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;
@@ -1153,15 +1159,15 @@ Do you want to stop the program?"),
regcache_raw_read_signed (regcache, tdep->arg3, &tmpulongest);
regcache_raw_read_unsigned (regcache, tdep->arg2, &msgp);
tmpint = (int) tmpulongest + 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;
@@ -1187,29 +1193,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:
@@ -1229,8 +1235,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;
@@ -1242,14 +1248,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;
@@ -1258,8 +1265,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;
@@ -1277,29 +1284,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;
}
@@ -1317,7 +1324,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;
@@ -1330,8 +1337,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;
@@ -1342,28 +1349,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;
@@ -1402,7 +1409,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;
}
@@ -1423,7 +1430,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;
@@ -1437,8 +1445,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;
@@ -1448,16 +1456,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;
@@ -1472,8 +1480,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;
@@ -1490,7 +1498,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;
@@ -1500,16 +1508,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;
@@ -1520,15 +1528,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;
}
@@ -1539,15 +1547,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;
@@ -1558,16 +1566,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;
@@ -1582,7 +1590,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;
@@ -1598,15 +1607,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;
@@ -1615,15 +1625,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;
@@ -1634,8 +1644,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;
@@ -1650,8 +1660,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;
@@ -1673,7 +1683,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;
@@ -1685,13 +1695,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;
@@ -1700,13 +1713,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;
@@ -1720,8 +1736,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;
@@ -1735,8 +1751,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;
@@ -1747,8 +1763,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
@@ -1776,7 +1792,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;
@@ -1790,7 +1807,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;
@@ -1803,8 +1821,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;
@@ -1819,27 +1837,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;
@@ -1853,8 +1874,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;
@@ -1885,7 +1906,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;
}
@@ -1894,8 +1915,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;
@@ -1924,7 +1945,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;
@@ -1940,8 +1962,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;
@@ -1952,21 +1975,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;
@@ -1977,30 +2001,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;
@@ -2013,7 +2037,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)
@@ -2021,8 +2046,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;
@@ -2040,12 +2065,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;
@@ -2054,8 +2080,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;
@@ -2064,12 +2090,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;
@@ -2089,8 +2115,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;
}
}
@@ -2111,8 +2137,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;
@@ -2129,7 +2155,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;
@@ -2140,20 +2167,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;
@@ -2164,13 +2191,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;
@@ -2180,21 +2207,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;
@@ -2210,22 +2239,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;
@@ -2237,7 +2268,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] 102+ messages in thread* Re: [patch v9 15/23] record-full.h: rename record_ into record_full_
2013-03-04 17:09 ` [patch v9 15/23] record-full.h: rename record_ into record_full_ Markus Metzger
@ 2013-03-05 20:10 ` Jan Kratochvil
0 siblings, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:10 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Mon, 04 Mar 2013 18:06:02 +0100, Markus Metzger wrote:
> 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-04 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.
OK.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 14/23] record-full.c: rename record_ in record_full_.
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (17 preceding siblings ...)
2013-03-04 17:09 ` [patch v9 15/23] record-full.h: rename record_ into record_full_ Markus Metzger
@ 2013-03-04 17:09 ` Markus Metzger
2013-03-05 20:10 ` Jan Kratochvil
2013-03-04 17:09 ` [patch v9 18/23] record: add "record function-call-history" command Markus Metzger
` (4 subsequent siblings)
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:09 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-04 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] 102+ messages in thread* [patch v9 18/23] record: add "record function-call-history" command
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (18 preceding siblings ...)
2013-03-04 17:09 ` [patch v9 14/23] record-full.c: rename record_ in record_full_ Markus Metzger
@ 2013-03-04 17:09 ` Markus Metzger
2013-03-04 18:07 ` Eli Zaretskii
2013-03-05 20:12 ` Jan Kratochvil
2013-03-04 17:09 ` [patch v9 21/23] doc, record: document record changes Markus Metzger
` (3 subsequent siblings)
23 siblings, 2 replies; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:09 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger, Eli Zaretskii
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.
CC: Eli Zaretskii <eliz@gnu.org>
2013-03-04 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 | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/record.h | 10 ++++
gdb/target.c | 51 ++++++++++++++++++++
gdb/target.h | 19 ++++++++
4 files changed, 226 insertions(+), 0 deletions(-)
diff --git a/gdb/record.c b/gdb/record.c
index 4c5f3f0..8bbd057 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;
@@ -463,6 +466,123 @@ 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);
+ 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;
@@ -486,6 +606,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);
@@ -546,4 +673,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 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 e9d70b7..a788a67 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4411,6 +4411,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 4ecb6e2..a3fd892 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -908,6 +908,16 @@ struct target_ops
/* Disassemble a section of the recorded execution trace. */
void (*to_insn_history_range) (ULONGEST begin, ULONGEST end, int flags);
+ /* Print a function trace of the recorded execution trace. */
+ void (*to_call_history) (int size, int flags);
+
+ /* Print a function trace of the recorded execution trace starting
+ at instruction FROM. */
+ void (*to_call_history_from) (ULONGEST begin, int size, int flags);
+
+ /* Print a function trace of an execution trace section. */
+ 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?
*/
@@ -2003,4 +2013,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] 102+ messages in thread* Re: [patch v9 18/23] record: add "record function-call-history" command
2013-03-04 17:09 ` [patch v9 18/23] record: add "record function-call-history" command Markus Metzger
@ 2013-03-04 18:07 ` Eli Zaretskii
2013-03-05 20:12 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Eli Zaretskii @ 2013-03-04 18:07 UTC (permalink / raw)
To: Markus Metzger; +Cc: jan.kratochvil, gdb-patches, markus.t.metzger
> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org, markus.t.metzger@gmail.com,
> Eli Zaretskii <eliz@gnu.org>
> Date: Mon, 4 Mar 2013 18:06:05 +0100
>
> +Two arguments with comma between specify a range of functions to print.\n\
^^^^^^^^^^^^^^
"between them"
OK with that change.
Thanks.
^ permalink raw reply [flat|nested] 102+ messages in thread* Re: [patch v9 18/23] record: add "record function-call-history" command
2013-03-04 17:09 ` [patch v9 18/23] record: add "record function-call-history" command Markus Metzger
2013-03-04 18:07 ` Eli Zaretskii
@ 2013-03-05 20:12 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:12 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger, Eli Zaretskii
On Mon, 04 Mar 2013 18:06:05 +0100, Markus Metzger wrote:
> 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.
>
> CC: Eli Zaretskii <eliz@gnu.org>
>
> 2013-03-04 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.
[...]
> --- a/gdb/record.c
> +++ b/gdb/record.c
[...]
> +/* 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);
> + size = (int) record_call_history_size;
> + if (size < 0)
> + size = INT_MAX;
Again please comment, I do not understand off-hand what is the goal of this
code.
> +
> + if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0)
> + target_call_history (size, flags);
> + else if (strcmp (arg, "-") == 0)
> + target_call_history (- size, flags);
Just '-size', no space there.
> + 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 ();
> + }
> +}
[...]
> --- a/gdb/target.h
> +++ b/gdb/target.h
> @@ -908,6 +908,16 @@ struct target_ops
> /* Disassemble a section of the recorded execution trace. */
> void (*to_insn_history_range) (ULONGEST begin, ULONGEST end, int flags);
>
> + /* Print a function trace of the recorded execution trace. */
> + void (*to_call_history) (int size, int flags);
Please comment the rules which range will be printed depending on SIZE.
> +
> + /* Print a function trace of the recorded execution trace starting
> + at instruction FROM. */
> + void (*to_call_history_from) (ULONGEST begin, int size, int flags);
Please comment the meaning/relationship of BEGIN and SIZE.
> +
> + /* Print a function trace of an execution trace section. */
Comment whether END is inclusive or 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?
> */
> @@ -2003,4 +2013,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
OK with the comments.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 21/23] doc, record: document record changes
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (19 preceding siblings ...)
2013-03-04 17:09 ` [patch v9 18/23] record: add "record function-call-history" command Markus Metzger
@ 2013-03-04 17:09 ` Markus Metzger
2013-03-04 18:13 ` Eli Zaretskii
2013-03-05 20:13 ` Jan Kratochvil
2013-03-04 17:09 ` [patch v9 23/23] btrace, remote: drop qbtrace packet Markus Metzger
` (2 subsequent siblings)
23 siblings, 2 replies; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:09 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger, Eli Zaretskii
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.
CC: Eli Zaretskii <eliz@gnu.org>
2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
* NEWS: Add record changes.
doc/
* gdb.texinfo (Process Record and Replay): Document record
changes.
---
gdb/NEWS | 26 ++++++
gdb/doc/gdb.texinfo | 215 +++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 207 insertions(+), 34 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 0877aa2..e8dec14 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,32 @@
*** 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":
+
+record insn-number-max
+record stop-at-limit
+record memory-query
+
+* Two new commands have been added for record/replay to give information
+ about the recorded execution without having to replay the execution.
+
+"record instruction-history" disassembles instructions stored in the
+execution log.
+
+"record function-call-history" prints the names of the functions
+from instructions stored in the execution log.
+
+* 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
+ above commands for investigating the recorded execution log.
+
+ The "record-btrace" target is only available on Intel Atom processors
+ and requires a Linux kernel 2.6.32 or later.
+
* New native configurations
ARM AArch64 GNU/Linux aarch64*-*-linux-gnu
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 337675c..a3ebcd2 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 @var{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 @var{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 @var{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 @var{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 @var{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 @var{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 @var{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 @var{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] 102+ messages in thread* Re: [patch v9 21/23] doc, record: document record changes
2013-03-04 17:09 ` [patch v9 21/23] doc, record: document record changes Markus Metzger
@ 2013-03-04 18:13 ` Eli Zaretskii
2013-03-05 20:13 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Eli Zaretskii @ 2013-03-04 18:13 UTC (permalink / raw)
To: Markus Metzger; +Cc: jan.kratochvil, gdb-patches, markus.t.metzger
> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org, markus.t.metzger@gmail.com,
> Eli Zaretskii <eliz@gnu.org>
> Date: Mon, 4 Mar 2013 18:06:08 +0100
>
> Document changes to the record target resulting from the renaming into
> record-full.
Thanks.
> +@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 @var{full} recording method. The following
@var{full} and @var{btrace} are incorrect usage of @var. "full" and
"btrace" both stand for literal strings, so using @var is wrong here.
Please use @code or @samp instead. (Here and elsewhere.)
OK with that change.
^ permalink raw reply [flat|nested] 102+ messages in thread* Re: [patch v9 21/23] doc, record: document record changes
2013-03-04 17:09 ` [patch v9 21/23] doc, record: document record changes Markus Metzger
2013-03-04 18:13 ` Eli Zaretskii
@ 2013-03-05 20:13 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:13 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger, Eli Zaretskii
On Mon, 04 Mar 2013 18:06:08 +0100, Markus Metzger wrote:
> 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.
>
> CC: Eli Zaretskii <eliz@gnu.org>
>
> 2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
>
> * NEWS: Add record changes.
>
> doc/
> * gdb.texinfo (Process Record and Replay): Document record
> changes.
[...]
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,32 @@
>
> *** 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":
> +
> +record insn-number-max
> +record stop-at-limit
> +record memory-query
Eli has not commented the NEWS file it but I would prefer to provide
(a) the full/valid commmands, (b) the new, rather than old names,
so that one can easily copy-paste them to GDB CLI to try them.
set|show record full insn-number-max
set|show record full stop-at-limit
set|show record full memory-query
> +
> +* Two new commands have been added for record/replay to give information
> + about the recorded execution without having to replay the execution.
> +
> +"record instruction-history" disassembles instructions stored in the
> +execution log.
> +
> +"record function-call-history" prints the names of the functions
> +from instructions stored in the execution log.
> +
> +* 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
> + above commands for investigating the recorded execution log.
> +
> + The "record-btrace" target is only available on Intel Atom processors
> + and requires a Linux kernel 2.6.32 or later.
> +
> * New native configurations
>
> ARM AArch64 GNU/Linux aarch64*-*-linux-gnu
Otherwise reviewed by Eli.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 23/23] btrace, remote: drop qbtrace packet
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (20 preceding siblings ...)
2013-03-04 17:09 ` [patch v9 21/23] doc, record: document record changes Markus Metzger
@ 2013-03-04 17:09 ` Markus Metzger
2013-03-04 18:15 ` Eli Zaretskii
2013-03-05 20:15 ` Jan Kratochvil
2013-03-04 17:10 ` [patch v9 12/23] record: split record Markus Metzger
2013-03-06 12:43 ` Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom] Jan Kratochvil
23 siblings, 2 replies; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:09 UTC (permalink / raw)
To: jan.kratochvil; +Cc: gdb-patches, markus.t.metzger, Pedro Alves, Eli Zaretskii
Use the qXfer:btrace:read packet's annex to encode a trace read method:
all ... read all trace
new ... read all trace if the trace has changed
This obsoletes the need for the qbtrace packet.
CC: Pedro Alves <palves@redhat.com>
CC: Jan Kratochvil <jan.kratochvil@redhat.com>
CC: Eli Zaretskii <eliz@gnu.org>
2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
* target.h (target_ops) <to_read_btrace>: Add type parameter.
(target_ops) <to_btrace_has_changed>: Remove.
(target_btrace_has_changed): Remove.
(target_read_btrace): Add type parameter.
* target.c (target_read_btrace): Add type parameter.
(target_btrace_has_changed): Remove.
* remote.c (PACKET_qbtrace): Remove.
(remote_protocol_features): Remove qbtrace.
(remote_supports_btrace): Remove check for qbtrace.
(remote_btrace_has_changed): Remove.
(remote_read_btrace): Consider read type.
(init_remote_ops): Remove to_disable_btrace.
(_initialize_remote): Remove qbtrace.
* i386-linux-nat.c (_initialize_i386_linux_nat): Remove
initialization of to_btrace_has_changed.
* common/linux-btrace.h (linux_read_btrace): Add type parameter.
(linux_btrace_has_changed): Removed.
* common/linux-btrace.c (linux_btrace_has_changed): Moved.
Changed to static.
(linux_read_btrace): Consider read type.
* common/btrace-common.h (btrace_read_type): New enum.
* btrace.c (btrace_fetch): Only update branch trace if it
changed.
* amd64-linux-nat.c (_initialize_amd64_linux_nat): Remove
initialization of to_btrace_has_changed.
gdbserver/
* target.h (target_ops): Remove btrace_has_changed. Add type
parameter to read_btrace. Update target_ macros.
* server.c: Include btrace-common.h.
(handle_qxfer_btrace): Consider read type in annex.
(handle_btrace_query): Removed.
(handle_query): Remove qbtrace from qSupported. Remove call to
handle_btrace_query.
* linux-low.c (linux_low_read_btrace): Consider read type.
(linux_target_ops): Remove linux_btrace_has_changed.
doc/
* gdb.texinfo (Remote Configuration): Remove qbtrace.
Describe annex of Qbtrace.
---
gdb/amd64-linux-nat.c | 1 -
gdb/btrace.c | 6 ++-
gdb/common/btrace-common.h | 11 +++++++
gdb/common/linux-btrace.c | 37 ++++++++++------------
gdb/common/linux-btrace.h | 6 +--
gdb/doc/gdb.texinfo | 32 ++++++--------------
gdb/gdbserver/linux-low.c | 6 ++--
gdb/gdbserver/server.c | 56 +++++++++--------------------------
gdb/gdbserver/target.h | 14 +++-----
gdb/i386-linux-nat.c | 1 -
gdb/remote.c | 70 ++++++++++---------------------------------
gdb/target.c | 19 ++----------
gdb/target.h | 12 ++-----
13 files changed, 90 insertions(+), 181 deletions(-)
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index c82edda..6f13fca 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -1196,7 +1196,6 @@ _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_btrace_has_changed = linux_btrace_has_changed;
t->to_read_btrace = linux_read_btrace;
/* Register the target. */
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 406508d..2fe6bf5 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -413,6 +413,7 @@ 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));
@@ -420,12 +421,13 @@ btrace_fetch (struct thread_info *tp)
if (btinfo->target == NULL)
return;
- if (!target_btrace_has_changed (btinfo->target))
+ btrace = target_read_btrace (btinfo->target, btrace_read_new);
+ if (VEC_empty (btrace_block_s, btrace))
return;
btrace_clear (tp);
- btinfo->btrace = target_read_btrace (btinfo->target);
+ btinfo->btrace = btrace;
btinfo->itrace = compute_itrace (btinfo->btrace);
btinfo->ftrace = compute_ftrace (btinfo->itrace);
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index 90372ba..eab6c74 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -59,4 +59,15 @@ 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/common/linux-btrace.c b/gdb/common/linux-btrace.c
index 238d7ba..08a34dd 100644
--- a/gdb/common/linux-btrace.c
+++ b/gdb/common/linux-btrace.c
@@ -448,16 +448,6 @@ linux_supports_btrace (void)
/* See linux-btrace.h. */
-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. */
-
struct btrace_target_info *
linux_enable_btrace (ptid_t ptid)
{
@@ -526,10 +516,21 @@ linux_disable_btrace (struct btrace_target_info *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)
+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;
@@ -537,6 +538,9 @@ linux_read_btrace (struct btrace_target_info *tinfo)
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);
@@ -589,14 +593,6 @@ linux_supports_btrace (void)
/* See linux-btrace.h. */
-int
-linux_btrace_has_changed (struct btrace_target_info *tinfo)
-{
- return 0;
-}
-
-/* See linux-btrace.h. */
-
struct btrace_target_info *
linux_enable_btrace (ptid_t ptid)
{
@@ -614,7 +610,8 @@ linux_disable_btrace (struct btrace_target_info *tinfo)
/* See linux-btrace.h. */
VEC (btrace_block_s) *
-linux_read_btrace (struct btrace_target_info *tinfo)
+linux_read_btrace (struct btrace_target_info *tinfo,
+ enum btrace_read_type type)
{
return NULL;
}
diff --git a/gdb/common/linux-btrace.h b/gdb/common/linux-btrace.h
index b382e49..df4a4ae 100644
--- a/gdb/common/linux-btrace.h
+++ b/gdb/common/linux-btrace.h
@@ -70,10 +70,8 @@ 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);
-/* Check whether there is new trace data available. */
-extern int linux_btrace_has_changed (struct btrace_target_info *);
-
/* Read branch trace data. */
-extern VEC (btrace_block_s) *linux_read_btrace (struct btrace_target_info *);
+extern VEC (btrace_block_s) *linux_read_btrace (struct btrace_target_info *,
+ enum btrace_read_type);
#endif /* LINUX_BTRACE_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a3ebcd2..e8c2b34 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -37393,11 +37393,6 @@ These are the currently defined stub features and their properties:
@tab @samp{-}
@tab No
-@item @samp{qbtrace}
-@tab No
-@tab @samp{-}
-@tab Yes
-
@item @samp{qXfer:auxv:read}
@tab No
@tab @samp{-}
@@ -37711,9 +37706,6 @@ 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
-The remote stub understands the @samp{qbtrace} packet.
-
@item Qbtrace:off
The remote stub understands the @samp{Qbtrace:off} packet.
@@ -37843,7 +37835,16 @@ by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
Return a description of the current branch trace.
@xref{Branch Trace Format}. The annex part of the generic @samp{qXfer}
-packet is empty.
+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}).
@@ -38084,19 +38085,6 @@ The remote server created a new process.
A badly formed request or an error was encountered.
@end table
-@item qbtrace
-Return whether new branch trace data is available for the current thread.
-
-Reply:
-@table @samp
-@item yes
-New branch trace data is available.
-@item no
-No new branch trace data is available.
-@item E.errtext
-A badly formed request or an error was encountered.
-@end table
-
@item Qbtrace:bts
Enable branch tracing for the current thread using bts tracing.
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index c4507c8..0131de6 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5838,13 +5838,14 @@ linux_low_enable_btrace (ptid_t ptid)
/* Read branch trace data as btrace xml document. */
static void
-linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer)
+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);
+ 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");
@@ -5927,7 +5928,6 @@ static struct target_ops linux_target_ops = {
linux_supports_btrace,
linux_low_enable_btrace,
linux_disable_btrace,
- linux_btrace_has_changed,
linux_low_read_btrace,
#else
NULL,
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 00cac8e..6c8bff4 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
@@ -1345,11 +1346,12 @@ handle_qxfer_btrace (const char *annex,
{
static struct buffer cache;
struct thread_info *thread;
+ int type;
if (the_target->read_btrace == NULL || writebuf != NULL)
return -2;
- if (!target_running () || annex[0] != '\0')
+ if (!target_running ())
return -1;
if (ptid_equal (general_thread, null_ptid)
@@ -1372,11 +1374,21 @@ handle_qxfer_btrace (const char *annex,
return -1;
}
+ 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 -1;
+ }
+
if (offset == 0)
{
buffer_free (&cache);
- target_read_btrace (thread->btrace, &cache);
+ target_read_btrace (thread->btrace, &cache, type);
}
else if (offset > cache.used_size)
{
@@ -1560,42 +1572,6 @@ crc32 (CORE_ADDR base, int len, unsigned int crc)
return (unsigned long long) crc;
}
-/* Handle the "qbtrace" packet. */
-
-static int
-handle_btrace_query (char *own_buf)
-{
- if (strncmp ("qbtrace", own_buf, strlen ("qbtrace")) == 0)
- {
- struct thread_info *thread;
-
- 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;
- }
-
- if (thread->btrace == NULL)
- {
- strcpy (own_buf, "E.Btrace not enabled.");
- return -1;
- }
-
- strcpy (own_buf,
- (target_btrace_has_changed (thread->btrace) ? "yes" : "no"));
- return 1;
- }
- return 0;
-}
-
/* Handle all of the extended 'q' packets. */
void
@@ -1827,7 +1803,6 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_btrace ())
{
- strcat (own_buf, ";qbtrace+");
strcat (own_buf, ";Qbtrace:bts+");
strcat (own_buf, ";Qbtrace:off+");
strcat (own_buf, ";qXfer:btrace:read+");
@@ -2023,9 +1998,6 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_tracepoints () && handle_tracepoint_query (own_buf))
return;
- if (handle_btrace_query (own_buf))
- return;
-
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index a597911..f257459 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -410,11 +410,10 @@ struct target_ops
/* Disable branch tracing. */
int (*disable_btrace) (struct btrace_target_info *tinfo);
- /* Check whether branch trace changed on the target. */
- int (*btrace_has_changed) (struct btrace_target_info *);
+ /* 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);
- /* Read branch trace data into buffer. */
- void (*read_btrace) (struct btrace_target_info *, struct buffer *);
};
extern struct target_ops *the_target;
@@ -547,11 +546,8 @@ int kill_inferior (int);
#define target_disable_btrace(tinfo) \
(*the_target->disable_btrace) (tinfo)
-#define target_btrace_has_changed(tinfo) \
- (*the_target->btrace_has_changed) (tinfo)
-
-#define target_read_btrace(tinfo, buffer) \
- (*the_target->read_btrace) (tinfo, buffer)
+#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. */
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index d439133..715c6d4 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -1118,7 +1118,6 @@ _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_btrace_has_changed = linux_btrace_has_changed;
t->to_read_btrace = linux_read_btrace;
/* Register the target. */
diff --git a/gdb/remote.c b/gdb/remote.c
index 2365713..f76846a 100755
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1285,7 +1285,6 @@ enum {
PACKET_qXfer_fdpic,
PACKET_QDisableRandomization,
PACKET_QAgent,
- PACKET_qbtrace,
PACKET_Qbtrace_off,
PACKET_Qbtrace_bts,
PACKET_qXfer_btrace,
@@ -4000,7 +3999,6 @@ static struct protocol_feature remote_protocol_features[] = {
{ "QAgent", PACKET_DISABLE, remote_supported_packet, PACKET_QAgent},
{ "tracenz", PACKET_DISABLE,
remote_string_tracing_feature, -1 },
- { "qbtrace", PACKET_DISABLE, remote_supported_packet, PACKET_qbtrace },
{ "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,
@@ -11140,8 +11138,6 @@ struct btrace_target_info
static int
remote_supports_btrace (void)
{
- if (remote_protocol_packets[PACKET_qbtrace].support != PACKET_ENABLE)
- return 0;
if (remote_protocol_packets[PACKET_Qbtrace_off].support != PACKET_ENABLE)
return 0;
if (remote_protocol_packets[PACKET_Qbtrace_bts].support != PACKET_ENABLE)
@@ -11208,57 +11204,16 @@ remote_disable_btrace (struct btrace_target_info *tinfo)
xfree (tinfo);
}
-/* Check whether branch trace data has changed. */
-
-static int
-remote_btrace_has_changed (struct btrace_target_info *tinfo)
-{
- struct packet_config *packet = &remote_protocol_packets[PACKET_qbtrace];
- 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);
-
- switch (packet_ok (rs->buf, packet))
- {
- case PACKET_OK:
- break;
-
- case PACKET_UNKNOWN:
- return 0;
-
- case PACKET_ERROR:
- error (_("Failed to check for branch trace data for %s: %s."),
- target_pid_to_str (tinfo->ptid), rs->buf);
- }
-
- if (strcmp (rs->buf, "yes") == 0)
- return 1;
-
- if (strcmp (rs->buf, "no") == 0)
- return 0;
-
- error (_("Bad remote reply: %s."), rs->buf);
-
- return 0;
-}
-
/* Read the branch trace. */
static VEC (btrace_block_s) *
-remote_read_btrace (struct btrace_target_info *tinfo)
+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)
@@ -11268,8 +11223,21 @@ remote_read_btrace (struct btrace_target_info *tinfo)
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:
+ annex = NULL;
+ break;
+ }
+
xml = target_read_stralloc (¤t_target,
- TARGET_OBJECT_BTRACE, NULL);
+ TARGET_OBJECT_BTRACE, annex);
if (xml != NULL)
{
struct cleanup *cleanup = make_cleanup (xfree, xml);
@@ -11400,7 +11368,6 @@ 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_btrace_has_changed = remote_btrace_has_changed;
remote_ops.to_read_btrace = remote_read_btrace;
}
@@ -11926,9 +11893,6 @@ 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],
- "qbtrace", "query-btrace", 0);
-
add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_off],
"Qbtrace:off", "disable-btrace", 0);
diff --git a/gdb/target.c b/gdb/target.c
index a788a67..778b6b9 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4203,28 +4203,15 @@ target_disable_btrace (struct btrace_target_info *btinfo)
}
/* See target.h. */
-int
-target_btrace_has_changed (struct btrace_target_info *btinfo)
-{
- struct target_ops *t;
-
- for (t = current_target.beneath; t != NULL; t = t->beneath)
- if (t->to_btrace_has_changed != NULL)
- return t->to_btrace_has_changed (btinfo);
-
- tcomplain ();
- return 0;
-}
-
-/* See target.h. */
VEC (btrace_block_s) *
-target_read_btrace (struct btrace_target_info *btinfo)
+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);
+ return t->to_read_btrace (btinfo, type);
tcomplain ();
return NULL;
diff --git a/gdb/target.h b/gdb/target.h
index a3fd892..88c13cc 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -870,11 +870,9 @@ struct target_ops
/* Disable branch tracing and deallocate @tinfo. */
void (*to_disable_btrace) (struct btrace_target_info *tinfo);
- /* Check whether branch trace changed on the target. */
- int (*to_btrace_has_changed) (struct btrace_target_info *);
-
/* Read branch trace data. */
- VEC (btrace_block_s) *(*to_read_btrace) (struct btrace_target_info *);
+ 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);
@@ -1973,12 +1971,10 @@ 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);
-/* Check whether there is no branch tracing data available. */
-extern int target_btrace_has_changed (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 *);
+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);
--
1.7.1
^ permalink raw reply [flat|nested] 102+ messages in thread* Re: [patch v9 23/23] btrace, remote: drop qbtrace packet
2013-03-04 17:09 ` [patch v9 23/23] btrace, remote: drop qbtrace packet Markus Metzger
@ 2013-03-04 18:15 ` Eli Zaretskii
2013-03-05 20:15 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Eli Zaretskii @ 2013-03-04 18:15 UTC (permalink / raw)
To: Markus Metzger; +Cc: jan.kratochvil, gdb-patches, markus.t.metzger, palves
> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org, markus.t.metzger@gmail.com,
> Pedro Alves <palves@redhat.com>, Eli Zaretskii <eliz@gnu.org>
> Date: Mon, 4 Mar 2013 18:06:10 +0100
>
> Use the qXfer:btrace:read packet's annex to encode a trace read method:
>
> all ... read all trace
> new ... read all trace if the trace has changed
>
> This obsoletes the need for the qbtrace packet.
>
> CC: Pedro Alves <palves@redhat.com>
> CC: Jan Kratochvil <jan.kratochvil@redhat.com>
> CC: Eli Zaretskii <eliz@gnu.org>
>
> 2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
>
> * target.h (target_ops) <to_read_btrace>: Add type parameter.
> (target_ops) <to_btrace_has_changed>: Remove.
> (target_btrace_has_changed): Remove.
> (target_read_btrace): Add type parameter.
> * target.c (target_read_btrace): Add type parameter.
> (target_btrace_has_changed): Remove.
> * remote.c (PACKET_qbtrace): Remove.
> (remote_protocol_features): Remove qbtrace.
> (remote_supports_btrace): Remove check for qbtrace.
> (remote_btrace_has_changed): Remove.
> (remote_read_btrace): Consider read type.
> (init_remote_ops): Remove to_disable_btrace.
> (_initialize_remote): Remove qbtrace.
> * i386-linux-nat.c (_initialize_i386_linux_nat): Remove
> initialization of to_btrace_has_changed.
> * common/linux-btrace.h (linux_read_btrace): Add type parameter.
> (linux_btrace_has_changed): Removed.
> * common/linux-btrace.c (linux_btrace_has_changed): Moved.
> Changed to static.
> (linux_read_btrace): Consider read type.
> * common/btrace-common.h (btrace_read_type): New enum.
> * btrace.c (btrace_fetch): Only update branch trace if it
> changed.
> * amd64-linux-nat.c (_initialize_amd64_linux_nat): Remove
> initialization of to_btrace_has_changed.
>
> gdbserver/
>
> * target.h (target_ops): Remove btrace_has_changed. Add type
> parameter to read_btrace. Update target_ macros.
> * server.c: Include btrace-common.h.
> (handle_qxfer_btrace): Consider read type in annex.
> (handle_btrace_query): Removed.
> (handle_query): Remove qbtrace from qSupported. Remove call to
> handle_btrace_query.
> * linux-low.c (linux_low_read_btrace): Consider read type.
> (linux_target_ops): Remove linux_btrace_has_changed.
>
> doc/
>
> * gdb.texinfo (Remote Configuration): Remove qbtrace.
> Describe annex of Qbtrace.
OK for the documentation part.
Thanks.
^ permalink raw reply [flat|nested] 102+ messages in thread
* Re: [patch v9 23/23] btrace, remote: drop qbtrace packet
2013-03-04 17:09 ` [patch v9 23/23] btrace, remote: drop qbtrace packet Markus Metzger
2013-03-04 18:15 ` Eli Zaretskii
@ 2013-03-05 20:15 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-05 20:15 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger, Pedro Alves, Eli Zaretskii
On Mon, 04 Mar 2013 18:06:10 +0100, Markus Metzger wrote:
> Use the qXfer:btrace:read packet's annex to encode a trace read method:
>
> all ... read all trace
> new ... read all trace if the trace has changed
BTW fixing previous patches by adding new patches is not right. It clutters
GDB history. There will be now target_btrace_has_changed in the history
despite it has never been approved for FSF GDB check-in.
I understand it is easier this way.
But GDB existing in many source variants and people (yes, incl. me) dig into
its history for various backports, regressions finding etc. so a minimal
logical changes are preferred.
Please merge it with the appropriate parts.
>
> This obsoletes the need for the qbtrace packet.
>
> CC: Pedro Alves <palves@redhat.com>
> CC: Jan Kratochvil <jan.kratochvil@redhat.com>
> CC: Eli Zaretskii <eliz@gnu.org>
>
> 2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
>
> * target.h (target_ops) <to_read_btrace>: Add type parameter.
> (target_ops) <to_btrace_has_changed>: Remove.
> (target_btrace_has_changed): Remove.
> (target_read_btrace): Add type parameter.
> * target.c (target_read_btrace): Add type parameter.
> (target_btrace_has_changed): Remove.
> * remote.c (PACKET_qbtrace): Remove.
> (remote_protocol_features): Remove qbtrace.
> (remote_supports_btrace): Remove check for qbtrace.
> (remote_btrace_has_changed): Remove.
> (remote_read_btrace): Consider read type.
> (init_remote_ops): Remove to_disable_btrace.
> (_initialize_remote): Remove qbtrace.
> * i386-linux-nat.c (_initialize_i386_linux_nat): Remove
> initialization of to_btrace_has_changed.
> * common/linux-btrace.h (linux_read_btrace): Add type parameter.
> (linux_btrace_has_changed): Removed.
> * common/linux-btrace.c (linux_btrace_has_changed): Moved.
> Changed to static.
> (linux_read_btrace): Consider read type.
> * common/btrace-common.h (btrace_read_type): New enum.
> * btrace.c (btrace_fetch): Only update branch trace if it
> changed.
> * amd64-linux-nat.c (_initialize_amd64_linux_nat): Remove
> initialization of to_btrace_has_changed.
>
> gdbserver/
>
> * target.h (target_ops): Remove btrace_has_changed. Add type
> parameter to read_btrace. Update target_ macros.
> * server.c: Include btrace-common.h.
> (handle_qxfer_btrace): Consider read type in annex.
> (handle_btrace_query): Removed.
> (handle_query): Remove qbtrace from qSupported. Remove call to
> handle_btrace_query.
> * linux-low.c (linux_low_read_btrace): Consider read type.
> (linux_target_ops): Remove linux_btrace_has_changed.
>
> doc/
>
> * gdb.texinfo (Remote Configuration): Remove qbtrace.
> Describe annex of Qbtrace.
[...]
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
[...]
> /* Read the branch trace. */
>
> static VEC (btrace_block_s) *
> -remote_read_btrace (struct btrace_target_info *tinfo)
> +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)
> @@ -11268,8 +11223,21 @@ remote_read_btrace (struct btrace_target_info *tinfo)
> 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:
Here should be internal_error call. It just cannot happen in valid GDB
binary.
> + annex = NULL;
> + break;
> + }
> +
> xml = target_read_stralloc (¤t_target,
> - TARGET_OBJECT_BTRACE, NULL);
> + TARGET_OBJECT_BTRACE, annex);
> if (xml != NULL)
> {
> struct cleanup *cleanup = make_cleanup (xfree, xml);
^ permalink raw reply [flat|nested] 102+ messages in thread
* [patch v9 12/23] record: split record
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (21 preceding siblings ...)
2013-03-04 17:09 ` [patch v9 23/23] btrace, remote: drop qbtrace packet Markus Metzger
@ 2013-03-04 17:10 ` Markus Metzger
2013-03-05 20:09 ` Jan Kratochvil
2013-03-06 12:43 ` Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom] Jan Kratochvil
23 siblings, 1 reply; 102+ messages in thread
From: Markus Metzger @ 2013-03-04 17:10 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-04 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] 102+ messages in thread* Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-04 17:07 [patch v9 00/23] branch tracing support for Atom Markus Metzger
` (22 preceding siblings ...)
2013-03-04 17:10 ` [patch v9 12/23] record: split record Markus Metzger
@ 2013-03-06 12:43 ` Jan Kratochvil
2013-03-06 14:40 ` Metzger, Markus T
2013-03-06 15:41 ` Jan Kratochvil
23 siblings, 2 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-06 12:43 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
Hi Markus,
./gdbserver :1234 true
./gdb true -ex 'target remote localhost:1234' -ex 'set debug remote 1' -ex 'record btrace' -ex c
will crash GDB. There were a similar thread on the list before, I have not
investigated it yet.
But this is sure not a regression when btrace is not involved.
Jan
#0 in serial_debug_p (scb=0x0) at serial.c:558
#1 in serial_write (scb=0x0, str=0x7fffffffc5d0 "$Hgp4406.4406#e9", len=16) at serial.c:414
#2 in putpkt_binary (buf=0x23c4a30 "Hgp4406.4406", cnt=12) at remote.c:7189
#3 in putpkt (buf=0x23c4a30 "Hgp4406.4406") at remote.c:7120
#4 in set_thread (ptid=..., gen=1) at remote.c:1760
#5 in set_general_thread (ptid=...) at remote.c:1771
#6 in remote_disable_btrace (tinfo=0x23803a0) at remote.c:11194
#7 in target_disable_btrace (btinfo=0x23803a0) at target.c:4200
#8 in btrace_disable (tp=0x23284e0) at btrace.c:391
#9 in clear_thread_inferior_resources (tp=0x23284e0) at thread.c:120
#10 in delete_thread_1 (ptid=..., silent=1) at thread.c:296
#11 in delete_thread_silent (ptid=...) at thread.c:319
#12 in delete_thread_of_inferior (tp=0x23284e0, data=0x7fffffffc9a0) at inferior.c:179
#13 in iterate_over_threads (callback=0x86f3aa <delete_thread_of_inferior>, data=0x7fffffffc9a0) at thread.c:370
#14 in exit_inferior_1 (inftoex=0x21a69c0, silent=1) at inferior.c:259
#15 in exit_inferior_silent (pid=17414) at inferior.c:299
#16 in discard_all_inferiors () at inferior.c:337
#17 in remote_close (quitting=0) at remote.c:3024
#18 in target_close (targ=0x1eb7b60 <remote_ops>, quitting=0) at target.c:3775
#19 in pop_target () at target.c:1069
#20 in readchar (timeout=2) at remote.c:7055
#21 in getpkt_or_notif_sane_1 (buf=0x1eb7ae0 <remote_state>, sizeof_buf=0x1eb7ae8 <remote_state+8>, forever=0, expecting_notif=0, is_notif=0x0) at remote.c:7571
#22 in getpkt_sane (buf=0x1eb7ae0 <remote_state>, sizeof_buf=0x1eb7ae8 <remote_state+8>, forever=0) at remote.c:7669
#23 in getpkt (buf=0x1eb7ae0 <remote_state>, sizeof_buf=0x1eb7ae8 <remote_state+8>, forever=0) at remote.c:7511
#24 in set_thread (ptid=..., gen=1) at remote.c:1761
#25 in set_general_thread (ptid=...) at remote.c:1771
#26 in remote_disable_btrace (tinfo=0x23803a0) at remote.c:11194
#27 in target_disable_btrace (btinfo=0x23803a0) at target.c:4200
#28 in btrace_disable (tp=0x23284e0) at btrace.c:391
#29 in record_btrace_disable_callback (arg=0x23284e0) at record-btrace.c:108
#30 in record_btrace_close (quitting=0) at record-btrace.c:192
#31 in target_close (targ=0x1ece880 <record_btrace_ops>, quitting=0) at target.c:3775
#32 in unpush_target (t=0x1ece880 <record_btrace_ops>) at target.c:1061
#33 in record_unpush () at record.c:108
#34 in record_mourn_inferior (ops=0x1ece880 <record_btrace_ops>) at record.c:140
#35 in target_mourn_inferior () at target.c:2817
#36 in handle_inferior_event (ecs=0x7fffffffd470) at infrun.c:3436
#37 in wait_for_inferior () at infrun.c:2743
#38 in proceed (addr=18446744073709551615, siggnal=GDB_SIGNAL_DEFAULT, step=0) at infrun.c:2324
#39 in continue_1 (all_threads=0) at infcmd.c:736
#40 in continue_command (args=0x0, from_tty=1) at infcmd.c:828
#41 in do_cfunc (c=0x2142650, args=0x0, from_tty=1) at ./cli/cli-decode.c:113
#42 in cmd_func (cmd=0x2142650, args=0x0, from_tty=1) at ./cli/cli-decode.c:1859
#43 in execute_command (p=0x7fffffffde73 "", from_tty=1) at top.c:484
#44 in catch_command_errors (command=0x845192 <execute_command>, arg=0x7fffffffde72 "c", from_tty=1, mask=6) at exceptions.c:573
#45 in captured_main (data=0x7fffffffd9a0) at main.c:1009
#46 in catch_errors (func=0x742243 <captured_main>, func_args=0x7fffffffd9a0, errstring=0xfbbdd4 "", mask=6) at exceptions.c:546
#47 in gdb_main (args=0x7fffffffd9a0) at main.c:1042
#48 in main (argc=10, argv=0x7fffffffdaa8) at gdb.c:34
^ permalink raw reply [flat|nested] 102+ messages in thread* RE: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-06 12:43 ` Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom] Jan Kratochvil
@ 2013-03-06 14:40 ` Metzger, Markus T
2013-03-06 15:31 ` Metzger, Markus T
2013-03-06 15:41 ` Jan Kratochvil
1 sibling, 1 reply; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 14:40 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: Wednesday, March 06, 2013 1:44 PM
> ./gdbserver :1234 true
> ./gdb true -ex 'target remote localhost:1234' -ex 'set debug remote 1' -ex 'record btrace' -ex c
>
> will crash GDB. There were a similar thread on the list before, I have not
> investigated it yet.
>
> But this is sure not a regression when btrace is not involved.
Thanks!
Here's the problem..
When we close the record-btrace target in response to mourn_inferior (should be
the same for any reason), we iterate over all threads and disable branch tracing for
each thread.
If we lose the connection to the remote target, we will pop all targets.
This has several effects:
- it will discard all inferiors
- this will also cause us to disable tracing twice
- thus we try to switch the remote thread twice
- here we crash due to an unchecked null pointer access
- even if we survived this it would free the thread_info we're using for our traversal
- it will remove all targets so we'll run into an internal error when forwarding
mourn_inferior to the target after unpushing the record target
We need to disable branch tracing when the thread goes away and when we stop
recording. I therefore put the disabling into the to_close method. Even if I moved
this somewhere else, I would still try to talk to the target when freeing the resources
for a thread that goes away.
As far as I understand, we may lose the connection at any time and for all kinds
of reasons. It just happens deterministically in the above example. So what we
would want is to be able to try to talk to the target after the connection has been
lost without crashing GDB.
Do you know what others are doing to avoid this problem?
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] 102+ messages in thread
* RE: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-06 14:40 ` Metzger, Markus T
@ 2013-03-06 15:31 ` Metzger, Markus T
2013-03-06 17:06 ` Jan Kratochvil
0 siblings, 1 reply; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 15:31 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, markus.t.metzger, Himpel, Christian
> -----Original Message-----
> From: Metzger, Markus T
> Sent: Wednesday, March 06, 2013 3:41 PM
> > ./gdbserver :1234 true
> > ./gdb true -ex 'target remote localhost:1234' -ex 'set debug remote 1' -ex 'record btrace' -ex c
> >
> > will crash GDB. There were a similar thread on the list before, I have not
> > investigated it yet.
> >
> > But this is sure not a regression when btrace is not involved.
>
> Thanks!
>
> Here's the problem..
> When we close the record-btrace target in response to mourn_inferior (should be
> the same for any reason), we iterate over all threads and disable branch tracing for
> each thread.
> If we lose the connection to the remote target, we will pop all targets.
> This has several effects:
> - it will discard all inferiors
> - this will also cause us to disable tracing twice
> - thus we try to switch the remote thread twice
> - here we crash due to an unchecked null pointer access
> - even if we survived this it would free the thread_info we're using for our traversal
> - it will remove all targets so we'll run into an internal error when forwarding
> mourn_inferior to the target after unpushing the record target
>
> We need to disable branch tracing when the thread goes away and when we stop
> recording. I therefore put the disabling into the to_close method. Even if I moved
> this somewhere else, I would still try to talk to the target when freeing the resources
> for a thread that goes away.
If I used a thread_exit notifier instead of adding the call directly to
clear_thread_inferior_resources, I would avoid trying to talk to the target as part of
deleting threads in the above example - since we're deleting threads silently.
I still disable threads in to_close which tries to talk to the target. We would thus still
pop all targets, but we wouldn't try to talk to the target during that, i.e. we would
survive this.
We still die later on since popping all targets discards all threads and thus disrupts
the thread traversal in record-btrace's to_close.
This might be avoided by moving the ALL_THREADS - btrace_disable into some other
function that is only called on "record stop". For all other stop reasons, we would rely
on the cleanup when GDB's threads are discarded.
This might leak resources, though! I don't know when threads are deleted silently
and when not. I also don't know what the thread notifier is meant for, i.e. if I should
have used it in the first place.
This doesn't fix the real problem IMO, but it could avoid this deterministic case.
> As far as I understand, we may lose the connection at any time and for all kinds
> of reasons. It just happens deterministically in the above example. So what we
> would want is to be able to try to talk to the target after the connection has been
> lost without crashing GDB.
>
> Do you know what others are doing to avoid this problem?
>
> 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] 102+ messages in thread
* Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-06 15:31 ` Metzger, Markus T
@ 2013-03-06 17:06 ` Jan Kratochvil
2013-03-06 18:08 ` Metzger, Markus T
0 siblings, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-06 17:06 UTC (permalink / raw)
To: Metzger, Markus T; +Cc: gdb-patches, markus.t.metzger, Himpel, Christian
Hi Markus,
On Wed, 06 Mar 2013 16:30:13 +0100, Metzger, Markus T wrote:
> I still disable threads in to_close which tries to talk to the target.
When one follows the Pedro's way which I forwarded to you in to_close one
should only clear resources, without doing any actions involving the rest of
GDB infrastructure.
Do you think the attached patch still has some leaks or other issues?
An unrelated small cleanup is that btrace_disconnect should be IMO called from
to_detach and not from detach_command.
Thanks,
Jan
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index 6f13fca..a1a2d42 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -1154,6 +1154,13 @@ amd64_linux_disable_btrace (struct btrace_target_info *tinfo)
error (_("Could not disable branch tracing: %s."), safe_strerror (errcode));
}
+static void
+amd64_linux_clear_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 +1203,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_clear_btrace = amd64_linux_clear_btrace;
t->to_read_btrace = linux_read_btrace;
/* Register the target. */
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 2fe6bf5..bd81ba5 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -447,6 +447,12 @@ btrace_clear (struct thread_info *tp)
btinfo = &tp->btrace;
+ if (btinfo->target != NULL)
+ {
+ target_clear_btrace (btinfo->target);
+ btinfo->target = NULL;
+ }
+
VEC_free (btrace_block_s, btinfo->btrace);
VEC_free (btrace_inst_s, btinfo->itrace);
VEC_free (btrace_func_s, btinfo->ftrace);
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 715c6d4..f48af01 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -1081,6 +1081,13 @@ i386_linux_disable_btrace (struct btrace_target_info *tinfo)
error (_("Could not disable branch tracing: %s."), safe_strerror (errcode));
}
+static void
+i386_linux_clear_btrace (struct btrace_target_info *tinfo)
+{
+ /* Ignore errors. */
+ linux_disable_btrace (tinfo);
+}
+
/* -Wmissing-prototypes */
extern initialize_file_ftype _initialize_i386_linux_nat;
@@ -1118,6 +1125,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_clear_btrace = i386_linux_clear_btrace;
t->to_read_btrace = linux_read_btrace;
/* Register the target. */
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index c1a7905..5af9f96 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -111,6 +111,14 @@ record_btrace_disable_callback (void *arg)
warning ("%s", error.message);
}
+static void
+record_btrace_clear_callback (void *arg)
+{
+ struct thread_info *tp = arg;
+
+ btrace_clear (tp);
+}
+
/* Enable automatic tracing of new threads. */
static void
@@ -189,7 +197,7 @@ record_btrace_close (int quitting)
turn errors into warnings since we cannot afford to throw an error. */
ALL_THREADS (tp)
if (tp->btrace.target != NULL)
- record_btrace_disable_callback (tp);
+ record_btrace_clear_callback (tp);
record_btrace_auto_disable ();
}
diff --git a/gdb/remote.c b/gdb/remote.c
index f76846a..ec2b305 100755
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -11204,6 +11204,12 @@ remote_disable_btrace (struct btrace_target_info *tinfo)
xfree (tinfo);
}
+static void
+remote_clear_btrace (struct btrace_target_info *tinfo)
+{
+ xfree (tinfo);
+}
+
/* Read the branch trace. */
static VEC (btrace_block_s) *
@@ -11368,6 +11374,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_clear_btrace = remote_clear_btrace;
remote_ops.to_read_btrace = remote_read_btrace;
}
diff --git a/gdb/target.c b/gdb/target.c
index 778b6b9..20cf704 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4203,6 +4203,19 @@ target_disable_btrace (struct btrace_target_info *btinfo)
}
/* See target.h. */
+void
+target_clear_btrace (struct btrace_target_info *btinfo)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_clear_btrace != NULL)
+ return t->to_clear_btrace (btinfo);
+
+ tcomplain ();
+}
+
+/* See target.h. */
VEC (btrace_block_s) *
target_read_btrace (struct btrace_target_info *btinfo,
enum btrace_read_type type)
diff --git a/gdb/target.h b/gdb/target.h
index 88c13cc..66e3a12 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -870,6 +870,8 @@ struct target_ops
/* Disable branch tracing and deallocate @tinfo. */
void (*to_disable_btrace) (struct btrace_target_info *tinfo);
+ void (*to_clear_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);
@@ -1971,6 +1973,8 @@ 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);
+extern void target_clear_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 *,
diff --git a/gdb/thread.c b/gdb/thread.c
index cffaa42..433b91d 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_clear (tp);
do_all_intermediate_continuations_thread (tp, 1);
do_all_continuations_thread (tp, 1);
^ permalink raw reply [flat|nested] 102+ messages in thread* RE: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-06 17:06 ` Jan Kratochvil
@ 2013-03-06 18:08 ` Metzger, Markus T
2013-03-07 9:06 ` Jan Kratochvil
0 siblings, 1 reply; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-06 18:08 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: Wednesday, March 06, 2013 6:06 PM
> To: Metzger, Markus T
> Cc: gdb-patches@sourceware.org; markus.t.metzger@gmail.com; Himpel, Christian
> Subject: Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
>
> Hi Markus,
>
> On Wed, 06 Mar 2013 16:30:13 +0100, Metzger, Markus T wrote:
> > I still disable threads in to_close which tries to talk to the target.
>
> When one follows the Pedro's way which I forwarded to you in to_close one
> should only clear resources, without doing any actions involving the rest of
> GDB infrastructure.
>
> Do you think the attached patch still has some leaks or other issues?
I'm not quite sure what the OS will do if tracing is requested twice for the same
thread, i.e. repeated "record stop" followed by "record btrace" . We may get
an error or we may get a second buffer, thus leaking resources (i.e. the mmapped
trace buffer). We will need another target method to disable branch tracing
that is called by the "record stop" command.
In a gdbserver --multi session, I would expect that we're leaking the mmapped trace
buffer also on re-run. I think this can be handled with an appropriate
to_create_inferior method.
Thanks a lot. I'll incorporate it and send an update of the patch series tomorrow.
> An unrelated small cleanup is that btrace_disconnect should be IMO called from
> to_detach and not from detach_command.
Thanks. I already fixed that then when I investigated the issue.
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] 102+ messages in thread
* Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-06 18:08 ` Metzger, Markus T
@ 2013-03-07 9:06 ` Jan Kratochvil
2013-03-07 9:41 ` Metzger, Markus T
0 siblings, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-07 9:06 UTC (permalink / raw)
To: Metzger, Markus T; +Cc: gdb-patches, markus.t.metzger, Himpel, Christian
On Wed, 06 Mar 2013 19:07:42 +0100, Metzger, Markus T wrote:
> I'm not quite sure what the OS will do if tracing is requested twice for the same
> thread, i.e. repeated "record stop" followed by "record btrace" . We may get
> an error or we may get a second buffer, thus leaking resources (i.e. the mmapped
> trace buffer). We will need another target method to disable branch tracing
> that is called by the "record stop" command.
Yes, thanks for catching it, "record stop" needs to call real btrace_disable
before unpushing the target.
> In a gdbserver --multi session, I would expect that we're leaking the mmapped trace
> buffer also on re-run.
During re-run the first process gets killed first, so btrace_clear on the GDB
side is appropriate in such case.
On the gdbserver side there is linux_disable_btrace still called:
#0 linux_disable_btrace (tinfo=0x66fd40) at ../common/linux-btrace.c:509
#1 in remove_thread (thread=0x66f900) at inferiors.c:165
#2 in delete_lwp (lwp=0x66f7d0) at linux-low.c:334
#3 in delete_lwp_callback (entry=0x66f7d0, proc=0x66f660) at linux-low.c:1234
#4 in find_inferior (list=0x666540 <all_lwps>, func=0x425c61 <delete_lwp_callback>, arg=0x66f660) at inferiors.c:185
#5 in linux_mourn (process=0x66f660) at linux-low.c:1248
#6 in linux_kill (pid=28282) at linux-low.c:1058
#7 in kill_inferior (pid=28282) at target.c:190
#8 in handle_v_kill (own_buf=0x667370 "vKill;6e7a") at server.c:2273
#9 in handle_v_requests (own_buf=0x667370 "vKill;6e7a", packet_len=10, new_packet_len=0x7fffffffd7c8) at server.c:2345
#10 in process_serial_event () at server.c:3484
So I find that OK.
> I think this can be handled with an appropriate to_create_inferior method.
I do not see a reason for that hook - could you be more specific?
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* RE: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 9:06 ` Jan Kratochvil
@ 2013-03-07 9:41 ` Metzger, Markus T
2013-03-07 10:00 ` Metzger, Markus T
2013-03-07 10:08 ` Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom] Jan Kratochvil
0 siblings, 2 replies; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-07 9:41 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: Thursday, March 07, 2013 10:07 AM
> > I'm not quite sure what the OS will do if tracing is requested twice for the same
> > thread, i.e. repeated "record stop" followed by "record btrace" . We may get
> > an error or we may get a second buffer, thus leaking resources (i.e. the mmapped
> > trace buffer). We will need another target method to disable branch tracing
> > that is called by the "record stop" command.
>
> Yes, thanks for catching it, "record stop" needs to call real btrace_disable
> before unpushing the target.
>
>
> > In a gdbserver --multi session, I would expect that we're leaking the mmapped trace
> > buffer also on re-run.
>
> During re-run the first process gets killed first, so btrace_clear on the GDB
> side is appropriate in such case.
The problem is that your patch wouldn't try to actually disable tracing on the target.
Gdbserver would still have the trace buffer mmapped. I don't know if the OS can
unmap those buffers when the traced process goes away - the buffers are owned
by another process that is still running.
This does not only affect re-run. We should have the same issue when a pthread
is joined.
> @@ -447,6 +447,12 @@ btrace_clear (struct thread_info *tp)
>
> btinfo = &tp->btrace;
>
> + if (btinfo->target != NULL)
> + {
> + target_clear_btrace (btinfo->target);
> + btinfo->target = NULL;
> + }
This is also something we don't want to do. It would disable tracing when we
just want to update the trace.
I have a patch that adds another disable path similar to your patch. That other
path is used in clear_thread_inferior_resources. So in to_close, we first try to
disable branch tracing normally. Should we realize that the target is gone, GDB
will pop all targets, discard all threads, and throw an error.
Discard all threads will now use the teardown path instead of the disable path.
The error will abort the thread traversal in to_close.
The remaining problem is that this will leak branch trace buffers for joined
pthreads in the remote case.
Is there a reliable way of determining whether the target connection is down?
If there is, I could disable normally as long as the target connection is up and
only leak resources when the connection is already down. I might not even need
the second disable path in that case.
Another approach would be to change pop_target to unpush the top target
instead of just closing it. This would prevent btrace from finding a target to
disable tracing and all I would need to do is remove the tcomplain call in
target_disable_btrace.
This would be quite elegant but I have no clue about the side effects this
might have.
> On the gdbserver side there is linux_disable_btrace still called:
> #0 linux_disable_btrace (tinfo=0x66fd40) at ../common/linux-btrace.c:509
> #1 in remove_thread (thread=0x66f900) at inferiors.c:165
> #2 in delete_lwp (lwp=0x66f7d0) at linux-low.c:334
> #3 in delete_lwp_callback (entry=0x66f7d0, proc=0x66f660) at linux-low.c:1234
> #4 in find_inferior (list=0x666540 <all_lwps>, func=0x425c61 <delete_lwp_callback>, arg=0x66f660) at inferiors.c:185
> #5 in linux_mourn (process=0x66f660) at linux-low.c:1248
> #6 in linux_kill (pid=28282) at linux-low.c:1058
> #7 in kill_inferior (pid=28282) at target.c:190
> #8 in handle_v_kill (own_buf=0x667370 "vKill;6e7a") at server.c:2273
> #9 in handle_v_requests (own_buf=0x667370 "vKill;6e7a", packet_len=10, new_packet_len=0x7fffffffd7c8) at server.c:2345
> #10 in process_serial_event () at server.c:3484
>
> So I find that OK.
>
>
> > I think this can be handled with an appropriate to_create_inferior method.
>
> I do not see a reason for that hook - could you be more specific?
I was only thinking about re-running an already running process. But the issue
is more general and thus requires a more general solution.
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] 102+ messages in thread* RE: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 9:41 ` Metzger, Markus T
@ 2013-03-07 10:00 ` Metzger, Markus T
2013-03-07 10:14 ` Jan Kratochvil
2013-03-07 10:08 ` Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom] Jan Kratochvil
1 sibling, 1 reply; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-07 10:00 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, markus.t.metzger, Himpel, Christian
> -----Original Message-----
> From: Metzger, Markus T
> Sent: Thursday, March 07, 2013 10:41 AM
> Another approach would be to change pop_target to unpush the top target
> instead of just closing it. This would prevent btrace from finding a target to
> disable tracing and all I would need to do is remove the tcomplain call in
> target_disable_btrace.
>
> This would be quite elegant but I have no clue about the side effects this
> might have.
void
pop_target (void)
{
target_close (target_stack, 0); /* Let it clean up. */
if (unpush_target (target_stack) == 1)
return;
fprintf_unfiltered (gdb_stderr,
"pop_target couldn't find target %s\n",
current_target.to_shortname);
internal_error (__FILE__, __LINE__,
_("failed internal consistency check"));
}
Isn't pop_target closing the topmost target twice?
When I remove the first call to target_close and do not turn errors into
warnings in record_btrace_close, the crash is gone. I have no clue about
the side effects of this, though.
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] 102+ messages in thread* Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 10:00 ` Metzger, Markus T
@ 2013-03-07 10:14 ` Jan Kratochvil
2013-03-07 10:33 ` Metzger, Markus T
0 siblings, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-07 10:14 UTC (permalink / raw)
To: Metzger, Markus T; +Cc: gdb-patches, markus.t.metzger, Himpel, Christian
On Thu, 07 Mar 2013 10:59:23 +0100, Metzger, Markus T wrote:
> > -----Original Message-----
> > From: Metzger, Markus T
> > Sent: Thursday, March 07, 2013 10:41 AM
>
>
> > Another approach would be to change pop_target to unpush the top target
> > instead of just closing it. This would prevent btrace from finding a target to
> > disable tracing and all I would need to do is remove the tcomplain call in
> > target_disable_btrace.
> >
> > This would be quite elegant but I have no clue about the side effects this
> > might have.
>
> void
> pop_target (void)
> {
> target_close (target_stack, 0); /* Let it clean up. */
> if (unpush_target (target_stack) == 1)
> return;
>
> fprintf_unfiltered (gdb_stderr,
> "pop_target couldn't find target %s\n",
> current_target.to_shortname);
> internal_error (__FILE__, __LINE__,
> _("failed internal consistency check"));
> }
>
> Isn't pop_target closing the topmost target twice?
>
> When I remove the first call to target_close and do not turn errors into
> warnings in record_btrace_close, the crash is gone. I have no clue about
> the side effects of this, though.
OK, I agree target_close seems excessive here, it also does not correspond to
the current description of target_close:
This routine is automatically always called after popping the target
off the target stack
While it is nice cleanup I find it a separate patch, not required for btrace.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread* RE: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 10:14 ` Jan Kratochvil
@ 2013-03-07 10:33 ` Metzger, Markus T
2013-03-07 12:07 ` Jan Kratochvil
0 siblings, 1 reply; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-07 10:33 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: Thursday, March 07, 2013 11:14 AM
> > void
> > pop_target (void)
> > {
> > target_close (target_stack, 0); /* Let it clean up. */
> > if (unpush_target (target_stack) == 1)
> > return;
> >
> > fprintf_unfiltered (gdb_stderr,
> > "pop_target couldn't find target %s\n",
> > current_target.to_shortname);
> > internal_error (__FILE__, __LINE__,
> > _("failed internal consistency check"));
> > }
> >
> > Isn't pop_target closing the topmost target twice?
> >
> > When I remove the first call to target_close and do not turn errors into
> > warnings in record_btrace_close, the crash is gone. I have no clue about
> > the side effects of this, though.
>
>
> OK, I agree target_close seems excessive here, it also does not correspond to
> the current description of target_close:
> This routine is automatically always called after popping the target
> off the target stack
>
> While it is nice cleanup I find it a separate patch, not required for btrace.
With this patch, the crash is gone with only minimal changes to btrace.
OK to add it as separate patch to the btrace series?
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] 102+ messages in thread* Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 10:33 ` Metzger, Markus T
@ 2013-03-07 12:07 ` Jan Kratochvil
2013-03-07 12:33 ` Metzger, Markus T
0 siblings, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-07 12:07 UTC (permalink / raw)
To: Metzger, Markus T; +Cc: gdb-patches, markus.t.metzger, Himpel, Christian
On Thu, 07 Mar 2013 11:31:39 +0100, Metzger, Markus T wrote:
> > OK, I agree target_close seems excessive here, it also does not correspond to
> > the current description of target_close:
> > This routine is automatically always called after popping the target
> > off the target stack
> >
> > While it is nice cleanup I find it a separate patch, not required for btrace.
>
> With this patch, the crash is gone with only minimal changes to btrace.
It is only a coincidence and workaround of it.
The problem here is not the specific crash but the violation of the current
to_close definition of operations, as discussed in the referenced Pedro's
mail. It may cause different problems later.
> OK to add it as separate patch to the btrace series?
No. But it would be interesting to post it as unrelated patch, for gdb-7.7+.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* RE: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 12:07 ` Jan Kratochvil
@ 2013-03-07 12:33 ` Metzger, Markus T
2013-03-07 14:45 ` Jan Kratochvil
2013-03-07 15:12 ` Pedro Alves
0 siblings, 2 replies; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-07 12:33 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: Thursday, March 07, 2013 1:07 PM
> > > OK, I agree target_close seems excessive here, it also does not correspond to
> > > the current description of target_close:
> > > This routine is automatically always called after popping the target
> > > off the target stack
> > >
> > > While it is nice cleanup I find it a separate patch, not required for btrace.
> >
> > With this patch, the crash is gone with only minimal changes to btrace.
>
> It is only a coincidence and workaround of it.
Hmmm, if we must no longer call methods in a certain target, why is
removing that target a workaround?
Pedro already moved the target_close call after removing the target in
http://sourceware.org/ml/gdb-patches/2012-01/msg00701.html.
He just did not consider the extra target_close call in pop_target, which
is not only closing the target twice but also breaking his attempt to
reorder target removing and closing.
If we removed disabling btrace from to_close, we would need to add a
separate path for "record stop". This means adding two new target
methods in total - one for clear/teardown and one for record stop. It
would further break the symmetry with to_open. Tracing would be
enabled in to_open but it would not be disabled in to_close, any more.
We also must not clear btrace in to_close since this would prevent btrace
from actually being disabled when the threads are discarded sometime
after the record target has been unpushed. We would thus leave threads
traced after the record target is gone and rely on thread cleanup to do
the actual disabling. This does not feel right.
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] 102+ messages in thread
* Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 12:33 ` Metzger, Markus T
@ 2013-03-07 14:45 ` Jan Kratochvil
2013-03-07 15:22 ` Metzger, Markus T
2013-03-07 15:12 ` Pedro Alves
1 sibling, 1 reply; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-07 14:45 UTC (permalink / raw)
To: Metzger, Markus T
Cc: gdb-patches, markus.t.metzger, Himpel, Christian, Pedro Alves
On Thu, 07 Mar 2013 13:32:16 +0100, Metzger, Markus T wrote:
> > > > OK, I agree target_close seems excessive here, it also does not correspond to
> > > > the current description of target_close:
> > > > This routine is automatically always called after popping the target
> > > > off the target stack
> > > >
> > > > While it is nice cleanup I find it a separate patch, not required for btrace.
> > >
> > > With this patch, the crash is gone with only minimal changes to btrace.
> >
> > It is only a coincidence and workaround of it.
>
> Hmmm, if we must no longer call methods in a certain target, why is
> removing that target a workaround?
OK, wrong term, it is snot a "workaround" but it hides the incorrect
implementation approach.
> Pedro already moved the target_close call after removing the target in
> http://sourceware.org/ml/gdb-patches/2012-01/msg00701.html.
Yes, such fix of pop_target seems to be OK. The problem is that it may IMO
have unexpected implications not good to check-in right before a release.
And I do not see a real reason to push that fix for gdb-7.6 right now.
> If we removed disabling btrace from to_close, we would need to add a
> separate path for "record stop".
Yes.
> It would further break the symmetry with to_open. Tracing would be
> enabled in to_open but it would not be disabled in to_close, any more.
It is more questionable whether tracing of inferiors should really be done at
to_open time. If you want symmetry then record_btrace_open could be split and
btrace_enable calls could be done from a new method (after to_open finishes).
But GDB already commonly does 'start' of the target from its to_open, this is
also why to_open has args. This brings in the asymmetry. It can be safely
done because to_open is called only under controlled conditions. Contrary to
it to_close can be called in arbitrary crash/teardown state so it should not
rely on much.
> We also must not clear btrace in to_close since this would prevent btrace
> from actually being disabled when the threads are discarded sometime
> after the record target has been unpushed. We would thus leave threads
> traced after the record target is gone and rely on thread cleanup to do
> the actual disabling. This does not feel right.
to_close can be called in controlled (such as "record stop") or uncontrolled
(inferior dies / gets killed). In the first case "record stop" should
explicitly disable the tracing before calling to_close. In the second case it
does not matter when the tracing disable happens, it just needs to happen.
For the second case there must be always someone who does the munmap + close.
In the linux-nat case it can be easily done from btrace's to_close. In the
gdbserver case it is gdbserver's responsibility (where it actually already
works).
By the plan above one avoids the situation of half-closed target, this is
still (AFAIK) the Pedro's design from the original mail.
pop_target fix is nice, thanks for catching it, but it is not a prerequisite.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* RE: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 14:45 ` Jan Kratochvil
@ 2013-03-07 15:22 ` Metzger, Markus T
2013-03-07 15:46 ` Jan Kratochvil
0 siblings, 1 reply; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-07 15:22 UTC (permalink / raw)
To: Jan Kratochvil
Cc: gdb-patches, markus.t.metzger, Himpel, Christian, Pedro Alves
> -----Original Message-----
> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
> Sent: Thursday, March 07, 2013 3:45 PM
Thanks for bearing with me on this.
[..]
> > We also must not clear btrace in to_close since this would prevent btrace
> > from actually being disabled when the threads are discarded sometime
> > after the record target has been unpushed. We would thus leave threads
> > traced after the record target is gone and rely on thread cleanup to do
> > the actual disabling. This does not feel right.
>
> to_close can be called in controlled (such as "record stop") or uncontrolled
> (inferior dies / gets killed). In the first case "record stop" should
> explicitly disable the tracing before calling to_close. In the second case it
> does not matter when the tracing disable happens, it just needs to happen.
>
> For the second case there must be always someone who does the munmap + close.
> In the linux-nat case it can be easily done from btrace's to_close. In the
> gdbserver case it is gdbserver's responsibility (where it actually already
> works).
I assume you mean from a new target to_teardown_btrace method and not
from btrace's to_close. That's where it currently is and where we want it moved
away from.
To summarize:
1. add a new target method to_teardown_btrace
1.1. disable btrace for native targets
1.2. only clear the trace and free the btrace_target_info for remote targets
2. call target_teardown_btrace from clear_thread_inferior_resources
3. add new target method to_stop_recording
3.1. disable btrace in record-btrace target
3.2. undefined in other record targets - may later split record-full's to_close.
4. call target_stop_recording in "record stop" before unpushing the record target
5. call target_stop_recording in record_mourn_inferior before unpushing the record target
6. call target_stop_recording in record_detach before unpushing the record target
7. call target_stop_recording in record_disconnect before unpushing the record target
8. call target_stop_recording in record_kill before unpushing the record target
9. remove btrace disable from record_btrace_to_close
This will make record_btrace_to_close empty. I must not touch the per-thread
btrace configuration since this is needed later in 2.
I'll make this a separate patch for easier review. I can later split it and merge
the pieces into the respective btrace patches.
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] 102+ messages in thread
* Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 15:22 ` Metzger, Markus T
@ 2013-03-07 15:46 ` Jan Kratochvil
0 siblings, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-07 15:46 UTC (permalink / raw)
To: Metzger, Markus T
Cc: gdb-patches, markus.t.metzger, Himpel, Christian, Pedro Alves
On Thu, 07 Mar 2013 16:21:58 +0100, Metzger, Markus T wrote:
> I assume you mean from a new target to_teardown_btrace method and not
> from btrace's to_close. That's where it currently is and where we want it moved
> away from.
>
>
> To summarize:
> 1. add a new target method to_teardown_btrace
> 1.1. disable btrace for native targets
> 1.2. only clear the trace and free the btrace_target_info for remote targets
> 2. call target_teardown_btrace from clear_thread_inferior_resources
> 3. add new target method to_stop_recording
> 3.1. disable btrace in record-btrace target
> 3.2. undefined in other record targets - may later split record-full's to_close.
> 4. call target_stop_recording in "record stop" before unpushing the record target
Yes.
> 5. call target_stop_recording in record_mourn_inferior before unpushing the record target
I believe it is safer no, gdbserver will take care of it and it may be
dangerous during some teardown situations.
> 6. call target_stop_recording in record_detach before unpushing the record target
Yes.
> 7. call target_stop_recording in record_disconnect before unpushing the record target
Currently probably yes.
But one would not have to. gdbserver then can continue btracing the inferior
and one can reconnect with new gdb later and fetch that information. But that
would require detecing upon new connection whether btrace is running in remote
target and pushing gdb btrace target if so.
> 8. call target_stop_recording in record_kill before unpushing the record target
Also better no like in 5.
> 9. remove btrace disable from record_btrace_to_close
>
> This will make record_btrace_to_close empty. I must not touch the per-thread
> btrace configuration since this is needed later in 2.
Great summary, thanks.
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 12:33 ` Metzger, Markus T
2013-03-07 14:45 ` Jan Kratochvil
@ 2013-03-07 15:12 ` Pedro Alves
2013-03-07 15:33 ` Metzger, Markus T
[not found] ` <20130318170643.GA15625@host2.jankratochvil.net>
1 sibling, 2 replies; 102+ messages in thread
From: Pedro Alves @ 2013-03-07 15:12 UTC (permalink / raw)
To: Metzger, Markus T
Cc: Jan Kratochvil, gdb-patches, markus.t.metzger, Himpel, Christian
On 03/07/2013 12:32 PM, Metzger, Markus T wrote:
>> -----Original Message-----
>> From: Jan Kratochvil [mailto:jan.kratochvil@redhat.com]
>> Sent: Thursday, March 07, 2013 1:07 PM
>
>
>>>> OK, I agree target_close seems excessive here, it also does not correspond to
>>>> the current description of target_close:
>>>> This routine is automatically always called after popping the target
>>>> off the target stack
>>>>
>>>> While it is nice cleanup I find it a separate patch, not required for btrace.
>>>
>>> With this patch, the crash is gone with only minimal changes to btrace.
>>
>> It is only a coincidence and workaround of it.
>
> Hmmm, if we must no longer call methods in a certain target, why is
> removing that target a workaround?
>
> Pedro already moved the target_close call after removing the target in
> http://sourceware.org/ml/gdb-patches/2012-01/msg00701.html.
>
> He just did not consider the extra target_close call in pop_target, which
> is not only closing the target twice but also breaking his attempt to
> reorder target removing and closing.
Indeed, that seems so. The close-twice isn't an issue for current
targets, as their close methods are idempotent:
static void
remote_close (int quitting)
{
if (remote_desc == NULL)
return; /* already closed */
But the reorder issue here does look like should be fixed.
I think the double closes are actually a workaround for the
"quitting" argument not being propagated to unpush_target (or
maybe unpush_target didn't close the target itself at some point):
void
pop_all_targets_above (enum strata above_stratum, int quitting)
{
while ((int) (current_target.to_stratum) > (int) above_stratum)
{
target_close (target_stack, quitting);
if (!unpush_target (target_stack))
...
void
pop_all_targets (int quitting)
{
pop_all_targets_above (dummy_stratum, quitting);
}
...
/* Called by the event loop to process a SIGHUP. */
static void
async_disconnect (gdb_client_data arg)
{
...
TRY_CATCH (exception, RETURN_MASK_ALL)
{
pop_all_targets (1);
}
...
}
QUITTING is documented here:
/* Does whatever cleanup is required for a target that we are no
longer going to be calling. QUITTING indicates that GDB is exiting
and should not get hung on an error (otherwise it is important to
perform clean termination, even if it takes a while). This routine
is automatically always called after popping the target off the
target stack - the target's own methods are no longer available
through the target vector. Closing file descriptors and freeing all
memory allocated memory are typical things it should do. */
void target_close (struct target_ops *targ, int quitting);
I'm not sure, but ISTR that no target nowadays actually does
anything with the 'quitting' flag.
--
Pedro Alves
^ permalink raw reply [flat|nested] 102+ messages in thread* RE: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 15:12 ` Pedro Alves
@ 2013-03-07 15:33 ` Metzger, Markus T
2013-03-07 15:39 ` Jan Kratochvil
2013-03-07 15:41 ` Pedro Alves
[not found] ` <20130318170643.GA15625@host2.jankratochvil.net>
1 sibling, 2 replies; 102+ messages in thread
From: Metzger, Markus T @ 2013-03-07 15:33 UTC (permalink / raw)
To: Pedro Alves
Cc: Jan Kratochvil, gdb-patches, markus.t.metzger, Himpel, Christian
On a related topic, remote.c calls pop_target at various places, e.g.
in readchar when the communication breaks down. It looks to me
as if it assumes that it is the topmost target.
If communication breaks down during remote recording, wouldn't
this pop the record target instead of the remote target?
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] 102+ messages in thread* Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 15:33 ` Metzger, Markus T
@ 2013-03-07 15:39 ` Jan Kratochvil
2013-03-07 15:41 ` Pedro Alves
1 sibling, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-07 15:39 UTC (permalink / raw)
To: Metzger, Markus T
Cc: Pedro Alves, gdb-patches, markus.t.metzger, Himpel, Christian
On Thu, 07 Mar 2013 16:31:23 +0100, Metzger, Markus T wrote:
> On a related topic, remote.c calls pop_target at various places, e.g.
> in readchar when the communication breaks down. It looks to me
> as if it assumes that it is the topmost target.
>
> If communication breaks down during remote recording, wouldn't
> this pop the record target instead of the remote target?
It seems so, in fact when I was playing here with btrace and gdbserver I had
to sometimes 'killall gdb' after gdbserver died. I did not put much attention
to it.
Explicit unpush_target for remote_ops or extended_remote_ops as appropriate
would be hopefully a fix.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 15:33 ` Metzger, Markus T
2013-03-07 15:39 ` Jan Kratochvil
@ 2013-03-07 15:41 ` Pedro Alves
1 sibling, 0 replies; 102+ messages in thread
From: Pedro Alves @ 2013-03-07 15:41 UTC (permalink / raw)
To: Metzger, Markus T
Cc: Jan Kratochvil, gdb-patches, markus.t.metzger, Himpel, Christian
On 03/07/2013 03:31 PM, Metzger, Markus T wrote:
> On a related topic, remote.c calls pop_target at various places, e.g.
> in readchar when the communication breaks down. It looks to me
> as if it assumes that it is the topmost target.
>
> If communication breaks down during remote recording, wouldn't
> this pop the record target instead of the remote target?
Yes.
record + gdbserver isn't much used I assume, as I've known
about that for ages, but never heard anyone complain.
Another similar issue in spirit is the to_stratum checks
in record.c:
static void
cmd_record_delete (char *args, int from_tty)
{
if (current_target.to_stratum == record_stratum)
That assumes the record target is always the topmost.
Nowadays we have arch_stratum on top of record. Only used
by Cell nowadays, so it's latent.
--
Pedro Alves
^ permalink raw reply [flat|nested] 102+ messages in thread
[parent not found: <20130318170643.GA15625@host2.jankratochvil.net>]
* Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-07 9:41 ` Metzger, Markus T
2013-03-07 10:00 ` Metzger, Markus T
@ 2013-03-07 10:08 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-07 10:08 UTC (permalink / raw)
To: Metzger, Markus T; +Cc: gdb-patches, markus.t.metzger, Himpel, Christian
On Thu, 07 Mar 2013 10:40:53 +0100, Metzger, Markus T wrote:
> The problem is that your patch wouldn't try to actually disable tracing on the target.
That is a responsibility of remote gdbserver. If gdbserver needs then it
should disable/discard btrace on its own (which AFAIK it does).
> Gdbserver would still have the trace buffer mmapped. I don't know if the OS can
> unmap those buffers when the traced process goes away - the buffers are owned
> by another process that is still running.
I have shown in the gdbserver backtrace that gdbserver's linux_mourn calls
linux_disable_btrace so I do not see why you think the btrace buffers remain
mapped on the gdbserver side:
#0 linux_disable_btrace (tinfo=0x66fd40) at ../common/linux-btrace.c:509
#1 in remove_thread (thread=0x66f900) at inferiors.c:165
#2 in delete_lwp (lwp=0x66f7d0) at linux-low.c:334
#3 in delete_lwp_callback (entry=0x66f7d0, proc=0x66f660) at linux-low.c:1234
#4 in find_inferior (list=0x666540 <all_lwps>, func=0x425c61 <delete_lwp_callback>, arg=0x66f660) at inferiors.c:185
#5 in linux_mourn (process=0x66f660) at linux-low.c:1248
#6 in linux_kill (pid=28282) at linux-low.c:1058
There sure may be a case I forgot about but from your problem description I do
not see such case.
> This does not only affect re-run. We should have the same issue when a pthread
> is joined.
The same like above, I do not see a reproducer of such case.
> > @@ -447,6 +447,12 @@ btrace_clear (struct thread_info *tp)
> >
> > btinfo = &tp->btrace;
> >
> > + if (btinfo->target != NULL)
> > + {
> > + target_clear_btrace (btinfo->target);
> > + btinfo->target = NULL;
> > + }
>
> This is also something we don't want to do. It would disable tracing when we
> just want to update the trace.
OK, I see - so there should be another function instead of reusing existing
btrace_clear.
> I have a patch that adds another disable path similar to your patch. That other
> path is used in clear_thread_inferior_resources. So in to_close, we first try to
> disable branch tracing normally. Should we realize that the target is gone, GDB
> will pop all targets, discard all threads, and throw an error.
The point was that during mourn inferior with gdbserver there should be no
gdb->gdbserver communication about btrace as it is gdbserver's problem.
GDB just asked gdbserver to mourn the inferior.
> Discard all threads will now use the teardown path instead of the disable path.
> The error will abort the thread traversal in to_close.
Also during to_close AFAIK no error should ever happen.
> The remaining problem is that this will leak branch trace buffers for joined
> pthreads in the remote case.
Again, gdbserver should track everything around its debuggee, gdb just asks
gdbserver to kill the inferior.
> Is there a reliable way of determining whether the target connection is down?
No, it may break in the middle of disabling btrace etc. And there is no
reason for gdb to care about.
> Another approach would be to change pop_target to unpush the top target
> instead of just closing it. This would prevent btrace from finding a target to
> disable tracing and all I would need to do is remove the tcomplain call in
> target_disable_btrace.
I do not see why, this will not run possible cleanups executed from its
to_close.
Thanks,
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread
* Re: Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom]
2013-03-06 12:43 ` Crash of GDB with gdbserver btrace enabled [Re: [patch v9 00/23] branch tracing support for Atom] Jan Kratochvil
2013-03-06 14:40 ` Metzger, Markus T
@ 2013-03-06 15:41 ` Jan Kratochvil
1 sibling, 0 replies; 102+ messages in thread
From: Jan Kratochvil @ 2013-03-06 15:41 UTC (permalink / raw)
To: Markus Metzger; +Cc: gdb-patches, markus.t.metzger
On Wed, 06 Mar 2013 13:43:34 +0100, Jan Kratochvil wrote:
> There were a similar thread on the list before, I have not investigated it
> yet.
Going to check it more but this referenced mail thread was:
Call target_close after unpushing, not before (was: Re: [patch] Fix remote.c crash on gdbserver close (+fix py-finish-breakpoint.exp for gdbserver))
Message-ID: <20111225113745.GA16273@host2.jankratochvil.net>
http://sourceware.org/ml/gdb-patches/2012-01/msg00701.html
Jan
^ permalink raw reply [flat|nested] 102+ messages in thread