Add the gdb remote target operations for branch tracing.

We define the following packets:

  Qbtrace:bts         enable branch tracing for the current thread
                      returns "OK" or "Enn"

  Qbtrace:off         disable branch tracing for the current thread
                      returns "OK" or "Enn"

  qXfer:btrace:read   read the full branch trace data for the current thread

gdb/
	* 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_teardown_btrace): New function.
	(remote_read_btrace): New function.
	(init_remote_ops): Add btrace ops.
	(enum <unnamed>): Add btrace packets.
	(struct protocol_feature remote_protocol_features[]): Add btrace packets.
	(_initialize_remote): Add packet configuration for branch tracing.

gdbserver/
	* target.h (struct target_ops): Add btrace ops.
	(target_supports_btrace): New macro.
	(target_enable_btrace): New macro.
	(target_disable_btrace): New macro.
	(target_read_btrace): New macro.
	* gdbthread.h (struct thread_info): Add btrace field.
	* server.c: Include btrace-common.h.
	(handle_btrace_general_set): New function.
	(handle_btrace_enable): New function.
	(handle_btrace_disable): New function.
	(handle_general_set): Call handle_btrace_general_set.
	(handle_qxfer_btrace): New function.
	(struct qxfer qxfer_packets[]): Add btrace entry.
	* inferiors.c (remove_thread): Disable btrace.
	* linux-low: Include linux-btrace.h.
	(linux_low_enable_btrace): New function.
	(linux_low_read_btrace): New function.
	(linux_target_ops): Add btrace ops.
	* configure.srv (i[34567]86-*-linux*): Add linux-btrace.o.
	Add srv_linux_btrace=yes.
	(x86_64-*-linux*): Add linux-btrace.o.
	Add srv_linux_btrace=yes.
	* configure.ac: Define HAVE_LINUX_BTRACE.
	* config.in: Regenerated.
	* configure: Regenerated.
This commit is contained in:
Markus Metzger 2013-03-11 08:35:11 +00:00
parent 5cc22e4cf7
commit 9accd112a6
13 changed files with 489 additions and 2 deletions

View file

@ -1,3 +1,19 @@
2013-03-11 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_teardown_btrace): New function.
(remote_read_btrace): New function.
(init_remote_ops): Add btrace ops.
(enum <unnamed>): Add btrace packets.
(struct protocol_feature remote_protocol_features[]): Add btrace packets.
(_initialize_remote): Add packet configuration for branch tracing.
2013-03-11 Markus Metzger <markus.t.metzger@intel.com>
* features/btrace.dtd: New file.

View file

@ -1,3 +1,31 @@
2013-03-11 Markus Metzger <markus.t.metzger@intel.com>
* target.h (struct target_ops): Add btrace ops.
(target_supports_btrace): New macro.
(target_enable_btrace): New macro.
(target_disable_btrace): New macro.
(target_read_btrace): New macro.
* gdbthread.h (struct thread_info): Add btrace field.
* server.c: Include btrace-common.h.
(handle_btrace_general_set): New function.
(handle_btrace_enable): New function.
(handle_btrace_disable): New function.
(handle_general_set): Call handle_btrace_general_set.
(handle_qxfer_btrace): New function.
(struct qxfer qxfer_packets[]): Add btrace entry.
* inferiors.c (remove_thread): Disable btrace.
* linux-low: Include linux-btrace.h.
(linux_low_enable_btrace): New function.
(linux_low_read_btrace): New function.
(linux_target_ops): Add btrace ops.
* configure.srv (i[34567]86-*-linux*): Add linux-btrace.o.
Add srv_linux_btrace=yes.
(x86_64-*-linux*): Add linux-btrace.o.
Add srv_linux_btrace=yes.
* configure.ac: Define HAVE_LINUX_BTRACE.
* config.in: Regenerated.
* configure: Regenerated.
2013-03-11 Markus Metzger <markus.t.metzger@intel.com>
* server.c (handle_qxfer): Preserve error message if -3 is

View file

@ -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

View file

@ -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; }

View file

@ -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)

View file

@ -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"

View file

@ -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;

View file

@ -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);
}

View file

@ -84,6 +84,10 @@
#endif
#endif
#ifdef HAVE_LINUX_BTRACE
# include "linux-btrace.h"
#endif
#ifndef HAVE_ELF32_AUXV_T
/* Copied from glibc's elf.h. */
typedef struct
@ -5821,6 +5825,47 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
return len;
}
#ifdef HAVE_LINUX_BTRACE
/* Enable branch tracing. */
static struct btrace_target_info *
linux_low_enable_btrace (ptid_t ptid)
{
struct btrace_target_info *tinfo;
tinfo = linux_enable_btrace (ptid);
if (tinfo != NULL)
tinfo->ptr_bits = register_size (0) * 8;
return tinfo;
}
/* Read branch trace data as btrace xml document. */
static void
linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
int type)
{
VEC (btrace_block_s) *btrace;
struct btrace_block *block;
int i;
btrace = linux_read_btrace (tinfo, type);
buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
for (i = 0; VEC_iterate (btrace_block_s, btrace, i, block); i++)
buffer_xml_printf (buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
paddress (block->begin), paddress (block->end));
buffer_grow_str (buffer, "</btrace>\n");
VEC_free (btrace_block_s, btrace);
}
#endif /* HAVE_LINUX_BTRACE */
static struct target_ops linux_target_ops = {
linux_create_inferior,
linux_attach,
@ -5885,6 +5930,18 @@ static struct target_ops linux_target_ops = {
linux_get_min_fast_tracepoint_insn_len,
linux_qxfer_libraries_svr4,
linux_supports_agent,
#ifdef HAVE_LINUX_BTRACE
linux_supports_btrace,
linux_low_enable_btrace,
linux_disable_btrace,
linux_low_read_btrace,
#else
NULL,
NULL,
NULL,
NULL,
NULL,
#endif
};
static void

View file

@ -28,6 +28,7 @@
#include <signal.h>
#endif
#include "gdb_wait.h"
#include "btrace-common.h"
/* The thread set with an `Hc' packet. `Hc' is deprecated in favor of
`vCont'. Note the multi-process extensions made `vCont' a
@ -396,6 +397,88 @@ write_qxfer_response (char *buf, const void *data, int len, int is_more)
PBUFSIZ - 2) + 1;
}
/* Handle btrace enabling. */
static const char *
handle_btrace_enable (struct thread_info *thread)
{
if (thread->btrace != NULL)
return "E.Btrace already enabled.";
thread->btrace = target_enable_btrace (thread->entry.id);
if (thread->btrace == NULL)
return "E.Could not enable btrace.";
return NULL;
}
/* Handle btrace disabling. */
static const char *
handle_btrace_disable (struct thread_info *thread)
{
if (thread->btrace == NULL)
return "E.Branch tracing not enabled.";
if (target_disable_btrace (thread->btrace) != 0)
return "E.Could not disable branch tracing.";
thread->btrace = NULL;
return NULL;
}
/* Handle the "Qbtrace" packet. */
static int
handle_btrace_general_set (char *own_buf)
{
struct thread_info *thread;
const char *err;
char *op;
if (strncmp ("Qbtrace:", own_buf, strlen ("Qbtrace:")) != 0)
return 0;
op = own_buf + strlen ("Qbtrace:");
if (!target_supports_btrace ())
{
strcpy (own_buf, "E.Target does not support branch tracing.");
return -1;
}
if (ptid_equal (general_thread, null_ptid)
|| ptid_equal (general_thread, minus_one_ptid))
{
strcpy (own_buf, "E.Must select a single thread.");
return -1;
}
thread = find_thread_ptid (general_thread);
if (thread == NULL)
{
strcpy (own_buf, "E.No such thread.");
return -1;
}
err = NULL;
if (strcmp (op, "bts") == 0)
err = handle_btrace_enable (thread);
else if (strcmp (op, "off") == 0)
err = handle_btrace_disable (thread);
else
err = "E.Bad Qbtrace operation. Use bts or off.";
if (err != 0)
strcpy (own_buf, err);
else
write_ok (own_buf);
return 1;
}
/* Handle all of the extended 'Q' packets. */
static void
@ -552,6 +635,9 @@ handle_general_set (char *own_buf)
return;
}
if (handle_btrace_general_set (own_buf))
return;
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@ -1251,9 +1337,77 @@ handle_qxfer_fdpic (const char *annex, gdb_byte *readbuf,
return (*the_target->read_loadmap) (annex, offset, readbuf, len);
}
/* Handle qXfer:btrace:read. */
static int
handle_qxfer_btrace (const char *annex,
gdb_byte *readbuf, const gdb_byte *writebuf,
ULONGEST offset, LONGEST len)
{
static struct buffer cache;
struct thread_info *thread;
int type;
if (the_target->read_btrace == NULL || writebuf != NULL)
return -2;
if (!target_running ())
return -1;
if (ptid_equal (general_thread, null_ptid)
|| ptid_equal (general_thread, minus_one_ptid))
{
strcpy (own_buf, "E.Must select a single thread.");
return -3;
}
thread = find_thread_ptid (general_thread);
if (thread == NULL)
{
strcpy (own_buf, "E.No such thread.");
return -3;
}
if (thread->btrace == NULL)
{
strcpy (own_buf, "E.Btrace not enabled.");
return -3;
}
if (strcmp (annex, "all") == 0)
type = btrace_read_all;
else if (strcmp (annex, "new") == 0)
type = btrace_read_new;
else
{
strcpy (own_buf, "E.Bad annex.");
return -3;
}
if (offset == 0)
{
buffer_free (&cache);
target_read_btrace (thread->btrace, &cache, type);
}
else if (offset > cache.used_size)
{
buffer_free (&cache);
return -3;
}
if (len > cache.used_size - offset)
len = cache.used_size - offset;
memcpy (readbuf, cache.buffer + offset, len);
return len;
}
static const struct qxfer qxfer_packets[] =
{
{ "auxv", handle_qxfer_auxv },
{ "btrace", handle_qxfer_btrace },
{ "fdpic", handle_qxfer_fdpic},
{ "features", handle_qxfer_features },
{ "libraries", handle_qxfer_libraries },
@ -1656,6 +1810,13 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_agent ())
strcat (own_buf, ";QAgent+");
if (target_supports_btrace ())
{
strcat (own_buf, ";Qbtrace:bts+");
strcat (own_buf, ";Qbtrace:off+");
strcat (own_buf, ";qXfer:btrace:read+");
}
return;
}

View file

@ -22,6 +22,8 @@
#define TARGET_H
struct emit_ops;
struct btrace_target_info;
struct buffer;
/* Ways to "resume" a thread. */
@ -397,6 +399,21 @@ struct target_ops
/* Return true if target supports debugging agent. */
int (*supports_agent) (void);
/* Check whether the target supports branch tracing. */
int (*supports_btrace) (void);
/* Enable branch tracing for @ptid and allocate a branch trace target
information struct for reading and for disabling branch trace. */
struct btrace_target_info *(*enable_btrace) (ptid_t ptid);
/* Disable branch tracing. */
int (*disable_btrace) (struct btrace_target_info *tinfo);
/* Read branch trace data into buffer. We use an int to specify the type
to break a cyclic dependency. */
void (*read_btrace) (struct btrace_target_info *, struct buffer *, int type);
};
extern struct target_ops *the_target;
@ -520,6 +537,18 @@ int kill_inferior (int);
(the_target->supports_agent ? \
(*the_target->supports_agent) () : 0)
#define target_supports_btrace() \
(the_target->supports_btrace ? (*the_target->supports_btrace) () : 0)
#define target_enable_btrace(ptid) \
(*the_target->enable_btrace) (ptid)
#define target_disable_btrace(tinfo) \
(*the_target->disable_btrace) (tinfo)
#define target_read_btrace(tinfo, buffer, type) \
(*the_target->read_btrace) (tinfo, buffer, type)
/* Start non-stop mode, returns 0 on success, -1 on failure. */
int start_non_stop (int nonstop);

View file

@ -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;
@ -1281,6 +1282,9 @@ enum {
PACKET_QDisableRandomization,
PACKET_QAgent,
PACKET_QTBuffer_size,
PACKET_Qbtrace_off,
PACKET_Qbtrace_bts,
PACKET_qXfer_btrace,
PACKET_MAX
};
@ -3994,6 +3998,10 @@ static struct protocol_feature remote_protocol_features[] = {
remote_supported_packet, PACKET_QTBuffer_size},
{ "tracenz", PACKET_DISABLE,
remote_string_tracing_feature, -1 },
{ "Qbtrace:off", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_off },
{ "Qbtrace:bts", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_bts },
{ "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_btrace }
};
static char *remote_support_xml;
@ -8795,6 +8803,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;
}
@ -11146,6 +11158,150 @@ remote_can_use_agent (void)
return (remote_protocol_packets[PACKET_QAgent].support != PACKET_DISABLE);
}
struct btrace_target_info
{
/* The ptid of the traced thread. */
ptid_t ptid;
};
/* Check whether the target supports branch tracing. */
static int
remote_supports_btrace (void)
{
if (remote_protocol_packets[PACKET_Qbtrace_off].support != PACKET_ENABLE)
return 0;
if (remote_protocol_packets[PACKET_Qbtrace_bts].support != PACKET_ENABLE)
return 0;
if (remote_protocol_packets[PACKET_qXfer_btrace].support != PACKET_ENABLE)
return 0;
return 1;
}
/* Enable branch tracing. */
static struct btrace_target_info *
remote_enable_btrace (ptid_t ptid)
{
struct btrace_target_info *tinfo = NULL;
struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace_bts];
struct remote_state *rs = get_remote_state ();
char *buf = rs->buf;
char *endbuf = rs->buf + get_remote_packet_size ();
if (packet->support != PACKET_ENABLE)
error (_("Target does not support branch tracing."));
set_general_thread (ptid);
buf += xsnprintf (buf, endbuf - buf, "%s", packet->name);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (packet_ok (rs->buf, packet) == PACKET_ERROR)
{
if (rs->buf[0] == 'E' && rs->buf[1] == '.')
error (_("Could not enable branch tracing for %s: %s"),
target_pid_to_str (ptid), rs->buf + 2);
else
error (_("Could not enable branch tracing for %s."),
target_pid_to_str (ptid));
}
tinfo = xzalloc (sizeof (*tinfo));
tinfo->ptid = ptid;
return tinfo;
}
/* Disable branch tracing. */
static void
remote_disable_btrace (struct btrace_target_info *tinfo)
{
struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace_off];
struct remote_state *rs = get_remote_state ();
char *buf = rs->buf;
char *endbuf = rs->buf + get_remote_packet_size ();
if (packet->support != PACKET_ENABLE)
error (_("Target does not support branch tracing."));
set_general_thread (tinfo->ptid);
buf += xsnprintf (buf, endbuf - buf, "%s", packet->name);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (packet_ok (rs->buf, packet) == PACKET_ERROR)
{
if (rs->buf[0] == 'E' && rs->buf[1] == '.')
error (_("Could not disable branch tracing for %s: %s"),
target_pid_to_str (tinfo->ptid), rs->buf + 2);
else
error (_("Could not disable branch tracing for %s."),
target_pid_to_str (tinfo->ptid));
}
xfree (tinfo);
}
/* Teardown branch tracing. */
static void
remote_teardown_btrace (struct btrace_target_info *tinfo)
{
/* We must not talk to the target during teardown. */
xfree (tinfo);
}
/* Read the branch trace. */
static VEC (btrace_block_s) *
remote_read_btrace (struct btrace_target_info *tinfo,
enum btrace_read_type type)
{
struct packet_config *packet = &remote_protocol_packets[PACKET_qXfer_btrace];
struct remote_state *rs = get_remote_state ();
VEC (btrace_block_s) *btrace = NULL;
const char *annex;
char *xml;
if (packet->support != PACKET_ENABLE)
error (_("Target does not support branch tracing."));
#if !defined(HAVE_LIBEXPAT)
error (_("Cannot process branch tracing result. XML parsing not supported."));
#endif
switch (type)
{
case btrace_read_all:
annex = "all";
break;
case btrace_read_new:
annex = "new";
break;
default:
internal_error (__FILE__, __LINE__,
_("Bad branch tracing read type: %u."),
(unsigned int) type);
}
xml = target_read_stralloc (&current_target,
TARGET_OBJECT_BTRACE, annex);
if (xml != NULL)
{
struct cleanup *cleanup = make_cleanup (xfree, xml);
btrace = parse_xml_btrace (xml);
do_cleanups (cleanup);
}
return btrace;
}
static void
init_remote_ops (void)
{
@ -11263,6 +11419,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_teardown_btrace = remote_teardown_btrace;
remote_ops.to_read_btrace = remote_read_btrace;
}
/* Set up the extended remote vector by making a copy of the standard
@ -11790,6 +11951,15 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_QTBuffer_size],
"QTBuffer:size", "trace-buffer-size", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_off],
"Qbtrace:off", "disable-btrace", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_bts],
"Qbtrace:bts", "enable-btrace", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace],
"qXfer:btrace", "read-btrace", 0);
/* Keep the old ``set remote Z-packet ...'' working. Each individual
Z sub-packet has its own set and show commands, but users may
have sets to this variable in their .gdbinit files (or in their

View file

@ -288,6 +288,8 @@ enum target_object
TARGET_OBJECT_DARWIN_DYLD_INFO,
/* OpenVMS Unwind Information Block. */
TARGET_OBJECT_OPENVMS_UIB,
/* Branch trace data, in XML format. */
TARGET_OBJECT_BTRACE
/* Possible future objects: TARGET_OBJECT_FILE, ... */
};