/* Prototypes for local functions. */
-static void until_break_command_continuation (struct continuation_arg *arg);
+static void until_break_command_continuation (struct continuation_arg *arg,
+ int error);
static void catch_command_1 (char *, int, int);
static enum print_stop_action print_bp_stop_message (bpstat bs);
-typedef struct
- {
- enum exception_event_kind kind;
- int enable_p;
- }
-args_for_catchpoint_enable;
-
static int watchpoint_check (void *);
static void maintenance_info_breakpoints (char *, int);
-static void create_longjmp_breakpoint (char *);
-
static void create_overlay_event_breakpoint (char *);
static int hw_breakpoint_used_count (void);
static char *ep_parse_optional_filename (char **arg);
-static void create_exception_catchpoint (int tempflag, char *cond_string,
- enum exception_event_kind ex_event,
- struct symtab_and_line *sal);
-
static void catch_exception_command_1 (enum exception_event_kind ex_event,
char *arg, int tempflag, int from_tty);
static void free_bp_location (struct bp_location *loc);
-static void mark_breakpoints_out (void);
-
static struct bp_location *
allocate_bp_location (struct breakpoint *bpt, enum bptype bp_type);
-static void
-unlink_locations_from_global_list (struct breakpoint *bpt);
+static void update_global_location_list (int);
-static int
-is_hardware_watchpoint (struct breakpoint *bpt);
+static void update_global_location_list_nothrow (int);
+
+static int is_hardware_watchpoint (struct breakpoint *bpt);
+
+static void insert_breakpoint_locations (void);
static const char *
bpdisp_text (enum bpdisp disp)
value);
}
+/* If 1, gdb will keep breakpoints inserted even as inferior is stopped,
+ and immediately insert any new breakpoints. If 0, gdb will insert
+ breakpoints into inferior only when resuming it, and will remove
+ breakpoints upon stop. */
+static int always_inserted_mode = 0;
+static void
+show_always_inserted_mode (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Always inserted breakpoint mode is %s.\n"), value);
+}
+
void _initialize_breakpoint (void);
struct bp_location *bp_location_chain;
+/* The locations that no longer correspond to any breakpoint,
+ unlinked from bp_location_chain, but for which a hit
+ may still be reported by a target. */
+VEC(bp_location_p) *moribund_locations = NULL;
+
/* Number of last breakpoint made. */
int breakpoint_count;
-/* Pointer to current exception event record */
-static struct exception_event_record *current_exception_event;
-
/* This function returns a pointer to the string representation of the
pathname of the dynamically-linked library that has just been
loaded.
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);
+ {
+ 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 = savestring (arg, strlen (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 ();
- breakpoint_modify_event (b->number);
- return;
- }
+ 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 = savestring (arg, strlen (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 ();
+ breakpoint_modify_event (b->number);
+ return;
+ }
error (_("No breakpoint number %d."), bnum);
}
breakpoints_changed ();
breakpoint_modify_event (b->number);
return simple_control;
- }
+ }
error (_("No breakpoint number %d."), bnum);
}
\f
struct bp_location *loc;
bpstat bs;
- unlink_locations_from_global_list (b);
- for (loc = b->loc; loc;)
- {
- struct bp_location *loc_next = loc->next;
- remove_breakpoint (loc, mark_uninserted);
- xfree (loc);
- loc = loc_next;
- }
+ /* We don't free locations. They are stored in
+ bp_location_chain and update_global_locations will
+ eventually delete them and remove breakpoints if
+ needed. */
b->loc = NULL;
if (b->disposition == disp_del_at_next_stop)
value_free (v);
}
- if (reparse && b->cond_string != NULL)
+ /* 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)
{
char *s = b->cond_string;
- if (b->loc->cond)
- {
- xfree (b->loc->cond);
- b->loc->cond = NULL;
- }
b->loc->cond = parse_exp_1 (&s, b->exp_valid_block, 0);
}
}
}
+/* Returns 1 iff breakpoint location should be
+ inserted in the inferior. */
+static int
+should_be_inserted (struct bp_location *bpt)
+{
+ if (!breakpoint_enabled (bpt->owner))
+ return 0;
+
+ if (bpt->owner->disposition == disp_del_at_next_stop)
+ return 0;
+
+ if (!bpt->enabled || bpt->shlib_disabled || bpt->duplicate)
+ return 0;
+
+ return 1;
+}
+
/* Insert a low-level "breakpoint" of some type. BPT is the breakpoint.
Any error messages are printed to TMP_ERROR_STREAM; and DISABLED_BREAKS,
PROCESS_WARNING, and HW_BREAKPOINT_ERROR are used to report problems.
{
int val = 0;
- if (!breakpoint_enabled (bpt->owner))
- return 0;
-
- if (!bpt->enabled || bpt->shlib_disabled || bpt->inserted || bpt->duplicate)
+ if (!should_be_inserted (bpt) || bpt->inserted)
return 0;
/* Initialize the target-specific information. */
return 0;
}
+/* Make sure all breakpoints are inserted in inferior.
+ Throws exception on any error.
+ A breakpoint that is already inserted won't be inserted
+ again, so calling this function twice is safe. */
+void
+insert_breakpoints (void)
+{
+ struct breakpoint *bpt;
+
+ ALL_BREAKPOINTS (bpt)
+ if (is_hardware_watchpoint (bpt))
+ update_watchpoint (bpt, 0 /* don't reparse. */);
+
+ update_global_location_list (1);
+
+ if (!always_inserted_mode && target_has_execution)
+ /* update_global_location_list does not insert breakpoints
+ when always_inserted_mode is not enabled. Explicitly
+ insert them now. */
+ insert_breakpoint_locations ();
+}
+
/* insert_breakpoints is used when starting or continuing the program.
remove_breakpoints is used when the program stops.
Both return zero if successful,
or an `errno' value if could not write the inferior. */
-void
-insert_breakpoints (void)
+static void
+insert_breakpoint_locations (void)
{
struct breakpoint *bpt;
struct bp_location *b, *temp;
struct ui_file *tmp_error_stream = mem_fileopen ();
make_cleanup_ui_file_delete (tmp_error_stream);
-
+
/* Explicitly mark the warning -- this will only be printed if
there was an error. */
fprintf_unfiltered (tmp_error_stream, "Warning:\n");
-
- ALL_BREAKPOINTS (bpt)
- if (is_hardware_watchpoint (bpt))
- update_watchpoint (bpt, 0 /* don't reparse */);
ALL_BP_LOCATIONS_SAFE (b, temp)
{
- if (!breakpoint_enabled (b->owner))
+ if (!should_be_inserted (b) || b->inserted)
continue;
/* There is no point inserting thread-specific breakpoints if the
if (bpt->enable_state != bp_enabled)
continue;
+
+ if (bpt->disposition == disp_del_at_next_stop)
+ continue;
for (loc = bpt->loc; loc; loc = loc->next)
if (!loc->inserted)
{
struct breakpoint *b;
struct breakpoint *temp;
-
- /* Doing this first prevents the badness of having delete_breakpoint()
- write a breakpoint's current "shadow contents" to lift the bp. That
- shadow is NOT valid after an exec()! */
- mark_breakpoints_out ();
+ struct bp_location *bploc;
+
+ /* We're about to delete breakpoints from GDB's lists. If the
+ INSERTED flag is true, GDB will try to lift the breakpoints by
+ writing the breakpoints' "shadow contents" back into memory. The
+ "shadow contents" are NOT valid after an exec, so GDB should not
+ do that. Instead, the target is responsible from marking
+ breakpoints out as soon as it detects an exec. We don't do that
+ here instead, because there may be other attempts to delete
+ breakpoints after detecting an exec and before reaching here. */
+ ALL_BP_LOCATIONS (bploc)
+ gdb_assert (!bploc->inserted);
ALL_BREAKPOINTS_SAFE (b, temp)
{
continue;
}
+ /* Longjmp and longjmp-resume breakpoints are also meaningless
+ after an exec. */
+ if (b->type == bp_longjmp || b->type == bp_longjmp_resume)
+ {
+ delete_breakpoint (b);
+ continue;
+ }
+
/* Don't delete an exec catchpoint, because else the inferior
won't stop when it ought!
/* Permanent breakpoints cannot be inserted or removed. */
return 0;
- if (b->owner->type == bp_none)
- warning (_("attempted to remove apparently deleted breakpoint #%d?"),
- b->owner->number);
+ /* The type of none suggests that owner is actually deleted.
+ This should not ever happen. */
+ gdb_assert (b->owner->type != bp_none);
if (b->loc_type == bp_loc_software_breakpoint
|| b->loc_type == bp_loc_hardware_breakpoint)
/* Clear the "inserted" flag in all breakpoints. */
-static void
+void
mark_breakpoints_out (void)
{
struct bp_location *bpt;
if (bs->commands != NULL)
tmp->commands = copy_command_lines (bs->commands);
if (bs->old_val != NULL)
- tmp->old_val = value_copy (bs->old_val);
+ {
+ tmp->old_val = value_copy (bs->old_val);
+ release_value (tmp->old_val);
+ }
if (p == NULL)
/* This is the first thing in the chain. */
annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (forked process %d), "),
b->number,
- b->forked_inferior_pid);
+ ptid_get_pid (b->forked_inferior_pid));
return PRINT_SRC_AND_LOC;
break;
annotate_catchpoint (b->number);
printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
b->number,
- b->forked_inferior_pid);
+ ptid_get_pid (b->forked_inferior_pid));
return PRINT_SRC_AND_LOC;
break;
for (loc = b->loc; loc; loc = loc->next)
/* Exact match not required. Within range is
sufficient. */
- if (addr >= loc->address
- && addr < loc->address + loc->length)
+ if (target_watchpoint_addr_within_range (¤t_target,
+ addr, loc->address,
+ loc->length))
{
b->watchpoint_triggered = watch_triggered_yes;
break;
}
}
+/* Return true if it looks like target has stopped due to hitting
+ breakpoint location BL. This function does not check if we
+ should stop, only if BL explains the stop. */
+static int
+bpstat_check_location (const struct bp_location *bl, CORE_ADDR bp_addr)
+{
+ struct breakpoint *b = bl->owner;
+
+ if (b->type != bp_watchpoint
+ && b->type != bp_hardware_watchpoint
+ && b->type != bp_read_watchpoint
+ && b->type != bp_access_watchpoint
+ && b->type != bp_hardware_breakpoint
+ && b->type != bp_catch_fork
+ && b->type != bp_catch_vfork
+ && b->type != bp_catch_exec) /* a non-watchpoint bp */
+ {
+ if (bl->address != bp_addr) /* address doesn't match */
+ return 0;
+ if (overlay_debugging /* unmapped overlay section */
+ && section_is_overlay (bl->section)
+ && !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)
+ && b->watchpoint_triggered == watch_triggered_no)
+ return 0;
+
+ if (b->type == bp_hardware_breakpoint)
+ {
+ if (bl->address != bp_addr)
+ return 0;
+ if (overlay_debugging /* unmapped overlay section */
+ && section_is_overlay (bl->section)
+ && !section_is_mapped (bl->section))
+ return 0;
+ }
+
+ /* Is this a catchpoint of a load or unload? If so, did we
+ get a load or unload of the specified library? If not,
+ ignore it. */
+ if ((b->type == bp_catch_load)
+#if defined(SOLIB_HAVE_LOAD_EVENT)
+ && (!SOLIB_HAVE_LOAD_EVENT (PIDGET (inferior_ptid))
+ || ((b->dll_pathname != NULL)
+ && (strcmp (b->dll_pathname,
+ SOLIB_LOADED_LIBRARY_PATHNAME (
+ PIDGET (inferior_ptid)))
+ != 0)))
+#endif
+ )
+ return 0;
+
+ if ((b->type == bp_catch_unload)
+#if defined(SOLIB_HAVE_UNLOAD_EVENT)
+ && (!SOLIB_HAVE_UNLOAD_EVENT (PIDGET (inferior_ptid))
+ || ((b->dll_pathname != NULL)
+ && (strcmp (b->dll_pathname,
+ SOLIB_UNLOADED_LIBRARY_PATHNAME (
+ PIDGET (inferior_ptid)))
+ != 0)))
+#endif
+ )
+ return 0;
+
+ if ((b->type == bp_catch_fork)
+ && !inferior_has_forked (inferior_ptid,
+ &b->forked_inferior_pid))
+ return 0;
+
+ if ((b->type == bp_catch_vfork)
+ && !inferior_has_vforked (inferior_ptid,
+ &b->forked_inferior_pid))
+ return 0;
+
+ if ((b->type == bp_catch_exec)
+ && !inferior_has_execd (inferior_ptid, &b->exec_pathname))
+ return 0;
+
+ return 1;
+}
+
+/* If BS refers to a watchpoint, determine if the watched values
+ has actually changed, and we should stop. If not, set BS->stop
+ to 0. */
+static void
+bpstat_check_watchpoint (bpstat bs)
+{
+ const struct bp_location *bl = bs->breakpoint_at;
+ struct breakpoint *b = bl->owner;
+
+ if (b->type == bp_watchpoint
+ || b->type == bp_read_watchpoint
+ || b->type == bp_access_watchpoint
+ || b->type == bp_hardware_watchpoint)
+ {
+ CORE_ADDR addr;
+ struct value *v;
+ int must_check_value = 0;
+
+ if (b->type == bp_watchpoint)
+ /* For a software watchpoint, we must always check the
+ watched value. */
+ must_check_value = 1;
+ else if (b->watchpoint_triggered == watch_triggered_yes)
+ /* We have a hardware watchpoint (read, write, or access)
+ and the target earlier reported an address watched by
+ this watchpoint. */
+ must_check_value = 1;
+ else if (b->watchpoint_triggered == watch_triggered_unknown
+ && b->type == bp_hardware_watchpoint)
+ /* We were stopped by a hardware watchpoint, but the target could
+ not report the data address. We must check the watchpoint's
+ value. Access and read watchpoints are out of luck; without
+ a data address, we can't figure it out. */
+ must_check_value = 1;
+
+ if (must_check_value)
+ {
+ char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
+ b->number);
+ struct cleanup *cleanups = make_cleanup (xfree, message);
+ int e = catch_errors (watchpoint_check, bs, message,
+ RETURN_MASK_ALL);
+ do_cleanups (cleanups);
+ switch (e)
+ {
+ case WP_DELETED:
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ /* Stop. */
+ 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;
+ }
+ break;
+ case WP_VALUE_NOT_CHANGED:
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_watchpoint)
+ {
+ /* Don't stop: write watchpoints shouldn't fire if
+ the value hasn't changed. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ }
+ /* Stop. */
+ break;
+ default:
+ /* Can't happen. */
+ case 0:
+ /* Error from catch_errors. */
+ printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
+ if (b->related_breakpoint)
+ b->related_breakpoint->disposition = disp_del_at_next_stop;
+ b->disposition = disp_del_at_next_stop;
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ break;
+ }
+ }
+ else /* must_check_value == 0 */
+ {
+ /* This is a case where some watchpoint(s) triggered, but
+ not at the address of this watchpoint, or else no
+ watchpoint triggered after all. So don't print
+ anything for this watchpoint. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ }
+ }
+}
+
+
+/* Check conditions (condition proper, frame, thread and ignore count)
+ of breakpoint referred to by BS. If we should not stop for this
+ breakpoint, set BS->stop to 0. */
+static void
+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;
+
+ if (frame_id_p (b->frame_id)
+ && !frame_id_eq (b->frame_id, get_frame_id (get_current_frame ())))
+ bs->stop = 0;
+ else if (bs->stop)
+ {
+ int value_is_zero = 0;
+
+ /* 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)
+ {
+ /* Need to select the frame, with all that implies
+ so that the conditions will have the right context. */
+ select_frame (get_current_frame ());
+ value_is_zero
+ = catch_errors (breakpoint_cond_eval, (bl->cond),
+ "Error in testing breakpoint condition:\n",
+ RETURN_MASK_ALL);
+ /* FIXME-someday, should give breakpoint # */
+ free_all_values ();
+ }
+ if (bl->cond && value_is_zero)
+ {
+ bs->stop = 0;
+ }
+ else if (b->thread != -1 && b->thread != thread_id)
+ {
+ bs->stop = 0;
+ }
+ else if (b->ignore_count > 0)
+ {
+ b->ignore_count--;
+ annotate_ignore_count_change ();
+ bs->stop = 0;
+ /* Increase the hit count even though we don't
+ stop. */
+ ++(b->hit_count);
+ }
+ }
+}
+
+
/* Get a bpstat associated with having just stopped at address
BP_ADDR in thread PTID.
{
struct breakpoint *b = NULL;
const struct bp_location *bl;
+ struct bp_location *loc;
/* Root of the chain of bpstat's */
struct bpstats root_bs[1];
/* Pointer to the last thing in the chain currently. */
bpstat bs = root_bs;
- int thread_id = pid_to_thread_id (ptid);
+ int ix;
ALL_BP_LOCATIONS (bl)
{
if (!breakpoint_enabled (b) && b->enable_state != bp_permanent)
continue;
- if (b->type != bp_watchpoint
- && b->type != bp_hardware_watchpoint
- && b->type != bp_read_watchpoint
- && b->type != bp_access_watchpoint
- && b->type != bp_hardware_breakpoint
- && b->type != bp_catch_fork
- && b->type != bp_catch_vfork
- && b->type != bp_catch_exec) /* a non-watchpoint bp */
- {
- if (bl->address != bp_addr) /* address doesn't match */
- continue;
- if (overlay_debugging /* unmapped overlay section */
- && section_is_overlay (bl->section)
- && !section_is_mapped (bl->section))
- continue;
- }
-
- /* 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)
- && b->watchpoint_triggered == watch_triggered_no)
- continue;
-
- if (b->type == bp_hardware_breakpoint)
- {
- if (bl->address != bp_addr)
- continue;
- if (overlay_debugging /* unmapped overlay section */
- && section_is_overlay (bl->section)
- && !section_is_mapped (bl->section))
- continue;
- }
-
- /* Is this a catchpoint of a load or unload? If so, did we
- get a load or unload of the specified library? If not,
- ignore it. */
- if ((b->type == bp_catch_load)
-#if defined(SOLIB_HAVE_LOAD_EVENT)
- && (!SOLIB_HAVE_LOAD_EVENT (PIDGET (inferior_ptid))
- || ((b->dll_pathname != NULL)
- && (strcmp (b->dll_pathname,
- SOLIB_LOADED_LIBRARY_PATHNAME (
- PIDGET (inferior_ptid)))
- != 0)))
-#endif
- )
- continue;
-
- if ((b->type == bp_catch_unload)
-#if defined(SOLIB_HAVE_UNLOAD_EVENT)
- && (!SOLIB_HAVE_UNLOAD_EVENT (PIDGET (inferior_ptid))
- || ((b->dll_pathname != NULL)
- && (strcmp (b->dll_pathname,
- SOLIB_UNLOADED_LIBRARY_PATHNAME (
- PIDGET (inferior_ptid)))
- != 0)))
-#endif
- )
- continue;
-
- if ((b->type == bp_catch_fork)
- && !inferior_has_forked (PIDGET (inferior_ptid),
- &b->forked_inferior_pid))
- continue;
-
- if ((b->type == bp_catch_vfork)
- && !inferior_has_vforked (PIDGET (inferior_ptid),
- &b->forked_inferior_pid))
- continue;
-
- if ((b->type == bp_catch_exec)
- && !inferior_has_execd (PIDGET (inferior_ptid), &b->exec_pathname))
- continue;
-
/* 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
if (b->type == bp_hardware_watchpoint && bl != b->loc)
continue;
+ if (!bpstat_check_location (bl, bp_addr))
+ continue;
+
/* Come here if it's a watchpoint, or if the break address matches */
bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */
- /* Watchpoints may change this, if not found to have triggered. */
+ /* 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;
- if (b->type == bp_watchpoint
- || b->type == bp_read_watchpoint
- || b->type == bp_access_watchpoint
- || b->type == bp_hardware_watchpoint)
- {
- CORE_ADDR addr;
- struct value *v;
- int must_check_value = 0;
-
- if (b->type == bp_watchpoint)
- /* For a software watchpoint, we must always check the
- watched value. */
- must_check_value = 1;
- else if (b->watchpoint_triggered == watch_triggered_yes)
- /* We have a hardware watchpoint (read, write, or access)
- and the target earlier reported an address watched by
- this watchpoint. */
- must_check_value = 1;
- else if (b->watchpoint_triggered == watch_triggered_unknown
- && b->type == bp_hardware_watchpoint)
- /* We were stopped by a hardware watchpoint, but the target could
- not report the data address. We must check the watchpoint's
- value. Access and read watchpoints are out of luck; without
- a data address, we can't figure it out. */
- must_check_value = 1;
-
- if (must_check_value)
- {
- char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
- b->number);
- struct cleanup *cleanups = make_cleanup (xfree, message);
- int e = catch_errors (watchpoint_check, bs, message,
- RETURN_MASK_ALL);
- do_cleanups (cleanups);
- switch (e)
- {
- case WP_DELETED:
- /* We've already printed what needs to be printed. */
- bs->print_it = print_it_done;
- /* Stop. */
- 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;
- continue;
- }
- ++(b->hit_count);
- break;
- case WP_VALUE_NOT_CHANGED:
- if (b->type == bp_hardware_watchpoint
- || b->type == bp_watchpoint)
- {
- /* Don't stop: write watchpoints shouldn't fire if
- the value hasn't changed. */
- bs->print_it = print_it_noop;
- bs->stop = 0;
- continue;
- }
- /* Stop. */
- ++(b->hit_count);
- break;
- default:
- /* Can't happen. */
- case 0:
- /* Error from catch_errors. */
- printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
- if (b->related_breakpoint)
- b->related_breakpoint->disposition = disp_del_at_next_stop;
- b->disposition = disp_del_at_next_stop;
- /* We've already printed what needs to be printed. */
- bs->print_it = print_it_done;
- break;
- }
- }
- else /* must_check_value == 0 */
- {
- /* This is a case where some watchpoint(s) triggered, but
- not at the address of this watchpoint, or else no
- watchpoint triggered after all. So don't print
- anything for this watchpoint. */
- bs->print_it = print_it_noop;
- bs->stop = 0;
- continue;
- }
- }
- else
- {
- /* By definition, an encountered breakpoint is a triggered
- breakpoint. */
- ++(b->hit_count);
- }
+ bpstat_check_watchpoint (bs);
+ if (!bs->stop)
+ continue;
- if (frame_id_p (b->frame_id)
- && !frame_id_eq (b->frame_id, get_frame_id (get_current_frame ())))
+ if (b->type == bp_thread_event || b->type == bp_overlay_event)
+ /* We do not stop for these. */
bs->stop = 0;
else
+ bpstat_check_breakpoint_conditions (bs, ptid);
+
+ if (bs->stop)
{
- int value_is_zero = 0;
-
- /* 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;
+ ++(b->hit_count);
- if (bl->cond && bl->owner->disposition != disp_del_at_next_stop)
- {
- /* Need to select the frame, with all that implies
- so that the conditions will have the right context. */
- select_frame (get_current_frame ());
- value_is_zero
- = catch_errors (breakpoint_cond_eval, (bl->cond),
- "Error in testing breakpoint condition:\n",
- RETURN_MASK_ALL);
- /* FIXME-someday, should give breakpoint # */
- free_all_values ();
- }
- if (bl->cond && value_is_zero)
+ /* We will stop here */
+ if (b->disposition == disp_disable)
{
- bs->stop = 0;
- /* Don't consider this a hit. */
- --(b->hit_count);
+ b->enable_state = bp_disabled;
+ update_global_location_list (0);
}
- else if (b->thread != -1 && b->thread != thread_id)
+ 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->stop = 0;
- /* Don't consider this a hit. */
- --(b->hit_count);
- }
- else if (b->ignore_count > 0)
- {
- b->ignore_count--;
- annotate_ignore_count_change ();
- bs->stop = 0;
- }
- else if (b->type == bp_thread_event || b->type == bp_overlay_event)
- /* We do not stop for these. */
- bs->stop = 0;
- else
- {
- /* We will stop here */
- if (b->disposition == disp_disable)
- b->enable_state = bp_disabled;
- 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);
+ bs->commands = bs->commands->next;
+ bs->print = 0;
}
+ bs->commands = copy_command_lines (bs->commands);
}
+
/* 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;
}
+ for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
+ {
+ if (loc->address == bp_addr)
+ {
+ bs = bpstat_alloc (loc, bs);
+ /* For hits of moribund locations, we should just proceed. */
+ bs->stop = 0;
+ bs->print = 0;
+ bs->print_it = print_it_noop;
+ }
+ }
+
bs->next = NULL; /* Terminate the chain */
bs = root_bs->next; /* Re-grab the head of the chain */
if (bs == NULL)
for (bs = root_bs->next; bs != NULL; bs = bs->next)
if (!bs->stop
+ && bs->breakpoint_at->owner
&& (bs->breakpoint_at->owner->type == bp_hardware_watchpoint
|| bs->breakpoint_at->owner->type == bp_read_watchpoint
|| bs->breakpoint_at->owner->type == bp_access_watchpoint))
#define sgl BPSTAT_WHAT_SINGLE
#define slr BPSTAT_WHAT_SET_LONGJMP_RESUME
#define clr BPSTAT_WHAT_CLEAR_LONGJMP_RESUME
-#define clrs BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE
#define sr BPSTAT_WHAT_STEP_RESUME
#define shl BPSTAT_WHAT_CHECK_SHLIBS
#define shlr BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK
ordering is:
kc < clr sgl shl shlr slr sn sr ss
- sgl < clrs shl shlr slr sn sr ss
+ sgl < shl shlr slr sn sr ss
slr < err shl shlr sn sr ss
- clr < clrs err shl shlr sn sr ss
- clrs < err shl shlr sn sr ss
+ clr < err shl shlr sn sr ss
ss < shl shlr sn sr
sn < shl shlr sr
shl < shlr sr
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, and the CLEAR_LONGJMP_RESUME/
- CLEAR_LONGJMP_RESUME_SINGLE distinction (which breakpoint.h says
- is messy anyway). */
+ 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
table[(int) class_last][(int) BPSTAT_WHAT_LAST] =
{
/* old action */
- /* kc ss sn sgl slr clr clrs sr shl shlr
+ /* kc ss sn sgl slr clr sr shl shlr
*/
/*no_effect */
- {kc, ss, sn, sgl, slr, clr, clrs, sr, shl, shlr},
+ {kc, ss, sn, sgl, slr, clr, sr, shl, shlr},
/*wp_silent */
- {ss, ss, sn, ss, ss, ss, ss, sr, shl, shlr},
+ {ss, ss, sn, ss, ss, ss, sr, shl, shlr},
/*wp_noisy */
- {sn, sn, sn, sn, sn, sn, sn, sr, shl, shlr},
+ {sn, sn, sn, sn, sn, sn, sr, shl, shlr},
/*bp_nostop */
- {sgl, ss, sn, sgl, slr, clrs, clrs, sr, shl, shlr},
+ {sgl, ss, sn, sgl, slr, slr, sr, shl, shlr},
/*bp_silent */
- {ss, ss, sn, ss, ss, ss, ss, sr, shl, shlr},
+ {ss, ss, sn, ss, ss, ss, sr, shl, shlr},
/*bp_noisy */
- {sn, sn, sn, sn, sn, sn, sn, sr, shl, shlr},
+ {sn, sn, sn, sn, sn, sn, sr, shl, shlr},
/*long_jump */
- {slr, ss, sn, slr, slr, err, err, sr, shl, shlr},
+ {slr, ss, sn, slr, slr, err, sr, shl, shlr},
/*long_resume */
- {clr, ss, sn, clrs, err, err, err, sr, shl, shlr},
+ {clr, ss, sn, err, err, err, sr, shl, shlr},
/*step_resume */
- {sr, sr, sr, sr, sr, sr, sr, sr, sr, sr},
+ {sr, sr, sr, sr, sr, sr, sr, sr, sr},
/*shlib */
- {shl, shl, shl, shl, shl, shl, shl, sr, shl, shlr},
+ {shl, shl, shl, shl, shl, shl, sr, shl, shlr},
/*catch_shlib */
- {shlr, shlr, shlr, shlr, shlr, shlr, shlr, sr, shlr, shlr}
+ {shlr, shlr, shlr, shlr, shlr, shlr, sr, shlr, shlr}
};
#undef kc
#undef sgl
#undef slr
#undef clr
-#undef clrs
#undef err
#undef sr
#undef ts
/* 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;
+ else
switch (bs->breakpoint_at->owner->type)
{
case bp_none:
if (addressprint)
ui_out_field_skip (uiout, "addr");
annotate_field (5);
- if (b->forked_inferior_pid != 0)
+ if (!ptid_equal (b->forked_inferior_pid, null_ptid))
{
ui_out_text (uiout, "process ");
- ui_out_field_int (uiout, "what", b->forked_inferior_pid);
+ ui_out_field_int (uiout, "what",
+ ptid_get_pid (b->forked_inferior_pid));
ui_out_spaces (uiout, 1);
}
break;
annotate_field (4);
if (header_of_multiple)
ui_out_field_string (uiout, "addr", "<MULTIPLE>");
- if (b->loc == NULL || loc->shlib_disabled)
+ else if (b->loc == NULL || loc->shlib_disabled)
ui_out_field_string (uiout, "addr", "<PENDING>");
else
ui_out_field_core_addr (uiout, "addr", loc->address);
print_command_lines (uiout, l, 4);
do_cleanups (script_chain);
}
+
+ if (ui_out_is_mi_like_p (uiout) && !part_of_multiple)
+ {
+ if (b->addr_string)
+ ui_out_field_string (uiout, "original-location", b->addr_string);
+ else if (b->exp_string)
+ ui_out_field_string (uiout, "original-location", b->exp_string);
+ }
+
do_cleanups (bkpt_chain);
do_cleanups (old_chain);
}
bp_read_watchpoint
bp_access_watchpoint
bp_catch_exec
- bp_longjmp_resume
bp_catch_fork
bp_catch_vork */
&& type != bp_read_watchpoint
&& type != bp_access_watchpoint
&& type != bp_catch_exec
- && type != bp_longjmp_resume
&& type != bp_catch_fork
&& type != bp_catch_vfork);
}
internal_error (__FILE__, __LINE__, _("unknown breakpoint type"));
}
- /* Add this breakpoint to the end of the chain. */
-
- loc_p = bp_location_chain;
- if (loc_p == 0)
- bp_location_chain = loc;
- else
- {
- while (loc_p->global_next)
- loc_p = loc_p->global_next;
- loc_p->global_next = loc;
- }
-
return loc;
}
{
if (loc->cond)
xfree (loc->cond);
+
+ if (loc->function_name)
+ xfree (loc->function_name);
+
xfree (loc);
}
b->frame_id = null_frame_id;
b->dll_pathname = NULL;
b->triggered_dll_pathname = NULL;
- b->forked_inferior_pid = 0;
+ b->forked_inferior_pid = null_ptid;
b->exec_pathname = NULL;
b->ops = NULL;
b->condition_not_parsed = 0;
set_breakpoint_location_function (b->loc);
- check_duplicates (b);
breakpoints_changed ();
return b;
struct breakpoint *b;
struct minimal_symbol *m;
- if (func_name == NULL)
- b = create_internal_breakpoint (0, bp_longjmp_resume);
- else
- {
- if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL)
- return;
-
- b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m), bp_longjmp);
- }
-
- b->enable_state = bp_disabled;
- b->silent = 1;
- if (func_name)
- b->addr_string = xstrdup (func_name);
+ if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL)
+ return;
+ set_momentary_breakpoint_at_pc (SYMBOL_VALUE_ADDRESS (m), bp_longjmp);
+ update_global_location_list (1);
}
/* Call this routine when stepping and nexting to enable a breakpoint
set_longjmp_resume_breakpoint() to figure out where we are going. */
void
-enable_longjmp_breakpoint (void)
+set_longjmp_breakpoint (void)
{
struct breakpoint *b;
- ALL_BREAKPOINTS (b)
- if (b->type == bp_longjmp)
+ if (gdbarch_get_longjmp_target_p (current_gdbarch))
{
- b->enable_state = bp_enabled;
- check_duplicates (b);
+ create_longjmp_breakpoint ("longjmp");
+ create_longjmp_breakpoint ("_longjmp");
+ create_longjmp_breakpoint ("siglongjmp");
+ create_longjmp_breakpoint ("_siglongjmp");
}
}
+/* Delete all longjmp breakpoints from THREAD. */
void
-disable_longjmp_breakpoint (void)
+delete_longjmp_breakpoint (int thread)
{
- struct breakpoint *b;
+ struct breakpoint *b, *temp;
- ALL_BREAKPOINTS (b)
- if (b->type == bp_longjmp
- || b->type == bp_longjmp_resume)
- {
- b->enable_state = bp_disabled;
- check_duplicates (b);
- }
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ if (b->type == bp_longjmp)
+ {
+ if (b->thread == thread)
+ delete_breakpoint (b);
+ }
}
static void
b->enable_state = bp_disabled;
overlay_events_enabled = 0;
}
+ update_global_location_list (1);
}
void
if (b->type == bp_overlay_event)
{
b->enable_state = bp_enabled;
- check_duplicates (b);
+ update_global_location_list (1);
overlay_events_enabled = 1;
}
}
if (b->type == bp_overlay_event)
{
b->enable_state = bp_disabled;
- check_duplicates (b);
+ update_global_location_list (0);
overlay_events_enabled = 0;
}
}
/* addr_string has to be used or breakpoint_re_set will delete me. */
b->addr_string = xstrprintf ("*0x%s", paddr (b->loc->address));
+ update_global_location_list_nothrow (1);
+
return b;
}
struct breakpoint *b;
b = create_internal_breakpoint (address, bp_shlib_event);
+ update_global_location_list_nothrow (1);
return b;
}
b->addr_string = NULL;
b->enable_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
- b->forked_inferior_pid = 0;
+ b->forked_inferior_pid = null_ptid;
+ update_global_location_list (1);
+
mention (b);
}
b->addr_string = NULL;
b->enable_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
+ update_global_location_list (1);
mention (b);
}
return i;
}
-/* Call this after hitting the longjmp() breakpoint. Use this to set
- a new breakpoint at the target of the jmp_buf.
-
- FIXME - This ought to be done by setting a temporary breakpoint
- that gets deleted automatically... */
-
-void
-set_longjmp_resume_breakpoint (CORE_ADDR pc, struct frame_id frame_id)
-{
- struct breakpoint *b;
-
- ALL_BREAKPOINTS (b)
- if (b->type == bp_longjmp_resume)
- {
- b->loc->requested_address = pc;
- b->loc->address = adjust_breakpoint_address (b->loc->requested_address,
- b->type);
- b->enable_state = bp_enabled;
- b->frame_id = frame_id;
- check_duplicates (b);
- return;
- }
-}
-
void
disable_watchpoints_before_interactive_call_start (void)
{
&& breakpoint_enabled (b))
{
b->enable_state = bp_call_disabled;
- check_duplicates (b);
+ update_global_location_list (0);
}
}
}
&& (b->enable_state == bp_call_disabled))
{
b->enable_state = bp_enabled;
- check_duplicates (b);
+ update_global_location_list (1);
}
}
}
if (in_thread_list (inferior_ptid))
b->thread = pid_to_thread_id (inferior_ptid);
+ update_global_location_list_nothrow (1);
+
return b;
}
+
+struct breakpoint *
+set_momentary_breakpoint_at_pc (CORE_ADDR pc, enum bptype type)
+{
+ struct symtab_and_line sal;
+
+ sal = find_pc_line (pc, 0);
+ sal.pc = pc;
+ sal.section = find_pc_overlay (pc);
+ sal.explicit_pc = 1;
+
+ return set_momentary_breakpoint (sal, null_frame_id, type);
+}
\f
/* Tell the user we have just set a breakpoint B. */
create_breakpoint (struct symtabs_and_lines sals, char *addr_string,
char *cond_string,
enum bptype type, enum bpdisp disposition,
- int thread, int ignore_count, int from_tty)
+ int thread, int ignore_count,
+ struct breakpoint_ops *ops, int from_tty)
{
struct breakpoint *b = NULL;
int i;
me. */
b->addr_string = xstrprintf ("*0x%s", paddr (b->loc->address));
+ b->ops = ops;
mention (b);
}
create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
char *cond_string,
enum bptype type, enum bpdisp disposition,
- int thread, int ignore_count, int from_tty)
+ int thread, int ignore_count,
+ struct breakpoint_ops *ops, int from_tty)
{
int i;
for (i = 0; i < sals.nelts; ++i)
create_breakpoint (expanded, addr_string[i],
cond_string, type, disposition,
- thread, ignore_count, from_tty);
+ thread, ignore_count, ops, from_tty);
}
+
+ update_global_location_list (1);
}
/* Parse ARG which is assumed to be a SAL specification possibly
int tempflag, int hardwareflag,
int ignore_count,
enum auto_boolean pending_break_support,
+ struct breakpoint_ops *ops,
int from_tty)
{
struct gdb_exception e;
breakpoint. */
if (!pending)
{
- if (parse_condition_and_thread)
+ if (parse_condition_and_thread)
{
/* Here we only parse 'arg' to separate condition
from thread number, so parsing in context of first
if (cond_string)
make_cleanup (xfree, cond_string);
}
- else
+ else
{
/* Create a private copy of condition string. */
if (cond_string)
hardwareflag ? bp_hardware_breakpoint
: bp_breakpoint,
tempflag ? disp_del : disp_donttouch,
- thread, ignore_count, from_tty);
+ thread, ignore_count, ops, from_tty);
}
else
{
b->ignore_count = ignore_count;
b->disposition = tempflag ? disp_del : disp_donttouch;
b->condition_not_parsed = 1;
+ b->ops = ops;
+
+ update_global_location_list (1);
mention (b);
}
NULL, 0, 1 /* parse arg */,
tempflag, hardwareflag,
0 /* Ignore count */,
- pending_break_support, from_tty);
+ pending_break_support,
+ NULL /* breakpoint_ops */,
+ from_tty);
}
ignore_count,
pending
? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE,
- 0);
+ NULL, 0);
}
/* Adjust SAL to the first instruction past the function prologue.
value_free_to_mark (mark);
mention (b);
+ update_global_location_list (1);
}
/* Return count of locations need to be watched and can be handled
care of cleaning up the temporary breakpoints set up by the until
command. */
static void
-until_break_command_continuation (struct continuation_arg *arg)
+until_break_command_continuation (struct continuation_arg *arg, int error)
{
- struct cleanup *cleanups;
-
- cleanups = (struct cleanup *) arg->data.pointer;
- do_exec_cleanups (cleanups);
+ delete_breakpoint ((struct breakpoint *)(arg->data.pointer));
+ if (arg->next)
+ delete_breakpoint ((struct breakpoint *)(arg->next->data.pointer));
}
void
struct frame_info *frame = get_selected_frame (NULL);
struct frame_info *prev_frame = get_prev_frame (frame);
struct breakpoint *breakpoint;
+ struct breakpoint *breakpoint2 = NULL;
struct cleanup *old_chain;
struct continuation_arg *arg1;
+ struct continuation_arg *arg2;
clear_proceed_status ();
breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame),
bp_until);
- if (!target_can_async_p ())
- old_chain = make_cleanup_delete_breakpoint (breakpoint);
- else
- old_chain = make_exec_cleanup_delete_breakpoint (breakpoint);
-
- /* If we are running asynchronously, and the target supports async
- execution, we are not waiting for the target to stop, in the call
- tp proceed, below. This means that we cannot delete the
- brekpoints until the target has actually stopped. The only place
- where we get a chance to do that is in fetch_inferior_event, so
- we must set things up for that. */
-
- if (target_can_async_p ())
- {
- /* In this case the arg for the continuation is just the point
- in the exec_cleanups chain from where to start doing
- cleanups, because all the continuation does is the cleanups in
- the exec_cleanup_chain. */
- arg1 =
- (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
- arg1->next = NULL;
- arg1->data.pointer = old_chain;
-
- add_continuation (until_break_command_continuation, arg1);
- }
+ old_chain = make_cleanup_delete_breakpoint (breakpoint);
/* Keep within the current frame, or in frames called by the current
one. */
{
sal = find_pc_line (get_frame_pc (prev_frame), 0);
sal.pc = get_frame_pc (prev_frame);
- breakpoint = set_momentary_breakpoint (sal, get_frame_id (prev_frame),
- bp_until);
- if (!target_can_async_p ())
- make_cleanup_delete_breakpoint (breakpoint);
- else
- make_exec_cleanup_delete_breakpoint (breakpoint);
+ breakpoint2 = set_momentary_breakpoint (sal, get_frame_id (prev_frame),
+ bp_until);
+ make_cleanup_delete_breakpoint (breakpoint2);
}
proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
- /* Do the cleanups now, anly if we are not running asynchronously,
- of if we are, but the target is still synchronous. */
- if (!target_can_async_p ())
+
+ /* If we are running asynchronously, and proceed call above has actually
+ managed to start the target, arrange for breakpoints to be
+ deleted when the target stops. Otherwise, we're already stopped and
+ delete breakpoints via cleanup chain. */
+
+ if (target_can_async_p () && is_running (inferior_ptid))
+ {
+ arg1 =
+ (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+ arg1->next = NULL;
+ arg1->data.pointer = breakpoint;
+
+ if (breakpoint2)
+ {
+ arg2 = (struct continuation_arg *)
+ xmalloc ( sizeof (struct continuation_arg));
+ arg2->next = NULL;
+ arg2->data.pointer = breakpoint2;
+ arg1->next = arg2;
+ }
+
+ discard_cleanups (old_chain);
+ add_continuation (until_break_command_continuation, arg1);
+ }
+ else
do_cleanups (old_chain);
}
static enum print_stop_action
print_exception_catchpoint (struct breakpoint *b)
{
- annotate_catchpoint (b->number);
+ int bp_temp, bp_throw;
- if (strstr (b->addr_string, "throw") != NULL)
- printf_filtered (_("\nCatchpoint %d (exception thrown)\n"),
- b->number);
- else
- printf_filtered (_("\nCatchpoint %d (exception caught)\n"),
- b->number);
+ annotate_catchpoint (b->number);
+ bp_throw = strstr (b->addr_string, "throw") != NULL;
+ if (b->loc->address != b->loc->requested_address)
+ breakpoint_adjustment_warning (b->loc->requested_address,
+ b->loc->address,
+ b->number, 1);
+ bp_temp = b->loc->owner->disposition == disp_del;
+ ui_out_text (uiout,
+ bp_temp ? "Temporary catchpoint "
+ : "Catchpoint ");
+ if (!ui_out_is_mi_like_p (uiout))
+ ui_out_field_int (uiout, "bkptno", b->number);
+ ui_out_text (uiout,
+ bp_throw ? " (exception thrown), "
+ : " (exception caught), ");
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ ui_out_field_string (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+ ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+ ui_out_field_int (uiout, "bkptno", b->number);
+ }
return PRINT_SRC_AND_LOC;
}
if (addressprint)
{
annotate_field (4);
- ui_out_field_core_addr (uiout, "addr", b->loc->address);
+ if (b->loc == NULL || b->loc->shlib_disabled)
+ ui_out_field_string (uiout, "addr", "<PENDING>");
+ else
+ ui_out_field_core_addr (uiout, "addr", b->loc->address);
}
annotate_field (5);
- *last_addr = b->loc->address;
+ if (b->loc)
+ *last_addr = b->loc->address;
if (strstr (b->addr_string, "throw") != NULL)
ui_out_field_string (uiout, "what", "exception throw");
else
static void
print_mention_exception_catchpoint (struct breakpoint *b)
{
- if (strstr (b->addr_string, "throw") != NULL)
- printf_filtered (_("Catchpoint %d (throw)"), b->number);
- else
- printf_filtered (_("Catchpoint %d (catch)"), b->number);
+ int bp_temp;
+ int bp_throw;
+
+ bp_temp = b->loc->owner->disposition == disp_del;
+ bp_throw = strstr (b->addr_string, "throw") != NULL;
+ ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
+ : _("Catchpoint "));
+ ui_out_field_int (uiout, "bkptno", b->number);
+ ui_out_text (uiout, bp_throw ? _(" (throw)")
+ : _(" (catch)"));
}
static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
handle_gnu_v3_exceptions (int tempflag, char *cond_string,
enum exception_event_kind ex_event, int from_tty)
{
- char *trigger_func_name, *nameptr;
- struct symtabs_and_lines sals;
- struct breakpoint *b;
-
+ char *trigger_func_name;
+
if (ex_event == EX_EVENT_CATCH)
- trigger_func_name = xstrdup ("__cxa_begin_catch");
+ trigger_func_name = "__cxa_begin_catch";
else
- trigger_func_name = xstrdup ("__cxa_throw");
-
- nameptr = trigger_func_name;
- sals = decode_line_1 (&nameptr, 1, NULL, 0, NULL, NULL);
- if (sals.nelts == 0)
- {
- xfree (trigger_func_name);
- return 0;
- }
+ trigger_func_name = "__cxa_throw";
- b = set_raw_breakpoint (sals.sals[0], bp_breakpoint);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
- b->cond_string = (cond_string == NULL) ?
- NULL : savestring (cond_string, strlen (cond_string));
- b->thread = -1;
- b->addr_string = trigger_func_name;
- b->enable_state = bp_enabled;
- b->disposition = tempflag ? disp_del : disp_donttouch;
- b->ops = &gnu_v3_exception_catchpoint_ops;
+ break_command_really (trigger_func_name, cond_string, -1,
+ 0 /* condition and thread are valid. */,
+ tempflag, 0,
+ 0,
+ AUTO_BOOLEAN_TRUE /* pending */,
+ &gnu_v3_exception_catchpoint_ops, from_tty);
- xfree (sals.sals);
- mention (b);
return 1;
}
b->ops = ops;
mention (b);
+ update_global_location_list (1);
}
/* Implement the "catch exception" command. */
struct breakpoint *b, *temp;
for (; bs; bs = bs->next)
- if (bs->breakpoint_at && bs->breakpoint_at->owner->disposition == disp_del
+ if (bs->breakpoint_at
+ && bs->breakpoint_at->owner
+ && bs->breakpoint_at->owner->disposition == disp_del
&& bs->stop)
delete_breakpoint (bs->breakpoint_at->owner);
}
}
-/* Remove locations of breakpoint BPT from
- the global list of breakpoint locations. */
+/* If SHOULD_INSERT is true, do not insert any breakpoint locations
+ into the inferior, only remove already-inserted locations that no
+ longer should be inserted. Functions that delete a breakpoint or
+ breakpoints should pass false, so that deleting a breakpoint
+ doesn't have the side effect of inserting the locations of other
+ breakpoints that are marked not-inserted, but should_be_inserted
+ returns true on them.
+
+ This behaviour is useful is situations close to tear-down -- e.g.,
+ after an exec, while the target still has execution, but breakpoint
+ shadows of the previous executable image should *NOT* be restored
+ to the new image; or before detaching, where the target still has
+ execution and wants to delete breakpoints from GDB's lists, and all
+ breakpoints had already been removed from the inferior. */
static void
-unlink_locations_from_global_list (struct breakpoint *bpt)
+update_global_location_list (int should_insert)
{
- /* This code assumes that the locations
- of a breakpoint are found in the global list
- in the same order, but not necessary adjacent. */
- struct bp_location **tmp = &bp_location_chain;
- struct bp_location *here = bpt->loc;
-
- if (here == NULL)
- return;
+ struct breakpoint *b;
+ struct bp_location **next = &bp_location_chain;
+ struct bp_location *loc;
+ struct bp_location *loc2;
+ struct gdb_exception e;
+ VEC(bp_location_p) *old_locations = NULL;
+ int ret;
+ int ix;
+
+ /* Store old locations for future reference. */
+ for (loc = bp_location_chain; loc; loc = loc->global_next)
+ VEC_safe_push (bp_location_p, old_locations, loc);
- for (; *tmp && here;)
+ bp_location_chain = NULL;
+ ALL_BREAKPOINTS (b)
{
- if (*tmp == here)
+ for (loc = b->loc; loc; loc = loc->next)
{
- *tmp = here->global_next;
- here = here->next;
+ *next = loc;
+ next = &(loc->global_next);
+ *next = NULL;
}
- else
+ }
+
+ /* Identify bp_location instances that are no longer present in the new
+ list, and therefore should be freed. Note that it's not necessary that
+ those locations should be removed from inferior -- if there's another
+ location at the same address (previously marked as duplicate),
+ we don't need to remove/insert the location. */
+ for (ix = 0; VEC_iterate(bp_location_p, old_locations, ix, loc); ++ix)
+ {
+ /* Tells if 'loc' is found amoung the new locations. If not, we
+ have to free it. */
+ int found_object = 0;
+ /* Tells if the location should remain inserted in the target. */
+ int keep_in_target = 0;
+ int removed = 0;
+ for (loc2 = bp_location_chain; loc2; loc2 = loc2->global_next)
+ if (loc2 == loc)
+ {
+ found_object = 1;
+ break;
+ }
+
+ /* If this location is no longer present, and inserted, look if there's
+ maybe a new location at the same address. If so, mark that one
+ inserted, and don't remove this one. This is needed so that we
+ don't have a time window where a breakpoint at certain location is not
+ inserted. */
+
+ if (loc->inserted)
{
- tmp = &((*tmp)->global_next);
+ /* If the location is inserted now, we might have to remove it. */
+
+ if (found_object && should_be_inserted (loc))
+ {
+ /* The location is still present in the location list, and still
+ should be inserted. Don't do anything. */
+ keep_in_target = 1;
+ }
+ else
+ {
+ /* The location is either no longer present, or got disabled.
+ See if there's another location at the same address, in which
+ case we don't need to remove this one from the target. */
+ if (breakpoint_address_is_meaningful (loc->owner))
+ for (loc2 = bp_location_chain; loc2; loc2 = loc2->global_next)
+ {
+ /* For the sake of should_insert_location. The
+ call to check_duplicates will fix up this later. */
+ loc2->duplicate = 0;
+ if (should_be_inserted (loc2)
+ && loc2 != loc && loc2->address == loc->address)
+ {
+ loc2->inserted = 1;
+ loc2->target_info = loc->target_info;
+ keep_in_target = 1;
+ break;
+ }
+ }
+ }
+
+ if (!keep_in_target)
+ {
+ if (remove_breakpoint (loc, mark_uninserted))
+ {
+ /* This is just about all we can do. We could keep this
+ location on the global list, and try to remove it next
+ time, but there's no particular reason why we will
+ succeed next time.
+
+ Note that at this point, loc->owner is still valid,
+ as delete_breakpoint frees the breakpoint only
+ after calling us. */
+ printf_filtered (_("warning: Error removing breakpoint %d\n"),
+ loc->owner->number);
+ }
+ removed = 1;
+ }
+ }
+
+ if (!found_object)
+ {
+ if (removed)
+ {
+ /* This location was removed from the targets. In non-stop mode,
+ a race condition is possible where we've removed a breakpoint,
+ but stop events for that breakpoint are already queued and will
+ arrive later. To suppress spurious SIGTRAPs reported to user,
+ we keep this breakpoint location for a bit, and will retire it
+ after we see 3 * thread_count events.
+ The theory here is that reporting of events should,
+ "on the average", be fair, so after that many event we'll see
+ events from all threads that have anything of interest, and no
+ longer need to keep this breakpoint. This is just a
+ heuristic, but if it's wrong, we'll report unexpected SIGTRAP,
+ which is usability issue, but not a correctness problem. */
+ loc->events_till_retirement = 3 * (thread_count () + 1);
+ loc->owner = NULL;
+ }
+
+ free_bp_location (loc);
}
}
+
+ ALL_BREAKPOINTS (b)
+ {
+ check_duplicates (b);
+ }
+
+ if (always_inserted_mode && should_insert && target_has_execution)
+ insert_breakpoint_locations ();
+}
+
+void
+breakpoint_retire_moribund (void)
+{
+ struct bp_location *loc;
+ int ix;
+
+ for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
+ if (--(loc->events_till_retirement) == 0)
+ {
+ free_bp_location (loc);
+ VEC_unordered_remove (bp_location_p, moribund_locations, ix);
+ --ix;
+ }
+}
+
+static void
+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. */
+static void
+bpstat_remove_breakpoint (bpstat bps, struct breakpoint *bpt)
+{
+ bpstat bs;
+ for (bs = bps; bs; bs = bs->next)
+ if (bs->breakpoint_at && bs->breakpoint_at->owner == bpt)
+ {
+ bs->breakpoint_at = NULL;
+ bs->old_val = NULL;
+ /* bs->commands will be freed later. */
+ }
+}
+
+/* Callback for iterate_over_threads. */
+static int
+bpstat_remove_breakpoint_callback (struct thread_info *th, void *data)
+{
+ struct breakpoint *bpt = data;
+ bpstat_remove_breakpoint (th->stop_bpstat, bpt);
+ return 0;
}
/* Delete a breakpoint and clean up all traces of it in the data
delete_breakpoint (struct breakpoint *bpt)
{
struct breakpoint *b;
- bpstat bs;
- struct bp_location *loc;
+ struct bp_location *loc, *next;
gdb_assert (bpt != NULL);
deprecated_delete_breakpoint_hook (bpt);
breakpoint_delete_event (bpt->number);
- for (loc = bpt->loc; loc; loc = loc->next)
- {
- if (loc->inserted)
- remove_breakpoint (loc, mark_inserted);
-
- if (loc->cond)
- xfree (loc->cond);
-
- if (loc->function_name)
- xfree (loc->function_name);
- }
-
if (breakpoint_chain == bpt)
breakpoint_chain = bpt->next;
break;
}
- unlink_locations_from_global_list (bpt);
-
- check_duplicates (bpt);
-
- if (bpt->type != bp_hardware_watchpoint
- && bpt->type != bp_read_watchpoint
- && bpt->type != bp_access_watchpoint
- && bpt->type != bp_catch_fork
- && bpt->type != bp_catch_vfork
- && bpt->type != bp_catch_exec)
- for (loc = bpt->loc; loc; loc = loc->next)
- {
- /* If this breakpoint location was inserted, and there is
- another breakpoint at the same address, we need to
- insert the other breakpoint. */
- if (loc->inserted)
- {
- struct bp_location *loc2;
- ALL_BP_LOCATIONS (loc2)
- if (loc2->address == loc->address
- && loc2->section == loc->section
- && !loc->duplicate
- && loc2->owner->enable_state != bp_disabled
- && loc2->enabled
- && !loc2->shlib_disabled
- && loc2->owner->enable_state != bp_call_disabled)
- {
- int val;
-
- /* We should never reach this point if there is a permanent
- breakpoint at the same address as the one being deleted.
- If there is a permanent breakpoint somewhere, it should
- always be the only one inserted. */
- if (loc2->owner->enable_state == bp_permanent)
- internal_error (__FILE__, __LINE__,
- _("another breakpoint was inserted on top of "
- "a permanent breakpoint"));
-
- memset (&loc2->target_info, 0, sizeof (loc2->target_info));
- loc2->target_info.placed_address = loc2->address;
- if (b->type == bp_hardware_breakpoint)
- val = target_insert_hw_breakpoint (&loc2->target_info);
- else
- val = target_insert_breakpoint (&loc2->target_info);
-
- /* If there was an error in the insert, print a message, then stop execution. */
- if (val != 0)
- {
- struct ui_file *tmp_error_stream = mem_fileopen ();
- make_cleanup_ui_file_delete (tmp_error_stream);
-
-
- if (b->type == bp_hardware_breakpoint)
- {
- fprintf_unfiltered (tmp_error_stream,
- "Cannot insert hardware breakpoint %d.\n"
- "You may have requested too many hardware breakpoints.\n",
- b->number);
- }
- else
- {
- fprintf_unfiltered (tmp_error_stream, "Cannot insert breakpoint %d.\n", b->number);
- fprintf_filtered (tmp_error_stream, "Error accessing memory address ");
- fputs_filtered (paddress (loc2->address),
- tmp_error_stream);
- fprintf_filtered (tmp_error_stream, ": %s.\n",
- safe_strerror (val));
- }
-
- fprintf_unfiltered (tmp_error_stream,"The same program may be running in another process.");
- target_terminal_ours_for_output ();
- error_stream(tmp_error_stream);
- }
- else
- loc2->inserted = 1;
- }
- }
- }
-
free_command_lines (&bpt->commands);
if (bpt->cond_string != NULL)
xfree (bpt->cond_string);
bpstat_do_actions (&stop_bpstat);
in event-top.c won't do anything, and temporary breakpoints
with commands won't work. */
- for (bs = stop_bpstat; bs; bs = bs->next)
- if (bs->breakpoint_at && bs->breakpoint_at->owner == bpt)
- {
- bs->breakpoint_at = NULL;
- bs->old_val = NULL;
- /* bs->commands will be freed later. */
- }
+
+ /* Clear the current context. */
+ bpstat_remove_breakpoint (stop_bpstat, bpt);
+ /* And from all threads. */
+ 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
+ this breakpoint. Do this before freeing
+ the breakpoint itself, since remove_breakpoint
+ looks at location's owner. It might be better
+ design to have location completely self-contained,
+ but it's not the case now. */
+ update_global_location_list (0);
+
+
/* On the chance that someone will soon try again to delete this same
bp, we mark it as deleted before freeing its storage. */
bpt->type = bp_none;
- for (loc = bpt->loc; loc;)
- {
- struct bp_location *loc_next = loc->next;
- xfree (loc);
- loc = loc_next;
- }
xfree (bpt);
}
return make_cleanup (do_delete_breakpoint_cleanup, b);
}
-struct cleanup *
-make_exec_cleanup_delete_breakpoint (struct breakpoint *b)
-{
- return make_exec_cleanup (do_delete_breakpoint_cleanup, b);
-}
-
void
delete_command (char *arg, int from_tty)
{
if (all_locations_are_pending (existing_locations) && sals.nelts == 0)
return;
- unlink_locations_from_global_list (b);
b->loc = NULL;
for (i = 0; i < sals.nelts; ++i)
}
}
- while (existing_locations)
- {
- struct bp_location *next = existing_locations->next;
- free_bp_location (existing_locations);
- existing_locations = next;
- }
+ update_global_location_list (1);
}
expanded = expand_line_sal_maybe (sals.sals[0]);
update_breakpoint_locations (b, expanded);
- /* Now that this is re-enabled, check_duplicates
- can be used. */
- check_duplicates (b);
-
xfree (sals.sals);
break;
default:
printf_filtered (_("Deleting unknown breakpoint type %d\n"), b->type);
/* fall through */
- /* Delete longjmp and overlay event breakpoints; they will be
- reset later by breakpoint_re_set. */
- case bp_longjmp:
- case bp_longjmp_resume:
+ /* Delete overlay event breakpoints; they will be reset later by
+ breakpoint_re_set. */
case bp_overlay_event:
delete_breakpoint (b);
break;
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_step_resume:
+ case bp_longjmp:
+ case bp_longjmp_resume:
break;
}
}
set_language (save_language);
input_radix = save_input_radix;
-
- if (gdbarch_get_longjmp_target_p (current_gdbarch))
- {
- create_longjmp_breakpoint ("longjmp");
- create_longjmp_breakpoint ("_longjmp");
- create_longjmp_breakpoint ("siglongjmp");
- create_longjmp_breakpoint ("_siglongjmp");
- create_longjmp_breakpoint (NULL);
- }
create_overlay_event_breakpoint ("_ovly_debug_event");
}
bpt->enable_state = bp_disabled;
- check_duplicates (bpt);
+ update_global_location_list (0);
if (deprecated_modify_breakpoint_hook)
deprecated_modify_breakpoint_hook (bpt);
struct bp_location *loc = find_location_by_number (args);
if (loc)
loc->enabled = 0;
- check_duplicates (loc->owner);
+ update_global_location_list (0);
}
else
map_breakpoint_numbers (args, disable_breakpoint);
if (bpt->enable_state != bp_permanent)
bpt->enable_state = bp_enabled;
bpt->disposition = disposition;
- check_duplicates (bpt);
+ update_global_location_list (1);
breakpoints_changed ();
if (deprecated_modify_breakpoint_hook)
struct bp_location *loc = find_location_by_number (args);
if (loc)
loc->enabled = 1;
- check_duplicates (loc->owner);
+ update_global_location_list (1);
}
else
map_breakpoint_numbers (args, enable_breakpoint);
return 0;
}
+int breakpoints_always_inserted_mode (void)
+{
+ return always_inserted_mode;
+}
+
\f
/* This help string is used for the break, hbreak, tbreak and thbreak commands.
It is defined as a macro to prevent duplication.
Set a watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\
an expression changes."));
- set_cmd_completer (c, location_completer);
+ set_cmd_completer (c, expression_completer);
c = add_com ("rwatch", class_breakpoint, rwatch_command, _("\
Set a read watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\
an expression is read."));
- set_cmd_completer (c, location_completer);
+ set_cmd_completer (c, expression_completer);
c = add_com ("awatch", class_breakpoint, awatch_command, _("\
Set a watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\
an expression is either read or written."));
- set_cmd_completer (c, location_completer);
+ set_cmd_completer (c, expression_completer);
add_info ("watchpoints", breakpoints_info,
_("Synonym for ``info breakpoints''."));
show_automatic_hardware_breakpoints,
&breakpoint_set_cmdlist,
&breakpoint_show_cmdlist);
+
+ add_setshow_boolean_cmd ("always-inserted", class_support,
+ &always_inserted_mode, _("\
+Set mode for inserting breakpoints."), _("\
+Show mode for inserting breakpoints."), _("\
+When this mode is off (which is the default), breakpoints are inserted in\n\
+inferior when it is resumed, and removed when execution stops. When this\n\
+mode is on, breakpoints are inserted immediately and removed only when\n\
+the user deletes the breakpoint."),
+ NULL,
+ &show_always_inserted_mode,
+ &breakpoint_set_cmdlist,
+ &breakpoint_show_cmdlist);
automatic_hardware_breakpoints = 1;
}