+/* 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;
+
+ switch (b->type)
+ {
+ case bp_tracepoint:
+ printf_filtered (_("Tracepoint"));
+ printf_filtered (_(" %d"), b->number);
+ break;
+ case bp_fast_tracepoint:
+ printf_filtered (_("Fast tracepoint"));
+ printf_filtered (_(" %d"), b->number);
+ break;
+ case bp_static_tracepoint:
+ printf_filtered (_("Static tracepoint"));
+ printf_filtered (_(" %d"), b->number);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("unhandled tracepoint type %d"), (int) b->type);
+ }
+
+ say_where (b);
+}
+
+static void
+tracepoint_print_recreate (struct breakpoint *self, struct ui_file *fp)
+{
+ struct tracepoint *tp = (struct tracepoint *) self;
+
+ if (self->type == bp_fast_tracepoint)
+ fprintf_unfiltered (fp, "ftrace");
+ if (self->type == bp_static_tracepoint)
+ fprintf_unfiltered (fp, "strace");
+ else if (self->type == bp_tracepoint)
+ fprintf_unfiltered (fp, "trace");
+ else
+ internal_error (__FILE__, __LINE__,
+ _("unhandled tracepoint type %d"), (int) self->type);
+
+ fprintf_unfiltered (fp, " %s", self->addr_string);
+ print_recreate_thread (self, fp);
+
+ if (tp->pass_count)
+ fprintf_unfiltered (fp, " passcount %d\n", tp->pass_count);
+}
+
+static void
+tracepoint_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
+tracepoint_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
+tracepoint_decode_linespec (struct breakpoint *b, char **s,
+ struct symtabs_and_lines *sals)
+{
+ decode_linespec_default (b, s, sals);
+}
+
+struct breakpoint_ops tracepoint_breakpoint_ops;
+
+/* The breakpoint_ops structure to be used on static tracepoints with
+ markers (`-m'). */
+
+static void
+strace_marker_create_sals_from_address (char **arg,
+ struct linespec_result *canonical,
+ enum bptype type_wanted,
+ char *addr_start, char **copy_arg)
+{
+ struct linespec_sals lsal;
+
+ lsal.sals = decode_static_tracepoint_spec (arg);
+
+ *copy_arg = savestring (addr_start, *arg - addr_start);
+
+ canonical->addr_string = xstrdup (*copy_arg);
+ lsal.canonical = xstrdup (*copy_arg);
+ VEC_safe_push (linespec_sals, canonical->sals, &lsal);
+}
+
+static void
+strace_marker_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)
+{
+ int i;
+
+ /* If the user is creating a static tracepoint by marker id
+ (strace -m MARKER_ID), then store the sals index, so that
+ breakpoint_re_set can try to match up which of the newly
+ found markers corresponds to this one, and, don't try to
+ expand multiple locations for each sal, given than SALS
+ already should contain all sals for MARKER_ID. */
+
+ for (i = 0; i < lsal->sals.nelts; ++i)
+ {
+ struct symtabs_and_lines expanded;
+ struct tracepoint *tp;
+ struct cleanup *old_chain;
+ char *addr_string;
+
+ expanded.nelts = 1;
+ expanded.sals = &lsal->sals.sals[i];
+
+ addr_string = xstrdup (canonical->addr_string);
+ old_chain = make_cleanup (xfree, addr_string);
+
+ tp = XCNEW (struct tracepoint);
+ init_breakpoint_sal (&tp->base, gdbarch, expanded,
+ addr_string, NULL,
+ cond_string, type_wanted, disposition,
+ thread, task, ignore_count, ops,
+ from_tty, enabled, internal,
+ canonical->special_display);
+ /* Given that its possible to have multiple markers with
+ the same string id, if the user is creating a static
+ tracepoint by marker id ("strace -m MARKER_ID"), then
+ store the sals index, so that breakpoint_re_set can
+ try to match up which of the newly found markers
+ corresponds to this one */
+ tp->static_trace_marker_id_idx = i;
+
+ install_breakpoint (internal, &tp->base, 0);
+
+ discard_cleanups (old_chain);
+ }
+}
+
+static void
+strace_marker_decode_linespec (struct breakpoint *b, char **s,
+ struct symtabs_and_lines *sals)