/* Tracepoint code for remote server for GDB.
- Copyright (C) 2009-2013 Free Software Foundation, Inc.
+ Copyright (C) 2009-2014 Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "server.h"
+#include "tracepoint.h"
#include "gdbthread.h"
#include "agent.h"
+#include "rsp-low.h"
#include <ctype.h>
#include <fcntl.h>
#include <stdint.h>
#include "ax.h"
+#include "tdesc.h"
+
+#define DEFAULT_TRACE_BUFFER_SIZE 5242880 /* 5*1024*1024 */
/* This file is built for both GDBserver, and the in-process
agent (IPA), a shared library that includes a tracing agent that is
*/
+#ifdef IN_PROCESS_AGENT
+
static void trace_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2);
static void
trace_vdebug ((fmt), ##args); \
} while (0)
+#else
+
+#define trace_debug_1(level, fmt, args...) \
+ do { \
+ if (level <= debug_threads) \
+ { \
+ debug_printf ((fmt), ##args); \
+ debug_printf ("\n"); \
+ } \
+ } while (0)
+
+#endif
+
#define trace_debug(FMT, args...) \
trace_debug_1 (1, FMT, ##args)
if (look_up_one_symbol (symbol_list[i].name, addrp, 1) == 0)
{
if (debug_threads)
- fprintf (stderr, "symbol `%s' not found\n", symbol_list[i].name);
+ debug_printf ("symbol `%s' not found\n", symbol_list[i].name);
return;
}
}
} ATTR_PACKED;
+/* The size of the EOB marker, in bytes. A traceframe with zeroed
+ fields (and no data) marks the end of trace data. */
+#define TRACEFRAME_EOB_MARKER_SIZE offsetof (struct traceframe, data)
+
/* The traceframe to be used as the source of data to send back to
GDB. A value of -1 means to get data from the live program. */
static int circular_trace_buffer;
#endif
+/* Size of the trace buffer. */
+
+static LONGEST trace_buffer_size;
+
/* Pointer to the block of memory that traceframes all go into. */
static unsigned char *trace_buffer_lo;
#endif
static void
-init_trace_buffer (unsigned char *buf, int bufsize)
+init_trace_buffer (LONGEST bufsize)
{
- trace_buffer_lo = buf;
- trace_buffer_hi = trace_buffer_lo + bufsize;
+ size_t alloc_size;
+
+ trace_buffer_size = bufsize;
+
+ /* Make sure to internally allocate at least space for the EOB
+ marker. */
+ alloc_size = (bufsize < TRACEFRAME_EOB_MARKER_SIZE
+ ? TRACEFRAME_EOB_MARKER_SIZE : bufsize);
+ trace_buffer_lo = xrealloc (trace_buffer_lo, alloc_size);
+
+ trace_buffer_hi = trace_buffer_lo + trace_buffer_size;
clear_trace_buffer ();
}
(long) amt, (long) sizeof (struct traceframe));
/* Account for the EOB marker. */
- amt += sizeof (struct traceframe);
+ amt += TRACEFRAME_EOB_MARKER_SIZE;
#ifdef IN_PROCESS_AGENT
again:
/* Make sure we don't try to read from a trace frame. */
current_traceframe = -1;
+ stop_tracing ();
+
trace_debug ("Initializing the trace");
clear_installed_tracepoints ();
packet = unpack_varlen_hex (packet, &slen);
++packet; /* skip a colon */
src = xmalloc (slen + 1);
- nbytes = unhexify (src, packet, strlen (packet) / 2);
+ nbytes = hex2bin (packet, (gdb_byte *) src, strlen (packet) / 2);
src[nbytes] = '\0';
newlast = xmalloc (sizeof (struct source_string));
nbytes = strlen (packet) / 2;
varname = xmalloc (nbytes + 1);
- nbytes = unhexify (varname, packet, nbytes);
+ nbytes = hex2bin (packet, (gdb_byte *) varname, nbytes);
varname[nbytes] = '\0';
tsv = create_trace_state_variable (num, 1);
cmd_qtv (char *own_buf)
{
ULONGEST num;
- LONGEST val;
+ LONGEST val = 0;
int err;
char *packet = own_buf;
str = (tracing_user_name ? tracing_user_name : "");
slen = strlen (str);
buf1 = (char *) alloca (slen * 2 + 1);
- hexify (buf1, str, slen);
+ bin2hex ((gdb_byte *) str, buf1, slen);
str = (tracing_notes ? tracing_notes : "");
slen = strlen (str);
buf2 = (char *) alloca (slen * 2 + 1);
- hexify (buf2, str, slen);
+ bin2hex ((gdb_byte *) str, buf2, slen);
str = (tracing_stop_note ? tracing_stop_note : "");
slen = strlen (str);
buf3 = (char *) alloca (slen * 2 + 1);
- hexify (buf3, str, slen);
+ bin2hex ((gdb_byte *) str, buf3, slen);
trace_debug ("Returning trace status as %d, stop reason %s",
tracing, tracing_stop_reason);
p = stop_reason_rsp = alloca (strlen ("terror:") + hexstr_len + 1);
strcpy (p, "terror:");
p += strlen (p);
- convert_int_to_ascii ((gdb_byte *) result_name, p, strlen (result_name));
+ bin2hex ((gdb_byte *) result_name, p, strlen (result_name));
}
/* If this was a forced stop, include any stop note that was supplied. */
"circular:%d;"
"disconn:%d;"
"starttime:%s;stoptime:%s;"
- "username:%s:;notes:%s:",
+ "username:%s;notes:%s:",
tracing ? 1 : 0,
stop_reason_rsp, tracing_stop_tpnum,
traceframe_count, traceframes_created,
free_space (), phex_nz (trace_buffer_hi - trace_buffer_lo, 0),
circular_trace_buffer,
disconnected_tracing,
- plongest (tracing_start_time), plongest (tracing_stop_time),
+ phex_nz (tracing_start_time, sizeof (tracing_start_time)),
+ phex_nz (tracing_stop_time, sizeof (tracing_stop_time)),
buf1, buf2);
}
/* State variables to help return all the tracepoint bits. */
static struct tracepoint *cur_tpoint;
-static int cur_action;
-static int cur_step_action;
+static unsigned int cur_action;
+static unsigned int cur_step_action;
static struct source_string *cur_source_string;
static struct trace_state_variable *cur_tsv;
len = strlen (src->str);
buf = alloca (len * 2 + 1);
- convert_int_to_ascii ((gdb_byte *) src->str, buf, len);
+ bin2hex ((gdb_byte *) src->str, buf, len);
sprintf (packet, "Z%x:%s:%s:%x:%x:%s",
tpoint->number, paddress (tpoint->address),
trace_debug ("Returning first tracepoint definition piece");
cur_tpoint = tracepoints;
- cur_action = cur_step_action = -1;
+ cur_action = cur_step_action = 0;
cur_source_string = NULL;
if (cur_tpoint)
GDB misbehavior. */
strcpy (packet, "l");
}
- else if (cur_action < cur_tpoint->numactions - 1)
+ else if (cur_action < cur_tpoint->numactions)
{
- ++cur_action;
response_action (packet, cur_tpoint,
cur_tpoint->actions_str[cur_action], 0);
+ ++cur_action;
}
- else if (cur_step_action < cur_tpoint->num_step_actions - 1)
+ else if (cur_step_action < cur_tpoint->num_step_actions)
{
- ++cur_step_action;
response_action (packet, cur_tpoint,
cur_tpoint->step_actions_str[cur_step_action], 1);
+ ++cur_step_action;
}
else if ((cur_source_string
? cur_source_string->next
else
{
cur_tpoint = cur_tpoint->next;
- cur_action = cur_step_action = -1;
+ cur_action = cur_step_action = 0;
cur_source_string = NULL;
if (cur_tpoint)
response_tracepoint (packet, cur_tpoint);
{
namelen = strlen (tsv->name);
buf = alloca (namelen * 2 + 1);
- convert_int_to_ascii ((gdb_byte *) tsv->name, buf, namelen);
+ bin2hex ((gdb_byte *) tsv->name, buf, namelen);
}
sprintf (packet, "%x:%s:%x:%s", tsv->number, phex_nz (tsv->initial_value, 0),
if (num >= (PBUFSIZ - 16) / 2 )
num = (PBUFSIZ - 16) / 2;
- convert_int_to_ascii (tbp, own_buf, num);
+ bin2hex (tbp, own_buf, num);
}
static void
write_ok (own_buf);
}
+static void
+cmd_bigqtbuffer_size (char *own_buf)
+{
+ ULONGEST val;
+ LONGEST sval;
+ char *packet = own_buf;
+
+ /* Can't change the size during a tracing run. */
+ if (tracing)
+ {
+ write_enn (own_buf);
+ return;
+ }
+
+ packet += strlen ("QTBuffer:size:");
+
+ /* -1 is sent as literal "-1". */
+ if (strcmp (packet, "-1") == 0)
+ sval = DEFAULT_TRACE_BUFFER_SIZE;
+ else
+ {
+ unpack_varlen_hex (packet, &val);
+ sval = (LONGEST) val;
+ }
+
+ init_trace_buffer (sval);
+ trace_debug ("Trace buffer is now %s bytes",
+ plongest (trace_buffer_size));
+ write_ok (own_buf);
+}
+
static void
cmd_qtnotes (char *own_buf)
{
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
user = xmalloc (nbytes + 1);
- nbytes = unhexify (user, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) user, nbytes);
user[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("User is '%s'", user);
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
notes = xmalloc (nbytes + 1);
- nbytes = unhexify (notes, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) notes, nbytes);
notes[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("Notes is '%s'", notes);
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
stopnote = xmalloc (nbytes + 1);
- nbytes = unhexify (stopnote, saved, nbytes);
+ nbytes = hex2bin (saved, (gdb_byte *) stopnote, nbytes);
stopnote[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("tstop note is '%s'", stopnote);
cmd_bigqtbuffer_circular (packet);
return 1;
}
+ else if (strncmp ("QTBuffer:size:", packet, strlen ("QTBuffer:size:")) == 0)
+ {
+ cmd_bigqtbuffer_size (packet);
+ return 1;
+ }
else if (strncmp ("QTNotes:", packet, strlen ("QTNotes:")) == 0)
{
cmd_qtnotes (packet);
#endif
+#ifdef IN_PROCESS_AGENT
+/* The target description used by the IPA. Given that the IPA library
+ is built for a specific architecture that is loaded into the
+ inferior, there only needs to be one such description per
+ build. */
+const struct target_desc *ipa_tdesc;
+#endif
+
static struct regcache *
get_context_regcache (struct tracepoint_hit_ctx *ctx)
{
if (!fctx->regcache_initted)
{
fctx->regcache_initted = 1;
- init_register_cache (&fctx->regcache, fctx->regspace);
+ init_register_cache (&fctx->regcache, ipa_tdesc, fctx->regspace);
supply_regblock (&fctx->regcache, NULL);
supply_fast_tracepoint_registers (&fctx->regcache, fctx->regs);
}
if (!sctx->regcache_initted)
{
sctx->regcache_initted = 1;
- init_register_cache (&sctx->regcache, sctx->regspace);
+ init_register_cache (&sctx->regcache, ipa_tdesc, sctx->regspace);
supply_regblock (&sctx->regcache, NULL);
/* Pass down the tracepoint address, because REGS doesn't
include the PC, but we know what it must have been. */
unsigned char *regspace;
struct regcache tregcache;
struct regcache *context_regcache;
-
+ int regcache_size;
trace_debug ("Want to collect registers");
+ context_regcache = get_context_regcache (ctx);
+ regcache_size = register_cache_size (context_regcache->tdesc);
+
/* Collect all registers for now. */
- regspace = add_traceframe_block (tframe, tpoint,
- 1 + register_cache_size ());
+ regspace = add_traceframe_block (tframe, tpoint, 1 + regcache_size);
if (regspace == NULL)
{
trace_debug ("Trace buffer block allocation failed, skipping");
/* Identify a register block. */
*regspace = 'R';
- context_regcache = get_context_regcache (ctx);
-
/* Wrap the regblock in a register cache (in the stack, we
don't want to malloc here). */
- init_register_cache (&tregcache, regspace + 1);
+ init_register_cache (&tregcache, context_regcache->tdesc,
+ regspace + 1);
/* Copy the register data to the regblock. */
regcache_cpy (&tregcache, context_regcache);
{
case 'R':
/* Skip over the registers block. */
- dataptr += register_cache_size ();
+ dataptr += current_target_desc ()->registers_size;
break;
case 'M':
/* Skip over the memory block. */
{
struct regcache regcache;
unsigned char *dataptr;
+ const struct target_desc *tdesc = current_target_desc ();
dataptr = traceframe_find_regblock (tframe, -1);
if (dataptr == NULL)
return 0;
- init_register_cache (®cache, dataptr);
+ init_register_cache (®cache, tdesc, dataptr);
return regcache_read_pc (®cache);
}
unsigned char *database, *dataptr;
unsigned int datasize;
int vnum;
+ int found = 0;
trace_debug ("traceframe_read_tsv");
datasize = tframe->data_size;
database = dataptr = &tframe->data[0];
- /* Iterate through a traceframe's blocks, looking for the tsv. */
+ /* Iterate through a traceframe's blocks, looking for the last
+ matched tsv. */
while ((dataptr = traceframe_find_block_type (dataptr,
datasize
- (dataptr - database),
if (tsvnum == vnum)
{
memcpy (val, dataptr, sizeof (*val));
- return 0;
+ found = 1;
}
/* Skip over this block. */
dataptr += sizeof (LONGEST);
}
- trace_debug ("traceframe %d has no data for variable %d",
- tfnum, tsvnum);
- return 1;
+ if (!found)
+ trace_debug ("traceframe %d has no data for variable %d",
+ tfnum, tsvnum);
+ return !found;
}
/* Read a requested block of static tracepoint data from a trace
break;
}
case 'V':
+ {
+ int vnum;
+
+ memcpy (&vnum, dataptr, sizeof (vnum));
+ buffer_xml_printf (buffer, "<tvar id=\"%d\"/>\n", vnum);
+ break;
+ }
case 'R':
case 'S':
{
ctx.regcache_initted = 0;
/* Wrap the regblock in a register cache (in the stack, we don't
want to malloc here). */
- ctx.regspace = alloca (register_cache_size ());
+ ctx.regspace = alloca (ipa_tdesc->registers_size);
if (ctx.regspace == NULL)
{
trace_debug ("Trace buffer block allocation failed, skipping");
if (ipa_action != 0)
write_inferior_data_ptr
- (actions_array + i * sizeof (sizeof (*tpoint->actions)),
+ (actions_array + i * sizeof (*tpoint->actions),
ipa_action);
}
}
/* Wrap the regblock in a register cache (in the stack, we don't
want to malloc here). */
- ctx.regspace = alloca (register_cache_size ());
+ ctx.regspace = alloca (ipa_tdesc->registers_size);
if (ctx.regspace == NULL)
{
trace_debug ("Trace buffer block allocation failed, skipping");
{
int len = strlen (str);
char *hexstr = xmalloc (len * 2 + 1);
- convert_int_to_ascii ((gdb_byte *) str, hexstr, len);
+ bin2hex ((gdb_byte *) str, hexstr, len);
return hexstr;
}
void
initialize_tracepoint (void)
{
- /* There currently no way to change the buffer size. */
- const int sizeOfBuffer = 5 * 1024 * 1024;
- unsigned char *buf = xmalloc (sizeOfBuffer);
- init_trace_buffer (buf, sizeOfBuffer);
+ /* Start with the default size. */
+ init_trace_buffer (DEFAULT_TRACE_BUFFER_SIZE);
/* Wire trace state variable 1 to be the timestamp. This will be
uploaded to GDB upon connection and become one of its trace state