#include "gdbthread.h"
#include "stack.h"
#include "gdbcore.h"
-
+#include "remote.h"
+#include "source.h"
#include "ax.h"
#include "ax-gdb.h"
tsv->initial_value = initval;
printf_filtered (_("Trace state variable $%s now has initial value %s.\n"),
tsv->name, plongest (tsv->initial_value));
+ do_cleanups (old_chain);
return;
}
void
delete_trace_variable_command (char *args, int from_tty)
{
- int i, ix;
+ int ix;
char **argv;
struct cleanup *back_to;
- struct trace_state_variable *tsv;
if (args == NULL)
{
argv = gdb_buildargv (args);
back_to = make_cleanup_freeargv (argv);
- for (i = 0; argv[i] != NULL; i++)
+ for (ix = 0; argv[ix] != NULL; ix++)
{
- if (*argv[i] == '$')
- delete_trace_state_variable (argv[i] + 1);
+ if (*argv[ix] == '$')
+ delete_trace_state_variable (argv[ix] + 1);
else
- warning (_("Name \"%s\" not prefixed with '$', ignoring"), argv[i]);
+ warning (_("Name \"%s\" not prefixed with '$', ignoring"), argv[ix]);
}
do_cleanups (back_to);
back_to2 = make_cleanup_ui_out_tuple_begin_end (uiout, "variable");
- name = concat ("$", tsv->name, NULL);
+ name = concat ("$", tsv->name, (char *) NULL);
make_cleanup (xfree, name);
ui_out_field_string (uiout, "name", name);
ui_out_field_string (uiout, "initial", plongest (tsv->initial_value));
internal errors. */
static void
-report_agent_reqs_errors (struct agent_expr *aexpr, struct agent_reqs *areqs)
+report_agent_reqs_errors (struct agent_expr *aexpr)
{
/* All of the "flaws" are serious bytecode generation issues that
should never occur. */
- if (areqs->flaw != agent_flaw_none)
+ if (aexpr->flaw != agent_flaw_none)
internal_error (__FILE__, __LINE__, _("expression is malformed"));
/* If analysis shows a stack underflow, GDB must have done something
badly wrong in its bytecode generation. */
- if (areqs->min_height < 0)
+ if (aexpr->min_height < 0)
internal_error (__FILE__, __LINE__,
_("expression has min height < 0"));
depth roughly corresponds to parenthesization, so a limit of 20
amounts to 20 levels of expression nesting, which is actually
a pretty big hairy expression. */
- if (areqs->max_height > 20)
+ if (aexpr->max_height > 20)
error (_("Expression is too complicated."));
}
char *p, *tmp_p;
struct bp_location *loc;
struct agent_expr *aexpr;
- struct agent_reqs areqs;
/* if EOF is typed, *line is NULL */
if (*line == NULL)
if (*p == '$') /* look for special pseudo-symbols */
{
- if ((0 == strncasecmp ("reg", p + 1, 3)) ||
- (0 == strncasecmp ("arg", p + 1, 3)) ||
- (0 == strncasecmp ("loc", p + 1, 3)))
+ if (0 == strncasecmp ("reg", p + 1, 3)
+ || 0 == strncasecmp ("arg", p + 1, 3)
+ || 0 == strncasecmp ("loc", p + 1, 3)
+ || 0 == strncasecmp ("_sdata", p + 1, 6))
{
p = strchr (p, ',');
continue;
if (aexpr->len > MAX_AGENT_EXPR_LEN)
error (_("Expression is too complicated."));
- ax_reqs (aexpr, &areqs);
- (void) make_cleanup (xfree, areqs.reg_mask);
+ ax_reqs (aexpr);
- report_agent_reqs_errors (aexpr, &areqs);
+ report_agent_reqs_errors (aexpr);
do_cleanups (old_chain);
}
if (aexpr->len > MAX_AGENT_EXPR_LEN)
error (_("Expression is too complicated."));
- ax_reqs (aexpr, &areqs);
- (void) make_cleanup (xfree, areqs.reg_mask);
-
- report_agent_reqs_errors (aexpr, &areqs);
+ ax_reqs (aexpr);
+ report_agent_reqs_errors (aexpr);
do_cleanups (old_chain);
}
long next_aexpr_elt;
struct agent_expr **aexpr_list;
+ /* True is the user requested a collection of "$_sdata", "static
+ tracepoint data". */
+ int strace_data;
}
tracepoint_list, stepping_list;
{
struct agent_expr *aexpr;
struct cleanup *old_chain1 = NULL;
- struct agent_reqs areqs;
aexpr = gen_trace_for_var (scope, gdbarch, sym);
old_chain1 = make_cleanup_free_agent_expr (aexpr);
- ax_reqs (aexpr, &areqs);
+ ax_reqs (aexpr);
- report_agent_reqs_errors (aexpr, &areqs);
+ report_agent_reqs_errors (aexpr);
discard_cleanups (old_chain1);
add_aexpr (collect, aexpr);
/* take care of the registers */
- if (areqs.reg_mask_len > 0)
+ if (aexpr->reg_mask_len > 0)
{
int ndx1, ndx2;
- for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
+ for (ndx1 = 0; ndx1 < aexpr->reg_mask_len; ndx1++)
{
QUIT; /* allow user to bail out with ^C */
- if (areqs.reg_mask[ndx1] != 0)
+ if (aexpr->reg_mask[ndx1] != 0)
{
/* assume chars have 8 bits */
for (ndx2 = 0; ndx2 < 8; ndx2++)
- if (areqs.reg_mask[ndx1] & (1 << ndx2))
+ if (aexpr->reg_mask[ndx1] & (1 << ndx2))
/* it's used -- record it */
add_register (collect, ndx1 * 8 + ndx2);
}
}
}
+static void
+add_static_trace_data (struct collection_list *collection)
+{
+ if (info_verbose)
+ printf_filtered ("collect static trace data\n");
+ collection->strace_data = 1;
+}
+
/* worker function */
static void
clear_collection_list (struct collection_list *list)
}
list->next_aexpr_elt = 0;
memset (list->regs_mask, 0, sizeof (list->regs_mask));
+ list->strace_data = 0;
}
/* reduce a collection list to string form (for gdb protocol) */
char *end;
long i;
- count = 1 + list->next_memrange + list->next_aexpr_elt + 1;
+ count = 1 + 1 + list->next_memrange + list->next_aexpr_elt + 1;
str_list = (char *(*)[]) xmalloc (count * sizeof (char *));
+ if (list->strace_data)
+ {
+ if (info_verbose)
+ printf_filtered ("\nCollecting static trace data\n");
+ end = temp_buf;
+ *end++ = 'L';
+ (*str_list)[ndx] = savestring (temp_buf, end - temp_buf);
+ ndx++;
+ }
+
for (i = sizeof (list->regs_mask) - 1; i > 0; i--)
if (list->regs_mask[i] != 0) /* skip leading zeroes in regs_mask */
break;
{
char *action_exp;
struct expression *exp = NULL;
- struct command_line *actions;
int i;
struct value *tempval;
struct cmd_list_element *cmd;
'L');
action_exp = strchr (action_exp, ','); /* more? */
}
+ else if (0 == strncasecmp ("$_sdata", action_exp, 7))
+ {
+ add_static_trace_data (collect);
+ action_exp = strchr (action_exp, ','); /* more? */
+ }
else
{
unsigned long addr, len;
struct cleanup *old_chain = NULL;
struct cleanup *old_chain1 = NULL;
- struct agent_reqs areqs;
exp = parse_exp_1 (&action_exp,
block_for_pc (tloc->address), 1);
old_chain1 = make_cleanup_free_agent_expr (aexpr);
- ax_reqs (aexpr, &areqs);
+ ax_reqs (aexpr);
- report_agent_reqs_errors (aexpr, &areqs);
+ report_agent_reqs_errors (aexpr);
discard_cleanups (old_chain1);
add_aexpr (collect, aexpr);
/* take care of the registers */
- if (areqs.reg_mask_len > 0)
+ if (aexpr->reg_mask_len > 0)
{
int ndx1;
int ndx2;
- for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
+ for (ndx1 = 0; ndx1 < aexpr->reg_mask_len; ndx1++)
{
QUIT; /* allow user to bail out with ^C */
- if (areqs.reg_mask[ndx1] != 0)
+ if (aexpr->reg_mask[ndx1] != 0)
{
/* assume chars have 8 bits */
for (ndx2 = 0; ndx2 < 8; ndx2++)
- if (areqs.reg_mask[ndx1] & (1 << ndx2))
+ if (aexpr->reg_mask[ndx1] & (1 << ndx2))
/* it's used -- record it */
add_register (collect,
ndx1 * 8 + ndx2);
action_exp++;
{
- unsigned long addr, len;
struct cleanup *old_chain = NULL;
struct cleanup *old_chain1 = NULL;
- struct agent_reqs areqs;
exp = parse_exp_1 (&action_exp,
block_for_pc (tloc->address), 1);
aexpr = gen_eval_for_expr (tloc->address, exp);
old_chain1 = make_cleanup_free_agent_expr (aexpr);
- ax_reqs (aexpr, &areqs);
-
- report_agent_reqs_errors (aexpr, &areqs);
+ ax_reqs (aexpr);
+ report_agent_reqs_errors (aexpr);
discard_cleanups (old_chain1);
/* Even though we're not officially collecting, add
here. */
gdb_assert (stepping_list);
- encode_actions_1 (action->body_list[0], t, tloc, frame_reg, frame_offset,
- stepping_list, NULL);
+ encode_actions_1 (action->body_list[0], t, tloc, frame_reg,
+ frame_offset, stepping_list, NULL);
}
else
error (_("Invalid tracepoint command '%s'"), action->line);
{
collect->aexpr_list =
xrealloc (collect->aexpr_list,
- 2 * collect->aexpr_listsize * sizeof (struct agent_expr *));
+ 2 * collect->aexpr_listsize * sizeof (struct agent_expr *));
collect->aexpr_listsize *= 2;
}
collect->aexpr_list[collect->next_aexpr_elt] = aexpr;
void
start_tracing (void)
{
- char buf[2048];
VEC(breakpoint_p) *tp_vec = NULL;
int ix;
struct breakpoint *t;
struct trace_state_variable *tsv;
- int any_enabled = 0;
+ int any_enabled = 0, num_to_download = 0;
tp_vec = all_tracepoints ();
for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
{
if (t->enable_state == bp_enabled)
- {
- any_enabled = 1;
- break;
- }
+ any_enabled = 1;
+
+ if ((t->type == bp_fast_tracepoint
+ ? may_insert_fast_tracepoints
+ : may_insert_tracepoints))
+ ++num_to_download;
+ else
+ warning (_("May not insert %stracepoints, skipping tracepoint %d"),
+ (t->type == bp_fast_tracepoint ? "fast " : ""), t->number);
}
/* No point in tracing with only disabled tracepoints. */
error (_("No tracepoints enabled, not starting trace"));
}
+ if (num_to_download <= 0)
+ {
+ VEC_free (breakpoint_p, tp_vec);
+ error (_("No tracepoints that may be downloaded, not starting trace"));
+ }
+
target_trace_init ();
for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
{
+ if ((t->type == bp_fast_tracepoint
+ ? !may_insert_fast_tracepoints
+ : !may_insert_tracepoints))
+ continue;
+
t->number_on_target = 0;
target_download_tracepoint (t);
t->number_on_target = t->number;
{
struct trace_status *ts = current_trace_status ();
int status;
- char *string_status;
status = target_get_trace_status (ts);
if (ts->traceframe_count != -1)
ui_out_field_int (uiout, "frames", ts->traceframe_count);
+ if (ts->traceframes_created != -1)
+ ui_out_field_int (uiout, "frames-created", ts->traceframes_created);
if (ts->buffer_size != -1)
ui_out_field_int (uiout, "buffer-size", ts->buffer_size);
if (ts->buffer_free != -1)
int from_tty)
{
int target_frameno = -1, target_tracept = -1;
- struct frame_id old_frame_id;
- char *reply;
+ struct frame_id old_frame_id = null_frame_id;
struct breakpoint *tp;
- old_frame_id = get_frame_id (get_current_frame ());
+ /* Only try to get the current stack frame if we have a chance of
+ succeeding. In particular, if we're trying to get a first trace
+ frame while all threads are running, it's not going to succeed,
+ so leave it with a default value and let the frame comparison
+ below (correctly) decide to print out the source location of the
+ trace frame. */
+ if (!(type == tfind_number && num == -1)
+ && (has_stack_frames () || traceframe_number >= 0))
+ old_frame_id = get_frame_id (get_current_frame ());
target_frameno = target_trace_find (type, num, addr1, addr2,
&target_tracept);
}
else if (target_frameno == -1)
{
- /* A request for a non-existant trace frame has failed.
+ /* A request for a non-existent trace frame has failed.
Our response will be different, depending on FROM_TTY:
If FROM_TTY is true, meaning that this command was
{
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "found", "0");
- else
- printf_unfiltered (_("No trace frame found"));
+ else if (type == tfind_number && num == -1)
+ printf_unfiltered (_("No longer looking at any trace frame\n"));
+ else /* this case may never occur, check */
+ printf_unfiltered (_("No trace frame found\n"));
}
/* If we're in nonstop mode and getting out of looking at trace
{
enum print_what print_what;
- /* NOTE: in immitation of the step command, try to determine
+ /* NOTE: in imitation of the step command, try to determine
whether we have made a transition from one function to
another. If so, we'll print the "stack frame" (ie. the new
function and it's arguments) -- otherwise we'll just show the
trace_find_pc_command (char *args, int from_tty)
{
CORE_ADDR pc;
- char tmp[40];
if (current_trace_status ()->running && !current_trace_status ()->from_file)
error ("May not look at trace frames while trace is running.");
struct symtabs_and_lines sals;
struct symtab_and_line sal;
struct cleanup *old_chain;
- char startpc_str[40], endpc_str[40];
if (current_trace_status ()->running && !current_trace_status ()->from_file)
error ("May not look at trace frames while trace is running.");
trace_find_range_command (char *args, int from_tty)
{
static CORE_ADDR start, stop;
- char start_str[40], stop_str[40];
char *tmp;
if (current_trace_status ()->running && !current_trace_status ()->from_file)
trace_find_outside_command (char *args, int from_tty)
{
CORE_ADDR start, stop;
- char start_str[40], stop_str[40];
char *tmp;
if (current_trace_status ()->running && !current_trace_status ()->from_file)
printf_filtered ("optimized out.\n");
continue;
case LOC_COMPUTED:
- SYMBOL_COMPUTED_OPS (sym)->describe_location (sym, gdb_stdout);
+ SYMBOL_COMPUTED_OPS (sym)->describe_location (sym,
+ BLOCK_START (block),
+ gdb_stdout);
break;
}
if (SYMBOL_TYPE (sym))
pathname = tilde_expand (filename);
cleanup = make_cleanup (xfree, pathname);
- fp = fopen (pathname, "w");
+ fp = fopen (pathname, "wb");
if (!fp)
error (_("Unable to open file '%s' for saving trace data (%s)"),
filename, safe_strerror (errno));
if (ts->stop_reason == tracepoint_error)
{
char *buf = (char *) alloca (strlen (ts->error_desc) * 2 + 1);
+
bin2hex ((gdb_byte *) ts->error_desc, buf, 0);
fprintf (fp, ":%s", buf);
}
filename = tilde_expand (filename);
if (!IS_ABSOLUTE_PATH(filename))
{
- temp = concat (current_directory, "/", filename, (char *)NULL);
+ temp = concat (current_directory, "/", filename, (char *) NULL);
xfree (filename);
filename = temp;
}
/* Parse the part of trace status syntax that is shared between
the remote protocol and the trace file reader. */
-extern char *unpack_varlen_hex (char *buff, ULONGEST *result);
-
void
parse_trace_status (char *line, struct trace_status *ts)
{
char *p;
char piece;
ULONGEST num, addr, step, pass, orig_size, xlen, start;
- int enabled, i, end;
+ int enabled, end;
enum bptype type;
- char *cond, *srctype, *src, *buf;
+ char *cond, *srctype, *buf;
struct uploaded_tp *utp = NULL;
p = line;
p++;
p = unpack_varlen_hex (p, &orig_size);
}
+ else if (*p == 'S')
+ {
+ type = bp_static_tracepoint;
+ p++;
+ }
else if (*p == 'X')
{
p++;
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
char block_type;
- int i, pos, offset, regn, regsize, gotten, pc_regno;
+ int pos, offset, regn, regsize, gotten, pc_regno;
unsigned short mlen;
char *regs;
if (amt > len)
amt = len;
- read (trace_fd, readbuf, amt);
+ gotten = read (trace_fd, readbuf, amt);
+ if (gotten < 0)
+ perror_with_name (trace_filename);
+ /* While it's acceptable to return less than was
+ originally asked for, it's not acceptable to return
+ less than what this block claims to contain. */
+ else if (gotten < amt)
+ error (_("Premature end of file while reading trace file"));
return amt;
}
lseek (trace_fd, mlen, SEEK_CUR);
tfile_ops.to_get_trace_status = tfile_get_trace_status;
tfile_ops.to_trace_find = tfile_trace_find;
tfile_ops.to_get_trace_state_variable_value = tfile_get_trace_state_variable_value;
- /* core_stratum might seem more logical, but GDB doesn't like having
- more than one core_stratum vector. */
tfile_ops.to_stratum = process_stratum;
tfile_ops.to_has_all_memory = tfile_has_all_memory;
tfile_ops.to_has_memory = tfile_has_memory;
tfile_ops.to_magic = OPS_MAGIC;
}
+/* Given a line of text defining a static tracepoint marker, parse it
+ into a "static tracepoint marker" object. Throws an error is
+ parsing fails. If PP is non-null, it points to one past the end of
+ the parsed marker definition. */
+
+void
+parse_static_tracepoint_marker_definition (char *line, char **pp,
+ struct static_tracepoint_marker *marker)
+{
+ char *p, *endp;
+ ULONGEST addr;
+ int end;
+
+ p = line;
+ p = unpack_varlen_hex (p, &addr);
+ p++; /* skip a colon */
+
+ marker->gdbarch = target_gdbarch;
+ marker->address = (CORE_ADDR) addr;
+
+ endp = strchr (p, ':');
+ if (endp == NULL)
+ error (_("bad marker definition: %s"), line);
+
+ marker->str_id = xmalloc (endp - p + 1);
+ end = hex2bin (p, (gdb_byte *) marker->str_id, (endp - p + 1) / 2);
+ marker->str_id[end] = '\0';
+
+ p += 2 * end;
+ p++; /* skip a colon */
+
+ marker->extra = xmalloc (strlen (p) + 1);
+ end = hex2bin (p, (gdb_byte *) marker->extra, strlen (p) / 2);
+ marker->extra[end] = '\0';
+
+ if (pp)
+ *pp = p;
+}
+
+/* Release a static tracepoint marker's contents. Note that the
+ object itself isn't released here. There objects are usually on
+ the stack. */
+
+void
+release_static_tracepoint_marker (struct static_tracepoint_marker *marker)
+{
+ xfree (marker->str_id);
+ marker->str_id = NULL;
+}
+
+/* Print MARKER to gdb_stdout. */
+
+static void
+print_one_static_tracepoint_marker (int count,
+ struct static_tracepoint_marker *marker)
+{
+ struct command_line *l;
+ struct symbol *sym;
+
+ char wrap_indent[80];
+ char extra_field_indent[80];
+ struct ui_stream *stb = ui_out_stream_new (uiout);
+ struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb);
+ struct cleanup *bkpt_chain;
+ VEC(breakpoint_p) *tracepoints;
+
+ struct symtab_and_line sal;
+
+ init_sal (&sal);
+
+ sal.pc = marker->address;
+
+ tracepoints = static_tracepoints_here (marker->address);
+
+ bkpt_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "marker");
+
+ /* A counter field to help readability. This is not a stable
+ identifier! */
+ ui_out_field_int (uiout, "count", count);
+
+ ui_out_field_string (uiout, "marker-id", marker->str_id);
+
+ ui_out_field_fmt (uiout, "enabled", "%c",
+ !VEC_empty (breakpoint_p, tracepoints) ? 'y' : 'n');
+ ui_out_spaces (uiout, 2);
+
+ strcpy (wrap_indent, " ");
+
+ if (gdbarch_addr_bit (marker->gdbarch) <= 32)
+ strcat (wrap_indent, " ");
+ else
+ strcat (wrap_indent, " ");
+
+ strcpy (extra_field_indent, " ");
+
+ ui_out_field_core_addr (uiout, "addr", marker->gdbarch, marker->address);
+
+ sal = find_pc_line (marker->address, 0);
+ sym = find_pc_sect_function (marker->address, NULL);
+ if (sym)
+ {
+ ui_out_text (uiout, "in ");
+ ui_out_field_string (uiout, "func",
+ SYMBOL_PRINT_NAME (sym));
+ ui_out_wrap_hint (uiout, wrap_indent);
+ ui_out_text (uiout, " at ");
+ }
+ else
+ ui_out_field_skip (uiout, "func");
+
+ if (sal.symtab != NULL)
+ {
+ ui_out_field_string (uiout, "file", sal.symtab->filename);
+ ui_out_text (uiout, ":");
+
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ char *fullname = symtab_to_fullname (sal.symtab);
+
+ if (fullname)
+ ui_out_field_string (uiout, "fullname", fullname);
+ }
+ else
+ ui_out_field_skip (uiout, "fullname");
+
+ ui_out_field_int (uiout, "line", sal.line);
+ }
+ else
+ {
+ ui_out_field_skip (uiout, "fullname");
+ ui_out_field_skip (uiout, "line");
+ }
+
+ ui_out_text (uiout, "\n");
+ ui_out_text (uiout, extra_field_indent);
+ ui_out_text (uiout, _("Data: \""));
+ ui_out_field_string (uiout, "extra-data", marker->extra);
+ ui_out_text (uiout, "\"\n");
+
+ if (!VEC_empty (breakpoint_p, tracepoints))
+ {
+ struct cleanup *cleanup_chain;
+ int ix;
+ struct breakpoint *b;
+
+ cleanup_chain = make_cleanup_ui_out_tuple_begin_end (uiout,
+ "tracepoints-at");
+
+ ui_out_text (uiout, extra_field_indent);
+ ui_out_text (uiout, _("Probed by static tracepoints: "));
+ for (ix = 0; VEC_iterate(breakpoint_p, tracepoints, ix, b); ix++)
+ {
+ if (ix > 0)
+ ui_out_text (uiout, ", ");
+ ui_out_text (uiout, "#");
+ ui_out_field_int (uiout, "tracepoint-id", b->number);
+ }
+
+ do_cleanups (cleanup_chain);
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_int (uiout, "number-of-tracepoints",
+ VEC_length(breakpoint_p, tracepoints));
+ else
+ ui_out_text (uiout, "\n");
+ }
+ VEC_free (breakpoint_p, tracepoints);
+
+ do_cleanups (bkpt_chain);
+ do_cleanups (old_chain);
+}
+
+static void
+info_static_tracepoint_markers_command (char *arg, int from_tty)
+{
+ VEC(static_tracepoint_marker_p) *markers;
+ struct cleanup *old_chain;
+ struct static_tracepoint_marker *marker;
+ int i;
+
+ old_chain
+ = make_cleanup_ui_out_table_begin_end (uiout, 5, -1,
+ "StaticTracepointMarkersTable");
+
+ ui_out_table_header (uiout, 7, ui_left, "counter", "Cnt");
+
+ ui_out_table_header (uiout, 40, ui_left, "marker-id", "ID");
+
+ ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb");
+ if (gdbarch_addr_bit (target_gdbarch) <= 32)
+ ui_out_table_header (uiout, 10, ui_left, "addr", "Address");
+ else
+ ui_out_table_header (uiout, 18, ui_left, "addr", "Address");
+ ui_out_table_header (uiout, 40, ui_noalign, "what", "What");
+
+ ui_out_table_body (uiout);
+
+ markers = target_static_tracepoint_markers_by_strid (NULL);
+ make_cleanup (VEC_cleanup (static_tracepoint_marker_p), &markers);
+
+ for (i = 0;
+ VEC_iterate (static_tracepoint_marker_p,
+ markers, i, marker);
+ i++)
+ {
+ print_one_static_tracepoint_marker (i + 1, marker);
+ release_static_tracepoint_marker (marker);
+ }
+
+ do_cleanups (old_chain);
+}
+
+/* The $_sdata convenience variable is a bit special. We don't know
+ for sure type of the value until we actually have a chance to fetch
+ the data --- the size of the object depends on what has been
+ collected. We solve this by making $_sdata be an internalvar that
+ creates a new value on access. */
+
+/* Return a new value with the correct type for the sdata object of
+ the current trace frame. Return a void value if there's no object
+ available. */
+
+static struct value *
+sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+{
+ LONGEST size;
+ gdb_byte *buf;
+
+ /* We need to read the whole object before we know its size. */
+ size = target_read_alloc (¤t_target,
+ TARGET_OBJECT_STATIC_TRACE_DATA,
+ NULL, &buf);
+ if (size >= 0)
+ {
+ struct value *v;
+ struct type *type;
+
+ type = init_vector_type (builtin_type (gdbarch)->builtin_true_char,
+ size);
+ v = allocate_value (type);
+ memcpy (value_contents_raw (v), buf, size);
+ xfree (buf);
+ return v;
+ }
+ else
+ return allocate_value (builtin_type (gdbarch)->builtin_void);
+}
+
/* module initialization */
void
_initialize_tracepoint (void)
{
struct cmd_list_element *c;
+ /* Explicitly create without lookup, since that tries to create a
+ value with a void typed value, and when we get here, gdbarch
+ isn't initialized yet. At this point, we're quite sure there
+ isn't another convenience variable of the same name. */
+ create_internalvar_type_lazy ("_sdata", sdata_make_value);
+
traceframe_number = -1;
tracepoint_number = -1;
add_info ("tvariables", tvariables_info, _("\
Status of trace state variables and their values.\n\
+"));
+
+ add_info ("static-tracepoint-markers",
+ info_static_tracepoint_markers_command, _("\
+List target static tracepoints markers.\n\
"));
add_prefix_cmd ("tfind", class_trace, trace_find_command, _("\
add_cmd ("line", class_trace, trace_find_line_command, _("\
Select a trace frame by source line.\n\
-Argument can be a line number (with optional source file), \n\
+Argument can be a line number (with optional source file),\n\
a function name, or '*' followed by an address.\n\
Default argument is 'the next source line that was traced'."),
&tfindlist);
$regs -- all registers.\n\
$args -- all function arguments.\n\
$locals -- all variables local to the block/function scope.\n\
+ $_sdata -- static tracepoint data (ignored for non-static tracepoints).\n\
Note: this command can only be used in a tracepoint \"actions\" list."));
add_com ("teval", class_trace, teval_pseudocommand, _("\
add_com ("actions", class_trace, trace_actions_command, _("\
Specify the actions to be taken at a tracepoint.\n\
-Tracepoint actions may include collecting of specified data, \n\
-single-stepping, or enabling/disabling other tracepoints, \n\
+Tracepoint actions may include collecting of specified data,\n\
+single-stepping, or enabling/disabling other tracepoints,\n\
depending on target's capabilities."));
default_collect = xstrdup ("");