Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009 Free Software Foundation, Inc.
+ 2008, 2009, 2010 Free Software Foundation, Inc.
This file is part of GDB.
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 int get_number_trailer (char **, int);
-void set_breakpoint_count (int);
-
typedef enum
{
mark_inserted,
static char *ep_parse_optional_if_clause (char **arg);
-static char *ep_parse_optional_filename (char **arg);
-
static void catch_exception_command_1 (enum exception_event_kind ex_event,
char *arg, int tempflag, int from_tty);
static int is_hardware_watchpoint (struct breakpoint *bpt);
+static int is_watchpoint (struct breakpoint *bpt);
+
static void insert_breakpoint_locations (void);
static int syscall_catchpoint_p (struct breakpoint *b);
#define ALL_TRACEPOINTS(B) \
for (B = breakpoint_chain; B; B = B->next) \
- if ((B)->type == bp_tracepoint)
+ if (tracepoint_type (B))
/* Chains of all breakpoints defined. */
/* Number of last breakpoint made. */
-int breakpoint_count;
+static int breakpoint_count;
+
+/* If the last command to create a breakpoint created multiple
+ breakpoints, this holds the start and end breakpoint numbers. */
+static int multi_start;
+static int multi_end;
+/* True if the last breakpoint set was part of a group set with a
+ single command, e.g., "rbreak". */
+static int last_was_multi;
/* Number of last tracepoint made. */
-int tracepoint_count;
+static int tracepoint_count;
/* Return whether a breakpoint is an active enabled breakpoint. */
static int
/* Set breakpoint count to NUM. */
-void
+static void
set_breakpoint_count (int num)
{
breakpoint_count = num;
+ last_was_multi = 0;
set_internalvar_integer (lookup_internalvar ("bpnum"), num);
}
+/* Called at the start an "rbreak" command to record the first
+ breakpoint made. */
+void
+start_rbreak_breakpoints (void)
+{
+ multi_start = breakpoint_count + 1;
+}
+
+/* Called at the end of an "rbreak" command to record the last
+ breakpoint made. */
+void
+end_rbreak_breakpoints (void)
+{
+ if (breakpoint_count >= multi_start)
+ {
+ multi_end = breakpoint_count;
+ last_was_multi = 1;
+ }
+}
+
/* Used in run_command to zero the hit count when a new run starts. */
void
b->hit_count = 0;
}
+/* Encapsulate tests for different types of tracepoints. */
+
+static int
+tracepoint_type (const struct breakpoint *b)
+{
+ return (b->type == bp_tracepoint || b->type == bp_fast_tracepoint);
+}
+
+/* Allocate a new counted_command_line with reference count of 1.
+ The new structure owns COMMANDS. */
+
+static struct counted_command_line *
+alloc_counted_command_line (struct command_line *commands)
+{
+ struct counted_command_line *result
+ = xmalloc (sizeof (struct counted_command_line));
+ result->refc = 1;
+ result->commands = commands;
+ return result;
+}
+
+/* Increment reference count. This does nothing if CMD is NULL. */
+
+static void
+incref_counted_command_line (struct counted_command_line *cmd)
+{
+ if (cmd)
+ ++cmd->refc;
+}
+
+/* Decrement reference count. If the reference count reaches 0,
+ destroy the counted_command_line. Sets *CMDP to NULL. This does
+ nothing if *CMDP is NULL. */
+
+static void
+decref_counted_command_line (struct counted_command_line **cmdp)
+{
+ if (*cmdp)
+ {
+ if (--(*cmdp)->refc == 0)
+ {
+ free_command_lines (&(*cmdp)->commands);
+ xfree (*cmdp);
+ }
+ *cmdp = NULL;
+ }
+}
+
+/* A cleanup function that calls decref_counted_command_line. */
+
+static void
+do_cleanup_counted_command_line (void *arg)
+{
+ decref_counted_command_line (arg);
+}
+
+/* Create a cleanup that calls decref_counted_command_line on the
+ argument. */
+
+static struct cleanup *
+make_cleanup_decref_counted_command_line (struct counted_command_line **cmdp)
+{
+ return make_cleanup (do_cleanup_counted_command_line, cmdp);
+}
+
/* Default address, symtab and line to put a breakpoint at
for "break" command with no arg.
if default_breakpoint_valid is zero, the other three are
struct bp_location *loc = b->loc;
for (; loc; loc = loc->next)
{
- if (loc->cond)
- {
- xfree (loc->cond);
- loc->cond = 0;
- }
+ xfree (loc->cond);
+ loc->cond = NULL;
}
- if (b->cond_string != NULL)
- xfree (b->cond_string);
+ xfree (b->cond_string);
+ b->cond_string = NULL;
+ xfree (b->cond_exp);
+ b->cond_exp = NULL;
if (*p == 0)
{
- b->cond_string = NULL;
if (from_tty)
printf_filtered (_("Breakpoint %d now unconditional.\n"), bnum);
}
typed in or the decompiled expression. */
b->cond_string = xstrdup (arg);
b->condition_not_parsed = 0;
- for (loc = b->loc; loc; loc = loc->next)
+
+ if (is_watchpoint (b))
{
+ innermost_block = NULL;
arg = p;
- loc->cond =
- parse_exp_1 (&arg, block_for_pc (loc->address), 0);
+ 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 = p;
+ loc->cond =
+ parse_exp_1 (&arg, block_for_pc (loc->address), 0);
+ if (*arg)
+ error (_("Junk at end of expression"));
+ }
}
}
breakpoints_changed ();
error (_("No breakpoint number %d."), bnum);
}
-/* Set the command list of B to COMMANDS. */
+/* Check that COMMAND do not contain commands that are suitable
+ only for tracepoints and not suitable for ordinary breakpoints.
+ Throw if any such commands is found.
+*/
+static void
+check_no_tracepoint_commands (struct command_line *commands)
+{
+ struct command_line *c;
+ for (c = commands; c; c = c->next)
+ {
+ int i;
+
+ if (c->control_type == while_stepping_control)
+ error (_("The 'while-stepping' command can only be used for tracepoints"));
+
+ for (i = 0; i < c->body_count; ++i)
+ check_no_tracepoint_commands ((c->body_list)[i]);
+
+ /* Not that command parsing removes leading whitespace and comment
+ lines and also empty lines. So, we only need to check for
+ command directly. */
+ if (strstr (c->line, "collect ") == c->line)
+ error (_("The 'collect' command can only be used for tracepoints"));
+
+ if (strstr (c->line, "teval ") == c->line)
+ error (_("The 'teval' command can only be used for tracepoints"));
+ }
+}
+
+int
+breakpoint_is_tracepoint (const struct breakpoint *b)
+{
+ switch (b->type)
+ {
+ case bp_tracepoint:
+ case bp_fast_tracepoint:
+ return 1;
+ default:
+ return 0;
+
+ }
+}
+
+/* A helper function that validsates that COMMANDS are valid for a
+ breakpoint. This function will throw an exception if a problem is
+ found. */
+
+static void
+validate_commands_for_breakpoint (struct breakpoint *b,
+ struct command_line *commands)
+{
+ if (breakpoint_is_tracepoint (b))
+ {
+ /* We need to verify that each top-level element of commands
+ is valid for tracepoints, that there's at most one while-stepping
+ element, and that while-stepping's body has valid tracing commands
+ excluding nested while-stepping. */
+ struct command_line *c;
+ struct command_line *while_stepping = 0;
+ for (c = commands; c; c = c->next)
+ {
+ char *l = c->line;
+ if (c->control_type == while_stepping_control)
+ {
+ if (b->type == bp_fast_tracepoint)
+ error (_("The 'while-stepping' command cannot be used for fast tracepoint"));
+
+ if (while_stepping)
+ error (_("The 'while-stepping' command can be used only once"));
+ else
+ while_stepping = c;
+ }
+ }
+ if (while_stepping)
+ {
+ struct command_line *c2;
+
+ gdb_assert (while_stepping->body_count == 1);
+ c2 = while_stepping->body_list[0];
+ for (; c2; c2 = c2->next)
+ {
+ char *l = c2->line;
+ if (c2->control_type == while_stepping_control)
+ error (_("The 'while-stepping' command cannot be nested"));
+ }
+ }
+ }
+ else
+ {
+ check_no_tracepoint_commands (commands);
+ }
+}
+
+/* Set the command list of B to COMMANDS. If breakpoint is tracepoint,
+ validate that only allowed commands are included.
+*/
void
breakpoint_set_commands (struct breakpoint *b, struct command_line *commands)
{
- free_command_lines (&b->commands);
- b->commands = commands;
+ validate_commands_for_breakpoint (b, commands);
+
+ decref_counted_command_line (&b->commands);
+ b->commands = alloc_counted_command_line (commands);
breakpoints_changed ();
observer_notify_breakpoint_modified (b->number);
}
+void
+check_tracepoint_command (char *line, void *closure)
+{
+ struct breakpoint *b = closure;
+ validate_actionline (&line, b);
+}
+
+/* A structure used to pass information through
+ map_breakpoint_numbers. */
+
+struct commands_info
+{
+ /* True if the command was typed at a tty. */
+ int from_tty;
+ /* Non-NULL if the body of the commands are being read from this
+ already-parsed command. */
+ struct command_line *control;
+ /* The command lines read from the user, or NULL if they have not
+ yet been read. */
+ struct counted_command_line *cmd;
+};
+
+/* A callback for map_breakpoint_numbers that sets the commands for
+ commands_command. */
+
static void
-commands_command (char *arg, int from_tty)
+do_map_commands_command (struct breakpoint *b, void *data)
{
- struct breakpoint *b;
- char *p;
- int bnum;
- struct command_line *l;
+ struct commands_info *info = data;
- /* If we allowed this, we would have problems with when to
- free the storage, if we change the commands currently
- being read from. */
+ if (info->cmd == NULL)
+ {
+ struct command_line *l;
- if (executing_breakpoint_commands)
- error (_("Can't use the \"commands\" command among a breakpoint's commands."));
+ if (info->control != NULL)
+ l = copy_command_lines (info->control->body_list[0]);
+ else
- p = arg;
- bnum = get_number (&p);
+ l = read_command_lines (_("Type commands for all specified breakpoints"),
+ info->from_tty, 1,
+ (breakpoint_is_tracepoint (b)
+ ? check_tracepoint_command : 0),
+ b);
- if (p && *p)
- error (_("Unexpected extra arguments following breakpoint number."));
+ info->cmd = alloc_counted_command_line (l);
+ }
- 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;
+ /* 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 (last_was_multi)
+ arg = xstrprintf ("%d-%d", multi_start, multi_end);
+ else if (breakpoint_count > 0)
+ arg = xstrprintf ("%d", breakpoint_count);
+ make_cleanup (xfree, arg);
+ }
+
+ map_breakpoint_numbers (arg, do_map_commands_command, &info);
+
+ if (info.cmd == NULL)
+ error (_("No breakpoints specified."));
+
+ do_cleanups (cleanups);
+}
+
+static void
+commands_command (char *arg, int from_tty)
+{
+ commands_command_1 (arg, from_tty, NULL);
}
/* Like commands_command, but instead of reading the commands from
enum command_control_type
commands_from_control_command (char *arg, struct command_line *cmd)
{
- struct breakpoint *b;
- char *p;
- int bnum;
-
- /* If we allowed this, we would have problems with when to
- free the storage, if we change the commands currently
- being read from. */
-
- if (executing_breakpoint_commands)
- error (_("Can't use the \"commands\" command among a breakpoint's commands."));
-
- /* An empty string for the breakpoint number means the last
- breakpoint, but get_number expects a NULL pointer. */
- if (arg && !*arg)
- p = NULL;
- else
- p = arg;
- bnum = get_number (&p);
-
- if (p && *p)
- error (_("Unexpected extra arguments following breakpoint number."));
-
- ALL_BREAKPOINTS (b)
- if (b->number == bnum)
- {
- free_command_lines (&b->commands);
- if (cmd->body_count != 1)
- error (_("Invalid \"commands\" block structure."));
- /* We need to copy the commands because if/while will free the
- list after it finishes execution. */
- b->commands = copy_command_lines (cmd->body_list[0]);
- breakpoints_changed ();
- observer_notify_breakpoint_modified (b->number);
- return simple_control;
- }
- error (_("No breakpoint number %d."), bnum);
+ commands_command_1 (arg, 0, cmd);
+ return simple_control;
}
/* Return non-zero if BL->TARGET_INFO contains valid information. */
b->ops->insert (b);
}
+/* Return true if BPT is of any hardware watchpoint kind. */
+
static int
is_hardware_watchpoint (struct breakpoint *bpt)
{
|| bpt->type == bp_access_watchpoint);
}
+/* Return true if BPT is of any watchpoint kind, hardware or
+ software. */
+
+static int
+is_watchpoint (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
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
{
int i, mem_cnt, other_type_used;
+ /* We need to determine how many resources are already used
+ for all other hardware watchpoints to see if we still have
+ enough resources to also fit this watchpoint in as well.
+ To avoid the hw_watchpoint_used_count call below from counting
+ this watchpoint, make sure that it is marked as a software
+ watchpoint. */
+ b->type = bp_watchpoint;
i = hw_watchpoint_used_count (bp_hardware_watchpoint,
&other_type_used);
mem_cnt = can_use_hardware_watchpoint (val_chain);
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)
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;
}
/* Tracepoints are inserted by the target at a time of its choosing,
not by us. */
- if (bpt->owner->type == bp_tracepoint)
+ if (tracepoint_type (bpt->owner))
return 0;
return 1;
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)
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
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;
return 0;
}
+int
+hardware_watchpoint_inserted_in_range (struct address_space *aspace,
+ CORE_ADDR addr, ULONGEST len)
+{
+ struct breakpoint *bpt;
+
+ ALL_BREAKPOINTS (bpt)
+ {
+ struct bp_location *loc;
+
+ if (bpt->type != bp_hardware_watchpoint
+ && bpt->type != bp_access_watchpoint)
+ continue;
+
+ if (!breakpoint_enabled (bpt))
+ continue;
+
+ for (loc = bpt->loc; loc; loc = loc->next)
+ if (loc->pspace->aspace == aspace && loc->inserted)
+ {
+ CORE_ADDR l, h;
+
+ /* Check for intersection. */
+ l = max (loc->address, addr);
+ h = min (loc->address + loc->length, addr + len);
+ if (l < h)
+ return 1;
+ }
+ }
+ return 0;
+}
+
/* breakpoint_thread_match (PC, PTID) returns true if the breakpoint at
PC is valid for process/thread PTID. */
{
if (bs->old_val != NULL)
value_free (bs->old_val);
- free_command_lines (&bs->commands);
+ decref_counted_command_line (&bs->commands);
xfree (bs);
}
{
tmp = (bpstat) xmalloc (sizeof (*tmp));
memcpy (tmp, bs, sizeof (*tmp));
- if (bs->commands != NULL)
- tmp->commands = copy_command_lines (bs->commands);
+ incref_counted_command_line (tmp->commands);
if (bs->old_val != NULL)
{
tmp->old_val = value_copy (bs->old_val);
{
for (; bs != NULL; bs = bs->next)
{
- free_command_lines (&bs->commands);
+ decref_counted_command_line (&bs->commands);
if (bs->old_val != NULL)
{
value_free (bs->old_val);
breakpoint_proceeded = 0;
for (; bs != NULL; bs = bs->next)
{
+ struct counted_command_line *ccmd;
struct command_line *cmd;
struct cleanup *this_cmd_tree_chain;
commands are only executed once, we don't need to copy it; we
can clear the pointer in the bpstat, and make sure we free
the tree when we're done. */
- cmd = bs->commands;
- bs->commands = 0;
- this_cmd_tree_chain = make_cleanup_free_command_lines (&cmd);
+ ccmd = bs->commands;
+ bs->commands = NULL;
+ this_cmd_tree_chain
+ = make_cleanup_decref_counted_command_line (&ccmd);
+ cmd = bs->commands_left;
+ bs->commands_left = NULL;
while (cmd != NULL)
{
result = PRINT_NOTHING;
break;
+ case bp_std_terminate_master:
+ /* These should never be enabled. */
+ printf_filtered (_("std::terminate Master Breakpoint: gdb should not stop!\n"));
+ result = PRINT_NOTHING;
+ break;
+
case bp_watchpoint:
case bp_hardware_watchpoint:
annotate_watchpoint (b->number);
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
+ case bp_std_terminate:
case bp_tracepoint:
+ case bp_fast_tracepoint:
case bp_jit_event:
default:
result = PRINT_UNKNOWN;
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;
#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
-/* Check watchpoint condition. */
+/* Evaluate watchpoint condition expression and check if its value changed.
+
+ P should be a pointer to struct bpstat, but is defined as a void *
+ in order for this function to be usable with catch_errors. */
static int
watchpoint_check (void *p)
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;
struct gdbarch *frame_arch = get_frame_arch (frame);
CORE_ADDR frame_pc = get_frame_pc (frame);
+ /* in_function_epilogue_p() returns a non-zero value if we're still
+ in the function but the stack frame has already been invalidated.
+ Since we can't rely on the values of local variables after the
+ stack has been destroyed, we are treating the watchpoint in that
+ state as `not changed' without further checking. Don't mark
+ watchpoints as changed if the current frame is in an epilogue -
+ 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_IGNORE;
+
fr = frame_find_by_id (b->watchpoint_frame);
within_current_scope = (fr != NULL);
|| !contained_in (b->exp_valid_block,
SYMBOL_BLOCK_VALUE (function)))
within_current_scope = 0;
- }
-
- /* in_function_epilogue_p() returns a non-zero value if we're still
- in the function but the stack frame has already been invalidated.
- Since we can't rely on the values of local variables after the
- stack has been destroyed, we are treating the watchpoint in that
- state as `not changed' without further checking. Don't mark
- watchpoints as changed if the current frame is in an epilogue -
- even if they are in some other frame, our view of the stack
- is likely to be wrong. */
- if (gdbarch_in_function_epilogue_p (frame_arch, frame_pc))
- return WP_VALUE_NOT_CHANGED;
+ }
if (within_current_scope)
/* If we end up stopping, the current frame will get selected
struct value *new_val;
fetch_watchpoint_value (b->exp, &new_val, NULL, NULL);
+
+ /* We use value_equal_contents instead of value_equal because the latter
+ coerces an array to a pointer, thus comparing just the address of the
+ array instead of its contents. This is not what we want. */
if ((b->val != NULL) != (new_val != NULL)
- || (b->val != NULL && !value_equal (b->val, new_val)))
+ || (b->val != NULL && !value_equal_contents (b->val, new_val)))
{
if (new_val != 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;
+ /* By definition, the inferior does not report stops at
+ tracepoints. */
+ if (tracepoint_type (b))
+ return 0;
+
if (b->type != bp_watchpoint
&& b->type != bp_hardware_watchpoint
&& b->type != bp_read_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:
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;
}
/* Pointer to the last thing in the chain currently. */
bpstat bs = root_bs;
int ix;
- int need_remove_insert, update_locations = 0;
+ int need_remove_insert;
- ALL_BP_LOCATIONS (bl, blp_tmp)
- {
- b = bl->owner;
- gdb_assert (b);
- if (!breakpoint_enabled (b) && b->enable_state != bp_permanent)
- continue;
+ /* ALL_BP_LOCATIONS iteration would break across
+ update_global_location_list possibly executed by
+ bpstat_check_breakpoint_conditions's inferior call. */
- /* 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
- already. */
- if (b->type == bp_hardware_watchpoint && bl != b->loc)
- continue;
+ ALL_BREAKPOINTS (b)
+ {
+ if (!breakpoint_enabled (b) && b->enable_state != bp_permanent)
+ continue;
- if (!bpstat_check_location (bl, aspace, bp_addr))
- continue;
+ 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
+ already. */
+ if (b->type == bp_hardware_watchpoint && bl != b->loc)
+ break;
- /* Come here if it's a watchpoint, or if the break address matches */
+ if (bl->shlib_disabled)
+ continue;
- bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */
+ if (!bpstat_check_location (bl, aspace, bp_addr))
+ continue;
- /* Assume we stop. Should we find watchpoint that is not actually
- triggered, or if condition of breakpoint is false, we'll reset
- 'stop' to 0. */
- bs->stop = 1;
- bs->print = 1;
+ /* Come here if it's a watchpoint, or if the break address matches */
- bpstat_check_watchpoint (bs);
- if (!bs->stop)
- continue;
+ bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */
- if (b->type == bp_thread_event || b->type == bp_overlay_event
- || b->type == bp_longjmp_master)
- /* We do not stop for these. */
- bs->stop = 0;
- else
- bpstat_check_breakpoint_conditions (bs, ptid);
-
- if (bs->stop)
- {
- if (b->enable_state != bp_disabled)
- ++(b->hit_count);
+ /* Assume we stop. Should we find watchpoint that is not actually
+ triggered, or if condition of breakpoint is false, we'll reset
+ 'stop' to 0. */
+ bs->stop = 1;
+ bs->print = 1;
- /* We will stop here */
- if (b->disposition == disp_disable)
- {
- if (b->enable_state != bp_permanent)
- b->enable_state = bp_disabled;
- update_locations = 1;
- }
- 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)))
- {
- bs->commands = bs->commands->next;
- bs->print = 0;
- }
- bs->commands = copy_command_lines (bs->commands);
- }
+ bpstat_check_watchpoint (bs);
+ if (!bs->stop)
+ continue;
- /* Print nothing for this entry if we dont stop or if we dont print. */
- if (bs->stop == 0 || bs->print == 0)
- bs->print_it = print_it_noop;
- }
+ if (b->type == bp_thread_event || b->type == bp_overlay_event
+ || b->type == bp_longjmp_master
+ || b->type == bp_std_terminate_master)
+ /* We do not stop for these. */
+ bs->stop = 0;
+ else
+ bpstat_check_breakpoint_conditions (bs, ptid);
+
+ if (bs->stop)
+ {
+ ++(b->hit_count);
- /* Delay this call which would break the ALL_BP_LOCATIONS iteration above. */
- if (update_locations)
- update_global_location_list (0);
+ /* We will stop here */
+ if (b->disposition == disp_disable)
+ {
+ if (b->enable_state != bp_permanent)
+ b->enable_state = bp_disabled;
+ update_global_location_list (0);
+ }
+ if (b->silent)
+ bs->print = 0;
+ bs->commands = b->commands;
+ 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_left = bs->commands_left->next;
+ bs->print = 0;
+ }
+ }
+
+ /* Print nothing for this entry if we dont stop or dont print. */
+ if (bs->stop == 0 || bs->print == 0)
+ bs->print_it = print_it_noop;
+ }
+ }
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
{
}
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
enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING;
struct bpstat_what retval;
- retval.call_dummy = 0;
+ retval.call_dummy = STOP_NONE;
for (; bs != NULL; bs = bs->next)
{
enum class bs_class = no_effect;
case bp_thread_event:
case bp_overlay_event:
case bp_longjmp_master:
+ case bp_std_terminate_master:
bs_class = bp_nostop;
break;
case bp_catchpoint:
/* Make sure the action is stop (silent or noisy),
so infrun.c pops the dummy frame. */
bs_class = bp_silent;
- retval.call_dummy = 1;
+ retval.call_dummy = STOP_STACK_DUMMY;
+ break;
+ case bp_std_terminate:
+ /* Make sure the action is stop (silent or noisy),
+ so infrun.c pops the dummy frame. */
+ bs_class = bp_silent;
+ retval.call_dummy = STOP_STD_TERMINATE;
break;
case bp_tracepoint:
+ case bp_fast_tracepoint:
/* 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: bp_tracepoint encountered"));
+ _("bpstat_what: tracepoint encountered"));
break;
}
current_action = table[(int) bs_class][(int) current_action];
\f
+/* Print the LOC location out of the list of B->LOC locations. */
+
static void print_breakpoint_location (struct breakpoint *b,
struct bp_location *loc,
char *wrap_indent,
{
struct cleanup *old_chain = save_current_program_space ();
+ if (loc != NULL && loc->shlib_disabled)
+ loc = NULL;
+
if (loc != NULL)
set_current_program_space (loc->pspace);
- if (b->source_file)
+ if (b->source_file && loc)
{
struct symbol *sym
= find_pc_sect_function (loc->address, loc->section);
ui_out_field_int (uiout, "line", b->line_number);
}
- else if (!b->loc)
- {
- ui_out_field_string (uiout, "pending", b->addr_string);
- }
- else
+ else if (loc)
{
- print_address_symbolic (loc->address, stb->stream, demangle, "");
+ print_address_symbolic (loc->gdbarch, loc->address, stb->stream,
+ demangle, "");
ui_out_field_stream (uiout, "at", stb);
}
+ else
+ ui_out_field_string (uiout, "pending", b->addr_string);
do_cleanups (old_chain);
}
{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_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_jit_event:
if (opts.addressprint)
{
because the condition is an internal implementation detail
that we do not want to expose to the user. */
annotate_field (7);
- if (b->type == bp_tracepoint)
+ if (tracepoint_type (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;
}
return (b->type == bp_breakpoint
|| b->type == bp_catchpoint
|| b->type == bp_hardware_breakpoint
- || b->type == bp_tracepoint
+ || tracepoint_type (b)
|| b->type == bp_watchpoint
|| b->type == bp_read_watchpoint
|| b->type == bp_access_watchpoint
annotate_breakpoints_table ();
ALL_BREAKPOINTS (b)
+ {
+ QUIT;
if (bnum == -1
|| bnum == b->number)
{
if (allflag || user_settable_breakpoint (b))
print_one_breakpoint (b, &last_loc, print_address_bits, allflag);
}
+ }
do_cleanups (bkpttbl_chain);
static int
watchpoint_locations_match (struct bp_location *loc1, struct bp_location *loc2)
{
+ /* 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
switch (bpt->type)
{
case bp_breakpoint:
- case bp_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:
loc->loc_type = bp_loc_other;
break;
default:
{
if (loc->owner->type == bp_breakpoint
|| loc->owner->type == bp_hardware_breakpoint
- || loc->owner->type == bp_tracepoint)
+ || tracepoint_type (loc->owner))
{
find_pc_partial_function (loc->address, &(loc->function_name),
NULL, NULL);
}
}
+/* Set an active std::terminate breakpoint for each std::terminate
+ master breakpoint. */
+void
+set_std_terminate_breakpoint (void)
+{
+ struct breakpoint *b, *temp;
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ if (b->pspace == current_program_space
+ && b->type == bp_std_terminate_master)
+ {
+ struct breakpoint *clone = clone_momentary_breakpoint (b);
+ clone->type = bp_std_terminate;
+ }
+}
+
+/* Delete all the std::terminate breakpoints. */
+void
+delete_std_terminate_breakpoint (void)
+{
+ struct breakpoint *b, *temp;
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ if (b->type == bp_std_terminate)
+ delete_breakpoint (b);
+}
+
struct breakpoint *
create_thread_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
{
all breakpoints. If we don't set shlib_disabled here, we'll try
to insert those breakpoints and fail. */
if (((b->type == bp_breakpoint)
+ || (b->type == bp_jit_event)
|| (b->type == bp_hardware_breakpoint)
- || (b->type == bp_tracepoint))
+ || (tracepoint_type (b)))
&& loc->pspace == current_program_space
&& !loc->shlib_disabled
#ifdef PC_SOLIB
|| 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 (_(" %d"), b->number);
say_where = 1;
break;
+ case bp_fast_tracepoint:
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ say_where = 0;
+ break;
+ }
+ printf_filtered (_("Fast 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;
if (expanded.nelts == 1)
{
- /* We had one sal, we got one sal. Without futher
- processing, just return the original sal. */
+ /* We had one sal, we got one sal. Return that sal, adjusting it
+ past the function prologue if necessary. */
xfree (expanded.sals);
expanded.nelts = 1;
expanded.sals = xmalloc (sizeof (struct symtab_and_line));
sal.pc = original_pc;
expanded.sals[0] = sal;
+ skip_prologue_sal (&expanded.sals[0]);
do_cleanups (old_chain);
return expanded;
}
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);
}
}
resolve_sal_pc (&sals->sals[i]);
}
+/* Fast tracepoints may have restrictions on valid locations. For
+ instance, a fast tracepoint using a jump instead of a trap will
+ likely have to overwrite more bytes than a trap would, and so can
+ only be placed where the instruction is longer than the jump, or a
+ multi-instruction sequence does not have a jump into the middle of
+ it, etc. */
+
+static void
+check_fast_tracepoint_sals (struct gdbarch *gdbarch,
+ struct symtabs_and_lines *sals)
+{
+ int i, rslt;
+ struct symtab_and_line *sal;
+ char *msg;
+ struct cleanup *old_chain;
+
+ for (i = 0; i < sals->nelts; i++)
+ {
+ sal = &sals->sals[i];
+
+ rslt = gdbarch_fast_tracepoint_valid_at (gdbarch, sal->pc,
+ NULL, &msg);
+ old_chain = make_cleanup (xfree, msg);
+
+ if (!rslt)
+ error (_("May not have a fast tracepoint at 0x%s%s"),
+ paddress (gdbarch, sal->pc), (msg ? msg : ""));
+
+ do_cleanups (old_chain);
+ }
+}
+
static void
do_captured_parse_breakpoint (struct ui_out *ui, void *data)
{
if (tok == tmptok)
error (_("Junk after task keyword."));
if (!valid_task_id (*task))
- error (_("Unknown task %d\n"), *task);
+ error (_("Unknown task %d."), *task);
}
else
error (_("Junk at end of arguments."));
}
}
-/* 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. */
+/* 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. */
-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)
+int
+create_breakpoint (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)
{
struct gdb_exception e;
struct symtabs_and_lines sals;
int not_found = 0;
enum bptype type_wanted;
int task = 0;
+ int first_bp_set = breakpoint_count + 1;
sals.sals = NULL;
sals.nelts = 0;
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;
}
/* Create a chain of things that always need to be cleaned up. */
breakpoint_sals_to_pc (&sals, addr_start);
type_wanted = (traceflag
- ? bp_tracepoint
+ ? (hardwareflag ? bp_fast_tracepoint : bp_tracepoint)
: (hardwareflag ? bp_hardware_breakpoint : bp_breakpoint));
+ /* Fast tracepoints may have additional restrictions on location. */
+ if (type_wanted == bp_fast_tracepoint)
+ check_fast_tracepoint_sals (gdbarch, &sals);
+
/* Verify that condition can be parsed, before setting any
breakpoints. Allocate a separate condition expression for each
breakpoint. */
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);
+ 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
{
}
if (sals.nelts > 1)
- warning (_("Multiple breakpoints were set.\n"
- "Use the \"delete\" command to delete unwanted breakpoints."));
+ {
+ warning (_("Multiple breakpoints were set.\n"
+ "Use the \"delete\" command to delete unwanted breakpoints."));
+ multi_start = first_bp_set;
+ multi_end = breakpoint_count;
+ last_was_multi = 1;
+ }
+
/* That's it. Discard the cleanups for data inserted into the
breakpoint. */
discard_cleanups (bkpt_chain);
/* error call may happen here - have BKPT_CHAIN already discarded. */
update_global_location_list (1);
+
+ return 1;
}
/* Set a breakpoint.
int hardwareflag = flag & BP_HARDWAREFLAG;
int tempflag = flag & BP_TEMPFLAG;
- 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 */);
+ create_breakpoint (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);
-}
/* Adjust SAL to the first instruction past the function prologue.
The end of the prologue is determined using the line table from
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;
{
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;
return cond_string;
}
-/* This function attempts to parse an optional filename from the arg
- string. If one is not found, it returns NULL.
-
- Else, it returns a pointer to the parsed filename. (This function
- makes no attempt to verify that a file of that name exists, or is
- accessible.) And, it updates arg to point to the first character
- following the parsed filename in the arg string.
-
- Note that clients needing to preserve the returned filename for
- future access should copy it to their own buffers. */
-static char *
-ep_parse_optional_filename (char **arg)
-{
- static char filename[1024];
- char *arg_p = *arg;
- int i;
- char c;
-
- if ((*arg_p == '\0') || isspace (*arg_p))
- return NULL;
-
- for (i = 0;; i++)
- {
- c = *arg_p;
- if (isspace (c))
- c = '\0';
- filename[i] = c;
- if (c == '\0')
- break;
- arg_p++;
- }
- *arg = arg_p;
-
- return filename;
-}
-
/* Commands to deal with catching events, such as signals, exceptions,
process start/exit, etc. */
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, 0, 0,
+ 0,
+ AUTO_BOOLEAN_TRUE /* pending */,
+ &gnu_v3_exception_catchpoint_ops, from_tty,
+ 1 /* enabled */);
return 1;
}
/* 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;
|| b->enable_state == bp_startup_disabled
|| !loc->enabled
|| loc->shlib_disabled
- || !breakpoint_address_is_meaningful (b))
+ || !breakpoint_address_is_meaningful (b)
+ || tracepoint_type (b))
continue;
/* Permanent breakpoint should always be inserted. */
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. */
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
case bp_breakpoint:
case bp_hardware_breakpoint:
case bp_tracepoint:
+ case bp_fast_tracepoint:
/* Do not attempt to re-set breakpoints disabled during startup. */
if (b->enable_state == bp_startup_disabled)
return 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:
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)
{
continue;
case bp_breakpoint:
case bp_tracepoint:
+ case bp_fast_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 (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. */
continue;
case bp_breakpoint:
case bp_tracepoint:
+ case bp_fast_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
{
}
+/* Invalidate last known value of any hardware watchpoint if
+ the memory which that value represents has been written to by
+ GDB itself. */
+
+static void
+invalidate_bp_value_on_memory_change (CORE_ADDR addr, int len,
+ const bfd_byte *data)
+{
+ struct breakpoint *bp;
+
+ ALL_BREAKPOINTS (bp)
+ if (bp->enable_state == bp_enabled
+ && bp->type == bp_hardware_watchpoint
+ && bp->val_valid && bp->val)
+ {
+ struct bp_location *loc;
+
+ for (loc = bp->loc; loc != NULL; loc = loc->next)
+ if (loc->loc_type == bp_loc_hardware_watchpoint
+ && loc->address + loc->length > addr
+ && addr + len > loc->address)
+ {
+ value_free (bp->val);
+ bp->val = NULL;
+ bp->val_valid = 0;
+ }
+ }
+}
+
/* Use default_breakpoint_'s, or nothing if they aren't valid. */
struct symtabs_and_lines
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 */, 0 /* hardwareflag */,
+ 1 /* traceflag */,
+ 0 /* Ignore count */,
+ pending_break_support,
+ NULL,
+ from_tty,
+ 1 /* enabled */))
+ set_tracepoint_count (breakpoint_count);
}
+void
+ftrace_command (char *arg, int from_tty)
+{
+ if (create_breakpoint (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);
+}
+
+/* Given information about a tracepoint as recorded on a target (which
+ can be either a live system or a trace file), attempt to create an
+ equivalent GDB tracepoint. This is not a reliable process, since
+ the target does not necessarily have all the information used when
+ the tracepoint was originally defined. */
+
+struct breakpoint *
+create_tracepoint_from_upload (struct uploaded_tp *utp)
+{
+ char buf[100];
+ struct breakpoint *tp;
+
+ /* In the absence of a source location, fall back to raw address. */
+ sprintf (buf, "*%s", paddress (get_current_arch(), utp->addr));
+
+ if (!create_breakpoint (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 */))
+ return NULL;
+
+ set_tracepoint_count (breakpoint_count);
+
+ tp = get_tracepoint (tracepoint_count);
+ gdb_assert (tp != NULL);
+
+ if (utp->pass > 0)
+ {
+ sprintf (buf, "%d %d", utp->pass, tp->number);
+
+ trace_pass_command (buf, 0);
+ }
+
+ if (utp->cond)
+ {
+ printf_filtered ("Want to restore a condition\n");
+ }
+
+ if (utp->numactions > 0)
+ {
+ printf_filtered ("Want to restore action list\n");
+ }
+
+ if (utp->num_step_actions > 0)
+ {
+ printf_filtered ("Want to restore action list\n");
+ }
+
+ return tp;
+ }
+
/* Print information on tracepoint number TPNUM_EXP, or all if
omitted. */
{
ALL_BREAKPOINTS_SAFE (b, temp)
{
- if (b->type == bp_tracepoint
+ if (tracepoint_type (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;
}
+/* Find the tracepoint with the given target-side number (which may be
+ different from the tracepoint number after disconnecting and
+ reconnecting). */
+
+struct breakpoint *
+get_tracepoint_by_number_on_target (int num)
+{
+ struct breakpoint *t;
+
+ ALL_TRACEPOINTS (t)
+ if (t->number_on_target == num)
+ return t;
+
+ return NULL;
+}
+
/* Utility: parse a tracepoint number and look it up in the list.
If MULTI_P is true, there might be a range of tracepoints in ARG.
if OPTIONAL_P is true, then if the argument is missing, the most
{
struct breakpoint *tp;
int any_tp = 0;
- struct action_line *line;
- FILE *fp;
- char *i1 = " ", *i2 = " ";
- char *indent, *actionline, *pathname;
+ struct command_line *line;
+ char *pathname;
char tmp[40];
struct cleanup *cleanup;
+ struct ui_file *fp;
if (args == 0 || *args == 0)
error (_("Argument required (file name in which to save tracepoints)"));
pathname = tilde_expand (args);
cleanup = make_cleanup (xfree, pathname);
- fp = fopen (pathname, "w");
+ fp = gdb_fopen (pathname, "w");
if (!fp)
error (_("Unable to open file '%s' for saving tracepoints (%s)"),
args, safe_strerror (errno));
- make_cleanup_fclose (fp);
+ make_cleanup_ui_file_delete (fp);
ALL_TRACEPOINTS (tp)
{
if (tp->addr_string)
- fprintf (fp, "trace %s\n", tp->addr_string);
+ fprintf_unfiltered (fp, "trace %s\n", tp->addr_string);
else
{
sprintf_vma (tmp, tp->loc->address);
- fprintf (fp, "trace *0x%s\n", tmp);
+ fprintf_unfiltered (fp, "trace *0x%s\n", tmp);
}
if (tp->pass_count)
- fprintf (fp, " passcount %d\n", tp->pass_count);
+ fprintf_unfiltered (fp, " passcount %d\n", tp->pass_count);
- if (tp->actions)
+ if (tp->commands)
{
- fprintf (fp, " actions\n");
- indent = i1;
- for (line = tp->actions; line; line = line->next)
+ volatile struct gdb_exception ex;
+
+ fprintf_unfiltered (fp, " actions\n");
+
+ ui_out_redirect (uiout, fp);
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
{
- struct cmd_list_element *cmd;
+ print_command_lines (uiout, tp->commands->commands, 2);
+ }
+ ui_out_redirect (uiout, NULL);
- QUIT; /* allow user to bail out with ^C */
- actionline = line->action;
- while (isspace ((int) *actionline))
- actionline++;
+ if (ex.reason < 0)
+ throw_exception (ex);
- fprintf (fp, "%s%s\n", indent, actionline);
- if (*actionline != '#') /* skip for comment lines */
- {
- cmd = lookup_cmd (&actionline, cmdlist, "", -1, 1);
- if (cmd == 0)
- error (_("Bad action list item: %s"), actionline);
- if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
- indent = i2;
- else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
- indent = i1;
- }
- }
+ fprintf_unfiltered (fp, " end\n");
}
}
do_cleanups (cleanup);
}
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);
observer_attach_solib_unloaded (disable_breakpoints_in_unloaded_shlib);
observer_attach_inferior_exit (clear_syscall_counts);
+ observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
breakpoint_chain = 0;
/* Don't bother to call set_breakpoint_count. $bpnum isn't useful
add_com_alias ("tra", "trace", class_alias, 1);
add_com_alias ("trac", "trace", class_alias, 1);
+ c = add_com ("ftrace", class_breakpoint, ftrace_command, _("\
+Set a fast tracepoint at specified line or function.\n\
+\n"
+BREAK_ARGS_HELP ("ftrace") "\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\