#include "valprint.h"
#include "jit.h"
#include "xml-syscall.h"
+#include "parser-defs.h"
/* readline include files */
#include "readline/readline.h"
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);
struct address_space *aspace2,
CORE_ADDR addr2);
+static int watchpoint_locations_match (struct bp_location *loc1,
+ struct bp_location *loc2);
+
static void breakpoints_info (char *, int);
-static void breakpoint_1 (int, int);
+static void watchpoints_info (char *, int);
+
+static int breakpoint_1 (int, int, int (*) (const struct breakpoint *));
static bpstat bpstat_alloc (const struct bp_location *, bpstat);
static int get_number_trailer (char **, int);
-void set_breakpoint_count (int);
-
typedef enum
{
mark_inserted,
static void ep_skip_leading_whitespace (char **s);
+static void detach_single_step_breakpoints (void);
+
static int single_step_breakpoint_inserted_here_p (struct address_space *,
CORE_ADDR pc);
static void update_global_location_list_nothrow (int);
-static int is_hardware_watchpoint (struct breakpoint *bpt);
+static int bpstat_remove_bp_location_callback (struct thread_info *th,
+ void *data);
+
+static int is_hardware_watchpoint (const struct breakpoint *bpt);
+
+static int is_watchpoint (const struct breakpoint *bpt);
static void insert_breakpoint_locations (void);
static void trace_pass_command (char *, int);
-static void skip_prologue_sal (struct symtab_and_line *sal);
+/* Assuming we're creating a static tracepoint, does S look like a
+ static tracepoint marker spec ("-m MARKER_ID")? */
+#define is_marker_spec(s) \
+ (strncmp (s, "-m", 2) == 0 && ((s)[2] == ' ' || (s)[2] == '\t'))
+/* A reference-counted struct command_line. This lets multiple
+ breakpoints share a single command list. */
+struct counted_command_line
+{
+ /* The reference count. */
+ int refc;
+
+ /* The command list. */
+ struct command_line *commands;
+};
+
+struct command_line *
+breakpoint_commands (struct breakpoint *b)
+{
+ return b->commands ? b->commands->commands : NULL;
+}
/* Flag indicating that a command has proceeded the inferior past the
current breakpoint. */
/* NOTE: the following values are a part of MI protocol and represent
values of 'disp' field returned when inferior stops at a breakpoint. */
static char *bpdisps[] = {"del", "dstp", "dis", "keep"};
+
return bpdisps[(int) disp];
}
#define ALL_TRACEPOINTS(B) \
for (B = breakpoint_chain; B; B = B->next) \
- if (tracepoint_type (B))
+ if (is_tracepoint (B))
/* Chains of all breakpoints defined. */
/* Number of last breakpoint made. */
-int breakpoint_count;
+static int breakpoint_count;
+
+/* The value of `breakpoint_count' before the last command that
+ created breakpoints. If the last (break-like) command created more
+ than one breakpoint, then the difference between BREAKPOINT_COUNT
+ and PREV_BREAKPOINT_COUNT is more than one. */
+static int prev_breakpoint_count;
/* Number of last tracepoint made. */
-int tracepoint_count;
+static int tracepoint_count;
+
+static struct cmd_list_element *breakpoint_set_cmdlist;
+static struct cmd_list_element *breakpoint_show_cmdlist;
+static struct cmd_list_element *save_cmdlist;
/* Return whether a breakpoint is an active enabled breakpoint. */
static int
/* Set breakpoint count to NUM. */
-void
+static void
set_breakpoint_count (int num)
{
+ prev_breakpoint_count = breakpoint_count;
breakpoint_count = num;
set_internalvar_integer (lookup_internalvar ("bpnum"), num);
}
+/* Used by `start_rbreak_breakpoints' below, to record the current
+ breakpoint count before "rbreak" creates any breakpoint. */
+static int rbreak_start_breakpoint_count;
+
+/* Called at the start an "rbreak" command to record the first
+ breakpoint made. */
+
+void
+start_rbreak_breakpoints (void)
+{
+ rbreak_start_breakpoint_count = breakpoint_count;
+}
+
+/* Called at the end of an "rbreak" command to record the last
+ breakpoint made. */
+
+void
+end_rbreak_breakpoints (void)
+{
+ prev_breakpoint_count = rbreak_start_breakpoint_count;
+}
+
/* Used in run_command to zero the hit count when a new run starts. */
void
b->hit_count = 0;
}
-/* Encapsulate tests for different types of tracepoints. */
+/* Allocate a new counted_command_line with reference count of 1.
+ The new structure owns COMMANDS. */
-static int
-tracepoint_type (const struct breakpoint *b)
+static struct counted_command_line *
+alloc_counted_command_line (struct command_line *commands)
{
- return (b->type == bp_tracepoint || b->type == bp_fast_tracepoint);
+ 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
}
\f
+
+void
+set_breakpoint_condition (struct breakpoint *b, char *exp,
+ int from_tty)
+{
+ struct bp_location *loc = b->loc;
+
+ for (; loc; loc = loc->next)
+ {
+ xfree (loc->cond);
+ loc->cond = NULL;
+ }
+ xfree (b->cond_string);
+ b->cond_string = NULL;
+ xfree (b->cond_exp);
+ b->cond_exp = NULL;
+
+ if (*exp == 0)
+ {
+ if (from_tty)
+ printf_filtered (_("Breakpoint %d now unconditional.\n"), b->number);
+ }
+ else
+ {
+ char *arg = exp;
+
+ /* I don't know if it matters whether this is the string the user
+ typed in or the decompiled expression. */
+ b->cond_string = xstrdup (arg);
+ b->condition_not_parsed = 0;
+
+ if (is_watchpoint (b))
+ {
+ innermost_block = NULL;
+ arg = exp;
+ b->cond_exp = parse_exp_1 (&arg, 0, 0);
+ if (*arg)
+ error (_("Junk at end of expression"));
+ b->cond_exp_valid_block = innermost_block;
+ }
+ else
+ {
+ for (loc = b->loc; loc; loc = loc->next)
+ {
+ arg = exp;
+ loc->cond =
+ parse_exp_1 (&arg, block_for_pc (loc->address), 0);
+ if (*arg)
+ error (_("Junk at end of expression"));
+ }
+ }
+ }
+ breakpoints_changed ();
+ observer_notify_breakpoint_modified (b->number);
+}
+
/* condition N EXP -- set break condition of breakpoint N to EXP. */
static void
ALL_BREAKPOINTS (b)
if (b->number == bnum)
{
- struct bp_location *loc = b->loc;
- for (; loc; loc = loc->next)
- {
- if (loc->cond)
- {
- xfree (loc->cond);
- loc->cond = 0;
- }
- }
- if (b->cond_string != NULL)
- xfree (b->cond_string);
-
- if (*p == 0)
- {
- b->cond_string = NULL;
- if (from_tty)
- printf_filtered (_("Breakpoint %d now unconditional.\n"), bnum);
- }
- else
- {
- arg = p;
- /* I don't know if it matters whether this is the string the user
- typed in or the decompiled expression. */
- b->cond_string = xstrdup (arg);
- b->condition_not_parsed = 0;
- for (loc = b->loc; loc; loc = loc->next)
- {
- arg = p;
- loc->cond =
- parse_exp_1 (&arg, block_for_pc (loc->address), 0);
- if (*arg)
- error (_("Junk at end of expression"));
- }
- }
- breakpoints_changed ();
- observer_notify_breakpoint_modified (b->number);
+ set_breakpoint_condition (b, p, from_tty);
return;
}
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"));
+ }
+}
+
+/* Encapsulate tests for different types of tracepoints. */
+
+int
+is_tracepoint (const struct breakpoint *b)
+{
+ return (b->type == bp_tracepoint
+ || b->type == bp_fast_tracepoint
+ || b->type == bp_static_tracepoint);
+}
+
+/* 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 (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)
+ {
+ if (c->control_type == while_stepping_control)
+ {
+ if (b->type == bp_fast_tracepoint)
+ error (_("\
+The 'while-stepping' command cannot be used for fast tracepoint"));
+ else if (b->type == bp_static_tracepoint)
+ error (_("\
+The 'while-stepping' command cannot be used for static 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)
+ {
+ if (c2->control_type == while_stepping_control)
+ error (_("The 'while-stepping' command cannot be nested"));
+ }
+ }
+ }
+ else
+ {
+ check_no_tracepoint_commands (commands);
+ }
+}
+
+/* Return a vector of all the static tracepoints set at ADDR. The
+ caller is responsible for releasing the vector. */
+
+VEC(breakpoint_p) *
+static_tracepoints_here (CORE_ADDR addr)
+{
+ struct breakpoint *b;
+ VEC(breakpoint_p) *found = 0;
+ struct bp_location *loc;
+
+ ALL_BREAKPOINTS (b)
+ if (b->type == bp_static_tracepoint)
+ {
+ for (loc = b->loc; loc; loc = loc->next)
+ if (loc->address == addr)
+ VEC_safe_push(breakpoint_p, found, b);
+ }
+
+ return found;
+}
+
+/* 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;
+
+ /* The breakpoint range spec. */
+ char *arg;
+
+ /* 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
+ {
+ struct cleanup *old_chain;
+ char *str;
- p = arg;
- bnum = get_number (&p);
+ str = xstrprintf (_("Type commands for breakpoint(s) %s, one per line."),
+ info->arg);
- if (p && *p)
- error (_("Unexpected extra arguments following breakpoint number."));
+ old_chain = make_cleanup (xfree, str);
- 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;
+ l = read_command_lines (str,
+ info->from_tty, 1,
+ (is_tracepoint (b)
+ ? check_tracepoint_command : 0),
+ b);
+
+ do_cleanups (old_chain);
+ }
+
+ info->cmd = alloc_counted_command_line (l);
+ }
+
+ /* 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);
}
- error (_("No breakpoint number %d."), bnum);
+}
+
+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 (breakpoint_count - prev_breakpoint_count > 1)
+ arg = xstrprintf ("%d-%d", prev_breakpoint_count + 1, breakpoint_count);
+ else if (breakpoint_count > 0)
+ arg = xstrprintf ("%d", breakpoint_count);
+ else
+ {
+ /* So that we don't try to free the incoming non-NULL
+ argument in the cleanup below. Mapping breakpoint
+ numbers will fail in this case. */
+ arg = NULL;
+ }
+ }
+ else
+ /* The command loop has some static state, so we need to preserve
+ our argument. */
+ arg = xstrdup (arg);
+
+ if (arg != NULL)
+ make_cleanup (xfree, arg);
+
+ info.arg = 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. */
int bp_size = 0;
int bptoffset = 0;
+ /* bp_location array has B->OWNER always non-NULL. */
if (b->owner->type == bp_none)
warning (_("reading through apparently deleted breakpoint #%d?"),
b->owner->number);
insert_catchpoint (struct ui_out *uo, void *args)
{
struct breakpoint *b = (struct breakpoint *) args;
- int val = -1;
gdb_assert (b->type == bp_catchpoint);
gdb_assert (b->ops != NULL && b->ops->insert != NULL);
b->ops->insert (b);
}
+/* Return true if BPT is of any hardware watchpoint kind. */
+
static int
-is_hardware_watchpoint (struct breakpoint *bpt)
+is_hardware_watchpoint (const struct breakpoint *bpt)
{
return (bpt->type == bp_hardware_watchpoint
|| bpt->type == bp_read_watchpoint
|| bpt->type == bp_access_watchpoint);
}
+/* Return true if BPT is of any watchpoint kind, hardware or
+ software. */
+
+static int
+is_watchpoint (const struct breakpoint *bpt)
+{
+ return (is_hardware_watchpoint (bpt)
+ || bpt->type == bp_watchpoint);
+}
+
/* Find the current value of a watchpoint on EXP. Return the value in
*VALP and *RESULTP and the chain of intermediate and final values
in *VAL_CHAIN. RESULTP and VAL_CHAIN may be NULL if the caller does
{
int within_current_scope;
struct frame_id saved_frame_id;
- struct bp_location *loc;
int frame_saved;
- bpstat bs;
/* If this is a local watchpoint, we only want to check if the
watchpoint frame is in scope if the current thread is the thread
value_free (b->val);
b->val = NULL;
b->val_valid = 0;
+
+ /* Note that unlike with breakpoints, the watchpoint's condition
+ expression is stored in the breakpoint object, not in the
+ locations (re)created below. */
+ if (b->cond_string != NULL)
+ {
+ if (b->cond_exp != NULL)
+ {
+ xfree (b->cond_exp);
+ b->cond_exp = NULL;
+ }
+
+ s = b->cond_string;
+ b->cond_exp = parse_exp_1 (&s, b->cond_exp_valid_block, 0);
+ }
}
/* If we failed to parse the expression, for example because
value_free (v);
}
- /* We just regenerated the list of breakpoint locations.
- The new location does not have its condition field set to anything
- and therefore, we must always reparse the cond_string, independently
- of the value of the reparse flag. */
- if (b->cond_string != NULL)
+ /* If a software watchpoint is not watching any memory, then the
+ above left it without any location set up. But,
+ bpstat_stop_status requires a location to be able to report
+ stops, so make sure there's at least a dummy one. */
+ if (b->type == bp_watchpoint && b->loc == NULL)
{
- char *s = b->cond_string;
- b->loc->cond = parse_exp_1 (&s, b->exp_valid_block, 0);
+ b->loc = allocate_bp_location (b);
+ b->loc->pspace = frame_pspace;
+ b->loc->address = -1;
+ b->loc->length = -1;
+ b->loc->watchpoint_type = -1;
}
}
else if (!within_current_scope)
{
printf_filtered (_("\
-Watchpoint %d deleted because the program has left the block \n\
+Watchpoint %d deleted because the program has left the block\n\
in which its expression is valid.\n"),
b->number);
if (b->related_breakpoint)
- b->related_breakpoint->disposition = disp_del_at_next_stop;
+ {
+ b->related_breakpoint->disposition = disp_del_at_next_stop;
+ b->related_breakpoint->related_breakpoint = NULL;
+ b->related_breakpoint= NULL;
+ }
b->disposition = disp_del_at_next_stop;
}
static int
should_be_inserted (struct bp_location *bpt)
{
- if (!breakpoint_enabled (bpt->owner))
+ if (bpt->owner == NULL || !breakpoint_enabled (bpt->owner))
return 0;
if (bpt->owner->disposition == disp_del_at_next_stop)
/* Tracepoints are inserted by the target at a time of its choosing,
not by us. */
- if (tracepoint_type (bpt->owner))
+ if (is_tracepoint (bpt->owner))
return 0;
return 1;
{
if (automatic_hardware_breakpoints)
{
- int changed = 0;
enum bp_loc_type new_type;
if (mr->attrib.mode != MEM_RW)
if (new_type != bpt->loc_type)
{
static int said = 0;
+
bpt->loc_type = new_type;
if (!said)
{
watchpoints. It's not clear that it's necessary... */
&& bpt->owner->disposition != disp_del_at_next_stop)
{
- val = target_insert_watchpoint (bpt->address,
+ val = target_insert_watchpoint (bpt->address,
bpt->length,
bpt->watchpoint_type);
- bpt->inserted = (val != -1);
+
+ /* If trying to set a read-watchpoint, and it turns out it's not
+ supported, try emulating one with an access watchpoint. */
+ if (val == 1 && bpt->watchpoint_type == hw_read)
+ {
+ struct bp_location *loc, **loc_temp;
+
+ /* But don't try to insert it, if there's already another
+ hw_access location that would be considered a duplicate
+ of this one. */
+ ALL_BP_LOCATIONS (loc, loc_temp)
+ if (loc != bpt
+ && loc->watchpoint_type == hw_access
+ && watchpoint_locations_match (bpt, loc))
+ {
+ bpt->duplicate = 1;
+ bpt->inserted = 1;
+ bpt->target_info = loc->target_info;
+ bpt->watchpoint_type = hw_access;
+ val = 0;
+ break;
+ }
+
+ if (val == 1)
+ {
+ val = target_insert_watchpoint (bpt->address,
+ bpt->length,
+ hw_access);
+ if (val == 0)
+ bpt->watchpoint_type = hw_access;
+ }
+ }
+
+ bpt->inserted = (val == 0);
}
else if (bpt->owner->type == bp_catchpoint)
if (loc->pspace == pspace)
{
+ /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */
if (loc->owner->loc == loc)
loc->owner->loc = loc->next;
else
ALL_BP_LOCATIONS (b, bp_tmp)
{
- struct thread_info *tp;
- CORE_ADDR last_addr;
-
if (!should_be_inserted (b) || b->inserted)
continue;
/* There is no point inserting thread-specific breakpoints if the
- thread no longer exists. */
+ thread no longer exists. ALL_BP_LOCATIONS bp_location has B->OWNER
+ always non-NULL. */
if (b->owner->thread != -1
&& !valid_thread_id (b->owner->thread))
continue;
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 (b->inserted)
val |= remove_breakpoint_1 (b, mark_inserted);
}
+
+ /* Detach single-step breakpoints as well. */
+ detach_single_step_breakpoints ();
+
do_cleanups (old_chain);
return val;
}
remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
{
int val;
- struct cleanup *old_chain;
+
+ /* B is never in moribund_locations by our callers. */
+ gdb_assert (b->owner != NULL);
if (b->owner->enable_state == bp_permanent)
/* Permanent breakpoints cannot be inserted or removed. */
}
else if (b->loc_type == bp_loc_hardware_watchpoint)
{
- struct value *v;
- struct value *n;
-
b->inserted = (is == mark_inserted);
val = target_remove_watchpoint (b->address, b->length,
b->watchpoint_type);
int ret;
struct cleanup *old_chain;
+ /* B is never in moribund_locations by our callers. */
+ gdb_assert (b->owner != NULL);
+
if (b->owner->enable_state == bp_permanent)
/* Permanent breakpoints cannot be inserted or removed. */
return 0;
ALL_BP_LOCATIONS (bpt, bptp_tmp)
{
+ /* ALL_BP_LOCATIONS bp_location has BPT->OWNER always non-NULL. */
if (bpt->pspace == pspace
&& bpt->owner->enable_state != bp_permanent)
bpt->inserted = 0;
switch (b->type)
{
case bp_call_dummy:
- case bp_watchpoint_scope:
/* If the call dummy breakpoint is at the entry point it will
- cause problems when the inferior is rerun, so we better
- get rid of it.
+ cause problems when the inferior is rerun, so we better get
+ rid of it. */
+
+ case bp_watchpoint_scope:
+
+ /* Also get rid of scope breakpoints. */
+
+ case bp_shlib_event:
+
+ /* Also remove solib event breakpoints. Their addresses may
+ have changed since the last time we ran the program.
+ Actually we may now be debugging against different target;
+ and so the solib backend that installed this breakpoint may
+ not be used in by the target. E.g.,
+
+ (gdb) file prog-linux
+ (gdb) run # native linux target
+ ...
+ (gdb) kill
+ (gdb) file prog-win.exe
+ (gdb) tar rem :9999 # remote Windows gdbserver.
+ */
- Also get rid of scope breakpoints. */
delete_breakpoint (b);
break;
&& bpt->loc_type != bp_loc_hardware_breakpoint)
continue;
+ /* ALL_BP_LOCATIONS bp_location has BPT->OWNER always non-NULL. */
if ((breakpoint_enabled (bpt->owner)
|| bpt->owner->enable_state == bp_permanent)
&& breakpoint_address_match (bpt->pspace->aspace, bpt->address,
software_breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
{
struct bp_location *bpt, **bptp_tmp;
- int any_breakpoint_here = 0;
ALL_BP_LOCATIONS (bpt, bptp_tmp)
{
&& bpt->loc_type != bp_loc_hardware_breakpoint)
continue;
+ /* ALL_BP_LOCATIONS bp_location has BPT->OWNER always non-NULL. */
if (!breakpoint_enabled (bpt->owner)
&& bpt->owner->enable_state != bp_permanent)
continue;
{
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);
return NULL;
}
-/* Find a step_resume breakpoint associated with this bpstat.
- (If there are multiple step_resume bp's on the list, this function
- will arbitrarily pick one.)
-
- It is an error to use this function if BPSTAT doesn't contain a
- step_resume breakpoint.
-
- See wait_for_inferior's use of this function. */
-struct breakpoint *
-bpstat_find_step_resume_breakpoint (bpstat bsp)
-{
- int current_thread;
-
- gdb_assert (bsp != NULL);
-
- current_thread = pid_to_thread_id (inferior_ptid);
-
- for (; bsp != NULL; bsp = bsp->next)
- {
- if ((bsp->breakpoint_at != NULL)
- && (bsp->breakpoint_at->owner->type == bp_step_resume)
- && (bsp->breakpoint_at->owner->thread == current_thread
- || bsp->breakpoint_at->owner->thread == -1))
- return bsp->breakpoint_at->owner;
- }
-
- internal_error (__FILE__, __LINE__, _("No step_resume breakpoint found."));
-}
-
-
/* Put in *NUM the breakpoint number of the first breakpoint we are stopped
at. *BSP upon return is a bpstat which points to the remaining
breakpoints stopped at (but which is not guaranteed to be good for
{
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)
{
if (bs->breakpoint_at == NULL)
return PRINT_UNKNOWN;
bl = bs->breakpoint_at;
+
+ /* bl->owner can be NULL if it was a momentary breakpoint
+ which has since been placed into moribund_locations. */
+ if (bl->owner == NULL)
+ return PRINT_UNKNOWN;
b = bl->owner;
stb = ui_out_stream_new (uiout);
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:
{
struct value *mark = value_mark ();
int i = !value_true (evaluate_expression ((struct expression *) exp));
+
value_free_to_mark (mark);
return i;
}
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;
/* We were not stopped by a watchpoint. Mark all watchpoints
as not triggered. */
ALL_BREAKPOINTS (b)
- if (b->type == bp_hardware_watchpoint
- || b->type == bp_read_watchpoint
- || b->type == bp_access_watchpoint)
+ if (is_hardware_watchpoint (b))
b->watchpoint_triggered = watch_triggered_no;
return 0;
/* We were stopped by a watchpoint, but we don't know where.
Mark all watchpoints as unknown. */
ALL_BREAKPOINTS (b)
- if (b->type == bp_hardware_watchpoint
- || b->type == bp_read_watchpoint
- || b->type == bp_access_watchpoint)
+ if (is_hardware_watchpoint (b))
b->watchpoint_triggered = watch_triggered_unknown;
return stopped_by_watchpoint;
triggered. */
ALL_BREAKPOINTS (b)
- if (b->type == bp_hardware_watchpoint
- || b->type == bp_read_watchpoint
- || b->type == bp_access_watchpoint)
+ if (is_hardware_watchpoint (b))
{
struct bp_location *loc;
- struct value *v;
b->watchpoint_triggered = watch_triggered_no;
for (loc = b->loc; loc; loc = loc->next)
#define WP_VALUE_CHANGED 2
/* The value has not changed. */
#define WP_VALUE_NOT_CHANGED 3
+/* Ignore this watchpoint, no matter if the value changed or not. */
+#define WP_IGNORE 4
#define BP_TEMPFLAG 1
#define BP_HARDWAREFLAG 2
struct frame_info *fr;
int within_current_scope;
+ /* BS is built for existing struct breakpoint. */
+ gdb_assert (bs->breakpoint_at != NULL);
+ gdb_assert (bs->breakpoint_at->owner != NULL);
b = bs->breakpoint_at->owner;
/* If this is a local watchpoint, we only want to check if the
watchpoint frame is in scope if the current thread is the thread
that was used to create the watchpoint. */
if (!watchpoint_in_thread_scope (b))
- return WP_VALUE_NOT_CHANGED;
+ return WP_IGNORE;
if (b->exp_valid_block == NULL)
within_current_scope = 1;
even if they are in some other frame, our view of the stack
is likely to be wrong and frame_find_by_id could error out. */
if (gdbarch_in_function_epilogue_p (frame_arch, frame_pc))
- return WP_VALUE_NOT_CHANGED;
+ return WP_IGNORE;
fr = frame_find_by_id (b->watchpoint_frame);
within_current_scope = (fr != NULL);
bs->old_val = b->val;
b->val = new_val;
b->val_valid = 1;
- /* We will stop here */
return WP_VALUE_CHANGED;
}
else
{
- /* Nothing changed, don't do anything. */
+ /* Nothing changed. */
value_free_to_mark (mark);
- /* We won't stop here */
return WP_VALUE_NOT_CHANGED;
}
}
which its expression is valid.\n");
if (b->related_breakpoint)
- b->related_breakpoint->disposition = disp_del_at_next_stop;
+ {
+ b->related_breakpoint->disposition = disp_del_at_next_stop;
+ b->related_breakpoint->related_breakpoint = NULL;
+ b->related_breakpoint = NULL;
+ }
b->disposition = disp_del_at_next_stop;
return WP_DELETED;
{
struct breakpoint *b = bl->owner;
+ /* BL is from existing struct breakpoint. */
+ gdb_assert (b != NULL);
+
/* By definition, the inferior does not report stops at
tracepoints. */
- if (tracepoint_type (b))
+ if (is_tracepoint (b))
return 0;
- if (b->type != bp_watchpoint
- && b->type != bp_hardware_watchpoint
- && b->type != bp_read_watchpoint
- && b->type != bp_access_watchpoint
+ if (!is_watchpoint (b)
&& b->type != bp_hardware_breakpoint
&& b->type != bp_catchpoint) /* a non-watchpoint bp */
{
&& !section_is_mapped (bl->section))
return 0;
}
-
+
/* Continuable hardware watchpoints are treated as non-existent if the
reason we stopped wasn't a hardware watchpoint (we didn't stop on
some data address). Otherwise gdb won't stop on a break instruction
in the code (not from a breakpoint) when a hardware watchpoint has
been defined. Also skip watchpoints which we know did not trigger
(did not match the data address). */
-
- if ((b->type == bp_hardware_watchpoint
- || b->type == bp_read_watchpoint
- || b->type == bp_access_watchpoint)
+
+ if (is_hardware_watchpoint (b)
&& b->watchpoint_triggered == watch_triggered_no)
return 0;
static void
bpstat_check_watchpoint (bpstat bs)
{
- const struct bp_location *bl = bs->breakpoint_at;
- struct breakpoint *b = bl->owner;
+ const struct bp_location *bl;
+ struct breakpoint *b;
+
+ /* BS is built for existing struct breakpoint. */
+ bl = bs->breakpoint_at;
+ gdb_assert (bl != NULL);
+ b = bl->owner;
+ gdb_assert (b != NULL);
- if (b->type == bp_watchpoint
- || b->type == bp_read_watchpoint
- || b->type == bp_access_watchpoint
- || b->type == bp_hardware_watchpoint)
+ if (is_watchpoint (b))
{
- CORE_ADDR addr;
- struct value *v;
int must_check_value = 0;
if (b->type == bp_watchpoint)
bs->print_it = print_it_done;
/* Stop. */
break;
+ case WP_IGNORE:
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ break;
case WP_VALUE_CHANGED:
if (b->type == bp_read_watchpoint)
{
- /* Don't stop: read watchpoints shouldn't fire if
- the value has changed. This is for targets
- which cannot set read-only watchpoints. */
- bs->print_it = print_it_noop;
- bs->stop = 0;
+ /* There are two cases to consider here:
+
+ 1. we're watching the triggered memory for reads.
+ In that case, trust the target, and always report
+ the watchpoint hit to the user. Even though
+ reads don't cause value changes, the value may
+ have changed since the last time it was read, and
+ since we're not trapping writes, we will not see
+ those, and as such we should ignore our notion of
+ old value.
+
+ 2. we're watching the triggered memory for both
+ reads and writes. There are two ways this may
+ happen:
+
+ 2.1. this is a target that can't break on data
+ reads only, but can break on accesses (reads or
+ writes), such as e.g., x86. We detect this case
+ at the time we try to insert read watchpoints.
+
+ 2.2. otherwise, the target supports read
+ watchpoints, but, the user set an access or write
+ watchpoint watching the same memory as this read
+ watchpoint.
+
+ If we're watching memory writes as well as reads,
+ ignore watchpoint hits when we find that the
+ value hasn't changed, as reads don't cause
+ changes. This still gives false positives when
+ the program writes the same value to memory as
+ what there was already in memory (we will confuse
+ it for a read), but it's much better than
+ nothing. */
+
+ int other_write_watchpoint = 0;
+
+ if (bl->watchpoint_type == hw_read)
+ {
+ struct breakpoint *other_b;
+
+ ALL_BREAKPOINTS (other_b)
+ if ((other_b->type == bp_hardware_watchpoint
+ || other_b->type == bp_access_watchpoint)
+ && (other_b->watchpoint_triggered
+ == watch_triggered_yes))
+ {
+ other_write_watchpoint = 1;
+ break;
+ }
+ }
+
+ if (other_write_watchpoint
+ || bl->watchpoint_type == hw_access)
+ {
+ /* We're watching the same memory for writes,
+ and the value changed since the last time we
+ updated it, so this trap must be for a write.
+ Ignore it. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ }
}
break;
case WP_VALUE_NOT_CHANGED:
bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
{
int thread_id = pid_to_thread_id (ptid);
- const struct bp_location *bl = bs->breakpoint_at;
- struct breakpoint *b = bl->owner;
+ const struct bp_location *bl;
+ struct breakpoint *b;
+
+ /* BS is built for existing struct breakpoint. */
+ bl = bs->breakpoint_at;
+ gdb_assert (bl != NULL);
+ b = bl->owner;
+ gdb_assert (b != NULL);
if (frame_id_p (b->frame_id)
&& !frame_id_eq (b->frame_id, get_stack_frame_id (get_current_frame ())))
else if (bs->stop)
{
int value_is_zero = 0;
-
+ struct expression *cond;
+
/* If this is a scope breakpoint, mark the associated
watchpoint as triggered so that we will handle the
out-of-scope event. We'll get to the watchpoint next
iteration. */
if (b->type == bp_watchpoint_scope)
b->related_breakpoint->watchpoint_triggered = watch_triggered_yes;
-
- if (bl->cond && bl->owner->disposition != disp_del_at_next_stop)
+
+ if (is_watchpoint (b))
+ cond = b->cond_exp;
+ else
+ cond = bl->cond;
+
+ if (cond && bl->owner->disposition != disp_del_at_next_stop)
{
+ int within_current_scope = 1;
+
/* We use value_mark and value_free_to_mark because it could
be a long time before we return to the command level and
call free_all_values. We can't call free_all_values
variables when we arrive at a breakpoint at the start
of the inlined function; the current frame will be the
call site. */
- select_frame (get_current_frame ());
- value_is_zero
- = catch_errors (breakpoint_cond_eval, (bl->cond),
- "Error in testing breakpoint condition:\n",
- RETURN_MASK_ALL);
+ if (!is_watchpoint (b) || b->cond_exp_valid_block == NULL)
+ select_frame (get_current_frame ());
+ else
+ {
+ struct frame_info *frame;
+
+ /* For local watchpoint expressions, which particular
+ instance of a local is being watched matters, so we
+ keep track of the frame to evaluate the expression
+ in. To evaluate the condition however, it doesn't
+ really matter which instantiation of the function
+ where the condition makes sense triggers the
+ watchpoint. This allows an expression like "watch
+ global if q > 10" set in `func', catch writes to
+ global on all threads that call `func', or catch
+ writes on all recursive calls of `func' by a single
+ thread. We simply always evaluate the condition in
+ the innermost frame that's executing where it makes
+ sense to evaluate the condition. It seems
+ intuitive. */
+ frame = block_innermost_frame (b->cond_exp_valid_block);
+ if (frame != NULL)
+ select_frame (frame);
+ else
+ within_current_scope = 0;
+ }
+ if (within_current_scope)
+ value_is_zero
+ = catch_errors (breakpoint_cond_eval, cond,
+ "Error in testing breakpoint condition:\n",
+ RETURN_MASK_ALL);
+ else
+ {
+ warning (_("Watchpoint condition cannot be tested "
+ "in the current scope"));
+ /* If we failed to set the right context for this
+ watchpoint, unconditionally report it. */
+ value_is_zero = 0;
+ }
/* FIXME-someday, should give breakpoint # */
value_free_to_mark (mark);
}
- if (bl->cond && value_is_zero)
+
+ if (cond && value_is_zero)
{
bs->stop = 0;
}
CORE_ADDR bp_addr, ptid_t ptid)
{
struct breakpoint *b = NULL;
- struct bp_location *bl, **blp_tmp;
+ struct bp_location *bl;
struct bp_location *loc;
/* Root of the chain of bpstat's */
struct bpstats root_bs[1];
for (bl = b->loc; bl != NULL; bl = bl->next)
{
/* For hardware watchpoints, we look only at the first location.
- The watchpoint_check function will work on entire expression,
- not the individual locations. For read watchopints, the
- watchpoints_triggered function have checked all locations
+ The watchpoint_check function will work on the entire expression,
+ not the individual locations. For read watchpoints, the
+ watchpoints_triggered function has checked all locations
already. */
if (b->type == bp_hardware_watchpoint && bl != b->loc)
break;
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. */
}
bs->next = NULL; /* Terminate the chain */
- bs = root_bs->next; /* Re-grab the head of the chain */
/* If we aren't stopping, the value of some hardware watchpoint may
not have changed, but the intermediate memory locations we are
watching may have. Don't bother if we're stopping; this will get
done later. */
- for (bs = root_bs->next; bs != NULL; bs = bs->next)
- if (bs->stop)
- break;
-
need_remove_insert = 0;
- if (bs == NULL)
+ if (! bpstat_causes_stop (root_bs->next))
for (bs = root_bs->next; bs != NULL; bs = bs->next)
if (!bs->stop
&& bs->breakpoint_at->owner
return root_bs->next;
}
-\f
-/* Tell what to do about this bpstat. */
-struct bpstat_what
-bpstat_what (bpstat bs)
-{
- /* Classify each bpstat as one of the following. */
- enum class
- {
- /* This bpstat element has no effect on the main_action. */
- no_effect = 0,
-
- /* There was a watchpoint, stop but don't print. */
- wp_silent,
-
- /* There was a watchpoint, stop and print. */
- wp_noisy,
-
- /* There was a breakpoint but we're not stopping. */
- bp_nostop,
- /* There was a breakpoint, stop but don't print. */
- bp_silent,
-
- /* There was a breakpoint, stop and print. */
- bp_noisy,
-
- /* We hit the longjmp breakpoint. */
- long_jump,
+static void
+handle_jit_event (void)
+{
+ struct frame_info *frame;
+ struct gdbarch *gdbarch;
- /* We hit the longjmp_resume breakpoint. */
- long_resume,
+ /* Switch terminal for any messages produced by
+ breakpoint_re_set. */
+ target_terminal_ours_for_output ();
- /* We hit the step_resume breakpoint. */
- step_resume,
+ frame = get_current_frame ();
+ gdbarch = get_frame_arch (frame);
- /* We hit the shared library event breakpoint. */
- shlib_event,
+ jit_event_handler (gdbarch);
- /* We hit the jit event breakpoint. */
- jit_event,
+ target_terminal_inferior ();
+}
- /* This is just used to count how many enums there are. */
- class_last
- };
+/* Prepare WHAT final decision for infrun. */
- /* Here is the table which drives this routine. So that we can
- format it pretty, we define some abbreviations for the
- enum bpstat_what codes. */
-#define kc BPSTAT_WHAT_KEEP_CHECKING
-#define ss BPSTAT_WHAT_STOP_SILENT
-#define sn BPSTAT_WHAT_STOP_NOISY
-#define sgl BPSTAT_WHAT_SINGLE
-#define slr BPSTAT_WHAT_SET_LONGJMP_RESUME
-#define clr BPSTAT_WHAT_CLEAR_LONGJMP_RESUME
-#define sr BPSTAT_WHAT_STEP_RESUME
-#define shl BPSTAT_WHAT_CHECK_SHLIBS
-#define jit BPSTAT_WHAT_CHECK_JIT
-
-/* "Can't happen." Might want to print an error message.
- abort() is not out of the question, but chances are GDB is just
- a bit confused, not unusable. */
-#define err BPSTAT_WHAT_STOP_NOISY
-
- /* Given an old action and a class, come up with a new action. */
- /* One interesting property of this table is that wp_silent is the same
- as bp_silent and wp_noisy is the same as bp_noisy. That is because
- after stopping, the check for whether to step over a breakpoint
- (BPSTAT_WHAT_SINGLE type stuff) is handled in proceed() without
- reference to how we stopped. We retain separate wp_silent and
- bp_silent codes in case we want to change that someday.
-
- Another possibly interesting property of this table is that
- there's a partial ordering, priority-like, of the actions. Once
- you've decided that some action is appropriate, you'll never go
- back and decide something of a lower priority is better. The
- ordering is:
-
- kc < jit clr sgl shl slr sn sr ss
- sgl < jit shl slr sn sr ss
- slr < jit err shl sn sr ss
- clr < jit err shl sn sr ss
- ss < jit shl sn sr
- sn < jit shl sr
- jit < shl sr
- shl < sr
- sr <
-
- What I think this means is that we don't need a damned table
- here. If you just put the rows and columns in the right order,
- it'd look awfully regular. We could simply walk the bpstat list
- and choose the highest priority action we find, with a little
- logic to handle the 'err' cases. */
-
- /* step_resume entries: a step resume breakpoint overrides another
- breakpoint of signal handling (see comment in wait_for_inferior
- at where we set the step_resume breakpoint). */
-
- static const enum bpstat_what_main_action
- table[(int) class_last][(int) BPSTAT_WHAT_LAST] =
- {
- /* old action */
- /* kc ss sn sgl slr clr sr shl jit */
-/* no_effect */ {kc, ss, sn, sgl, slr, clr, sr, shl, jit},
-/* wp_silent */ {ss, ss, sn, ss, ss, ss, sr, shl, jit},
-/* wp_noisy */ {sn, sn, sn, sn, sn, sn, sr, shl, jit},
-/* bp_nostop */ {sgl, ss, sn, sgl, slr, slr, sr, shl, jit},
-/* bp_silent */ {ss, ss, sn, ss, ss, ss, sr, shl, jit},
-/* bp_noisy */ {sn, sn, sn, sn, sn, sn, sr, shl, jit},
-/* long_jump */ {slr, ss, sn, slr, slr, err, sr, shl, jit},
-/* long_resume */ {clr, ss, sn, err, err, err, sr, shl, jit},
-/* step_resume */ {sr, sr, sr, sr, sr, sr, sr, sr, sr },
-/* shlib */ {shl, shl, shl, shl, shl, shl, sr, shl, shl},
-/* jit_event */ {jit, jit, jit, jit, jit, jit, sr, jit, jit}
- };
+/* Decide what infrun needs to do with this bpstat. */
-#undef kc
-#undef ss
-#undef sn
-#undef sgl
-#undef slr
-#undef clr
-#undef err
-#undef sr
-#undef ts
-#undef shl
-#undef jit
- enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING;
+struct bpstat_what
+bpstat_what (bpstat bs)
+{
struct bpstat_what retval;
+ /* We need to defer calling `solib_add', as adding new symbols
+ resets breakpoints, which in turn deletes breakpoint locations,
+ and hence may clear unprocessed entries in the BS chain. */
+ int shlib_event = 0;
+ int jit_event = 0;
+
+ retval.main_action = BPSTAT_WHAT_KEEP_CHECKING;
+ retval.call_dummy = STOP_NONE;
- retval.call_dummy = 0;
for (; bs != NULL; bs = bs->next)
{
- enum class bs_class = no_effect;
+ /* Extract this BS's action. After processing each BS, we check
+ if its action overrides all we've seem so far. */
+ enum bpstat_what_main_action this_action = BPSTAT_WHAT_KEEP_CHECKING;
+ enum bptype bptype;
+
if (bs->breakpoint_at == NULL)
- /* I suspect this can happen if it was a momentary breakpoint
- which has since been deleted. */
- continue;
- if (bs->breakpoint_at->owner == NULL)
- bs_class = bp_nostop;
+ {
+ /* I suspect this can happen if it was a momentary
+ breakpoint which has since been deleted. */
+ bptype = bp_none;
+ }
+ else if (bs->breakpoint_at->owner == NULL)
+ bptype = bp_none;
else
- switch (bs->breakpoint_at->owner->type)
+ bptype = bs->breakpoint_at->owner->type;
+
+ switch (bptype)
{
case bp_none:
- continue;
-
+ break;
case bp_breakpoint:
case bp_hardware_breakpoint:
case bp_until:
if (bs->stop)
{
if (bs->print)
- bs_class = bp_noisy;
+ this_action = BPSTAT_WHAT_STOP_NOISY;
else
- bs_class = bp_silent;
+ this_action = BPSTAT_WHAT_STOP_SILENT;
}
else
- bs_class = bp_nostop;
+ this_action = BPSTAT_WHAT_SINGLE;
break;
case bp_watchpoint:
case bp_hardware_watchpoint:
if (bs->stop)
{
if (bs->print)
- bs_class = wp_noisy;
+ this_action = BPSTAT_WHAT_STOP_NOISY;
else
- bs_class = wp_silent;
+ this_action = BPSTAT_WHAT_STOP_SILENT;
}
else
- /* There was a watchpoint, but we're not stopping.
- This requires no further action. */
- bs_class = no_effect;
+ {
+ /* There was a watchpoint, but we're not stopping.
+ This requires no further action. */
+ }
break;
case bp_longjmp:
- bs_class = long_jump;
+ this_action = BPSTAT_WHAT_SET_LONGJMP_RESUME;
break;
case bp_longjmp_resume:
- bs_class = long_resume;
+ this_action = BPSTAT_WHAT_CLEAR_LONGJMP_RESUME;
break;
case bp_step_resume:
if (bs->stop)
+ this_action = BPSTAT_WHAT_STEP_RESUME;
+ else
{
- bs_class = step_resume;
+ /* It is for the wrong frame. */
+ this_action = BPSTAT_WHAT_SINGLE;
}
- else
- /* It is for the wrong frame. */
- bs_class = bp_nostop;
break;
case bp_watchpoint_scope:
- bs_class = bp_nostop;
- break;
- case bp_shlib_event:
- bs_class = shlib_event;
- break;
- case bp_jit_event:
- bs_class = jit_event;
- break;
case bp_thread_event:
case bp_overlay_event:
case bp_longjmp_master:
- bs_class = bp_nostop;
+ case bp_std_terminate_master:
+ this_action = BPSTAT_WHAT_SINGLE;
break;
case bp_catchpoint:
if (bs->stop)
{
if (bs->print)
- bs_class = bp_noisy;
+ this_action = BPSTAT_WHAT_STOP_NOISY;
else
- bs_class = bp_silent;
+ this_action = BPSTAT_WHAT_STOP_SILENT;
+ }
+ else
+ {
+ /* There was a catchpoint, but we're not stopping.
+ This requires no further action. */
}
+ break;
+ case bp_shlib_event:
+ shlib_event = 1;
+
+ /* If requested, stop when the dynamic linker notifies GDB
+ of events. This allows the user to get control and place
+ breakpoints in initializer routines for dynamically
+ loaded objects (among other things). */
+ if (stop_on_solib_events)
+ this_action = BPSTAT_WHAT_STOP_NOISY;
else
- /* There was a catchpoint, but we're not stopping.
- This requires no further action. */
- bs_class = no_effect;
+ this_action = BPSTAT_WHAT_SINGLE;
+ break;
+ case bp_jit_event:
+ jit_event = 1;
+ this_action = BPSTAT_WHAT_SINGLE;
break;
case bp_call_dummy:
/* 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;
+ this_action = BPSTAT_WHAT_STOP_SILENT;
+ break;
+ case bp_std_terminate:
+ /* Make sure the action is stop (silent or noisy),
+ so infrun.c pops the dummy frame. */
+ retval.call_dummy = STOP_STD_TERMINATE;
+ this_action = BPSTAT_WHAT_STOP_SILENT;
break;
case bp_tracepoint:
case bp_fast_tracepoint:
+ case bp_static_tracepoint:
/* Tracepoint hits should not be reported back to GDB, and
if one got through somehow, it should have been filtered
out already. */
internal_error (__FILE__, __LINE__,
_("bpstat_what: tracepoint encountered"));
- break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("bpstat_what: unhandled bptype %d"), (int) bptype);
}
- current_action = table[(int) bs_class][(int) current_action];
+
+ retval.main_action = max (retval.main_action, this_action);
+ }
+
+ if (shlib_event)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "bpstat_what: bp_shlib_event\n");
+
+ /* Check for any newly added shared libraries if we're supposed
+ to be adding them automatically. */
+
+ /* Switch terminal for any messages produced by
+ breakpoint_re_set. */
+ target_terminal_ours_for_output ();
+
+#ifdef SOLIB_ADD
+ SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add);
+#else
+ solib_add (NULL, 0, ¤t_target, auto_solib_add);
+#endif
+
+ target_terminal_inferior ();
}
- retval.main_action = current_action;
+
+ if (jit_event)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "bpstat_what: bp_jit_event\n");
+
+ handle_jit_event ();
+ }
+
return retval;
}
bpstat_should_step (void)
{
struct breakpoint *b;
+
ALL_BREAKPOINTS (b)
if (breakpoint_enabled (b) && b->type == bp_watchpoint && b->loc != NULL)
return 1;
int allflag)
{
struct command_line *l;
- struct symbol *sym;
struct ep_type_description
{
enum bptype type;
{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"},
+ {bp_static_tracepoint, "static tracepoint"},
{bp_jit_event, "jit events"},
};
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_static_tracepoint:
case bp_jit_event:
if (opts.addressprint)
{
|| (!gdbarch_has_global_breakpoints (target_gdbarch)
&& (number_of_program_spaces () > 1
|| number_of_inferiors () > 1)
+ /* LOC is for existing B, it cannot be in moribund_locations and
+ thus having NULL OWNER. */
&& loc->owner->type != bp_catchpoint)))
{
struct inferior *inf;
ui_out_text (uiout, "\n");
+ if (!part_of_multiple && b->static_trace_marker_id)
+ {
+ gdb_assert (b->type == bp_static_tracepoint);
+
+ ui_out_text (uiout, "\tmarker id is ");
+ ui_out_field_string (uiout, "static-tracepoint-marker-string-id",
+ b->static_trace_marker_id);
+ ui_out_text (uiout, "\n");
+ }
+
if (part_of_multiple && frame_id_p (b->frame_id))
{
annotate_field (6);
because the condition is an internal implementation detail
that we do not want to expose to the user. */
annotate_field (7);
- if (tracepoint_type (b))
+ if (is_tracepoint (b))
ui_out_text (uiout, "\ttrace only if ");
else
ui_out_text (uiout, "\tstop only if ");
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)
for (loc = b->loc; loc; loc = loc->next)
{
- int addr_bit = gdbarch_addr_bit (loc->gdbarch);
+ int addr_bit;
+
+ /* Software watchpoints that aren't watching memory don't have
+ an address to print. */
+ if (b->type == bp_watchpoint && loc->watchpoint_type == -1)
+ continue;
+
+ addr_bit = gdbarch_addr_bit (loc->gdbarch);
if (addr_bit > print_address_bits)
print_address_bits = addr_bit;
}
struct captured_breakpoint_query_args *args = data;
struct breakpoint *b;
struct bp_location *dummy_loc = NULL;
+
ALL_BREAKPOINTS (b)
{
if (args->bnum == b->number)
{
int print_address_bits = breakpoint_address_bits (b);
+
print_one_breakpoint (b, &dummy_loc, print_address_bits, 0);
return GDB_RC_OK;
}
gdb_breakpoint_query (struct ui_out *uiout, int bnum, char **error_message)
{
struct captured_breakpoint_query_args args;
+
args.bnum = bnum;
/* For the moment we don't trust print_one_breakpoint() to not throw
an error. */
return (b->type == bp_breakpoint
|| b->type == bp_catchpoint
|| b->type == bp_hardware_breakpoint
- || tracepoint_type (b)
- || b->type == bp_watchpoint
- || b->type == bp_read_watchpoint
- || b->type == bp_access_watchpoint
- || b->type == bp_hardware_watchpoint);
+ || is_tracepoint (b)
+ || is_watchpoint (b));
}
/* Print information on user settable breakpoint (watchpoint, etc)
- number BNUM. If BNUM is -1 print all user settable breakpoints.
- If ALLFLAG is non-zero, include non- user settable breakpoints. */
+ number BNUM. If BNUM is -1 print all user-settable breakpoints.
+ If ALLFLAG is non-zero, include non-user-settable breakpoints. If
+ FILTER is non-NULL, call it on each breakpoint and only include the
+ ones for which it returns non-zero. Return the total number of
+ breakpoints listed. */
-static void
-breakpoint_1 (int bnum, int allflag)
+static int
+breakpoint_1 (int bnum, int allflag, int (*filter) (const struct breakpoint *))
{
struct breakpoint *b;
struct bp_location *last_loc = NULL;
if (bnum == -1
|| bnum == b->number)
{
+ /* If we have a filter, only list the breakpoints it accepts. */
+ if (filter && !filter (b))
+ continue;
+
if (allflag || user_settable_breakpoint (b))
{
int addr_bit = breakpoint_address_bits (b);
annotate_breakpoints_table ();
ALL_BREAKPOINTS (b)
+ {
+ QUIT;
if (bnum == -1
|| bnum == b->number)
{
+ /* If we have a filter, only list the breakpoints it accepts. */
+ if (filter && !filter (b))
+ continue;
+
/* We only print out user settable breakpoints unless the
allflag is set. */
if (allflag || user_settable_breakpoint (b))
print_one_breakpoint (b, &last_loc, print_address_bits, allflag);
}
+ }
do_cleanups (bkpttbl_chain);
if (nr_printable_breakpoints == 0)
{
- if (bnum == -1)
- ui_out_message (uiout, 0, "No breakpoints or watchpoints.\n");
- else
- ui_out_message (uiout, 0, "No breakpoint or watchpoint number %d.\n",
- bnum);
+ /* If there's a filter, let the caller decide how to report empty list. */
+ if (!filter)
+ {
+ if (bnum == -1)
+ ui_out_message (uiout, 0, "No breakpoints or watchpoints.\n");
+ else
+ ui_out_message (uiout, 0, "No breakpoint or watchpoint number %d.\n",
+ bnum);
+ }
}
else
{
/* FIXME? Should this be moved up so that it is only called when
there have been breakpoints? */
annotate_breakpoints_table_end ();
+
+ return nr_printable_breakpoints;
}
+/* Display the value of default-collect in a way that is generally
+ compatible with the breakpoint list. */
+
+static void
+default_collect_info (void)
+{
+ /* If it has no value (which is frequently the case), say nothing; a
+ message like "No default-collect." gets in user's face when it's
+ not wanted. */
+ if (!*default_collect)
+ return;
+
+ /* The following phrase lines up nicely with per-tracepoint collect
+ actions. */
+ ui_out_text (uiout, "default collect ");
+ ui_out_field_string (uiout, "default-collect", default_collect);
+ ui_out_text (uiout, " \n");
+}
+
static void
breakpoints_info (char *bnum_exp, int from_tty)
{
if (bnum_exp)
bnum = parse_and_eval_long (bnum_exp);
- breakpoint_1 (bnum, 0);
+ breakpoint_1 (bnum, 0, NULL);
+
+ default_collect_info ();
+}
+
+static void
+watchpoints_info (char *wpnum_exp, int from_tty)
+{
+ int wpnum = -1, num_printed;
+
+ if (wpnum_exp)
+ wpnum = parse_and_eval_long (wpnum_exp);
+
+ num_printed = breakpoint_1 (wpnum, 0, is_watchpoint);
+
+ if (num_printed == 0)
+ {
+ if (wpnum == -1)
+ ui_out_message (uiout, 0, "No watchpoints.\n");
+ else
+ ui_out_message (uiout, 0, "No watchpoint number %d.\n", wpnum);
+ }
}
static void
if (bnum_exp)
bnum = parse_and_eval_long (bnum_exp);
- breakpoint_1 (bnum, 1);
+ breakpoint_1 (bnum, 1, NULL);
+
+ default_collect_info ();
}
static int
CORE_ADDR pc, struct obj_section *section)
{
struct bp_location *bl = b->loc;
+
for (; bl; bl = bl->next)
{
if (bl->pspace == pspace
static int
watchpoint_locations_match (struct bp_location *loc1, struct bp_location *loc2)
{
+ /* Both of them must not be in moribund_locations. */
+ gdb_assert (loc1->owner != NULL);
+ gdb_assert (loc2->owner != NULL);
+
+ /* Note that this checks the owner's type, not the location's. In
+ case the target does not support read watchpoints, but does
+ support access watchpoints, we'll have bp_read_watchpoint
+ watchpoints with hw_access locations. Those should be considered
+ duplicates of hw_read locations. The hw_read locations will
+ become hw_access locations later. */
return (loc1->owner->type == loc2->owner->type
&& loc1->pspace->aspace == loc2->pspace->aspace
&& loc1->address == loc2->address
static int
breakpoint_locations_match (struct bp_location *loc1, struct bp_location *loc2)
{
- int hw_point1 = is_hardware_watchpoint (loc1->owner);
- int hw_point2 = is_hardware_watchpoint (loc2->owner);
+ int hw_point1, hw_point2;
+
+ /* Both of them must not be in moribund_locations. */
+ gdb_assert (loc1->owner != NULL);
+ gdb_assert (loc2->owner != NULL);
+
+ hw_point1 = is_hardware_watchpoint (loc1->owner);
+ hw_point2 = is_hardware_watchpoint (loc2->owner);
if (hw_point1 != hw_point2)
return 0;
static struct bp_location *
allocate_bp_location (struct breakpoint *bpt)
{
- struct bp_location *loc, *loc_p;
+ struct bp_location *loc;
loc = xmalloc (sizeof (struct bp_location));
memset (loc, 0, sizeof (*loc));
switch (bpt->type)
{
case bp_breakpoint:
- case bp_tracepoint:
- case bp_fast_tracepoint:
case bp_until:
case bp_finish:
case bp_longjmp:
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:
break;
case bp_watchpoint:
case bp_catchpoint:
+ case bp_tracepoint:
+ case bp_fast_tracepoint:
+ case bp_static_tracepoint:
loc->loc_type = bp_loc_other;
break;
default:
static void free_bp_location (struct bp_location *loc)
{
+ /* Be sure no bpstat's are pointing at it after it's been freed. */
+ /* FIXME, how can we find all bpstat's?
+ We just check stop_bpstat for now. Note that we cannot just
+ remove bpstats pointing at bpt from the stop_bpstat list
+ entirely, as breakpoint commands are associated with the bpstat;
+ if we remove it here, then the later call to
+ bpstat_do_actions (&stop_bpstat);
+ in event-top.c won't do anything, and temporary breakpoints
+ with commands won't work. */
+
+ iterate_over_threads (bpstat_remove_bp_location_callback, loc);
+
if (loc->cond)
xfree (loc->cond);
static void
set_breakpoint_location_function (struct bp_location *loc)
{
+ gdb_assert (loc->owner != NULL);
+
if (loc->owner->type == bp_breakpoint
|| loc->owner->type == bp_hardware_breakpoint
- || tracepoint_type (loc->owner))
+ || is_tracepoint (loc->owner))
{
find_pc_partial_function (loc->address, &(loc->function_name),
NULL, NULL);
make_breakpoint_permanent (struct breakpoint *b)
{
struct bp_location *bl;
+
b->enable_state = bp_permanent;
/* By definition, permanent breakpoints are already present in the code.
&& b->type == bp_longjmp_master)
{
struct breakpoint *clone = clone_momentary_breakpoint (b);
+
clone->type = bp_longjmp;
clone->thread = thread;
}
}
}
+/* 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_BP_LOCATIONS (loc, locp_tmp)
{
+ /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */
struct breakpoint *b = loc->owner;
+
/* We apply the check to all breakpoints, including disabled
for those with loc->duplicate set. This is so that when breakpoint
becomes enabled, or the duplicate is removed, gdb will try to insert
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)))
+ || (is_tracepoint (b)))
&& loc->pspace == current_program_space
&& !loc->shlib_disabled
#ifdef PC_SOLIB
ALL_BP_LOCATIONS (loc, locp_tmp)
{
+ /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */
struct breakpoint *b = loc->owner;
+
if ((loc->loc_type == bp_loc_hardware_breakpoint
|| 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;
printf_filtered (_("Catchpoint %d (fork)"), b->number);
}
+/* Implement the "print_recreate" breakpoint_ops method for fork
+ catchpoints. */
+
+static void
+print_recreate_catch_fork (struct breakpoint *b, struct ui_file *fp)
+{
+ fprintf_unfiltered (fp, "catch fork");
+}
+
/* The breakpoint_ops structure to be used in fork catchpoints. */
static struct breakpoint_ops catch_fork_breakpoint_ops =
breakpoint_hit_catch_fork,
print_it_catch_fork,
print_one_catch_fork,
- print_mention_catch_fork
+ print_mention_catch_fork,
+ print_recreate_catch_fork
};
/* Implement the "insert" breakpoint_ops method for vfork catchpoints. */
printf_filtered (_("Catchpoint %d (vfork)"), b->number);
}
+/* Implement the "print_recreate" breakpoint_ops method for vfork
+ catchpoints. */
+
+static void
+print_recreate_catch_vfork (struct breakpoint *b, struct ui_file *fp)
+{
+ fprintf_unfiltered (fp, "catch vfork");
+}
+
/* The breakpoint_ops structure to be used in vfork catchpoints. */
static struct breakpoint_ops catch_vfork_breakpoint_ops =
breakpoint_hit_catch_vfork,
print_it_catch_vfork,
print_one_catch_vfork,
- print_mention_catch_vfork
+ print_mention_catch_vfork,
+ print_recreate_catch_vfork
};
/* Implement the "insert" breakpoint_ops method for syscall
else
{
int i, iter;
+
for (i = 0;
VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
i++)
{
int elem;
+
if (iter >= VEC_length (int, inf->syscalls_counts))
{
int old_size = VEC_length (int, inf->syscalls_counts);
else
{
int i, iter;
+
for (i = 0;
VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
i++)
if (b->syscalls_to_be_caught)
{
int i, iter;
+
for (i = 0;
VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
i++)
{
int i, iter;
char *text = xstrprintf ("%s", "");
+
for (i = 0;
VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
i++)
b->number);
}
+/* Implement the "print_recreate" breakpoint_ops method for syscall
+ catchpoints. */
+
+static void
+print_recreate_catch_syscall (struct breakpoint *b, struct ui_file *fp)
+{
+ fprintf_unfiltered (fp, "catch syscall");
+
+ if (b->syscalls_to_be_caught)
+ {
+ int i, iter;
+
+ for (i = 0;
+ VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ i++)
+ {
+ struct syscall s;
+
+ get_syscall_by_number (iter, &s);
+ if (s.name)
+ fprintf_unfiltered (fp, " %s", s.name);
+ else
+ fprintf_unfiltered (fp, " %d", s.number);
+ }
+ }
+}
+
/* The breakpoint_ops structure to be used in syscall catchpoints. */
static struct breakpoint_ops catch_syscall_breakpoint_ops =
breakpoint_hit_catch_syscall,
print_it_catch_syscall,
print_one_catch_syscall,
- print_mention_catch_syscall
+ print_mention_catch_syscall,
+ print_recreate_catch_syscall
};
/* Returns non-zero if 'b' is a syscall catchpoint. */
printf_filtered (_("Catchpoint %d (exec)"), b->number);
}
+/* Implement the "print_recreate" breakpoint_ops method for exec
+ catchpoints. */
+
+static void
+print_recreate_catch_exec (struct breakpoint *b, struct ui_file *fp)
+{
+ fprintf_unfiltered (fp, "catch exec");
+}
+
static struct breakpoint_ops catch_exec_breakpoint_ops =
{
insert_catch_exec,
breakpoint_hit_catch_exec,
print_it_catch_exec,
print_one_catch_exec,
- print_mention_catch_exec
+ print_mention_catch_exec,
+ print_recreate_catch_exec
};
static void
{
if (b->type == type)
i++;
- else if ((b->type == bp_hardware_watchpoint
- || b->type == bp_read_watchpoint
- || b->type == bp_access_watchpoint))
+ else if (is_hardware_watchpoint (b))
*other_type_used = 1;
}
}
ALL_BREAKPOINTS (b)
{
- if (((b->type == bp_watchpoint)
- || (b->type == bp_hardware_watchpoint)
- || (b->type == bp_read_watchpoint)
- || (b->type == bp_access_watchpoint))
- && breakpoint_enabled (b))
+ if (is_watchpoint (b) && breakpoint_enabled (b))
{
b->enable_state = bp_call_disabled;
update_global_location_list (0);
ALL_BREAKPOINTS (b)
{
- if (((b->type == bp_watchpoint)
- || (b->type == bp_hardware_watchpoint)
- || (b->type == bp_read_watchpoint)
- || (b->type == bp_access_watchpoint))
- && (b->enable_state == bp_call_disabled))
+ if (is_watchpoint (b) && b->enable_state == bp_call_disabled)
{
b->enable_state = bp_enabled;
update_global_location_list (1);
printf_filtered (_(" %d"), b->number);
say_where = 1;
break;
+ case bp_static_tracepoint:
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ say_where = 0;
+ break;
+ }
+ printf_filtered (_("Static tracepoint"));
+ printf_filtered (_(" %d"), b->number);
+ say_where = 1;
+ break;
case bp_until:
case bp_finish:
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;
}
as condition expression. */
static void
-create_breakpoint (struct gdbarch *gdbarch,
- struct symtabs_and_lines sals, char *addr_string,
- char *cond_string,
- enum bptype type, enum bpdisp disposition,
- int thread, int task, int ignore_count,
- struct breakpoint_ops *ops, int from_tty, int enabled)
+create_breakpoint_sal (struct gdbarch *gdbarch,
+ struct symtabs_and_lines sals, char *addr_string,
+ char *cond_string,
+ enum bptype type, enum bpdisp disposition,
+ int thread, int task, int ignore_count,
+ struct breakpoint_ops *ops, int from_tty, int enabled)
{
struct breakpoint *b = NULL;
int i;
b->ignore_count = ignore_count;
b->enable_state = enabled ? bp_enabled : bp_disabled;
b->disposition = disposition;
-
b->pspace = sals.sals[0].pspace;
+ if (type == bp_static_tracepoint)
+ {
+ struct static_tracepoint_marker marker;
+
+ if (is_marker_spec (addr_string))
+ {
+ /* We already know the marker exists, otherwise, we
+ wouldn't see a sal for it. */
+ char *p = &addr_string[3];
+ char *endp;
+ char *marker_str;
+ int i;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ endp = p;
+ while (*endp != ' ' && *endp != '\t' && *endp != '\0')
+ endp++;
+
+ marker_str = savestring (p, endp - p);
+ b->static_trace_marker_id = marker_str;
+
+ printf_filtered (_("Probed static tracepoint marker \"%s\"\n"),
+ b->static_trace_marker_id);
+ }
+ else if (target_static_tracepoint_marker_at (sal.pc, &marker))
+ {
+ b->static_trace_marker_id = xstrdup (marker.str_id);
+ release_static_tracepoint_marker (&marker);
+
+ printf_filtered (_("Probed static tracepoint marker \"%s\"\n"),
+ b->static_trace_marker_id);
+ }
+ else
+ warning (_("\
+Couldn't determine the static tracepoint marker to probe"));
+ }
+
if (enabled && b->pspace->executing_startup
&& (b->type == bp_breakpoint
|| b->type == bp_hardware_breakpoint))
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);
COND and SALS arrays and each of those arrays contents. */
static void
-create_breakpoints (struct gdbarch *gdbarch,
- struct symtabs_and_lines sals, char **addr_string,
- char *cond_string,
- enum bptype type, enum bpdisp disposition,
- int thread, int task, int ignore_count,
- struct breakpoint_ops *ops, int from_tty,
- int enabled)
+create_breakpoints_sal (struct gdbarch *gdbarch,
+ struct symtabs_and_lines sals, char **addr_string,
+ char *cond_string,
+ enum bptype type, enum bpdisp disposition,
+ int thread, int task, int ignore_count,
+ struct breakpoint_ops *ops, int from_tty,
+ int enabled)
{
int i;
+
for (i = 0; i < sals.nelts; ++i)
{
struct symtabs_and_lines expanded =
expand_line_sal_maybe (sals.sals[i]);
- create_breakpoint (gdbarch, expanded, addr_string[i],
- cond_string, type, disposition,
- thread, task, ignore_count, ops, from_tty, enabled);
+ create_breakpoint_sal (gdbarch, expanded, addr_string[i],
+ cond_string, type, disposition,
+ thread, task, ignore_count, ops, from_tty, enabled);
}
}
int *not_found_ptr)
{
char *addr_start = *address;
+
*addr_string = NULL;
/* If no arg given, or if first arg is 'if ', use the default
breakpoint. */
if (default_breakpoint_valid)
{
struct symtab_and_line sal;
+
init_sal (&sal); /* initialize to zeroes */
sals->sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
if (addr_start != (*address))
{
int i;
+
for (i = 0; i < sals->nelts; i++)
{
/* Add the string if not present. */
if ((*addr_string)[i] == NULL)
- (*addr_string)[i] = savestring (addr_start, (*address) - addr_start);
+ (*addr_string)[i] = savestring (addr_start,
+ (*address) - addr_start);
}
}
}
inserted as a breakpoint. If it can't throw an error. */
static void
-breakpoint_sals_to_pc (struct symtabs_and_lines *sals,
- char *address)
+breakpoint_sals_to_pc (struct symtabs_and_lines *sals)
{
int i;
+
for (i = 0; i < sals->nelts; i++)
resolve_sal_pc (&sals->sals[i]);
}
int toklen;
char *cond_start = NULL;
char *cond_end = NULL;
+
while (*tok == ' ' || *tok == '\t')
tok++;
}
}
-/* Set a breakpoint. This function is shared between
- CLI and MI functions for setting a breakpoint.
- This function has two major modes of operations,
- selected by the PARSE_CONDITION_AND_THREAD parameter.
- If non-zero, the function will parse arg, extracting
- breakpoint location, address and thread. Otherwise,
- ARG is just the location of breakpoint, with condition
- and thread specified by the COND_STRING and THREAD
- parameters. */
+/* Decode a static tracepoint marker spec. */
-static void
-break_command_really (struct gdbarch *gdbarch,
- char *arg, char *cond_string, int thread,
- int parse_condition_and_thread,
- int tempflag, int hardwareflag, int traceflag,
- int ignore_count,
- enum auto_boolean pending_break_support,
- struct breakpoint_ops *ops,
- int from_tty,
- int enabled)
+static struct symtabs_and_lines
+decode_static_tracepoint_spec (char **arg_p)
+{
+ VEC(static_tracepoint_marker_p) *markers = NULL;
+ struct symtabs_and_lines sals;
+ struct symtab_and_line sal;
+ struct symbol *sym;
+ struct cleanup *old_chain;
+ char *p = &(*arg_p)[3];
+ char *endp;
+ char *marker_str;
+ int i;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ endp = p;
+ while (*endp != ' ' && *endp != '\t' && *endp != '\0')
+ endp++;
+
+ marker_str = savestring (p, endp - p);
+ old_chain = make_cleanup (xfree, marker_str);
+
+ markers = target_static_tracepoint_markers_by_strid (marker_str);
+ if (VEC_empty(static_tracepoint_marker_p, markers))
+ error (_("No known static tracepoint marker named %s"), marker_str);
+
+ sals.nelts = VEC_length(static_tracepoint_marker_p, markers);
+ sals.sals = xmalloc (sizeof *sals.sals * sals.nelts);
+
+ for (i = 0; i < sals.nelts; i++)
+ {
+ struct static_tracepoint_marker *marker;
+
+ marker = VEC_index (static_tracepoint_marker_p, markers, i);
+
+ init_sal (&sals.sals[i]);
+
+ sals.sals[i] = find_pc_line (marker->address, 0);
+ sals.sals[i].pc = marker->address;
+
+ release_static_tracepoint_marker (marker);
+ }
+
+ do_cleanups (old_chain);
+
+ *arg_p = endp;
+ return sals;
+}
+
+/* Set a breakpoint. This function is shared between CLI and MI
+ functions for setting a breakpoint. This function has two major
+ modes of operations, selected by the PARSE_CONDITION_AND_THREAD
+ parameter. If non-zero, the function will parse arg, extracting
+ breakpoint location, address and thread. Otherwise, ARG is just the
+ location of breakpoint, with condition and thread specified by the
+ COND_STRING and THREAD parameters. Returns true if any breakpoint
+ was created; false otherwise. */
+
+int
+create_breakpoint (struct gdbarch *gdbarch,
+ char *arg, char *cond_string, int thread,
+ int parse_condition_and_thread,
+ int tempflag, enum bptype type_wanted,
+ int ignore_count,
+ enum auto_boolean pending_break_support,
+ struct breakpoint_ops *ops,
+ int from_tty,
+ int enabled)
{
struct gdb_exception e;
struct symtabs_and_lines sals;
struct symtab_and_line pending_sal;
char *copy_arg;
- char *err_msg;
char *addr_start = arg;
char **addr_string;
struct cleanup *old_chain;
int i;
int pending = 0;
int not_found = 0;
- enum bptype type_wanted;
int task = 0;
+ int prev_bkpt_count = breakpoint_count;
sals.sals = NULL;
sals.nelts = 0;
parse_args.addr_string_p = &addr_string;
parse_args.not_found_ptr = ¬_found;
+ if (type_wanted == bp_static_tracepoint && is_marker_spec (arg))
+ {
+ int i;
+
+ sals = decode_static_tracepoint_spec (&arg);
+
+ copy_arg = savestring (addr_start, arg - addr_start);
+ addr_string = xcalloc (sals.nelts, sizeof (char **));
+ for (i = 0; i < sals.nelts; i++)
+ addr_string[i] = xstrdup (copy_arg);
+ goto done;
+ }
+
e = catch_exception (uiout, do_captured_parse_breakpoint,
&parse_args, RETURN_MASK_ALL);
selects no, then simply return the error code. */
if (pending_break_support == AUTO_BOOLEAN_AUTO
&& !nquery ("Make breakpoint pending on future shared library load? "))
- return;
+ return 0;
/* At this point, either the user was queried about setting
a pending breakpoint and selected yes, or pending
}
default:
if (!sals.nelts)
- return;
+ return 0;
}
+ done:
+
/* Create a chain of things that always need to be cleaned up. */
old_chain = make_cleanup (null_cleanup, 0);
/* Resolve all line numbers to PC's and verify that the addresses
are ok for the target. */
if (!pending)
- breakpoint_sals_to_pc (&sals, addr_start);
-
- type_wanted = (traceflag
- ? (hardwareflag ? bp_fast_tracepoint : bp_tracepoint)
- : (hardwareflag ? bp_hardware_breakpoint : bp_breakpoint));
+ breakpoint_sals_to_pc (&sals);
/* Fast tracepoints may have additional restrictions on location. */
if (type_wanted == bp_fast_tracepoint)
make_cleanup (xfree, cond_string);
}
}
- create_breakpoints (gdbarch, sals, addr_string, cond_string, type_wanted,
- tempflag ? disp_del : disp_donttouch,
- thread, task, ignore_count, ops, from_tty, enabled);
+
+ /* If the user is creating a static tracepoint by marker id
+ (strace -m MARKER_ID), then store the sals index, so that
+ breakpoint_re_set can try to match up which of the newly
+ found markers corresponds to this one, and, don't try to
+ expand multiple locations for each sal, given than SALS
+ already should contain all sals for MARKER_ID. */
+ if (type_wanted == bp_static_tracepoint
+ && is_marker_spec (addr_string[0]))
+ {
+ int i;
+
+ for (i = 0; i < sals.nelts; ++i)
+ {
+ struct symtabs_and_lines expanded;
+ struct breakpoint *tp;
+ struct cleanup *old_chain;
+
+ expanded.nelts = 1;
+ expanded.sals = xmalloc (sizeof (struct symtab_and_line));
+ expanded.sals[0] = sals.sals[i];
+ old_chain = make_cleanup (xfree, expanded.sals);
+
+ create_breakpoint_sal (gdbarch, expanded, addr_string[i],
+ cond_string, type_wanted,
+ tempflag ? disp_del : disp_donttouch,
+ thread, task, ignore_count, ops,
+ from_tty, enabled);
+
+ do_cleanups (old_chain);
+
+ /* Get the tracepoint we just created. */
+ tp = get_breakpoint (breakpoint_count);
+ gdb_assert (tp != NULL);
+
+ /* Given that its possible to have multiple markers with
+ the same string id, if the user is creating a static
+ tracepoint by marker id ("strace -m MARKER_ID"), then
+ store the sals index, so that breakpoint_re_set can
+ try to match up which of the newly found markers
+ corresponds to this one */
+ tp->static_trace_marker_id_idx = i;
+ }
+ }
+ else
+ create_breakpoints_sal (gdbarch, sals, addr_string, cond_string,
+ type_wanted, tempflag ? disp_del : disp_donttouch,
+ thread, task, ignore_count, ops, from_tty,
+ enabled);
}
else
{
- struct symtab_and_line sal = {0};
struct breakpoint *b;
make_cleanup (xfree, copy_arg);
}
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."));
+ prev_breakpoint_count = prev_bkpt_count;
+ }
+
/* That's it. Discard the cleanups for data inserted into the
breakpoint. */
discard_cleanups (bkpt_chain);
/* error call may happen here - have BKPT_CHAIN already discarded. */
update_global_location_list (1);
+
+ return 1;
}
/* Set a breakpoint.
static void
break_command_1 (char *arg, int flag, int from_tty)
{
- int hardwareflag = flag & BP_HARDWAREFLAG;
int tempflag = flag & BP_TEMPFLAG;
+ enum bptype type_wanted = (flag & BP_HARDWAREFLAG
+ ? bp_hardware_breakpoint
+ : bp_breakpoint);
- break_command_really (get_current_arch (),
- arg,
- NULL, 0, 1 /* parse arg */,
- tempflag, hardwareflag, 0 /* traceflag */,
- 0 /* Ignore count */,
- pending_break_support,
- NULL /* breakpoint_ops */,
- from_tty,
- 1 /* enabled */);
-}
-
-
-void
-set_breakpoint (struct gdbarch *gdbarch,
- char *address, char *condition,
- int hardwareflag, int tempflag,
- int thread, int ignore_count,
- int pending, int enabled)
-{
- break_command_really (gdbarch,
- address, condition, thread,
- 0 /* condition and thread are valid. */,
- tempflag, hardwareflag, 0 /* traceflag */,
- ignore_count,
- pending
- ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE,
- NULL, 0, enabled);
+ create_breakpoint (get_current_arch (),
+ arg,
+ NULL, 0, 1 /* parse arg */,
+ tempflag, type_wanted,
+ 0 /* Ignore count */,
+ pending_break_support,
+ NULL /* breakpoint_ops */,
+ from_tty,
+ 1 /* enabled */);
}
-/* 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. */
/* 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_command_1 (arg, 0, from_tty);
}
+/* Return non-zero if EXP is verified as constant. Returned zero means EXP is
+ variable. Also the constant detection may fail for some constant
+ expressions and in such case still falsely return zero. */
+static int
+watchpoint_exp_is_const (const struct expression *exp)
+{
+ int i = exp->nelts;
+
+ while (i > 0)
+ {
+ int oplenp, argsp;
+
+ /* We are only interested in the descriptor of each element. */
+ operator_length (exp, i, &oplenp, &argsp);
+ i -= oplenp;
+
+ switch (exp->elts[i].opcode)
+ {
+ case BINOP_ADD:
+ case BINOP_SUB:
+ case BINOP_MUL:
+ case BINOP_DIV:
+ case BINOP_REM:
+ case BINOP_MOD:
+ case BINOP_LSH:
+ case BINOP_RSH:
+ case BINOP_LOGICAL_AND:
+ case BINOP_LOGICAL_OR:
+ case BINOP_BITWISE_AND:
+ case BINOP_BITWISE_IOR:
+ case BINOP_BITWISE_XOR:
+ case BINOP_EQUAL:
+ case BINOP_NOTEQUAL:
+ case BINOP_LESS:
+ case BINOP_GTR:
+ case BINOP_LEQ:
+ case BINOP_GEQ:
+ case BINOP_REPEAT:
+ case BINOP_COMMA:
+ case BINOP_EXP:
+ case BINOP_MIN:
+ case BINOP_MAX:
+ case BINOP_INTDIV:
+ case BINOP_CONCAT:
+ case BINOP_IN:
+ case BINOP_RANGE:
+ case TERNOP_COND:
+ case TERNOP_SLICE:
+ case TERNOP_SLICE_COUNT:
+
+ case OP_LONG:
+ case OP_DOUBLE:
+ case OP_DECFLOAT:
+ case OP_LAST:
+ case OP_COMPLEX:
+ case OP_STRING:
+ case OP_BITSTRING:
+ case OP_ARRAY:
+ case OP_TYPE:
+ case OP_NAME:
+ case OP_OBJC_NSSTRING:
+
+ case UNOP_NEG:
+ case UNOP_LOGICAL_NOT:
+ case UNOP_COMPLEMENT:
+ case UNOP_ADDR:
+ case UNOP_HIGH:
+ /* Unary, binary and ternary operators: We have to check their
+ operands. If they are constant, then so is the result of
+ that operation. For instance, if A and B are determined to be
+ constants, then so is "A + B".
+
+ UNOP_IND is one exception to the rule above, because the value
+ of *ADDR is not necessarily a constant, even when ADDR is. */
+ break;
+
+ case OP_VAR_VALUE:
+ /* Check whether the associated symbol is a constant.
+ We use SYMBOL_CLASS rather than TYPE_CONST because it's
+ possible that a buggy compiler could mark a variable as constant
+ even when it is not, and TYPE_CONST would return true in this
+ case, while SYMBOL_CLASS wouldn't.
+ We also have to check for function symbols because they are
+ always constant. */
+ {
+ struct symbol *s = exp->elts[i + 2].symbol;
+
+ if (SYMBOL_CLASS (s) != LOC_BLOCK
+ && SYMBOL_CLASS (s) != LOC_CONST
+ && SYMBOL_CLASS (s) != LOC_CONST_BYTES)
+ return 0;
+ break;
+ }
+
+ /* The default action is to return 0 because we are using
+ the optimistic approach here: If we don't know something,
+ then it is not a constant. */
+ default:
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
/* accessflag: hw_write: watch write,
hw_read: watch read,
hw_access: watch access (read or write) */
static void
watch_command_1 (char *arg, int accessflag, int from_tty)
{
- struct gdbarch *gdbarch = get_current_arch ();
struct breakpoint *b, *scope_breakpoint = NULL;
struct expression *exp;
- struct block *exp_valid_block;
+ struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL;
struct value *val, *mark;
struct frame_info *frame;
char *exp_start = NULL;
while (exp_end > exp_start && (exp_end[-1] == ' ' || exp_end[-1] == '\t'))
--exp_end;
+ /* Checking if the expression is not constant. */
+ if (watchpoint_exp_is_const (exp))
+ {
+ int len;
+
+ len = exp_end - exp_start;
+ while (len > 0 && isspace (exp_start[len - 1]))
+ len--;
+ error (_("Cannot watch constant value `%.*s'."), len, exp_start);
+ }
+
exp_valid_block = innermost_block;
mark = value_mark ();
fetch_watchpoint_value (exp, &val, NULL, NULL);
{
struct expression *cond;
+ innermost_block = NULL;
tok = cond_start = end_tok + 1;
cond = parse_exp_1 (&tok, 0, 0);
+
+ /* The watchpoint expression may not be local, but the condition
+ may still be. E.g.: `watch global if local > 0'. */
+ cond_exp_valid_block = innermost_block;
+
xfree (cond);
cond_end = tok;
}
breakpoint at the point where we've left the scope of the watchpoint
expression. Create the scope breakpoint before the watchpoint, so
that we will encounter it first in bpstat_stop_status. */
- if (innermost_block && frame)
+ if (exp_valid_block && frame)
{
if (frame_id_p (frame_unwind_caller_id (frame)))
{
b->disposition = disp_donttouch;
b->exp = exp;
b->exp_valid_block = exp_valid_block;
+ b->cond_exp_valid_block = cond_exp_valid_block;
b->exp_string = savestring (exp_start, exp_end - exp_start);
b->val = val;
b->val_valid = 1;
catch_fork_kind;
static void
-catch_fork_command_1 (char *arg, int from_tty, struct cmd_list_element *command)
+catch_fork_command_1 (char *arg, int from_tty,
+ struct cmd_list_element *command)
{
struct gdbarch *gdbarch = get_current_arch ();
char *cond_string = NULL;
}
static void
-catch_exec_command_1 (char *arg, int from_tty, struct cmd_list_element *command)
+catch_exec_command_1 (char *arg, int from_tty,
+ struct cmd_list_element *command)
{
struct gdbarch *gdbarch = get_current_arch ();
int tempflag;
}
static void
-print_one_exception_catchpoint (struct breakpoint *b, struct bp_location **last_loc)
+print_one_exception_catchpoint (struct breakpoint *b,
+ struct bp_location **last_loc)
{
struct value_print_options opts;
+
get_user_print_options (&opts);
if (opts.addressprint)
{
: _(" (catch)"));
}
+/* Implement the "print_recreate" breakpoint_ops method for throw and
+ catch catchpoints. */
+
+static void
+print_recreate_exception_catchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+ int bp_temp;
+ int bp_throw;
+
+ bp_temp = b->disposition == disp_del;
+ bp_throw = strstr (b->addr_string, "throw") != NULL;
+ fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch ");
+ fprintf_unfiltered (fp, bp_throw ? "throw" : "catch");
+}
+
static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
NULL, /* insert */
NULL, /* remove */
NULL, /* breakpoint_hit */
print_exception_catchpoint,
print_one_exception_catchpoint,
- print_mention_exception_catchpoint
+ print_mention_exception_catchpoint,
+ print_recreate_exception_catchpoint
};
static int
else
trigger_func_name = "__cxa_throw";
- break_command_really (get_current_arch (),
- trigger_func_name, cond_string, -1,
- 0 /* condition and thread are valid. */,
- tempflag, 0, 0,
- 0,
- AUTO_BOOLEAN_TRUE /* pending */,
- &gnu_v3_exception_catchpoint_ops, from_tty,
- 1 /* enabled */);
+ create_breakpoint (get_current_arch (),
+ trigger_func_name, cond_string, -1,
+ 0 /* condition and thread are valid. */,
+ tempflag, bp_breakpoint,
+ 0,
+ AUTO_BOOLEAN_TRUE /* pending */,
+ &gnu_v3_exception_catchpoint_ops, from_tty,
+ 1 /* enabled */);
return 1;
}
int tempflag, int from_tty)
{
char *cond_string = NULL;
- struct symtab_and_line *sal = NULL;
if (!arg)
arg = "";
catch_catch_command (char *arg, int from_tty, struct cmd_list_element *command)
{
int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty);
}
catch_throw_command (char *arg, int from_tty, struct cmd_list_element *command)
{
int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
}
struct gdbarch *gdbarch = get_current_arch ();
int tempflag;
struct symtab_and_line sal;
- enum bptype type;
char *addr_string = NULL;
char *exp_string = NULL;
char *cond_string = NULL;
/* Implement the "catch syscall" command. */
static void
-catch_syscall_command_1 (char *arg, int from_tty, struct cmd_list_element *command)
+catch_syscall_command_1 (char *arg, int from_tty,
+ struct cmd_list_element *command)
{
int tempflag;
VEC(int) *filter;
{
int match = 0;
/* Are we going to delete b? */
- if (b->type != bp_none
- && b->type != bp_watchpoint
- && b->type != bp_hardware_watchpoint
- && b->type != bp_read_watchpoint
- && b->type != bp_access_watchpoint)
+ if (b->type != bp_none && !is_watchpoint (b))
{
struct bp_location *loc = b->loc;
for (; loc; loc = loc->next)
{
struct bp_location *a = *(void **) ap;
struct bp_location *b = *(void **) bp;
+ /* A and B come from existing breakpoints having non-NULL OWNER. */
int a_perm = a->owner->enable_state == bp_permanent;
int b_perm = b->owner->enable_state == bp_permanent;
See if there's another location at the same address, in which
case we don't need to remove this one from the target. */
+ /* OLD_LOC comes from existing struct breakpoint. */
if (breakpoint_address_is_meaningful (old_loc->owner))
{
for (loc2p = locp;
/* For the sake of should_be_inserted.
Duplicates check below will fix up this later. */
loc2->duplicate = 0;
+
+ /* Read watchpoint locations are switched to
+ access watchpoints, if the former are not
+ supported, but the latter are. */
+ if (is_hardware_watchpoint (old_loc->owner))
+ {
+ gdb_assert (is_hardware_watchpoint (loc2->owner));
+ loc2->watchpoint_type = old_loc->watchpoint_type;
+ }
+
if (loc2 != old_loc && should_be_inserted (loc2))
{
loc2->inserted = 1;
soon, we'll fail to do the PC adjustment, and report
a random SIGTRAP to the user. When the user resumes
the inferior, it will most likely immediately crash
- with SIGILL/SIGBUS/SEGSEGV, or worse, get silently
+ with SIGILL/SIGBUS/SIGSEGV, or worse, get silently
corrupted, because of being resumed e.g., in the
middle of a multi-byte instruction, or skipped a
one-byte instruction. This was actually seen happen
rwp_loc_first = NULL;
ALL_BP_LOCATIONS (loc, locp)
{
+ /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */
struct breakpoint *b = loc->owner;
struct bp_location **loc_first_p;
|| b->enable_state == bp_startup_disabled
|| !loc->enabled
|| loc->shlib_disabled
- || !breakpoint_address_is_meaningful (b))
+ || !breakpoint_address_is_meaningful (b)
+ || is_tracepoint (b))
continue;
/* Permanent breakpoint should always be inserted. */
update_global_location_list_nothrow (int inserting)
{
struct gdb_exception e;
+
TRY_CATCH (e, RETURN_MASK_ERROR)
update_global_location_list (inserting);
}
-/* Clear BPT from a BPS. */
+/* Clear LOC from a BPS. */
static void
-bpstat_remove_breakpoint (bpstat bps, struct breakpoint *bpt)
+bpstat_remove_bp_location (bpstat bps, struct bp_location *loc)
{
bpstat bs;
+
for (bs = bps; bs; bs = bs->next)
- if (bs->breakpoint_at && bs->breakpoint_at->owner == bpt)
+ if (bs->breakpoint_at == loc)
{
bs->breakpoint_at = NULL;
bs->old_val = NULL;
/* Callback for iterate_over_threads. */
static int
-bpstat_remove_breakpoint_callback (struct thread_info *th, void *data)
+bpstat_remove_bp_location_callback (struct thread_info *th, void *data)
{
- struct breakpoint *bpt = data;
- bpstat_remove_breakpoint (th->stop_bpstat, bpt);
+ struct bp_location *loc = data;
+
+ bpstat_remove_bp_location (th->stop_bpstat, loc);
return 0;
}
delete_breakpoint (struct breakpoint *bpt)
{
struct breakpoint *b;
- struct bp_location *loc, *next;
gdb_assert (bpt != NULL);
if (bpt->type == bp_none)
return;
+ /* At least avoid this stale reference until the reference counting of
+ breakpoints gets resolved. */
+ if (bpt->related_breakpoint != NULL)
+ {
+ gdb_assert (bpt->related_breakpoint->related_breakpoint == bpt);
+ bpt->related_breakpoint->disposition = disp_del_at_next_stop;
+ bpt->related_breakpoint->related_breakpoint = NULL;
+ bpt->related_breakpoint = NULL;
+ }
+
observer_notify_breakpoint_deleted (bpt->number);
if (breakpoint_chain == bpt)
break;
}
- free_command_lines (&bpt->commands);
- if (bpt->cond_string != NULL)
- xfree (bpt->cond_string);
- if (bpt->addr_string != NULL)
- xfree (bpt->addr_string);
- if (bpt->exp != NULL)
- xfree (bpt->exp);
- if (bpt->exp_string != NULL)
- xfree (bpt->exp_string);
- if (bpt->val != NULL)
- value_free (bpt->val);
- if (bpt->source_file != NULL)
- xfree (bpt->source_file);
- if (bpt->exec_pathname != NULL)
- xfree (bpt->exec_pathname);
+ decref_counted_command_line (&bpt->commands);
+ xfree (bpt->cond_string);
+ xfree (bpt->cond_exp);
+ xfree (bpt->addr_string);
+ xfree (bpt->exp);
+ xfree (bpt->exp_string);
+ value_free (bpt->val);
+ xfree (bpt->source_file);
+ xfree (bpt->exec_pathname);
clean_up_filters (&bpt->syscalls_to_be_caught);
- /* Be sure no bpstat's are pointing at it after it's been freed. */
- /* FIXME, how can we find all bpstat's?
- We just check stop_bpstat for now. Note that we cannot just
- remove bpstats pointing at bpt from the stop_bpstat list
- entirely, as breakpoint commands are associated with the bpstat;
- if we remove it here, then the later call to
- bpstat_do_actions (&stop_bpstat);
- in event-top.c won't do anything, and temporary breakpoints
- with commands won't work. */
-
- iterate_over_threads (bpstat_remove_breakpoint_callback, bpt);
-
/* Now that breakpoint is removed from breakpoint
list, update the global location list. This
will remove locations that used to belong to
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
{
struct bp_location *l;
htab_t htab = htab_create_alloc (13, htab_hash_string,
- (int (*) (const void *, const void *)) streq,
+ (int (*) (const void *,
+ const void *)) streq,
NULL, xcalloc, xfree);
for (l = loc; l != NULL; l = l->next)
return 0;
}
+/* When symbols change, it probably means the sources changed as well,
+ and it might mean the static tracepoint markers are no longer at
+ the same address or line numbers they used to be at last we
+ checked. Losing your static tracepoints whenever you rebuild is
+ undesirable. This function tries to resync/rematch gdb static
+ tracepoints with the markers on the target, for static tracepoints
+ that have not been set by marker id. Static tracepoint that have
+ been set by marker id are reset by marker id in breakpoint_re_set.
+ The heuristic is:
+
+ 1) For a tracepoint set at a specific address, look for a marker at
+ the old PC. If one is found there, assume to be the same marker.
+ If the name / string id of the marker found is different from the
+ previous known name, assume that means the user renamed the marker
+ in the sources, and output a warning.
+
+ 2) For a tracepoint set at a given line number, look for a marker
+ at the new address of the old line number. If one is found there,
+ assume to be the same marker. If the name / string id of the
+ marker found is different from the previous known name, assume that
+ means the user renamed the marker in the sources, and output a
+ warning.
+
+ 3) If a marker is no longer found at the same address or line, it
+ may mean the marker no longer exists. But it may also just mean
+ the code changed a bit. Maybe the user added a few lines of code
+ that made the marker move up or down (in line number terms). Ask
+ the target for info about the marker with the string id as we knew
+ it. If found, update line number and address in the matching
+ static tracepoint. This will get confused if there's more than one
+ marker with the same ID (possible in UST, although unadvised
+ precisely because it confuses tools). */
+
+static struct symtab_and_line
+update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
+{
+ struct static_tracepoint_marker marker;
+ CORE_ADDR pc;
+ int i;
+
+ pc = sal.pc;
+ if (sal.line)
+ find_line_pc (sal.symtab, sal.line, &pc);
+
+ if (target_static_tracepoint_marker_at (pc, &marker))
+ {
+ if (strcmp (b->static_trace_marker_id, marker.str_id) != 0)
+ warning (_("static tracepoint %d changed probed marker from %s to %s"),
+ b->number,
+ b->static_trace_marker_id, marker.str_id);
+
+ xfree (b->static_trace_marker_id);
+ b->static_trace_marker_id = xstrdup (marker.str_id);
+ release_static_tracepoint_marker (&marker);
+
+ return sal;
+ }
+
+ /* Old marker wasn't found on target at lineno. Try looking it up
+ by string ID. */
+ if (!sal.explicit_pc
+ && sal.line != 0
+ && sal.symtab != NULL
+ && b->static_trace_marker_id != NULL)
+ {
+ VEC(static_tracepoint_marker_p) *markers;
+
+ markers
+ = target_static_tracepoint_markers_by_strid (b->static_trace_marker_id);
+
+ if (!VEC_empty(static_tracepoint_marker_p, markers))
+ {
+ struct symtab_and_line sal;
+ struct symbol *sym;
+ struct static_tracepoint_marker *marker;
+
+ marker = VEC_index (static_tracepoint_marker_p, markers, 0);
+
+ xfree (b->static_trace_marker_id);
+ b->static_trace_marker_id = xstrdup (marker->str_id);
+
+ warning (_("marker for static tracepoint %d (%s) not "
+ "found at previous line number"),
+ b->number, b->static_trace_marker_id);
+
+ init_sal (&sal);
+
+ sal.pc = marker->address;
+
+ sal = find_pc_line (marker->address, 0);
+ sym = find_pc_sect_function (marker->address, NULL);
+ ui_out_text (uiout, "Now in ");
+ if (sym)
+ {
+ ui_out_field_string (uiout, "func",
+ SYMBOL_PRINT_NAME (sym));
+ ui_out_text (uiout, " at ");
+ }
+ 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);
+ }
+
+ ui_out_field_int (uiout, "line", sal.line);
+ ui_out_text (uiout, "\n");
+
+ b->line_number = sal.line;
+
+ xfree (b->source_file);
+ if (sym)
+ b->source_file = xstrdup (sal.symtab->filename);
+ else
+ b->source_file = NULL;
+
+ xfree (b->addr_string);
+ b->addr_string = xstrprintf ("%s:%d",
+ sal.symtab->filename, b->line_number);
+
+ /* Might be nice to check if function changed, and warn if
+ so. */
+
+ release_static_tracepoint_marker (marker);
+ }
+ }
+ return sal;
+}
+
static void
update_breakpoint_locations (struct breakpoint *b,
struct symtabs_and_lines sals)
update_global_location_list (1);
}
-
/* Reset a breakpoint given it's struct breakpoint * BINT.
The value we return ends up being the return value from catch_errors.
Unused in this case. */
{
/* get past catch_errs */
struct breakpoint *b = (struct breakpoint *) bint;
- struct value *mark;
- int i;
int not_found = 0;
int *not_found_ptr = ¬_found;
struct symtabs_and_lines sals = {0};
struct symtabs_and_lines expanded = {0};
char *s;
- enum enable_state save_enable;
struct gdb_exception e;
struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+ int marker_spec = 0;
switch (b->type)
{
case bp_hardware_breakpoint:
case bp_tracepoint:
case bp_fast_tracepoint:
+ case bp_static_tracepoint:
/* Do not attempt to re-set breakpoints disabled during startup. */
if (b->enable_state == bp_startup_disabled)
return 0;
save_current_space_and_thread ();
switch_to_program_space_and_thread (b->pspace);
+ marker_spec = b->type == bp_static_tracepoint && is_marker_spec (s);
+
TRY_CATCH (e, RETURN_MASK_ERROR)
{
- sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, (char ***) NULL,
- not_found_ptr);
+ if (marker_spec)
+ {
+ sals = decode_static_tracepoint_spec (&s);
+ if (sals.nelts > b->static_trace_marker_id_idx)
+ {
+ sals.sals[0] = sals.sals[b->static_trace_marker_id_idx];
+ sals.nelts = 1;
+ }
+ else
+ error (_("marker %s not found"), b->static_trace_marker_id);
+ }
+ else
+ sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, (char ***) NULL,
+ not_found_ptr);
}
if (e.reason < 0)
{
b->condition_not_parsed = 0;
}
+ if (b->type == bp_static_tracepoint && !marker_spec)
+ sals.sals[0] = update_static_tracepoint (b, sals.sals[0]);
+
expanded = expand_line_sal_maybe (sals.sals[0]);
}
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:
ALL_BREAKPOINTS (b)
if (b->number == bptnum)
{
+ if (is_tracepoint (b))
+ {
+ if (from_tty && count != 0)
+ printf_filtered (_("Ignore count ignored for tracepoint %d."),
+ bptnum);
+ return;
+ }
+
b->ignore_count = count;
if (from_tty)
{
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)
{
struct breakpoint *bpt;
+
if (args == 0)
ALL_BREAKPOINTS (bpt)
switch (bpt->type)
case bp_breakpoint:
case bp_tracepoint:
case bp_fast_tracepoint:
+ case bp_static_tracepoint:
case bp_catchpoint:
case bp_hardware_breakpoint:
case bp_watchpoint:
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 (struct breakpoint *bpt, enum bpdisp disposition)
{
- int target_resources_ok, other_type_used;
- struct value *mark;
+ int target_resources_ok;
if (bpt->type == bp_hardware_breakpoint)
{
error (_("Hardware breakpoints used exceeds limit."));
}
- if (bpt->type == bp_watchpoint
- || bpt->type == bp_hardware_watchpoint
- || bpt->type == bp_read_watchpoint
- || bpt->type == bp_access_watchpoint)
+ if (is_watchpoint (bpt))
{
struct gdb_exception e;
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. */
enable_command (char *args, int from_tty)
{
struct breakpoint *bpt;
+
if (args == 0)
ALL_BREAKPOINTS (bpt)
switch (bpt->type)
case bp_breakpoint:
case bp_tracepoint:
case bp_fast_tracepoint:
+ case bp_static_tracepoint:
case bp_catchpoint:
case bp_hardware_breakpoint:
case bp_watchpoint:
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
decode_line_spec_1 (char *string, int funfirstline)
{
struct symtabs_and_lines sals;
+
if (string == 0)
error (_("Empty line specification."));
if (default_breakpoint_valid)
}
}
+/* Delete software single step breakpoints without removing them from
+ the inferior. This is intended to be used if the inferior's address
+ space where they were inserted is already gone, e.g. after exit or
+ exec. */
+
+void
+cancel_single_step_breakpoints (void)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (single_step_breakpoints[i])
+ {
+ xfree (single_step_breakpoints[i]);
+ single_step_breakpoints[i] = NULL;
+ single_step_gdbarch[i] = NULL;
+ }
+}
+
+/* Detach software single-step breakpoints from INFERIOR_PTID without
+ removing them. */
+
+static void
+detach_single_step_breakpoints (void)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (single_step_breakpoints[i])
+ target_remove_breakpoint (single_step_gdbarch[i],
+ single_step_breakpoints[i]);
+}
+
/* Check whether a software single-step breakpoint is inserted at PC. */
static int
-single_step_breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
+single_step_breakpoint_inserted_here_p (struct address_space *aspace,
+ CORE_ADDR pc)
{
int i;
char *text, char *word)
{
const char **list = get_syscall_names ();
+
return (list == NULL) ? NULL : complete_on_enum (list, text, word);
}
void
trace_command (char *arg, int from_tty)
{
- break_command_really (get_current_arch (),
- arg,
- NULL, 0, 1 /* parse arg */,
- 0 /* tempflag */, 0 /* hardwareflag */,
- 1 /* traceflag */,
- 0 /* Ignore count */,
- pending_break_support,
- NULL,
- from_tty,
- 1 /* enabled */);
- set_tracepoint_count (breakpoint_count);
+ if (create_breakpoint (get_current_arch (),
+ arg,
+ NULL, 0, 1 /* parse arg */,
+ 0 /* tempflag */,
+ bp_tracepoint /* type_wanted */,
+ 0 /* Ignore count */,
+ pending_break_support,
+ NULL,
+ from_tty,
+ 1 /* enabled */))
+ set_tracepoint_count (breakpoint_count);
}
void
ftrace_command (char *arg, int from_tty)
{
- break_command_really (get_current_arch (),
- arg,
- NULL, 0, 1 /* parse arg */,
- 0 /* tempflag */, 1 /* hardwareflag */,
- 1 /* traceflag */,
- 0 /* Ignore count */,
- pending_break_support,
- NULL,
- from_tty,
- 1 /* enabled */);
- set_tracepoint_count (breakpoint_count);
+ if (create_breakpoint (get_current_arch (),
+ arg,
+ NULL, 0, 1 /* parse arg */,
+ 0 /* tempflag */,
+ bp_fast_tracepoint /* type_wanted */,
+ 0 /* Ignore count */,
+ pending_break_support,
+ NULL,
+ from_tty,
+ 1 /* enabled */))
+ set_tracepoint_count (breakpoint_count);
+}
+
+/* strace command implementation. Creates a static tracepoint. */
+
+void
+strace_command (char *arg, int from_tty)
+{
+ if (create_breakpoint (get_current_arch (),
+ arg,
+ NULL, 0, 1 /* parse arg */,
+ 0 /* tempflag */,
+ bp_static_tracepoint /* type_wanted */,
+ 0 /* Ignore count */,
+ pending_break_support,
+ NULL,
+ from_tty,
+ 1 /* enabled */))
+ 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 int next_cmd;
+
+static char *
+read_uploaded_action (void)
+{
+ char *rslt;
+
+ VEC_iterate (char_ptr, this_utp->cmd_strings, next_cmd, rslt);
+
+ next_cmd++;
+
+ return rslt;
}
/* Given information about a tracepoint as recorded on a target (which
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));
-
- break_command_really (get_current_arch (),
- buf,
- NULL, 0, 1 /* parse arg */,
- 0 /* tempflag */,
- (utp->type == bp_fast_tracepoint) /* hardwareflag */,
- 1 /* traceflag */,
- 0 /* Ignore count */,
- pending_break_support,
- NULL,
- 0 /* from_tty */,
- utp->enabled /* enabled */);
+
+ 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 (),
+ addr_str,
+ utp->cond_string, -1, 0 /* parse cond/thread */,
+ 0 /* tempflag */,
+ utp->type /* type_wanted */,
+ 0 /* Ignore count */,
+ pending_break_support,
+ NULL,
+ 0 /* from_tty */,
+ utp->enabled /* enabled */))
+ return NULL;
+
set_tracepoint_count (breakpoint_count);
- tp = get_tracepoint (tracepoint_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 (!VEC_empty (char_ptr, 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 = 0;
- 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 (!VEC_empty (char_ptr, utp->actions)
+ || !VEC_empty (char_ptr, utp->step_actions))
+ warning (_("Uploaded tracepoint %d actions have no source form, ignoring them"),
+ utp->number);
return tp;
}
static void
tracepoints_info (char *tpnum_exp, int from_tty)
{
- struct breakpoint *b;
- int tps_to_list = 0;
+ int tpnum = -1, num_printed;
- /* In the no-arguments case, say "No tracepoints" if none found. */
- if (tpnum_exp == 0)
+ if (tpnum_exp)
+ tpnum = parse_and_eval_long (tpnum_exp);
+
+ num_printed = breakpoint_1 (tpnum, 0, is_tracepoint);
+
+ if (num_printed == 0)
{
- ALL_TRACEPOINTS (b)
- {
- if (b->number >= 0)
- {
- tps_to_list = 1;
- break;
- }
- }
- if (!tps_to_list)
- {
- ui_out_message (uiout, 0, "No tracepoints.\n");
- return;
- }
+ if (tpnum == -1)
+ ui_out_message (uiout, 0, "No tracepoints.\n");
+ else
+ ui_out_message (uiout, 0, "No tracepoint number %d.\n", tpnum);
}
- /* Otherwise be the same as "info break". */
- breakpoints_info (tpnum_exp, from_tty);
+ default_collect_info ();
}
/* The 'enable trace' command enables tracepoints.
{
ALL_BREAKPOINTS_SAFE (b, temp)
{
- if (tracepoint_type (b)
+ if (is_tracepoint (b)
&& b->number >= 0)
delete_breakpoint (b);
}
}
}
else
- map_breakpoint_numbers (arg, delete_breakpoint);
+ map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
}
/* Set passcount for tracepoint.
return NULL;
}
-/* save-tracepoints command */
+/* Save information on user settable breakpoints (watchpoints, etc) to
+ a new script file named FILENAME. If FILTER is non-NULL, call it
+ on each breakpoint and only include the ones for which it returns
+ non-zero. */
+
static void
-tracepoint_save_command (char *args, int from_tty)
+save_breakpoints (char *filename, int from_tty,
+ int (*filter) (const struct breakpoint *))
{
struct breakpoint *tp;
- int any_tp = 0;
- struct action_line *line;
- FILE *fp;
- char *i1 = " ", *i2 = " ";
- char *indent, *actionline, *pathname;
- char tmp[40];
+ int any = 0;
+ char *pathname;
struct cleanup *cleanup;
+ struct ui_file *fp;
+ int extra_trace_bits = 0;
- if (args == 0 || *args == 0)
- error (_("Argument required (file name in which to save tracepoints)"));
+ if (filename == 0 || *filename == 0)
+ error (_("Argument required (file name in which to save)"));
/* See if we have anything to save. */
- ALL_TRACEPOINTS (tp)
+ ALL_BREAKPOINTS (tp)
{
- any_tp = 1;
- break;
+ /* Skip internal and momentary breakpoints. */
+ if (!user_settable_breakpoint (tp))
+ continue;
+
+ /* If we have a filter, only save the breakpoints it accepts. */
+ if (filter && !filter (tp))
+ continue;
+
+ any = 1;
+
+ if (is_tracepoint (tp))
+ {
+ extra_trace_bits = 1;
+
+ /* We can stop searching. */
+ break;
+ }
}
- if (!any_tp)
+
+ if (!any)
{
- warning (_("save-tracepoints: no tracepoints to save."));
+ warning (_("Nothing to save."));
return;
}
- pathname = tilde_expand (args);
+ pathname = tilde_expand (filename);
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);
-
- ALL_TRACEPOINTS (tp)
+ error (_("Unable to open file '%s' for saving (%s)"),
+ filename, safe_strerror (errno));
+ make_cleanup_ui_file_delete (fp);
+
+ if (extra_trace_bits)
+ save_trace_state_variables (fp);
+
+ ALL_BREAKPOINTS (tp)
{
- if (tp->addr_string)
- fprintf (fp, "trace %s\n", tp->addr_string);
+ /* Skip internal and momentary breakpoints. */
+ if (!user_settable_breakpoint (tp))
+ continue;
+
+ /* If we have a filter, only save the breakpoints it accepts. */
+ if (filter && !filter (tp))
+ continue;
+
+ if (tp->ops != NULL)
+ (tp->ops->print_recreate) (tp, fp);
else
{
- sprintf_vma (tmp, tp->loc->address);
- fprintf (fp, "trace *0x%s\n", tmp);
+ if (tp->type == bp_fast_tracepoint)
+ fprintf_unfiltered (fp, "ftrace");
+ if (tp->type == bp_static_tracepoint)
+ fprintf_unfiltered (fp, "strace");
+ else if (tp->type == bp_tracepoint)
+ fprintf_unfiltered (fp, "trace");
+ else if (tp->type == bp_breakpoint && tp->disposition == disp_del)
+ fprintf_unfiltered (fp, "tbreak");
+ else if (tp->type == bp_breakpoint)
+ fprintf_unfiltered (fp, "break");
+ else if (tp->type == bp_hardware_breakpoint
+ && tp->disposition == disp_del)
+ fprintf_unfiltered (fp, "thbreak");
+ else if (tp->type == bp_hardware_breakpoint)
+ fprintf_unfiltered (fp, "hbreak");
+ else if (tp->type == bp_watchpoint)
+ fprintf_unfiltered (fp, "watch");
+ else if (tp->type == bp_hardware_watchpoint)
+ fprintf_unfiltered (fp, "watch");
+ else if (tp->type == bp_read_watchpoint)
+ fprintf_unfiltered (fp, "rwatch");
+ else if (tp->type == bp_access_watchpoint)
+ fprintf_unfiltered (fp, "awatch");
+ else
+ internal_error (__FILE__, __LINE__,
+ _("unhandled breakpoint type %d"), (int) tp->type);
+
+ if (tp->exp_string)
+ fprintf_unfiltered (fp, " %s", tp->exp_string);
+ else if (tp->addr_string)
+ fprintf_unfiltered (fp, " %s", tp->addr_string);
+ else
+ {
+ char tmp[40];
+
+ sprintf_vma (tmp, tp->loc->address);
+ fprintf_unfiltered (fp, " *0x%s", tmp);
+ }
}
+ if (tp->thread != -1)
+ fprintf_unfiltered (fp, " thread %d", tp->thread);
+
+ if (tp->task != 0)
+ fprintf_unfiltered (fp, " task %d", tp->task);
+
+ fprintf_unfiltered (fp, "\n");
+
+ /* Note, we can't rely on tp->number for anything, as we can't
+ assume the recreated breakpoint numbers will match. Use $bpnum
+ instead. */
+
+ if (tp->cond_string)
+ fprintf_unfiltered (fp, " condition $bpnum %s\n", tp->cond_string);
+
+ if (tp->ignore_count)
+ fprintf_unfiltered (fp, " ignore $bpnum %d\n", tp->ignore_count);
+
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, " commands\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");
+ }
+
+ if (tp->enable_state == bp_disabled)
+ fprintf_unfiltered (fp, "disable\n");
+
+ /* If this is a multi-location breakpoint, check if the locations
+ should be individually disabled. Watchpoint locations are
+ special, and not user visible. */
+ if (!is_watchpoint (tp) && tp->loc && tp->loc->next)
+ {
+ struct bp_location *loc;
+ int n = 1;
+
+ for (loc = tp->loc; loc != NULL; loc = loc->next, n++)
+ if (!loc->enabled)
+ fprintf_unfiltered (fp, "disable $bpnum.%d\n", n);
}
}
+
+ if (extra_trace_bits && *default_collect)
+ fprintf_unfiltered (fp, "set default-collect %s\n", default_collect);
+
do_cleanups (cleanup);
if (from_tty)
- printf_filtered (_("Tracepoints saved to file '%s'.\n"), args);
- return;
+ printf_filtered (_("Saved to file '%s'.\n"), filename);
+}
+
+/* The `save breakpoints' command. */
+
+static void
+save_breakpoints_command (char *args, int from_tty)
+{
+ save_breakpoints (args, from_tty, NULL);
+}
+
+/* The `save tracepoints' command. */
+
+static void
+save_tracepoints_command (char *args, int from_tty)
+{
+ save_breakpoints (args, from_tty, is_tracepoint);
}
/* Create a vector of all tracepoints. */
}
static void
-clear_syscall_counts (int pid)
+clear_syscall_counts (struct inferior *inf)
{
- struct inferior *inf = find_inferior_pid (pid);
-
inf->total_syscalls_count = 0;
inf->any_syscall_count = 0;
VEC_free (int, inf->syscalls_counts);
}
+static void
+save_command (char *arg, int from_tty)
+{
+ printf_unfiltered (_("\
+\"save\" must be followed by the name of a save subcommand.\n"));
+ help_list (save_cmdlist, "save ", -1, gdb_stdout);
+}
+
void
_initialize_breakpoint (void)
{
- static struct cmd_list_element *breakpoint_set_cmdlist;
- static struct cmd_list_element *breakpoint_show_cmdlist;
struct cmd_list_element *c;
observer_attach_solib_unloaded (disable_breakpoints_in_unloaded_shlib);
add_com_alias ("en", "enable", class_breakpoint, 1);
- add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command, _("\
+ add_prefix_cmd ("breakpoints", class_breakpoint, enable_command, _("\
Enable some breakpoints.\n\
Give breakpoint numbers (separated by spaces) as arguments.\n\
This is used to cancel the effect of the \"disable\" command.\n\
an expression is either read or written."));
set_cmd_completer (c, expression_completer);
- add_info ("watchpoints", breakpoints_info,
- _("Synonym for ``info breakpoints''."));
+ add_info ("watchpoints", watchpoints_info, _("\
+Status of watchpoints, or watchpoint number NUMBER."));
+
/* XXX: cagney/2005-02-23: This should be a boolean, and should
Do \"help tracepoints\" for info on other tracepoint commands."));
set_cmd_completer (c, location_completer);
+ c = add_com ("strace", class_breakpoint, strace_command, _("\
+Set a static tracepoint at specified line, function or marker.\n\
+\n\
+strace [LOCATION] [if CONDITION]\n\
+LOCATION may be a line number, function name, \"*\" and an address,\n\
+or -m MARKER_ID.\n\
+If a line number is specified, probe the marker at start of code\n\
+for that line. If a function is specified, probe the marker at start\n\
+of code for that function. If an address is specified, probe the marker\n\
+at that exact address. If a marker id is specified, probe the marker\n\
+with that name. With no LOCATION, uses current execution address of\n\
+the selected stack frame.\n\
+Static tracepoints accept an extra collect action -- ``collect $_sdata''.\n\
+This collects arbitrary user data passed in the probe point call to the\n\
+tracing library. You can inspect it when analyzing the trace buffer,\n\
+by printing the $_sdata variable like any other convenience variable.\n\
+\n\
+CONDITION is a boolean expression.\n\
+\n\
+Multiple tracepoints at one place are permitted, and useful if conditional.\n\
+\n\
+Do \"help breakpoints\" for info on other commands dealing with breakpoints.\n\
+Do \"help tracepoints\" for info on other tracepoint commands."));
+ set_cmd_completer (c, location_completer);
+
add_info ("tracepoints", tracepoints_info, _("\
Status of tracepoints, or tracepoint number NUMBER.\n\
Convenience variable \"$tpnum\" contains the number of the\n\
Usage: passcount COUNT TPNUM, where TPNUM may also be \"all\";\n\
if TPNUM is omitted, passcount refers to the last tracepoint defined."));
- c = add_com ("save-tracepoints", class_trace, tracepoint_save_command, _("\
+ add_prefix_cmd ("save", class_breakpoint, save_command,
+ _("Save breakpoint definitions as a script."),
+ &save_cmdlist, "save ",
+ 0/*allow-unknown*/, &cmdlist);
+
+ c = add_cmd ("breakpoints", class_breakpoint, save_breakpoints_command, _("\
+Save current breakpoint definitions as a script.\n\
+This includes all types of breakpoints (breakpoints, watchpoints,\n\
+catchpoints, tracepoints). Use the 'source' command in another debug\n\
+session to restore them."),
+ &save_cmdlist);
+ set_cmd_completer (c, filename_completer);
+
+ c = add_cmd ("tracepoints", class_trace, save_tracepoints_command, _("\
Save current tracepoint definitions as a script.\n\
-Use the 'source' command in another debug session to restore them."));
+Use the 'source' command in another debug session to restore them."),
+ &save_cmdlist);
set_cmd_completer (c, filename_completer);
+ c = add_com_alias ("save-tracepoints", "save tracepoints", class_trace, 0);
+ deprecate_cmd (c, "save tracepoints");
+
add_prefix_cmd ("breakpoint", class_maintenance, set_breakpoint_cmd, _("\
Breakpoint specific settings\n\
Configure various breakpoint-specific variables such as\n\