+ /* Rescan breakpoints at the same address and section, marking the
+ first one as "first" and any others as "duplicates". This is so
+ that the bpt instruction is only inserted once. If we have a
+ permanent breakpoint at the same place as BPT, make that one the
+ official one, and the rest as duplicates. Permanent breakpoints
+ are sorted first for the same address.
+
+ Do the same for hardware watchpoints, but also considering the
+ watchpoint's type (regular/access/read) and length. */
+
+ bp_loc_first = NULL;
+ wp_loc_first = NULL;
+ awp_loc_first = NULL;
+ rwp_loc_first = NULL;
+ ALL_BP_LOCATIONS (loc, locp)
+ {
+ /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always
+ non-NULL. */
+ struct bp_location **loc_first_p;
+ b = loc->owner;
+
+ if (!should_be_inserted (loc)
+ || !breakpoint_address_is_meaningful (b)
+ /* Don't detect duplicate for tracepoint locations because they are
+ never duplicated. See the comments in field `duplicate' of
+ `struct bp_location'. */
+ || is_tracepoint (b))
+ {
+ /* Clear the condition modification flag. */
+ loc->condition_changed = condition_unchanged;
+ continue;
+ }
+
+ /* Permanent breakpoint should always be inserted. */
+ if (b->enable_state == bp_permanent && ! loc->inserted)
+ internal_error (__FILE__, __LINE__,
+ _("allegedly permanent breakpoint is not "
+ "actually inserted"));
+
+ if (b->type == bp_hardware_watchpoint)
+ loc_first_p = &wp_loc_first;
+ else if (b->type == bp_read_watchpoint)
+ loc_first_p = &rwp_loc_first;
+ else if (b->type == bp_access_watchpoint)
+ loc_first_p = &awp_loc_first;
+ else
+ loc_first_p = &bp_loc_first;
+
+ if (*loc_first_p == NULL
+ || (overlay_debugging && loc->section != (*loc_first_p)->section)
+ || !breakpoint_locations_match (loc, *loc_first_p))
+ {
+ *loc_first_p = loc;
+ loc->duplicate = 0;
+
+ if (is_breakpoint (loc->owner) && loc->condition_changed)
+ {
+ loc->needs_update = 1;
+ /* Clear the condition modification flag. */
+ loc->condition_changed = condition_unchanged;
+ }
+ continue;
+ }
+
+
+ /* This and the above ensure the invariant that the first location
+ is not duplicated, and is the inserted one.
+ All following are marked as duplicated, and are not inserted. */
+ if (loc->inserted)
+ swap_insertion (loc, *loc_first_p);
+ loc->duplicate = 1;
+
+ /* Clear the condition modification flag. */
+ loc->condition_changed = condition_unchanged;
+
+ if ((*loc_first_p)->owner->enable_state == bp_permanent && loc->inserted
+ && b->enable_state != bp_permanent)
+ internal_error (__FILE__, __LINE__,
+ _("another breakpoint was inserted on top of "
+ "a permanent breakpoint"));
+ }
+
+ if (breakpoints_always_inserted_mode ()
+ && (have_live_inferiors ()
+ || (gdbarch_has_global_breakpoints (target_gdbarch))))
+ {
+ if (should_insert)
+ insert_breakpoint_locations ();
+ else
+ {
+ /* Though should_insert is false, we may need to update conditions
+ on the target's side if it is evaluating such conditions. We
+ only update conditions for locations that are marked
+ "needs_update". */
+ update_inserted_breakpoint_locations ();
+ }
+ }
+
+ if (should_insert)
+ download_tracepoint_locations ();
+
+ do_cleanups (cleanups);
+}
+
+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)
+ {
+ decref_bp_location (&loc);
+ VEC_unordered_remove (bp_location_p, moribund_locations, ix);
+ --ix;
+ }
+}
+
+static void
+update_global_location_list_nothrow (int inserting)
+{
+ volatile struct gdb_exception e;
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ update_global_location_list (inserting);
+}
+
+/* Clear BKP from a BPS. */
+
+static void
+bpstat_remove_bp_location (bpstat bps, struct breakpoint *bpt)
+{
+ bpstat bs;
+
+ for (bs = bps; bs; bs = bs->next)
+ if (bs->breakpoint_at == 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_bp_location (th->control.stop_bpstat, bpt);
+ return 0;
+}
+
+/* Helper for breakpoint and tracepoint breakpoint_ops->mention
+ callbacks. */
+
+static void
+say_where (struct breakpoint *b)
+{
+ struct ui_out *uiout = current_uiout;
+ struct value_print_options opts;
+
+ get_user_print_options (&opts);
+
+ /* i18n: cagney/2005-02-11: Below needs to be merged into a
+ single string. */
+ if (b->loc == NULL)
+ {
+ printf_filtered (_(" (%s) pending."), b->addr_string);
+ }
+ else
+ {
+ if (opts.addressprint || b->loc->source_file == NULL)
+ {
+ printf_filtered (" at ");
+ fputs_filtered (paddress (b->loc->gdbarch, b->loc->address),
+ gdb_stdout);
+ }
+ if (b->loc->source_file)
+ {
+ /* If there is a single location, we can print the location
+ more nicely. */
+ if (b->loc->next == NULL)
+ printf_filtered (": file %s, line %d.",
+ b->loc->source_file, b->loc->line_number);
+ else
+ /* This is not ideal, but each location may have a
+ different file name, and this at least reflects the
+ real situation somewhat. */
+ printf_filtered (": %s.", b->addr_string);
+ }
+
+ if (b->loc->next)
+ {
+ struct bp_location *loc = b->loc;
+ int n = 0;
+ for (; loc; loc = loc->next)
+ ++n;
+ printf_filtered (" (%d locations)", n);
+ }
+ }
+}
+
+/* Default bp_location_ops methods. */
+
+static void
+bp_location_dtor (struct bp_location *self)
+{
+ xfree (self->cond);
+ if (self->cond_bytecode)
+ free_agent_expr (self->cond_bytecode);
+ xfree (self->function_name);
+ xfree (self->source_file);
+}
+
+static const struct bp_location_ops bp_location_ops =
+{
+ bp_location_dtor
+};
+
+/* Default breakpoint_ops methods all breakpoint_ops ultimately
+ inherit from. */
+
+static void
+base_breakpoint_dtor (struct breakpoint *self)
+{
+ decref_counted_command_line (&self->commands);
+ xfree (self->cond_string);
+ xfree (self->addr_string);
+ xfree (self->filter);
+ xfree (self->addr_string_range_end);
+}
+
+static struct bp_location *
+base_breakpoint_allocate_location (struct breakpoint *self)
+{
+ struct bp_location *loc;
+
+ loc = XNEW (struct bp_location);
+ init_bp_location (loc, &bp_location_ops, self);
+ return loc;
+}
+
+static void
+base_breakpoint_re_set (struct breakpoint *b)
+{
+ /* Nothing to re-set. */
+}
+
+#define internal_error_pure_virtual_called() \
+ gdb_assert_not_reached ("pure virtual function called")
+
+static int
+base_breakpoint_insert_location (struct bp_location *bl)
+{
+ internal_error_pure_virtual_called ();
+}
+
+static int
+base_breakpoint_remove_location (struct bp_location *bl)
+{
+ internal_error_pure_virtual_called ();
+}
+
+static int
+base_breakpoint_breakpoint_hit (const struct bp_location *bl,
+ struct address_space *aspace,
+ CORE_ADDR bp_addr,
+ const struct target_waitstatus *ws)
+{
+ internal_error_pure_virtual_called ();
+}
+
+static void
+base_breakpoint_check_status (bpstat bs)
+{
+ /* Always stop. */
+}
+
+/* A "works_in_software_mode" breakpoint_ops method that just internal
+ errors. */
+
+static int
+base_breakpoint_works_in_software_mode (const struct breakpoint *b)
+{
+ internal_error_pure_virtual_called ();
+}
+
+/* A "resources_needed" breakpoint_ops method that just internal
+ errors. */
+
+static int
+base_breakpoint_resources_needed (const struct bp_location *bl)
+{
+ internal_error_pure_virtual_called ();
+}
+
+static enum print_stop_action
+base_breakpoint_print_it (bpstat bs)
+{
+ internal_error_pure_virtual_called ();
+}
+
+static void
+base_breakpoint_print_one_detail (const struct breakpoint *self,
+ struct ui_out *uiout)
+{
+ /* nothing */
+}
+
+static void
+base_breakpoint_print_mention (struct breakpoint *b)
+{
+ internal_error_pure_virtual_called ();
+}
+
+static void
+base_breakpoint_print_recreate (struct breakpoint *b, struct ui_file *fp)
+{
+ internal_error_pure_virtual_called ();
+}
+
+static void
+base_breakpoint_create_sals_from_address (char **arg,
+ struct linespec_result *canonical,
+ enum bptype type_wanted,
+ char *addr_start,
+ char **copy_arg)
+{
+ internal_error_pure_virtual_called ();
+}
+
+static void
+base_breakpoint_create_breakpoints_sal (struct gdbarch *gdbarch,
+ struct linespec_result *c,
+ struct linespec_sals *lsal,
+ char *cond_string,
+ enum bptype type_wanted,
+ enum bpdisp disposition,
+ int thread,
+ int task, int ignore_count,
+ const struct breakpoint_ops *o,
+ int from_tty, int enabled,
+ int internal)
+{
+ internal_error_pure_virtual_called ();
+}
+
+static void
+base_breakpoint_decode_linespec (struct breakpoint *b, char **s,
+ struct symtabs_and_lines *sals)
+{
+ internal_error_pure_virtual_called ();
+}
+
+static struct breakpoint_ops base_breakpoint_ops =
+{
+ base_breakpoint_dtor,
+ base_breakpoint_allocate_location,
+ base_breakpoint_re_set,
+ base_breakpoint_insert_location,
+ base_breakpoint_remove_location,
+ base_breakpoint_breakpoint_hit,
+ base_breakpoint_check_status,
+ base_breakpoint_resources_needed,
+ base_breakpoint_works_in_software_mode,
+ base_breakpoint_print_it,
+ NULL,
+ base_breakpoint_print_one_detail,
+ base_breakpoint_print_mention,
+ base_breakpoint_print_recreate,
+ base_breakpoint_create_sals_from_address,
+ base_breakpoint_create_breakpoints_sal,
+ base_breakpoint_decode_linespec,
+};
+
+/* Default breakpoint_ops methods. */
+
+static void
+bkpt_re_set (struct breakpoint *b)
+{
+ /* FIXME: is this still reachable? */
+ if (b->addr_string == NULL)
+ {
+ /* Anything without a string can't be re-set. */
+ delete_breakpoint (b);
+ return;
+ }
+
+ breakpoint_re_set_default (b);
+}
+
+static int
+bkpt_insert_location (struct bp_location *bl)
+{
+ if (bl->loc_type == bp_loc_hardware_breakpoint)
+ return target_insert_hw_breakpoint (bl->gdbarch,
+ &bl->target_info);
+ else
+ return target_insert_breakpoint (bl->gdbarch,
+ &bl->target_info);
+}
+
+static int
+bkpt_remove_location (struct bp_location *bl)
+{
+ if (bl->loc_type == bp_loc_hardware_breakpoint)
+ return target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
+ else
+ return target_remove_breakpoint (bl->gdbarch, &bl->target_info);
+}
+
+static int
+bkpt_breakpoint_hit (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr,
+ const struct target_waitstatus *ws)
+{
+ struct breakpoint *b = bl->owner;
+
+ if (ws->kind != TARGET_WAITKIND_STOPPED
+ || ws->value.sig != TARGET_SIGNAL_TRAP)
+ return 0;
+
+ if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
+ aspace, bp_addr))
+ return 0;
+
+ if (overlay_debugging /* unmapped overlay section */
+ && section_is_overlay (bl->section)
+ && !section_is_mapped (bl->section))
+ return 0;
+
+ return 1;
+}
+
+static int
+bkpt_resources_needed (const struct bp_location *bl)
+{
+ gdb_assert (bl->owner->type == bp_hardware_breakpoint);
+
+ return 1;
+}
+
+static enum print_stop_action
+bkpt_print_it (bpstat bs)
+{
+ struct breakpoint *b;
+ const struct bp_location *bl;
+ int bp_temp;
+ struct ui_out *uiout = current_uiout;
+
+ gdb_assert (bs->bp_location_at != NULL);
+
+ bl = bs->bp_location_at;
+ b = bs->breakpoint_at;
+
+ bp_temp = b->disposition == disp_del;
+ if (bl->address != bl->requested_address)
+ breakpoint_adjustment_warning (bl->requested_address,
+ bl->address,
+ b->number, 1);
+ annotate_breakpoint (b->number);
+ if (bp_temp)
+ ui_out_text (uiout, "\nTemporary breakpoint ");
+ else
+ ui_out_text (uiout, "\nBreakpoint ");
+ 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);
+ ui_out_text (uiout, ", ");
+
+ return PRINT_SRC_AND_LOC;
+}
+
+static void
+bkpt_print_mention (struct breakpoint *b)
+{
+ if (ui_out_is_mi_like_p (current_uiout))
+ return;
+
+ switch (b->type)
+ {
+ case bp_breakpoint:
+ case bp_gnu_ifunc_resolver:
+ if (b->disposition == disp_del)
+ printf_filtered (_("Temporary breakpoint"));
+ else
+ printf_filtered (_("Breakpoint"));
+ printf_filtered (_(" %d"), b->number);
+ if (b->type == bp_gnu_ifunc_resolver)
+ printf_filtered (_(" at gnu-indirect-function resolver"));
+ break;
+ case bp_hardware_breakpoint:
+ printf_filtered (_("Hardware assisted breakpoint %d"), b->number);
+ break;
+ }
+
+ say_where (b);
+}
+
+static void
+bkpt_print_recreate (struct breakpoint *tp, struct ui_file *fp)
+{
+ if (tp->type == bp_breakpoint && tp->disposition == disp_del)
+ fprintf_unfiltered (fp, "tbreak");
+ else if (tp->type == bp_breakpoint)
+ fprintf_unfiltered (fp, "break");
+ else if (tp->type == bp_hardware_breakpoint
+ && tp->disposition == disp_del)
+ fprintf_unfiltered (fp, "thbreak");
+ else if (tp->type == bp_hardware_breakpoint)
+ fprintf_unfiltered (fp, "hbreak");
+ else
+ internal_error (__FILE__, __LINE__,
+ _("unhandled breakpoint type %d"), (int) tp->type);
+
+ fprintf_unfiltered (fp, " %s", tp->addr_string);
+ print_recreate_thread (tp, fp);
+}
+
+static void
+bkpt_create_sals_from_address (char **arg,
+ struct linespec_result *canonical,
+ enum bptype type_wanted,
+ char *addr_start, char **copy_arg)
+{
+ create_sals_from_address_default (arg, canonical, type_wanted,
+ addr_start, copy_arg);
+}
+
+static void
+bkpt_create_breakpoints_sal (struct gdbarch *gdbarch,
+ struct linespec_result *canonical,
+ struct linespec_sals *lsal,
+ char *cond_string,
+ enum bptype type_wanted,
+ enum bpdisp disposition,
+ int thread,
+ int task, int ignore_count,
+ const struct breakpoint_ops *ops,
+ int from_tty, int enabled,
+ int internal)
+{
+ create_breakpoints_sal_default (gdbarch, canonical, lsal,
+ cond_string, type_wanted,
+ disposition, thread, task,
+ ignore_count, ops, from_tty,
+ enabled, internal);
+}
+
+static void
+bkpt_decode_linespec (struct breakpoint *b, char **s,
+ struct symtabs_and_lines *sals)
+{
+ decode_linespec_default (b, s, sals);
+}
+
+/* Virtual table for internal breakpoints. */
+
+static void
+internal_bkpt_re_set (struct breakpoint *b)
+{
+ switch (b->type)
+ {
+ /* Delete overlay event and longjmp master breakpoints; they
+ will be reset later by breakpoint_re_set. */
+ case bp_overlay_event:
+ case bp_longjmp_master:
+ case bp_std_terminate_master:
+ case bp_exception_master:
+ delete_breakpoint (b);
+ break;
+
+ /* This breakpoint is special, it's set up when the inferior
+ starts and we really don't want to touch it. */
+ case bp_shlib_event:
+
+ /* Like bp_shlib_event, this breakpoint type is special. Once
+ it is set up, we do not want to touch it. */
+ case bp_thread_event:
+ break;
+ }
+}
+
+static void
+internal_bkpt_check_status (bpstat bs)
+{
+ if (bs->breakpoint_at->type == bp_shlib_event)
+ {
+ /* If requested, stop when the dynamic linker notifies GDB of
+ events. This allows the user to get control and place
+ breakpoints in initializer routines for dynamically loaded
+ objects (among other things). */
+ bs->stop = stop_on_solib_events;
+ bs->print = stop_on_solib_events;
+ }
+ else
+ bs->stop = 0;
+}
+
+static enum print_stop_action
+internal_bkpt_print_it (bpstat bs)
+{
+ struct ui_out *uiout = current_uiout;
+ struct breakpoint *b;
+
+ b = bs->breakpoint_at;
+
+ switch (b->type)
+ {
+ case bp_shlib_event:
+ /* Did we stop because the user set the stop_on_solib_events
+ variable? (If so, we report this as a generic, "Stopped due
+ to shlib event" message.) */
+ print_solib_event (0);
+ break;
+
+ case bp_thread_event:
+ /* Not sure how we will get here.
+ GDB should not stop for these breakpoints. */
+ printf_filtered (_("Thread Event Breakpoint: gdb should not stop!\n"));
+ break;
+
+ case bp_overlay_event:
+ /* By analogy with the thread event, GDB should not stop for these. */
+ printf_filtered (_("Overlay Event Breakpoint: gdb should not stop!\n"));
+ break;
+
+ case bp_longjmp_master:
+ /* These should never be enabled. */
+ printf_filtered (_("Longjmp Master Breakpoint: gdb should not stop!\n"));
+ break;
+
+ case bp_std_terminate_master:
+ /* These should never be enabled. */
+ printf_filtered (_("std::terminate Master Breakpoint: "
+ "gdb should not stop!\n"));
+ break;
+
+ case bp_exception_master:
+ /* These should never be enabled. */
+ printf_filtered (_("Exception Master Breakpoint: "
+ "gdb should not stop!\n"));
+ break;
+ }
+
+ return PRINT_NOTHING;
+}
+
+static void
+internal_bkpt_print_mention (struct breakpoint *b)
+{
+ /* Nothing to mention. These breakpoints are internal. */
+}
+
+/* Virtual table for momentary breakpoints */
+
+static void
+momentary_bkpt_re_set (struct breakpoint *b)
+{
+ /* Keep temporary breakpoints, which can be encountered when we step
+ over a dlopen call and SOLIB_ADD is resetting the breakpoints.
+ Otherwise these should have been blown away via the cleanup chain
+ or by breakpoint_init_inferior when we rerun the executable. */
+}
+
+static void
+momentary_bkpt_check_status (bpstat bs)
+{
+ /* Nothing. The point of these breakpoints is causing a stop. */
+}
+
+static enum print_stop_action
+momentary_bkpt_print_it (bpstat bs)
+{
+ struct ui_out *uiout = current_uiout;
+
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ struct breakpoint *b = bs->breakpoint_at;
+
+ switch (b->type)
+ {
+ case bp_finish:
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_FUNCTION_FINISHED));
+ break;
+
+ case bp_until:
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_LOCATION_REACHED));
+ break;
+ }
+ }
+
+ return PRINT_UNKNOWN;
+}
+
+static void
+momentary_bkpt_print_mention (struct breakpoint *b)
+{
+ /* Nothing to mention. These breakpoints are internal. */
+}
+
+/* The breakpoint_ops structure to be used in tracepoints. */
+
+static void
+tracepoint_re_set (struct breakpoint *b)
+{
+ breakpoint_re_set_default (b);
+}
+
+static int
+tracepoint_breakpoint_hit (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr,
+ const struct target_waitstatus *ws)
+{
+ /* By definition, the inferior does not report stops at
+ tracepoints. */
+ return 0;
+}
+
+static void
+tracepoint_print_one_detail (const struct breakpoint *self,
+ struct ui_out *uiout)
+{
+ struct tracepoint *tp = (struct tracepoint *) self;
+ if (tp->static_trace_marker_id)
+ {
+ gdb_assert (self->type == bp_static_tracepoint);
+
+ ui_out_text (uiout, "\tmarker id is ");
+ ui_out_field_string (uiout, "static-tracepoint-marker-string-id",
+ tp->static_trace_marker_id);
+ ui_out_text (uiout, "\n");
+ }
+}
+
+static void
+tracepoint_print_mention (struct breakpoint *b)
+{
+ if (ui_out_is_mi_like_p (current_uiout))
+ return;