Unify actions and commands
* defs.h (read_command_lines, read_command_lines_1): New parameters validator and closure. * tracepoint.h (struct action_line): Remove. * breakpoint.h (struct breakpoint): Remove the 'actions' field. * defs.h (enum command_control_type): New value while_stepping_control. (struct command_line): Add comments. * breakpoint.c (breakoint_is_tracepoint): New. (breakpoint_set_commands): For tracepoints, verify the commands are permissible. (check_tracepoint_commands): New. (commands_command): Require that each new line is validated using check_tracepoint_command, if we set commands for a tracepoint. (create_tracepoint_from_upload): Likewise. (print_one_breakpoint_location): Remove the code to print actions specifically. (tracepoint_save_command): Relay to print_command_lines. * cli/cli-script.c (process_next_line): New parameters validator and closure. Handle 'while-stepping'. Call validator if not null. (read_command_lines, read_command_lines1): Likewise. (recurse_read_control_structure): New parameters validator and closure. Handle while_stepping_control. (print_command_lines): Handle while-stepping. (get_command_line, define_command, document_command): Adjust. * remote.c (remote_download_tracepoint): Adjust. * tracepoint.c (make_cleanup_free_actions, read_actions) (free_actions, do_free_actions_cleanup): Remove. (trace_actions_command): Use read_command_lines. (validate_actionline): Use error in one place. (encode_actions_1): New, extracted from... (encode_actions): ...this. Also use cleanups for exception safety. (trace_dump_command): Adjust. * mi/mi-cmd-break (mi_cmd_break_commands): Validate commands if it's tracepoint.
This commit is contained in:
parent
64e3cf3d4f
commit
a7bdde9e63
14 changed files with 377 additions and 344 deletions
174
gdb/breakpoint.c
174
gdb/breakpoint.c
|
@ -692,17 +692,109 @@ condition_command (char *arg, int from_tty)
|
|||
error (_("No breakpoint number %d."), bnum);
|
||||
}
|
||||
|
||||
/* Set the command list of B to COMMANDS. */
|
||||
/* Check that COMMAND do not contain commands that are suitable
|
||||
only for tracepoints and not suitable for ordinary breakpoints.
|
||||
Throw if any such commands is found.
|
||||
*/
|
||||
static void
|
||||
check_no_tracepoint_commands (struct command_line *commands)
|
||||
{
|
||||
struct command_line *c;
|
||||
for (c = commands; c; c = c->next)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (c->control_type == while_stepping_control)
|
||||
error (_("The 'while-stepping' command can only be used for tracepoints"));
|
||||
|
||||
for (i = 0; i < c->body_count; ++i)
|
||||
check_no_tracepoint_commands ((c->body_list)[i]);
|
||||
|
||||
/* Not that command parsing removes leading whitespace and comment
|
||||
lines and also empty lines. So, we only need to check for
|
||||
command directly. */
|
||||
if (strstr (c->line, "collect ") == c->line)
|
||||
error (_("The 'collect' command can only be used for tracepoints"));
|
||||
|
||||
if (strstr (c->line, "eval ") == c->line)
|
||||
error (_("The 'eval' command can only be used for tracepoints"));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
breakpoint_is_tracepoint (const struct breakpoint *b)
|
||||
{
|
||||
switch (b->type)
|
||||
{
|
||||
case bp_tracepoint:
|
||||
case bp_fast_tracepoint:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the command list of B to COMMANDS. If breakpoint is tracepoint,
|
||||
validate that only allowed commands are included.
|
||||
*/
|
||||
|
||||
void
|
||||
breakpoint_set_commands (struct breakpoint *b, struct command_line *commands)
|
||||
{
|
||||
if (breakpoint_is_tracepoint (b))
|
||||
{
|
||||
/* We need to verify that each top-level element of commands
|
||||
is valid for tracepoints, that there's at most one while-stepping
|
||||
element, and that while-stepping's body has valid tracing commands
|
||||
excluding nested while-stepping. */
|
||||
struct command_line *c;
|
||||
struct command_line *while_stepping = 0;
|
||||
for (c = commands; c; c = c->next)
|
||||
{
|
||||
char *l = c->line;
|
||||
if (c->control_type == while_stepping_control)
|
||||
{
|
||||
if (b->type == bp_fast_tracepoint)
|
||||
error (_("The 'while-stepping' command cannot be used for fast tracepoint"));
|
||||
|
||||
if (while_stepping)
|
||||
error (_("The 'while-stepping' command can be used only once"));
|
||||
else
|
||||
while_stepping = c;
|
||||
}
|
||||
}
|
||||
if (while_stepping)
|
||||
{
|
||||
struct command_line *c2;
|
||||
|
||||
gdb_assert (while_stepping->body_count == 1);
|
||||
c2 = while_stepping->body_list[0];
|
||||
for (; c2; c2 = c2->next)
|
||||
{
|
||||
char *l = c2->line;
|
||||
if (c2->control_type == while_stepping_control)
|
||||
error (_("The 'while-stepping' command cannot be nested"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
check_no_tracepoint_commands (commands);
|
||||
}
|
||||
|
||||
free_command_lines (&b->commands);
|
||||
b->commands = commands;
|
||||
breakpoints_changed ();
|
||||
observer_notify_breakpoint_modified (b->number);
|
||||
}
|
||||
|
||||
void check_tracepoint_command (char *line, void *closure)
|
||||
{
|
||||
struct breakpoint *b = closure;
|
||||
validate_actionline (&line, b);
|
||||
}
|
||||
|
||||
static void
|
||||
commands_command (char *arg, int from_tty)
|
||||
{
|
||||
|
@ -730,7 +822,12 @@ commands_command (char *arg, int from_tty)
|
|||
char *tmpbuf = xstrprintf ("Type commands for when breakpoint %d is hit, one per line.",
|
||||
bnum);
|
||||
struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
|
||||
l = read_command_lines (tmpbuf, from_tty, 1);
|
||||
|
||||
if (breakpoint_is_tracepoint (b))
|
||||
l = read_command_lines (tmpbuf, from_tty, 1,
|
||||
check_tracepoint_command, b);
|
||||
else
|
||||
l = read_command_lines (tmpbuf, from_tty, 1, 0, 0);
|
||||
do_cleanups (cleanups);
|
||||
breakpoint_set_commands (b, l);
|
||||
return;
|
||||
|
@ -4539,26 +4636,6 @@ print_one_breakpoint_location (struct breakpoint *b,
|
|||
ui_out_text (uiout, " \n");
|
||||
}
|
||||
|
||||
if (!part_of_multiple && b->step_count)
|
||||
{
|
||||
annotate_field (11);
|
||||
ui_out_text (uiout, "\tstep count ");
|
||||
ui_out_field_int (uiout, "step", b->step_count);
|
||||
ui_out_text (uiout, " \n");
|
||||
}
|
||||
|
||||
if (!part_of_multiple && b->actions)
|
||||
{
|
||||
struct action_line *action;
|
||||
annotate_field (12);
|
||||
for (action = b->actions; action; action = action->next)
|
||||
{
|
||||
ui_out_text (uiout, " A\t");
|
||||
ui_out_text (uiout, action->action);
|
||||
ui_out_text (uiout, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (ui_out_is_mi_like_p (uiout) && !part_of_multiple)
|
||||
{
|
||||
if (b->addr_string)
|
||||
|
@ -10318,12 +10395,11 @@ tracepoint_save_command (char *args, int from_tty)
|
|||
{
|
||||
struct breakpoint *tp;
|
||||
int any_tp = 0;
|
||||
struct action_line *line;
|
||||
FILE *fp;
|
||||
char *i1 = " ", *i2 = " ";
|
||||
char *indent, *actionline, *pathname;
|
||||
struct command_line *line;
|
||||
char *pathname;
|
||||
char tmp[40];
|
||||
struct cleanup *cleanup;
|
||||
struct ui_file *fp;
|
||||
|
||||
if (args == 0 || *args == 0)
|
||||
error (_("Argument required (file name in which to save tracepoints)"));
|
||||
|
@ -10342,50 +10418,42 @@ tracepoint_save_command (char *args, int from_tty)
|
|||
|
||||
pathname = tilde_expand (args);
|
||||
cleanup = make_cleanup (xfree, pathname);
|
||||
fp = fopen (pathname, "w");
|
||||
fp = gdb_fopen (pathname, "w");
|
||||
if (!fp)
|
||||
error (_("Unable to open file '%s' for saving tracepoints (%s)"),
|
||||
args, safe_strerror (errno));
|
||||
make_cleanup_fclose (fp);
|
||||
make_cleanup_ui_file_delete (fp);
|
||||
|
||||
ALL_TRACEPOINTS (tp)
|
||||
{
|
||||
if (tp->addr_string)
|
||||
fprintf (fp, "trace %s\n", tp->addr_string);
|
||||
fprintf_unfiltered (fp, "trace %s\n", tp->addr_string);
|
||||
else
|
||||
{
|
||||
sprintf_vma (tmp, tp->loc->address);
|
||||
fprintf (fp, "trace *0x%s\n", tmp);
|
||||
fprintf_unfiltered (fp, "trace *0x%s\n", tmp);
|
||||
}
|
||||
|
||||
if (tp->pass_count)
|
||||
fprintf (fp, " passcount %d\n", tp->pass_count);
|
||||
fprintf_unfiltered (fp, " passcount %d\n", tp->pass_count);
|
||||
|
||||
if (tp->actions)
|
||||
if (tp->commands)
|
||||
{
|
||||
fprintf (fp, " actions\n");
|
||||
indent = i1;
|
||||
for (line = tp->actions; line; line = line->next)
|
||||
volatile struct gdb_exception ex;
|
||||
|
||||
fprintf_unfiltered (fp, " actions\n");
|
||||
|
||||
ui_out_redirect (uiout, fp);
|
||||
TRY_CATCH (ex, RETURN_MASK_ERROR)
|
||||
{
|
||||
struct cmd_list_element *cmd;
|
||||
|
||||
QUIT; /* allow user to bail out with ^C */
|
||||
actionline = line->action;
|
||||
while (isspace ((int) *actionline))
|
||||
actionline++;
|
||||
|
||||
fprintf (fp, "%s%s\n", indent, actionline);
|
||||
if (*actionline != '#') /* skip for comment lines */
|
||||
{
|
||||
cmd = lookup_cmd (&actionline, cmdlist, "", -1, 1);
|
||||
if (cmd == 0)
|
||||
error (_("Bad action list item: %s"), actionline);
|
||||
if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
|
||||
indent = i2;
|
||||
else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
|
||||
indent = i1;
|
||||
}
|
||||
print_command_lines (uiout, tp->commands, 2);
|
||||
}
|
||||
ui_out_redirect (uiout, NULL);
|
||||
|
||||
if (ex.reason < 0)
|
||||
throw_exception (ex);
|
||||
|
||||
fprintf_unfiltered (fp, " end\n");
|
||||
}
|
||||
}
|
||||
do_cleanups (cleanup);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue