/* Tracing functionality for remote targets in custom GDB protocol
- Copyright (C) 1997-2020 Free Software Foundation, Inc.
+ Copyright (C) 1997-2022 Free Software Foundation, Inc.
This file is part of GDB.
#include "location.h"
#include <algorithm>
#include "cli/cli-style.h"
+#include "expop.h"
+#include "gdbsupport/buildargv.h"
#include <unistd.h>
static struct cmd_list_element *tfindlist;
/* List of expressions to collect by default at each tracepoint hit. */
-char *default_collect;
+std::string default_collect;
static bool disconnected_tracing;
/* Textual notes applying to the current and/or future trace runs. */
-char *trace_user = NULL;
+static std::string trace_user;
/* Textual notes applying to the current and/or future trace runs. */
-char *trace_notes = NULL;
+static std::string trace_notes;
/* Textual notes applying to the stopping of a trace. */
-char *trace_stop_notes = NULL;
+static std::string trace_stop_notes;
/* support routines */
struct cmd_list_element *c;
const char *tmp_p;
const char *p;
- struct bp_location *loc;
struct tracepoint *t = (struct tracepoint *) b;
/* If EOF is typed, *line is NULL. */
if (*p == '#') /* comment line */
return;
- c = lookup_cmd (&p, cmdlist, "", -1, 1);
+ c = lookup_cmd (&p, cmdlist, "", NULL, -1, 1);
if (c == 0)
error (_("`%s' is not a tracepoint action, or is ambiguous."), p);
- if (cmd_cfunc_eq (c, collect_pseudocommand))
+ if (cmd_simple_func_eq (c, collect_pseudocommand))
{
int trace_string = 0;
/* else fall thru, treat p as an expression and parse it! */
}
tmp_p = p;
- for (loc = t->loc; loc; loc = loc->next)
+ for (bp_location *loc : t->locations ())
{
p = tmp_p;
expression_up exp = parse_exp_1 (&p, loc->address,
block_for_pc (loc->address), 1);
- if (exp->elts[0].opcode == OP_VAR_VALUE)
+ if (exp->first_opcode () == OP_VAR_VALUE)
{
- if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
+ symbol *sym;
+ expr::var_value_operation *vvop
+ = (dynamic_cast<expr::var_value_operation *>
+ (exp->op.get ()));
+ sym = vvop->get_symbol ();
+
+ if (SYMBOL_CLASS (sym) == LOC_CONST)
{
error (_("constant `%s' (value %s) "
"will not be collected."),
- exp->elts[2].symbol->print_name (),
- plongest (SYMBOL_VALUE (exp->elts[2].symbol)));
+ sym->print_name (),
+ plongest (SYMBOL_VALUE (sym)));
}
- else if (SYMBOL_CLASS (exp->elts[2].symbol)
- == LOC_OPTIMIZED_OUT)
+ else if (SYMBOL_CLASS (sym) == LOC_OPTIMIZED_OUT)
{
error (_("`%s' is optimized away "
"and cannot be collected."),
- exp->elts[2].symbol->print_name ());
+ sym->print_name ());
}
}
while (p && *p++ == ',');
}
- else if (cmd_cfunc_eq (c, teval_pseudocommand))
+ else if (cmd_simple_func_eq (c, teval_pseudocommand))
{
do
{ /* Repeat over a comma-separated list. */
p = skip_spaces (p);
tmp_p = p;
- for (loc = t->loc; loc; loc = loc->next)
+ for (bp_location *loc : t->locations ())
{
p = tmp_p;
while (p && *p++ == ',');
}
- else if (cmd_cfunc_eq (c, while_stepping_pseudocommand))
+ else if (cmd_simple_func_eq (c, while_stepping_pseudocommand))
{
char *endp;
p = endp;
}
- else if (cmd_cfunc_eq (c, end_actions_pseudocommand))
+ else if (cmd_simple_func_eq (c, end_actions_pseudocommand))
;
else
}
{
- bfd_signed_vma length
+ bfd_signed_vma length
= m_memranges[i].end - m_memranges[i].start;
- /* The "%X" conversion specifier expects an unsigned argument,
- so passing -1 (memrange_absolute) to it directly gives you
- "FFFFFFFF" (or more, depending on sizeof (unsigned)).
- Special-case it. */
- if (m_memranges[i].type == memrange_absolute)
- sprintf (end, "M-1,%s,%lX", phex_nz (m_memranges[i].start, 0),
+ /* The "%X" conversion specifier expects an unsigned argument,
+ so passing -1 (memrange_absolute) to it directly gives you
+ "FFFFFFFF" (or more, depending on sizeof (unsigned)).
+ Special-case it. */
+ if (m_memranges[i].type == memrange_absolute)
+ sprintf (end, "M-1,%s,%lX", phex_nz (m_memranges[i].start, 0),
(long) length);
- else
- sprintf (end, "M%X,%s,%lX", m_memranges[i].type,
+ else
+ sprintf (end, "M%X,%s,%lX", m_memranges[i].type,
phex_nz (m_memranges[i].start, 0), (long) length);
}
return str_list;
}
-/* Add the printed expression EXP to *LIST. */
+/* Add the expression STR to M_COMPUTED. */
void
-collection_list::append_exp (struct expression *exp)
+collection_list::append_exp (std::string &&str)
{
- string_file tmp_stream;
-
- print_expression (exp, &tmp_stream);
-
- m_computed.push_back (std::move (tmp_stream.string ()));
+ m_computed.push_back (std::move (str));
}
void
action_exp = action->line;
action_exp = skip_spaces (action_exp);
- cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
+ cmd = lookup_cmd (&action_exp, cmdlist, "", NULL, -1, 1);
if (cmd == 0)
error (_("Bad action list item: %s"), action_exp);
- if (cmd_cfunc_eq (cmd, collect_pseudocommand))
+ if (cmd_simple_func_eq (cmd, collect_pseudocommand))
{
int trace_string = 0;
{
unsigned long addr;
+ const char *exp_start = action_exp;
expression_up exp = parse_exp_1 (&action_exp, tloc->address,
block_for_pc (tloc->address),
1);
- switch (exp->elts[0].opcode)
+ switch (exp->first_opcode ())
{
case OP_REGISTER:
{
- const char *name = &exp->elts[2].string;
+ expr::register_operation *regop
+ = (dynamic_cast<expr::register_operation *>
+ (exp->op.get ()));
+ const char *name = regop->get_name ();
i = user_reg_map_name_to_regnum (target_gdbarch (),
name, strlen (name));
}
case UNOP_MEMVAL:
- /* Safe because we know it's a simple expression. */
- tempval = evaluate_expression (exp.get ());
- addr = value_address (tempval);
- /* Initialize the TYPE_LENGTH if it is a typedef. */
- check_typedef (exp->elts[1].type);
- collect->add_memrange (target_gdbarch (),
- memrange_absolute, addr,
- TYPE_LENGTH (exp->elts[1].type),
- tloc->address);
- collect->append_exp (exp.get ());
+ {
+ /* Safe because we know it's a simple expression. */
+ tempval = evaluate_expression (exp.get ());
+ addr = value_address (tempval);
+ expr::unop_memval_operation *memop
+ = (dynamic_cast<expr::unop_memval_operation *>
+ (exp->op.get ()));
+ struct type *type = memop->get_type ();
+ /* Initialize the TYPE_LENGTH if it is a typedef. */
+ check_typedef (type);
+ collect->add_memrange (target_gdbarch (),
+ memrange_absolute, addr,
+ TYPE_LENGTH (type),
+ tloc->address);
+ collect->append_exp (std::string (exp_start,
+ action_exp));
+ }
break;
case OP_VAR_VALUE:
{
- struct symbol *sym = exp->elts[2].symbol;
+ expr::var_value_operation *vvo
+ = (dynamic_cast<expr::var_value_operation *>
+ (exp->op.get ()));
+ struct symbol *sym = vvo->get_symbol ();
const char *name = sym->natural_name ();
- collect->collect_symbol (exp->elts[2].symbol,
+ collect->collect_symbol (sym,
target_gdbarch (),
frame_reg,
frame_offset,
collect->add_ax_registers (aexpr.get ());
collect->add_aexpr (std::move (aexpr));
- collect->append_exp (exp.get ());
+ collect->append_exp (std::string (exp_start,
+ action_exp));
break;
} /* switch */
} /* do */
}
while (action_exp && *action_exp++ == ',');
} /* if */
- else if (cmd_cfunc_eq (cmd, teval_pseudocommand))
+ else if (cmd_simple_func_eq (cmd, teval_pseudocommand))
{
do
{ /* Repeat over a comma-separated list. */
}
while (action_exp && *action_exp++ == ',');
} /* if */
- else if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
+ else if (cmd_simple_func_eq (cmd, while_stepping_pseudocommand))
{
/* We check against nested while-stepping when setting
breakpoint action, so no way to run into nested
}
else
{
- struct bp_location *loc1;
-
- for (loc1 = b->loc; loc1; loc1 = loc1->next)
+ for (bp_location *loc1 : b->locations ())
{
if (loc1->shlib_disabled)
{
int any_enabled = 0, num_to_download = 0;
int ret;
- std::vector<breakpoint *> tp_vec = all_tracepoints ();
+ auto tracepoint_range = all_tracepoints ();
/* No point in tracing without any tracepoints... */
- if (tp_vec.empty ())
+ if (tracepoint_range.begin () == tracepoint_range.end ())
error (_("No tracepoints defined, not starting trace"));
- for (breakpoint *b : tp_vec)
+ for (breakpoint *b : tracepoint_range)
{
if (b->enable_state == bp_enabled)
any_enabled = 1;
target_trace_init ();
- for (breakpoint *b : tp_vec)
+ for (breakpoint *b : tracepoint_range)
{
struct tracepoint *t = (struct tracepoint *) b;
- struct bp_location *loc;
int bp_location_downloaded = 0;
/* Clear `inserted' flag. */
- for (loc = b->loc; loc; loc = loc->next)
+ for (bp_location *loc : b->locations ())
loc->inserted = 0;
if ((b->type == bp_fast_tracepoint
t->number_on_target = 0;
- for (loc = b->loc; loc; loc = loc->next)
+ for (bp_location *loc : b->locations ())
{
/* Since tracepoint locations are never duplicated, `inserted'
flag should be zero. */
t->number_on_target = b->number;
- for (loc = b->loc; loc; loc = loc->next)
+ for (bp_location *loc : b->locations ())
if (loc->probe.prob != NULL)
loc->probe.prob->set_semaphore (loc->probe.objfile,
loc->gdbarch);
target_set_trace_buffer_size (trace_buffer_size);
if (!notes)
- notes = trace_notes;
- ret = target_set_trace_notes (trace_user, notes, NULL);
+ notes = trace_notes.c_str ();
+
+ ret = target_set_trace_notes (trace_user.c_str (), notes, NULL);
- if (!ret && (trace_user || notes))
+ if (!ret && (!trace_user.empty () || notes))
warning (_("Target does not support trace user/notes, info ignored"));
/* Now insert traps and begin collecting data. */
for (breakpoint *t : all_tracepoints ())
{
- struct bp_location *loc;
-
if ((t->type == bp_fast_tracepoint
? !may_insert_fast_tracepoints
: !may_insert_tracepoints))
continue;
- for (loc = t->loc; loc; loc = loc->next)
+ for (bp_location *loc : t->locations ())
{
/* GDB can be totally absent in some disconnected trace scenarios,
but we don't really care if this semaphore goes out of sync.
}
if (!note)
- note = trace_stop_notes;
+ note = trace_stop_notes.c_str ();
+
ret = target_set_trace_notes (NULL, NULL, note);
if (!ret && note)
}
else
{
- printf_unfiltered (_("Found trace frame %d, tracepoint %d\n"),
- traceframe_number, tracepoint_number);
+ printf_filtered (_("Found trace frame %d, tracepoint %d\n"),
+ traceframe_number, tracepoint_number);
}
}
else
if (uiout->is_mi_like_p ())
uiout->field_string ("found", "0");
else if (type == tfind_number && num == -1)
- printf_unfiltered (_("No longer looking at any trace frame\n"));
+ printf_filtered (_("No longer looking at any trace frame\n"));
else /* This case may never occur, check. */
- printf_unfiltered (_("No trace frame found\n"));
+ printf_filtered (_("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 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
- new source line. */
+ 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
+ new source line. */
if (frame_id_eq (old_frame_id,
get_frame_id (get_current_frame ())))
{ /* TFIND with no args means find NEXT trace frame. */
if (traceframe_number == -1)
frameno = 0; /* "next" is first one. */
- else
+ else
frameno = traceframe_number + 1;
}
else if (0 == strcmp (args, "-"))
if (sal.line > 0 && find_line_pc_range (sal, &start_pc, &end_pc))
{
if (start_pc == end_pc)
- {
+ {
printf_filtered ("Line %d of \"%s\"",
sal.line,
symtab_to_filename_for_display (sal.symtab));
&& start_pc != end_pc)
printf_filtered ("Attempting to find line %d instead.\n",
sal.line);
- else
+ else
error (_("Cannot find a good line."));
- }
+ }
}
else
- /* Is there any case in which we get here, and have an address
- which the user would want to see? If we have debugging
- symbols and no line numbers? */
- error (_("Line number %d is out of range for \"%s\"."),
- sal.line, symtab_to_filename_for_display (sal.symtab));
+ {
+ /* Is there any case in which we get here, and have an address
+ which the user would want to see? If we have debugging
+ symbols and no line numbers? */
+ error (_("Line number %d is out of range for \"%s\"."),
+ sal.line, symtab_to_filename_for_display (sal.symtab));
+ }
/* Find within range of stated line. */
if (args && *args)
printf_filtered ("optimized out.\n");
continue;
case LOC_COMPUTED:
- gdb_assert_not_reached (_("LOC_COMPUTED variable missing a method"));
+ gdb_assert_not_reached ("LOC_COMPUTED variable missing a method");
}
}
if (SYMBOL_TYPE (sym))
action_exp = skip_spaces (action_exp);
/* The collection actions to be done while stepping are
- bracketed by the commands "while-stepping" and "end". */
+ bracketed by the commands "while-stepping" and "end". */
if (*action_exp == '#') /* comment line */
continue;
- cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
+ cmd = lookup_cmd (&action_exp, cmdlist, "", NULL, -1, 1);
if (cmd == 0)
error (_("Bad action list item: %s"), action_exp);
- if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
+ if (cmd_simple_func_eq (cmd, while_stepping_pseudocommand))
{
gdb_assert (action->body_list_1 == nullptr);
trace_dump_actions (action->body_list_0.get (),
1, stepping_frame, from_tty);
}
- else if (cmd_cfunc_eq (cmd, collect_pseudocommand))
+ else if (cmd_simple_func_eq (cmd, collect_pseudocommand))
{
/* Display the collected data.
For the trap frame, display only what was collected at
get_traceframe_location (int *stepping_frame_p)
{
struct tracepoint *t;
- struct bp_location *tloc;
struct regcache *regcache;
if (tracepoint_number == -1)
locations, assume it is a direct hit rather than a while-stepping
frame. (FIXME this is not reliable, should record each frame's
type.) */
- for (tloc = t->loc; tloc; tloc = tloc->next)
+ for (bp_location *tloc : t->locations ())
if (tloc->address == regcache_read_pc (regcache))
{
*stepping_frame_p = 0;
validation is per-tracepoint (local var "xyz" might be valid for
one tracepoint and not another, etc), we make up the action on
the fly, and don't cache it. */
- if (*default_collect)
+ if (!default_collect.empty ())
{
gdb::unique_xmalloc_ptr<char> default_collect_line
- (xstrprintf ("collect %s", default_collect));
+ = xstrprintf ("collect %s", default_collect.c_str ());
validate_actionline (default_collect_line.get (), t);
actions.reset (new struct command_line (simple_control,
{
int ret;
- ret = target_set_trace_notes (trace_user, NULL, NULL);
+ ret = target_set_trace_notes (trace_user.c_str (), NULL, NULL);
if (!ret)
warning (_("Target does not support trace notes, user ignored"));
{
int ret;
- ret = target_set_trace_notes (NULL, trace_notes, NULL);
+ ret = target_set_trace_notes (NULL, trace_notes.c_str (), NULL);
if (!ret)
warning (_("Target does not support trace notes, note ignored"));
{
int ret;
- ret = target_set_trace_notes (NULL, NULL, trace_stop_notes);
+ ret = target_set_trace_notes (NULL, NULL, trace_stop_notes.c_str ());
if (!ret)
warning (_("Target does not support trace notes, stop note ignored"));
if (b->type == utp->type
&& t->step_count == utp->step
&& t->pass_count == utp->pass
- && cond_string_is_same (t->cond_string,
+ && cond_string_is_same (t->cond_string.get (),
utp->cond_string.get ())
/* FIXME also test actions. */
)
identifier! */
uiout->field_signed ("count", count);
- uiout->field_string ("marker-id", marker.str_id.c_str ());
+ uiout->field_string ("marker-id", marker.str_id);
uiout->field_fmt ("enabled", "%c",
!tracepoints.empty () ? 'y' : 'n');
uiout->text ("\n");
uiout->text (extra_field_indent);
uiout->text (_("Data: \""));
- uiout->field_string ("extra-data", marker.extra.c_str ());
+ uiout->field_string ("extra-data", marker.extra);
uiout->text ("\"\n");
if (!tracepoints.empty ())
{
/* We need to read the whole object before we know its size. */
gdb::optional<gdb::byte_vector> buf
- = target_read_alloc (current_top_target (), TARGET_OBJECT_STATIC_TRACE_DATA,
+ = target_read_alloc (current_inferior ()->top_target (),
+ TARGET_OBJECT_STATIC_TRACE_DATA,
NULL);
if (buf)
{
type = init_vector_type (builtin_type (gdbarch)->builtin_true_char,
buf->size ());
v = allocate_value (type);
- memcpy (value_contents_raw (v), buf->data (), buf->size ());
+ memcpy (value_contents_raw (v).data (), buf->data (), buf->size ());
return v;
}
else
add_prefix_cmd ("tfind", class_trace, tfind_command, _("\
Select a trace frame.\n\
No argument means forward by one frame; '-' means backward by one frame."),
- &tfindlist, "tfind ", 1, &cmdlist);
+ &tfindlist, 1, &cmdlist);
add_cmd ("outside", class_trace, tfind_outside_command, _("\
Select a trace frame whose PC is outside the given range (exclusive).\n\
Default is the current PC, or the PC of the current trace frame."),
&tfindlist);
- add_cmd ("end", class_trace, tfind_end_command, _("\
-De-select any trace frame and resume 'live' debugging."),
- &tfindlist);
+ cmd_list_element *tfind_end_cmd
+ = add_cmd ("end", class_trace, tfind_end_command, _("\
+De-select any trace frame and resume 'live' debugging."), &tfindlist);
- add_alias_cmd ("none", "end", class_trace, 0, &tfindlist);
+ add_alias_cmd ("none", tfind_end_cmd, class_trace, 0, &tfindlist);
add_cmd ("start", class_trace, tfind_start_command,
_("Select the first trace frame in the trace buffer."),
while single-stepping.\n\n\
Note: this command can only be used in a tracepoint \"actions\" list."));
- add_com_alias ("ws", "while-stepping", class_alias, 0);
- add_com_alias ("stepping", "while-stepping", class_alias, 0);
+ add_com_alias ("ws", while_stepping_cmd_element, class_trace, 0);
+ add_com_alias ("stepping", while_stepping_cmd_element, class_trace, 0);
add_com ("collect", class_trace, collect_pseudocommand, _("\
Specify one or more data items to be collected at a tracepoint.\n\
single-stepping, or enabling/disabling other tracepoints,\n\
depending on target's capabilities."));
- default_collect = xstrdup ("");
add_setshow_string_cmd ("default-collect", class_trace,
&default_collect, _("\
Set the list of expressions to collect by default."), _("\