static void enable_delete_command (char *, int);
-static void enable_delete_breakpoint (struct breakpoint *);
-
static void enable_once_command (char *, int);
-static void enable_once_breakpoint (struct breakpoint *);
-
static void disable_command (char *, int);
static void enable_command (char *, int);
-static void map_breakpoint_numbers (char *, void (*)(struct breakpoint *));
+static void map_breakpoint_numbers (char *, void (*) (struct breakpoint *,
+ void *),
+ void *);
static void ignore_command (char *, int);
static int get_number_trailer (char **, int);
-void set_breakpoint_count (int);
-
typedef enum
{
mark_inserted,
static void trace_pass_command (char *, int);
-static void skip_prologue_sal (struct symtab_and_line *sal);
-
/* Flag indicating that a command has proceeded the inferior past the
current breakpoint. */
/* Number of last breakpoint made. */
-int breakpoint_count;
+static int breakpoint_count;
+
+/* If the last command to create a breakpoint created multiple
+ breakpoints, this holds the start and end breakpoint numbers. */
+static int multi_start;
+static int multi_end;
+/* True if the last breakpoint set was part of a group set with a
+ single command, e.g., "rbreak". */
+static int last_was_multi;
/* Number of last tracepoint made. */
-int tracepoint_count;
+static int tracepoint_count;
/* Return whether a breakpoint is an active enabled breakpoint. */
static int
/* Set breakpoint count to NUM. */
-void
+static void
set_breakpoint_count (int num)
{
breakpoint_count = num;
+ last_was_multi = 0;
set_internalvar_integer (lookup_internalvar ("bpnum"), num);
}
+/* Called at the start an "rbreak" command to record the first
+ breakpoint made. */
+void
+start_rbreak_breakpoints (void)
+{
+ multi_start = breakpoint_count + 1;
+}
+
+/* Called at the end of an "rbreak" command to record the last
+ breakpoint made. */
+void
+end_rbreak_breakpoints (void)
+{
+ if (breakpoint_count >= multi_start)
+ {
+ multi_end = breakpoint_count;
+ last_was_multi = 1;
+ }
+}
+
/* Used in run_command to zero the hit count when a new run starts. */
void
return (b->type == bp_tracepoint || b->type == bp_fast_tracepoint);
}
+/* Allocate a new counted_command_line with reference count of 1.
+ The new structure owns COMMANDS. */
+
+static struct counted_command_line *
+alloc_counted_command_line (struct command_line *commands)
+{
+ struct counted_command_line *result
+ = xmalloc (sizeof (struct counted_command_line));
+ result->refc = 1;
+ result->commands = commands;
+ return result;
+}
+
+/* Increment reference count. This does nothing if CMD is NULL. */
+
+static void
+incref_counted_command_line (struct counted_command_line *cmd)
+{
+ if (cmd)
+ ++cmd->refc;
+}
+
+/* Decrement reference count. If the reference count reaches 0,
+ destroy the counted_command_line. Sets *CMDP to NULL. This does
+ nothing if *CMDP is NULL. */
+
+static void
+decref_counted_command_line (struct counted_command_line **cmdp)
+{
+ if (*cmdp)
+ {
+ if (--(*cmdp)->refc == 0)
+ {
+ free_command_lines (&(*cmdp)->commands);
+ xfree (*cmdp);
+ }
+ *cmdp = NULL;
+ }
+}
+
+/* A cleanup function that calls decref_counted_command_line. */
+
+static void
+do_cleanup_counted_command_line (void *arg)
+{
+ decref_counted_command_line (arg);
+}
+
+/* Create a cleanup that calls decref_counted_command_line on the
+ argument. */
+
+static struct cleanup *
+make_cleanup_decref_counted_command_line (struct counted_command_line **cmdp)
+{
+ return make_cleanup (do_cleanup_counted_command_line, cmdp);
+}
+
/* Default address, symtab and line to put a breakpoint at
for "break" command with no arg.
if default_breakpoint_valid is zero, the other three are
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, "teval ") == c->line)
+ error (_("The 'teval' 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;
+
+ }
+}
+
+/* A helper function that validsates that COMMANDS are valid for a
+ breakpoint. This function will throw an exception if a problem is
+ found. */
+
+static void
+validate_commands_for_breakpoint (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);
+ }
+}
+
+/* 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)
{
- free_command_lines (&b->commands);
- b->commands = commands;
+ validate_commands_for_breakpoint (b, commands);
+
+ decref_counted_command_line (&b->commands);
+ b->commands = alloc_counted_command_line (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);
+}
+
+/* A structure used to pass information through
+ map_breakpoint_numbers. */
+
+struct commands_info
+{
+ /* True if the command was typed at a tty. */
+ int from_tty;
+ /* Non-NULL if the body of the commands are being read from this
+ already-parsed command. */
+ struct command_line *control;
+ /* The command lines read from the user, or NULL if they have not
+ yet been read. */
+ struct counted_command_line *cmd;
+};
+
+/* A callback for map_breakpoint_numbers that sets the commands for
+ commands_command. */
+
static void
-commands_command (char *arg, int from_tty)
+do_map_commands_command (struct breakpoint *b, void *data)
{
- struct breakpoint *b;
- char *p;
- int bnum;
- struct command_line *l;
+ struct commands_info *info = data;
- /* If we allowed this, we would have problems with when to
- free the storage, if we change the commands currently
- being read from. */
+ if (info->cmd == NULL)
+ {
+ struct command_line *l;
- if (executing_breakpoint_commands)
- error (_("Can't use the \"commands\" command among a breakpoint's commands."));
+ if (info->control != NULL)
+ l = copy_command_lines (info->control->body_list[0]);
+ else
- p = arg;
- bnum = get_number (&p);
+ l = read_command_lines (_("Type commands for all specified breakpoints"),
+ info->from_tty, 1,
+ (breakpoint_is_tracepoint (b)
+ ? check_tracepoint_command : 0),
+ b);
+
+ info->cmd = alloc_counted_command_line (l);
+ }
- if (p && *p)
- error (_("Unexpected extra arguments following breakpoint number."));
+ /* If a breakpoint was on the list more than once, we don't need to
+ do anything. */
+ if (b->commands != info->cmd)
+ {
+ validate_commands_for_breakpoint (b, info->cmd->commands);
+ incref_counted_command_line (info->cmd);
+ decref_counted_command_line (&b->commands);
+ b->commands = info->cmd;
+ breakpoints_changed ();
+ observer_notify_breakpoint_modified (b->number);
+ }
+}
- ALL_BREAKPOINTS (b)
- if (b->number == bnum)
- {
- 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);
- do_cleanups (cleanups);
- breakpoint_set_commands (b, l);
- return;
+static void
+commands_command_1 (char *arg, int from_tty, struct command_line *control)
+{
+ struct cleanup *cleanups;
+ struct commands_info info;
+
+ info.from_tty = from_tty;
+ info.control = control;
+ info.cmd = NULL;
+ /* If we read command lines from the user, then `info' will hold an
+ extra reference to the commands that we must clean up. */
+ cleanups = make_cleanup_decref_counted_command_line (&info.cmd);
+
+ if (arg == NULL || !*arg)
+ {
+ if (last_was_multi)
+ arg = xstrprintf ("%d-%d", multi_start, multi_end);
+ else if (breakpoint_count > 0)
+ arg = xstrprintf ("%d", breakpoint_count);
}
- error (_("No breakpoint number %d."), bnum);
+ else
+ /* The command loop has some static state, so we need to preserve
+ our argument. */
+ arg = xstrdup (arg);
+ make_cleanup (xfree, arg);
+
+ map_breakpoint_numbers (arg, do_map_commands_command, &info);
+
+ if (info.cmd == NULL)
+ error (_("No breakpoints specified."));
+
+ do_cleanups (cleanups);
+}
+
+static void
+commands_command (char *arg, int from_tty)
+{
+ commands_command_1 (arg, from_tty, NULL);
}
/* Like commands_command, but instead of reading the commands from
enum command_control_type
commands_from_control_command (char *arg, struct command_line *cmd)
{
- struct breakpoint *b;
- char *p;
- int bnum;
-
- /* If we allowed this, we would have problems with when to
- free the storage, if we change the commands currently
- being read from. */
-
- if (executing_breakpoint_commands)
- error (_("Can't use the \"commands\" command among a breakpoint's commands."));
-
- /* An empty string for the breakpoint number means the last
- breakpoint, but get_number expects a NULL pointer. */
- if (arg && !*arg)
- p = NULL;
- else
- p = arg;
- bnum = get_number (&p);
-
- if (p && *p)
- error (_("Unexpected extra arguments following breakpoint number."));
-
- ALL_BREAKPOINTS (b)
- if (b->number == bnum)
- {
- free_command_lines (&b->commands);
- if (cmd->body_count != 1)
- error (_("Invalid \"commands\" block structure."));
- /* We need to copy the commands because if/while will free the
- list after it finishes execution. */
- b->commands = copy_command_lines (cmd->body_list[0]);
- breakpoints_changed ();
- observer_notify_breakpoint_modified (b->number);
- return simple_control;
- }
- error (_("No breakpoint number %d."), bnum);
+ commands_command_1 (arg, 0, cmd);
+ return simple_control;
}
/* Return non-zero if BL->TARGET_INFO contains valid information. */
do_cleanups (old_chain);
}
+/* Create a master std::terminate breakpoint. The actual function
+ looked for is named FUNC_NAME. */
+static void
+create_std_terminate_master_breakpoint (const char *func_name)
+{
+ struct program_space *pspace;
+ struct objfile *objfile;
+ struct cleanup *old_chain;
+
+ old_chain = save_current_program_space ();
+
+ ALL_PSPACES (pspace)
+ ALL_OBJFILES (objfile)
+ {
+ struct breakpoint *b;
+ struct minimal_symbol *m;
+
+ set_current_program_space (pspace);
+
+ m = lookup_minimal_symbol (func_name, NULL, objfile);
+ if (m == NULL || (MSYMBOL_TYPE (m) != mst_text
+ && MSYMBOL_TYPE (m) != mst_file_text))
+ continue;
+
+ b = create_internal_breakpoint (get_objfile_arch (objfile),
+ SYMBOL_VALUE_ADDRESS (m),
+ bp_std_terminate_master);
+ b->addr_string = xstrdup (func_name);
+ b->enable_state = bp_disabled;
+ }
+ update_global_location_list (1);
+
+ do_cleanups (old_chain);
+}
+
void
update_breakpoints_after_exec (void)
{
/* Thread event breakpoints must be set anew after an exec(),
as must overlay event and longjmp master breakpoints. */
if (b->type == bp_thread_event || b->type == bp_overlay_event
- || b->type == bp_longjmp_master)
+ || b->type == bp_longjmp_master || b->type == bp_std_terminate_master)
{
delete_breakpoint (b);
continue;
create_longjmp_master_breakpoint ("_longjmp");
create_longjmp_master_breakpoint ("siglongjmp");
create_longjmp_master_breakpoint ("_siglongjmp");
+ create_std_terminate_master_breakpoint ("std::terminate()");
}
int
{
if (bs->old_val != NULL)
value_free (bs->old_val);
- free_command_lines (&bs->commands);
+ decref_counted_command_line (&bs->commands);
xfree (bs);
}
{
tmp = (bpstat) xmalloc (sizeof (*tmp));
memcpy (tmp, bs, sizeof (*tmp));
- if (bs->commands != NULL)
- tmp->commands = copy_command_lines (bs->commands);
+ incref_counted_command_line (tmp->commands);
if (bs->old_val != NULL)
{
tmp->old_val = value_copy (bs->old_val);
{
for (; bs != NULL; bs = bs->next)
{
- free_command_lines (&bs->commands);
+ decref_counted_command_line (&bs->commands);
+ bs->commands_left = NULL;
if (bs->old_val != NULL)
{
value_free (bs->old_val);
breakpoint_proceeded = 0;
for (; bs != NULL; bs = bs->next)
{
+ struct counted_command_line *ccmd;
struct command_line *cmd;
struct cleanup *this_cmd_tree_chain;
commands are only executed once, we don't need to copy it; we
can clear the pointer in the bpstat, and make sure we free
the tree when we're done. */
- cmd = bs->commands;
- bs->commands = 0;
- this_cmd_tree_chain = make_cleanup_free_command_lines (&cmd);
+ ccmd = bs->commands;
+ bs->commands = NULL;
+ this_cmd_tree_chain
+ = make_cleanup_decref_counted_command_line (&ccmd);
+ cmd = bs->commands_left;
+ bs->commands_left = NULL;
while (cmd != NULL)
{
result = PRINT_NOTHING;
break;
+ case bp_std_terminate_master:
+ /* These should never be enabled. */
+ printf_filtered (_("std::terminate Master Breakpoint: gdb should not stop!\n"));
+ result = PRINT_NOTHING;
+ break;
+
case bp_watchpoint:
case bp_hardware_watchpoint:
annotate_watchpoint (b->number);
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
+ case bp_std_terminate:
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_jit_event:
bs->breakpoint_at = bl;
/* If the condition is false, etc., don't do the commands. */
bs->commands = NULL;
+ bs->commands_left = NULL;
bs->old_val = NULL;
bs->print_it = print_it_normal;
return bs;
continue;
if (b->type == bp_thread_event || b->type == bp_overlay_event
- || b->type == bp_longjmp_master)
+ || b->type == bp_longjmp_master
+ || b->type == bp_std_terminate_master)
/* We do not stop for these. */
bs->stop = 0;
else
if (b->silent)
bs->print = 0;
bs->commands = b->commands;
- if (bs->commands
- && (strcmp ("silent", bs->commands->line) == 0
- || (xdb_commands && strcmp ("Q",
- bs->commands->line) == 0)))
+ incref_counted_command_line (bs->commands);
+ bs->commands_left = bs->commands ? bs->commands->commands : NULL;
+ if (bs->commands_left
+ && (strcmp ("silent", bs->commands_left->line) == 0
+ || (xdb_commands
+ && strcmp ("Q",
+ bs->commands_left->line) == 0)))
{
- bs->commands = bs->commands->next;
+ bs->commands_left = bs->commands_left->next;
bs->print = 0;
}
- bs->commands = copy_command_lines (bs->commands);
}
/* Print nothing for this entry if we dont stop or dont print. */
enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING;
struct bpstat_what retval;
- retval.call_dummy = 0;
+ retval.call_dummy = STOP_NONE;
for (; bs != NULL; bs = bs->next)
{
enum class bs_class = no_effect;
case bp_thread_event:
case bp_overlay_event:
case bp_longjmp_master:
+ case bp_std_terminate_master:
bs_class = bp_nostop;
break;
case bp_catchpoint:
/* Make sure the action is stop (silent or noisy),
so infrun.c pops the dummy frame. */
bs_class = bp_silent;
- retval.call_dummy = 1;
+ retval.call_dummy = STOP_STACK_DUMMY;
+ break;
+ case bp_std_terminate:
+ /* Make sure the action is stop (silent or noisy),
+ so infrun.c pops the dummy frame. */
+ bs_class = bp_silent;
+ retval.call_dummy = STOP_STD_TERMINATE;
break;
case bp_tracepoint:
case bp_fast_tracepoint:
{bp_step_resume, "step resume"},
{bp_watchpoint_scope, "watchpoint scope"},
{bp_call_dummy, "call dummy"},
+ {bp_std_terminate, "std::terminate"},
{bp_shlib_event, "shlib events"},
{bp_thread_event, "thread events"},
{bp_overlay_event, "overlay events"},
{bp_longjmp_master, "longjmp master"},
+ {bp_std_terminate_master, "std::terminate master"},
{bp_catchpoint, "catchpoint"},
{bp_tracepoint, "tracepoint"},
{bp_fast_tracepoint, "fast tracepoint"},
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
+ case bp_std_terminate:
case bp_shlib_event:
case bp_thread_event:
case bp_overlay_event:
case bp_longjmp_master:
+ case bp_std_terminate_master:
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_jit_event:
ui_out_text (uiout, " hits\n");
}
- l = b->commands;
+ l = b->commands ? b->commands->commands : NULL;
if (!part_of_multiple && l)
{
struct cleanup *script_chain;
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)
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
+ case bp_std_terminate:
case bp_shlib_event:
case bp_thread_event:
case bp_overlay_event:
case bp_jit_event:
case bp_longjmp_master:
+ case bp_std_terminate_master:
loc->loc_type = bp_loc_software_breakpoint;
break;
case bp_hardware_breakpoint:
}
}
+/* Set an active std::terminate breakpoint for each std::terminate
+ master breakpoint. */
+void
+set_std_terminate_breakpoint (void)
+{
+ struct breakpoint *b, *temp;
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ if (b->pspace == current_program_space
+ && b->type == bp_std_terminate_master)
+ {
+ struct breakpoint *clone = clone_momentary_breakpoint (b);
+ clone->type = bp_std_terminate;
+ }
+}
+
+/* Delete all the std::terminate breakpoints. */
+void
+delete_std_terminate_breakpoint (void)
+{
+ struct breakpoint *b, *temp;
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ if (b->type == bp_std_terminate)
+ delete_breakpoint (b);
+}
+
struct breakpoint *
create_thread_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
{
all breakpoints. If we don't set shlib_disabled here, we'll try
to insert those breakpoints and fail. */
if (((b->type == bp_breakpoint)
+ || (b->type == bp_jit_event)
|| (b->type == bp_hardware_breakpoint)
|| (tracepoint_type (b)))
&& loc->pspace == current_program_space
|| loc->loc_type == bp_loc_software_breakpoint)
&& solib->pspace == loc->pspace
&& !loc->shlib_disabled
- && (b->type == bp_breakpoint || b->type == bp_hardware_breakpoint)
+ && (b->type == bp_breakpoint
+ || b->type == bp_jit_event
+ || b->type == bp_hardware_breakpoint)
&& solib_contains_address_p (solib, loc->address))
{
loc->shlib_disabled = 1;
case bp_longjmp_resume:
case bp_step_resume:
case bp_call_dummy:
+ case bp_std_terminate:
case bp_watchpoint_scope:
case bp_shlib_event:
case bp_thread_event:
case bp_overlay_event:
case bp_jit_event:
case bp_longjmp_master:
+ case bp_std_terminate_master:
break;
}
remove_sal (&expanded, i);
--i;
}
- else if (func_addr == pc)
- {
- /* We're at beginning of a function, and should
- skip prologue. */
- struct symbol *sym = find_pc_function (pc);
- if (sym)
- expanded.sals[i] = find_function_start_sal (sym, 1);
- else
- {
- /* Since find_pc_partial_function returned true,
- we should really always find the section here. */
- struct obj_section *section = find_pc_section (pc);
- if (section)
- {
- struct gdbarch *gdbarch
- = get_objfile_arch (section->objfile);
- expanded.sals[i].pc
- = gdbarch_skip_prologue (gdbarch, pc);
- }
- }
- }
}
}
}
- else
- {
- for (i = 0; i < expanded.nelts; ++i)
- {
- /* If this SAL corresponds to a breakpoint inserted using a
- line number, then skip the function prologue if necessary. */
- skip_prologue_sal (&expanded.sals[i]);
- }
- }
+
+ /* Skip the function prologue if necessary. */
+ for (i = 0; i < expanded.nelts; ++i)
+ skip_prologue_sal (&expanded.sals[i]);
do_cleanups (old_chain);
int not_found = 0;
enum bptype type_wanted;
int task = 0;
+ int first_bp_set = breakpoint_count + 1;
sals.sals = NULL;
sals.nelts = 0;
}
if (sals.nelts > 1)
- warning (_("Multiple breakpoints were set.\n"
- "Use the \"delete\" command to delete unwanted breakpoints."));
+ {
+ warning (_("Multiple breakpoints were set.\n"
+ "Use the \"delete\" command to delete unwanted breakpoints."));
+ multi_start = first_bp_set;
+ multi_end = breakpoint_count;
+ last_was_multi = 1;
+ }
+
/* That's it. Discard the cleanups for data inserted into the
breakpoint. */
discard_cleanups (bkpt_chain);
-/* Adjust SAL to the first instruction past the function prologue.
- The end of the prologue is determined using the line table from
- the debugging information. explicit_pc and explicit_line are
- not modified.
-
- If SAL is already past the prologue, then do nothing. */
-
-static void
-skip_prologue_sal (struct symtab_and_line *sal)
-{
- struct symbol *sym;
- struct symtab_and_line start_sal;
- struct cleanup *old_chain;
-
- old_chain = save_current_space_and_thread ();
-
- sym = find_pc_function (sal->pc);
- if (sym != NULL)
- {
- start_sal = find_function_start_sal (sym, 1);
- if (sal->pc < start_sal.pc)
- {
- start_sal.explicit_line = sal->explicit_line;
- start_sal.explicit_pc = sal->explicit_pc;
- *sal = start_sal;
- }
- }
-
- do_cleanups (old_chain);
-}
-
/* Helper function for break_command_1 and disassemble_command. */
void
/* If this SAL corresponds to a breakpoint inserted using
a line number, then skip the function prologue if necessary. */
if (sal->explicit_line)
- {
- /* Preserve the original line number. */
- int saved_line = sal->line;
- skip_prologue_sal (sal);
- sal->line = saved_line;
- }
+ skip_prologue_sal (sal);
}
if (sal->section == 0 && sal->symtab != NULL)
break;
}
- free_command_lines (&bpt->commands);
+ decref_counted_command_line (&bpt->commands);
xfree (bpt->cond_string);
xfree (bpt->cond_exp);
xfree (bpt->addr_string);
return make_cleanup (do_delete_breakpoint_cleanup, b);
}
+/* A callback for map_breakpoint_numbers that calls
+ delete_breakpoint. */
+
+static void
+do_delete_breakpoint (struct breakpoint *b, void *ignore)
+{
+ delete_breakpoint (b);
+}
+
void
delete_command (char *arg, int from_tty)
{
ALL_BREAKPOINTS (b)
{
if (b->type != bp_call_dummy
+ && b->type != bp_std_terminate
&& b->type != bp_shlib_event
&& b->type != bp_jit_event
&& b->type != bp_thread_event
&& b->type != bp_overlay_event
&& b->type != bp_longjmp_master
+ && b->type != bp_std_terminate_master
&& b->number >= 0)
{
breaks_to_delete = 1;
ALL_BREAKPOINTS_SAFE (b, temp)
{
if (b->type != bp_call_dummy
+ && b->type != bp_std_terminate
&& b->type != bp_shlib_event
&& b->type != bp_thread_event
&& b->type != bp_jit_event
&& b->type != bp_overlay_event
&& b->type != bp_longjmp_master
+ && b->type != bp_std_terminate_master
&& b->number >= 0)
delete_breakpoint (b);
}
}
}
else
- map_breakpoint_numbers (arg, delete_breakpoint);
+ map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
}
static int
reset later by breakpoint_re_set. */
case bp_overlay_event:
case bp_longjmp_master:
+ case bp_std_terminate_master:
delete_breakpoint (b);
break;
case bp_finish:
case bp_watchpoint_scope:
case bp_call_dummy:
+ case bp_std_terminate:
case bp_step_resume:
case bp_longjmp:
case bp_longjmp_resume:
create_longjmp_master_breakpoint ("_longjmp");
create_longjmp_master_breakpoint ("siglongjmp");
create_longjmp_master_breakpoint ("_siglongjmp");
+ create_std_terminate_master_breakpoint ("std::terminate()");
}
\f
/* Reset the thread number of this breakpoint:
whose numbers are given in ARGS. */
static void
-map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *))
+map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *,
+ void *),
+ void *data)
{
char *p = args;
char *p1;
{
struct breakpoint *related_breakpoint = b->related_breakpoint;
match = 1;
- function (b);
+ function (b, data);
if (related_breakpoint)
- function (related_breakpoint);
+ function (related_breakpoint, data);
break;
}
if (match == 0)
observer_notify_breakpoint_modified (bpt->number);
}
+/* A callback for map_breakpoint_numbers that calls
+ disable_breakpoint. */
+
+static void
+do_map_disable_breakpoint (struct breakpoint *b, void *ignore)
+{
+ disable_breakpoint (b);
+}
+
static void
disable_command (char *args, int from_tty)
{
update_global_location_list (0);
}
else
- map_breakpoint_numbers (args, disable_breakpoint);
+ map_breakpoint_numbers (args, do_map_disable_breakpoint, NULL);
}
static void
do_enable_breakpoint (bpt, bpt->disposition);
}
+/* A callback for map_breakpoint_numbers that calls
+ enable_breakpoint. */
+
+static void
+do_map_enable_breakpoint (struct breakpoint *b, void *ignore)
+{
+ enable_breakpoint (b);
+}
+
/* The enable command enables the specified breakpoints (or all defined
breakpoints) so they once again become (or continue to be) effective
in stopping the inferior. */
update_global_location_list (1);
}
else
- map_breakpoint_numbers (args, enable_breakpoint);
+ map_breakpoint_numbers (args, do_map_enable_breakpoint, NULL);
}
static void
-enable_once_breakpoint (struct breakpoint *bpt)
+enable_once_breakpoint (struct breakpoint *bpt, void *ignore)
{
do_enable_breakpoint (bpt, disp_disable);
}
static void
enable_once_command (char *args, int from_tty)
{
- map_breakpoint_numbers (args, enable_once_breakpoint);
+ map_breakpoint_numbers (args, enable_once_breakpoint, NULL);
}
static void
-enable_delete_breakpoint (struct breakpoint *bpt)
+enable_delete_breakpoint (struct breakpoint *bpt, void *ignore)
{
do_enable_breakpoint (bpt, disp_del);
}
static void
enable_delete_command (char *args, int from_tty)
{
- map_breakpoint_numbers (args, enable_delete_breakpoint);
+ map_breakpoint_numbers (args, enable_delete_breakpoint, NULL);
}
\f
static void
set_tracepoint_count (breakpoint_count);
}
+/* Set up a fake reader function that gets command lines from a linked
+ list that was acquired during tracepoint uploading. */
+
+static struct uploaded_tp *this_utp;
+static struct uploaded_string *next_cmd;
+
+static char *
+read_uploaded_action (void)
+{
+ char *rslt;
+
+ if (!next_cmd)
+ return NULL;
+
+ rslt = next_cmd->str;
+ next_cmd = next_cmd->next;
+
+ return rslt;
+}
+
/* Given information about a tracepoint as recorded on a target (which
can be either a live system or a trace file), attempt to create an
equivalent GDB tracepoint. This is not a reliable process, since
struct breakpoint *
create_tracepoint_from_upload (struct uploaded_tp *utp)
{
- char buf[100];
+ char *addr_str, small_buf[100];
struct breakpoint *tp;
- /* In the absence of a source location, fall back to raw address. */
- sprintf (buf, "*%s", paddress (get_current_arch(), utp->addr));
+ if (utp->at_string)
+ addr_str = utp->at_string;
+ else
+ {
+ /* In the absence of a source location, fall back to raw
+ address. Since there is no way to confirm that the address
+ means the same thing as when the trace was started, warn the
+ user. */
+ warning (_("Uploaded tracepoint %d has no source location, using raw address"),
+ utp->number);
+ sprintf (small_buf, "*%s", hex_string (utp->addr));
+ addr_str = small_buf;
+ }
+
+ /* There's not much we can do with a sequence of bytecodes. */
+ if (utp->cond && !utp->cond_string)
+ warning (_("Uploaded tracepoint %d condition has no source form, ignoring it"),
+ utp->number);
if (!create_breakpoint (get_current_arch (),
- buf,
- NULL, 0, 1 /* parse arg */,
+ addr_str,
+ utp->cond_string, -1, 0 /* parse cond/thread */,
0 /* tempflag */,
(utp->type == bp_fast_tracepoint) /* hardwareflag */,
1 /* traceflag */,
set_tracepoint_count (breakpoint_count);
+ /* Get the tracepoint we just created. */
tp = get_tracepoint (tracepoint_count);
gdb_assert (tp != NULL);
if (utp->pass > 0)
{
- sprintf (buf, "%d %d", utp->pass, tp->number);
+ sprintf (small_buf, "%d %d", utp->pass, tp->number);
- trace_pass_command (buf, 0);
+ trace_pass_command (small_buf, 0);
}
- if (utp->cond)
+ /* If we have uploaded versions of the original commands, set up a
+ special-purpose "reader" function and call the usual command line
+ reader, then pass the result to the breakpoint command-setting
+ function. */
+ if (utp->cmd_strings)
{
- printf_filtered ("Want to restore a condition\n");
- }
+ struct command_line *cmd_list;
- if (utp->numactions > 0)
- {
- printf_filtered ("Want to restore action list\n");
- }
+ this_utp = utp;
+ next_cmd = utp->cmd_strings;
- if (utp->num_step_actions > 0)
- {
- printf_filtered ("Want to restore action list\n");
+ cmd_list = read_command_lines_1 (read_uploaded_action, 1, NULL, NULL);
+
+ breakpoint_set_commands (tp, cmd_list);
}
+ else if (utp->numactions > 0 || utp->num_step_actions > 0)
+ warning (_("Uploaded tracepoint %d actions have no source form, ignoring them"),
+ utp->number);
return tp;
}
}
}
else
- map_breakpoint_numbers (arg, delete_breakpoint);
+ map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
}
/* Set passcount for tracepoint.
{
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)"));
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;
+ print_command_lines (uiout, tp->commands->commands, 2);
+ }
+ ui_out_redirect (uiout, NULL);
- QUIT; /* allow user to bail out with ^C */
- actionline = line->action;
- while (isspace ((int) *actionline))
- actionline++;
+ if (ex.reason < 0)
+ throw_exception (ex);
- 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;
- }
- }
+ fprintf_unfiltered (fp, " end\n");
}
}
do_cleanups (cleanup);