Re: [patch] [python] Expose some breakpoint operations to Python

Pedro Alves
2011-06-23T15:30:13Z

On Thursday 23 June 2011 15:46:14, Phil Muldoon wrote:
> Pedro Alves <pedro@codesourcery.com> writes:
>
> >> What do you think?
> >
> > Well, here's my kneee jerk reaction. Last night I started converting
> > all breakpoints to use breakpoint_ops, and I immediately stumbled on
> > the fact that the print_one method doesn't appear to work as is. I
> > don't like the idea of exposing the API as is and getting stuck
> > with it when we haven't even made sure it's a good fit for
> > gdb's own regular breakpoints. :-(
>
> I'm curious to know what is wrong with it. print_one just passes the
> breakpoint and the address to the consumer, and the consumer then just
> prints to the "Addr" and "What" fields. In the strict context of the
> API, it works in the Python tests.
>
> Can you expand on that instance?

...
>
> If you have a plan for the API, could your write it up? I am ready and
> willing to help out wherever and whenever needed.

No plan yet. I just started out by adding a single breakpoint_ops instance
that handles all breakpoint types that currently aren't using breakpoint_ops,
and moving all default actions to the corresponding callback. This would
be straightforward if the API is a good fit. But take a look at
the fallback code in print_one_breakpoint_location, and print_one_breakpoint.
Breakpoints with multiple locations are handled a bit differently than
just a fallbach, with multiple calls to print_one_breakpoint. Maybe we
could move all that !print_one code inside the new print_one callback?
Not sure. Also, maybe we should split printing the "what" from
the "address"? Not sure either, but it looks bizarre to me that
current print_one implementations need to know to call annotate_field.
Then there are implementations that print free form text
surrounding those values, e.g., see print_one_catch_vfork. These
issues certainly inpact the python api.

(You'll also note that the ->insert_location and
->remove_location call sites reveal that something isn't fully
abstracted, since failing to insert different kinds of breakpoints
leads to different reactions in the code).

Note, the doesn't even compile.

Something else that's obviously missing with exposing breakpoint_ops
to python as is (yes I know you haven't exported all of it), is that most
certainly users will want to be able to call the "super" method. That is,
say, e.g, override, the ->check_status method, and still call the default
method, whatever it was.

> OTOH, in a larger sense, I agree with your internal API statement. If
> it is not suitable yet, we should not expose it yet. For example the
> "print_it" enum 'SRC_ONLY' just prints a source-line number (without a
> file). I cannot fathom how it would be useful.

Well, what does grep tell us?

breakpoint.c: PRINT_SRC_ONLY: Means we printed something, and we do *not* desire
breakpoint.c: PRINT_SRC_ONLY: Means we printed something, but there is no need
breakpoint.c: if (val == PRINT_SRC_ONLY
breakpoint.h: PRINT_SRC_ONLY,
infrun.c: case PRINT_SRC_ONLY:

Looks like it's never used? Maybe gdbtk uses it, haven't checked.
Certainly a good example of that cleaning up the house a little before
exposing the API is a good idea.

> Then again, there is
> lots that I do not consider useful, but it is in some other GDB context.

--
Pedro Alves
---
gdb/breakpoint.c | 1539 ++++++++++++++++++++++++++++---------------------------
1 file changed, 802 insertions(+), 737 deletions(-)

Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c 2011-06-23 01:25:32.000000000 +0100
+++ src/gdb/breakpoint.c 2011-06-23 15:59:56.489910546 +0100
@@ -104,9 +104,7 @@ static void break_command_1 (char *, int

static void mention (struct breakpoint *);

-/* This function is used in gdbtk sources and thus can not be made
- static. */
-struct breakpoint *set_raw_breakpoint (struct gdbarch *gdbarch,
+static struct breakpoint *set_raw_breakpoint (struct gdbarch *gdbarch,
struct symtab_and_line,
enum bptype);

@@ -1436,10 +1434,7 @@ update_watchpoint (struct breakpoint *b,
(b->type, i, other_type_used);
if (target_resources_ok <= 0)
{
- /* If there's no works_in_software_mode method, we
- assume that the watchpoint works in software mode. */
- int sw_mode = (!b->ops || !b->ops->works_in_software_mode
- || b->ops->works_in_software_mode (b));
+ int sw_mode = b->ops->works_in_software_mode (b);

if (target_resources_ok == 0 && !sw_mode)
error (_("Target does not support this type of "
@@ -1451,8 +1446,7 @@ update_watchpoint (struct breakpoint *b,
b->type = bp_watchpoint;
}
}
- else if (b->ops && b->ops->works_in_software_mode
- && !b->ops->works_in_software_mode (b))
+ else if (!b->ops->works_in_software_mode (b))
error (_("Expression cannot be implemented with "
"read/access watchpoint."));
else
@@ -1555,127 +1549,11 @@ insert_bp_location (struct bp_location *
bl->target_info.placed_address_space = bl->pspace->aspace;
bl->target_info.length = bl->length;

+ val = bl->owner->ops->insert_location (bl);
+
if (bl->loc_type == bp_loc_software_breakpoint
|| bl->loc_type == bp_loc_hardware_breakpoint)
{
- if (bl->owner->type != bp_hardware_breakpoint)
- {
- /* If the explicitly specified breakpoint type
- is not hardware breakpoint, check the memory map to see
- if the breakpoint address is in read only memory or not.
-
- Two important cases are:
- - location type is not hardware breakpoint, memory
- is readonly. We change the type of the location to
- hardware breakpoint.
- - location type is hardware breakpoint, memory is
- read-write. This means we've previously made the
- location hardware one, but then the memory map changed,
- so we undo.
-
- When breakpoints are removed, remove_breakpoints will use
- location types we've just set here, the only possible
- problem is that memory map has changed during running
- program, but it's not going to work anyway with current
- gdb. */
- struct mem_region *mr
- = lookup_mem_region (bl->target_info.placed_address);
-
- if (mr)
- {
- if (automatic_hardware_breakpoints)
- {
- enum bp_loc_type new_type;
-
- if (mr->attrib.mode != MEM_RW)
- new_type = bp_loc_hardware_breakpoint;
- else
- new_type = bp_loc_software_breakpoint;
-
- if (new_type != bl->loc_type)
- {
- static int said = 0;
-
- bl->loc_type = new_type;
- if (!said)
- {
- fprintf_filtered (gdb_stdout,
- _("Note: automatically using "
- "hardware breakpoints for "
- "read-only addresses.\n"));
- said = 1;
- }
- }
- }
- else if (bl->loc_type == bp_loc_software_breakpoint
- && mr->attrib.mode != MEM_RW)
- warning (_("cannot set software breakpoint "
- "at readonly address %s"),
- paddress (bl->gdbarch, bl->address));
- }
- }
-
- /* First check to see if we have to handle an overlay. */
- if (overlay_debugging == ovly_off
- || bl->section == NULL
- || !(section_is_overlay (bl->section)))
- {
- /* No overlay handling: just set the breakpoint. */
-
- if (bl->loc_type == bp_loc_hardware_breakpoint)
- val = target_insert_hw_breakpoint (bl->gdbarch,
- &bl->target_info);
- else
- val = target_insert_breakpoint (bl->gdbarch,
- &bl->target_info);
- }
- else
- {
- /* This breakpoint is in an overlay section.
- Shall we set a breakpoint at the LMA? */
- if (!overlay_events_enabled)
- {
- /* Yes -- overlay event support is not active,
- so we must try to set a breakpoint at the LMA.
- This will not work for a hardware breakpoint. */
- if (bl->loc_type == bp_loc_hardware_breakpoint)
- warning (_("hardware breakpoint %d not supported in overlay!"),
- bl->owner->number);
- else
- {
- CORE_ADDR addr = overlay_unmapped_address (bl->address,
- bl->section);
- /* Set a software (trap) breakpoint at the LMA. */
- bl->overlay_target_info = bl->target_info;
- bl->overlay_target_info.placed_address = addr;
- val = target_insert_breakpoint (bl->gdbarch,
- &bl->overlay_target_info);
- if (val != 0)
- fprintf_unfiltered (tmp_error_stream,
- "Overlay breakpoint %d "
- "failed: in ROM?\n",
- bl->owner->number);
- }
- }
- /* Shall we set a breakpoint at the VMA? */
- if (section_is_mapped (bl->section))
- {
- /* Yes. This overlay section is mapped into memory. */
- if (bl->loc_type == bp_loc_hardware_breakpoint)
- val = target_insert_hw_breakpoint (bl->gdbarch,
- &bl->target_info);
- else
- val = target_insert_breakpoint (bl->gdbarch,
- &bl->target_info);
- }
- else
- {
- /* No. This breakpoint will not be inserted.
- No error, but do not mark the bp as 'inserted'. */
- return 0;
- }
- }
-
if (val)
{
/* Can't set the breakpoint. */
@@ -1734,11 +1612,6 @@ insert_bp_location (struct bp_location *
watchpoints. It's not clear that it's necessary... */
&& bl->owner->disposition != disp_del_at_next_stop)
{
- gdb_assert (bl->owner->ops != NULL
- && bl->owner->ops->insert_location != NULL);
-
- val = bl->owner->ops->insert_location (bl);
-
/* If trying to set a read-watchpoint, and it turns out it's not
supported, try emulating one with an access watchpoint. */
if (val == 1 && bl->watchpoint_type == hw_read)
@@ -1777,10 +1650,6 @@ insert_bp_location (struct bp_location *

else if (bl->owner->type == bp_catchpoint)
{
- gdb_assert (bl->owner->ops != NULL
- && bl->owner->ops->insert_location != NULL);
-
- val = bl->owner->ops->insert_location (bl);
if (val)
{
bl->owner->enable_state = bp_disabled;
@@ -2537,74 +2406,7 @@ remove_breakpoint_1 (struct bp_location
if (bl->loc_type == bp_loc_software_breakpoint
|| bl->loc_type == bp_loc_hardware_breakpoint)
{
- /* "Normal" instruction breakpoint: either the standard
- trap-instruction bp (bp_breakpoint), or a
- bp_hardware_breakpoint. */
-
- /* First check to see if we have to handle an overlay. */
- if (overlay_debugging == ovly_off
- || bl->section == NULL
- || !(section_is_overlay (bl->section)))
- {
- /* No overlay handling: just remove the breakpoint. */
-
- if (bl->loc_type == bp_loc_hardware_breakpoint)
- val = target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
- else
- val = target_remove_breakpoint (bl->gdbarch, &bl->target_info);
- }
- else
- {
- /* This breakpoint is in an overlay section.
- Did we set a breakpoint at the LMA? */
- if (!overlay_events_enabled)
- {
- /* Yes -- overlay event support is not active, so we
- should have set a breakpoint at the LMA. Remove it.
- */
- /* Ignore any failures: if the LMA is in ROM, we will
- have already warned when we failed to insert it. */
- if (bl->loc_type == bp_loc_hardware_breakpoint)
- target_remove_hw_breakpoint (bl->gdbarch,
- &bl->overlay_target_info);
- else
- target_remove_breakpoint (bl->gdbarch,
- &bl->overlay_target_info);
- }
- /* Did we set a breakpoint at the VMA?
- If so, we will have marked the breakpoint 'inserted'. */
- if (bl->inserted)
- {
- /* Yes -- remove it. Previously we did not bother to
- remove the breakpoint if the section had been
- unmapped, but let's not rely on that being safe. We
- don't know what the overlay manager might do. */
- if (bl->loc_type == bp_loc_hardware_breakpoint)
- val = target_remove_hw_breakpoint (bl->gdbarch,
- &bl->target_info);
-
- /* However, we should remove *software* breakpoints only
- if the section is still mapped, or else we overwrite
- wrong code with the saved shadow contents. */
- else if (section_is_mapped (bl->section))
- val = target_remove_breakpoint (bl->gdbarch,
- &bl->target_info);
- else
- val = 0;
- }
- else
- {
- /* No -- not inserted, so no need to remove. No error. */
- val = 0;
- }
- }
-
- /* In some cases, we might not be able to remove a breakpoint
- in a shared library that has already been removed, but we
- have not yet processed the shlib unload event. */
- if (val && solib_name_from_address (bl->pspace, bl->address))
- val = 0;
-
+ val = bl->owner->ops->remove_location (bl);
if (val)
return val;
bl->inserted = (is == mark_inserted);
@@ -2626,9 +2428,6 @@ remove_breakpoint_1 (struct bp_location
&& breakpoint_enabled (bl->owner)
&& !bl->duplicate)
{
- gdb_assert (bl->owner->ops != NULL
- && bl->owner->ops->remove_location != NULL);
-
val = bl->owner->ops->remove_location (bl);
if (val)
return val;
@@ -3549,12 +3348,8 @@ print_bp_stop_message (bpstat bs)
if (b == NULL)
return PRINT_UNKNOWN;

- /* Normal case. Call the breakpoint's print_it method, or
- print_it_typical. */
- if (b->ops != NULL && b->ops->print_it != NULL)
- return b->ops->print_it (b);
- else
- return print_it_typical (bs);
+ /* Normal case. Call the breakpoint's print_it method. */
+ return b->ops->print_it (b);
}
break;

@@ -3873,60 +3668,19 @@ which its expression is valid.\n");
}

/* 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. */
+ 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,
struct address_space *aspace, CORE_ADDR bp_addr)
{
struct breakpoint *b = bl->owner;

- /* BL is from existing struct breakpoint. */
+ /* BL is from an existing breakpoint. */
gdb_assert (b != NULL);

- if (b->ops && b->ops->breakpoint_hit)
- return b->ops->breakpoint_hit (bl, aspace, bp_addr);
-
- /* By definition, the inferior does not report stops at
- tracepoints. */
- if (is_tracepoint (b))
- return 0;
-
- if (!is_watchpoint (b)
- && b->type != bp_hardware_breakpoint
- && b->type != bp_catchpoint) /* a non-watchpoint bp */
- {
- 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;
- }
-
- /* 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 (is_hardware_watchpoint (b)
- && 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;
- }
-
- return 1;
+ return b->ops->breakpoint_hit (bl, aspace, bp_addr);
}

/* If BS refers to a watchpoint, determine if the watched values
@@ -4307,27 +4061,11 @@ bpstat_stop_status (struct address_space
if (!bs->stop)
continue;

- bpstat_check_watchpoint (bs);
- if (!bs->stop)
- continue;
-
b = bs->breakpoint_at;
-
- if (b->ops != NULL && b->ops->check_status != NULL)
+ b->ops->check_status (bs);
+ if (bs->stop)
{
- b->ops->check_status (bs);
- if (!bs->stop)
- continue;
- }
-
- if (b->type == bp_thread_event || b->type == bp_overlay_event
- || b->type == bp_longjmp_master
- || b->type == bp_std_terminate_master
- || b->type == bp_exception_master)
- /* We do not stop for these. */
- bs->stop = 0;
- else
- bpstat_check_breakpoint_conditions (bs, ptid);
+ bpstat_check_breakpoint_conditions (bs, ptid);

if (bs->stop)
{
@@ -4360,6 +4098,7 @@ bpstat_stop_status (struct address_space
/* Print nothing for this entry if we dont stop or dont print. */
if (bs->stop == 0 || bs->print == 0)
bs->print_it = print_it_noop;
+ }
}

/* If we aren't stopping, the value of some hardware watchpoint may
@@ -4992,20 +4731,10 @@ print_one_breakpoint_location (struct br

ui_out_text (uiout, "\n");

- if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+ if (!part_of_multiple)
b->ops->print_one_detail (b, uiout);

- if (!part_of_multiple && b->static_trace_marker_id)
- {
- gdb_assert (b->type == bp_static_tracepoint);
-
- ui_out_text (uiout, "\tmarker id is ");
- ui_out_field_string (uiout, "static-tracepoint-marker-string-id",
- b->static_trace_marker_id);
- ui_out_text (uiout, "\n");
- }
-
- if (part_of_multiple && frame_id_p (b->frame_id))
+ if (part_of_multiple && frame_id_p (b->frame_id))
{
annotate_field (6);
ui_out_text (uiout, "\tstop only in stack frame at ");
@@ -5753,28 +5482,13 @@ init_bp_location (struct bp_location *lo
static struct bp_location *
allocate_bp_location (struct breakpoint *bpt)
{
- struct bp_location *loc;
-
- if (bpt->ops && bpt->ops->allocate_location)
- return bpt->ops->allocate_location (bpt);
-
- loc = xmalloc (sizeof (struct bp_location));
- init_bp_location (loc, NULL, bpt);
- return loc;
+ return bpt->ops->allocate_location (bpt);
}

static void
free_bp_location (struct bp_location *loc)
{
- if (loc->ops && loc->ops->dtor)
- loc->ops->dtor (loc);
-
- if (loc->cond)
- xfree (loc->cond);
-
- if (loc->function_name)
- xfree (loc->function_name);
-
+ loc->ops->dtor (loc);
xfree (loc);
}

@@ -5992,13 +5706,13 @@ init_raw_breakpoint (struct breakpoint *
prior to completing the initialization of the breakpoint. If this
should happen, a bogus breakpoint will be left on the chain. */

-struct breakpoint *
+static struct breakpoint *
set_raw_breakpoint (struct gdbarch *gdbarch,
struct symtab_and_line sal, enum bptype bptype)
{
struct breakpoint *b = XNEW (struct breakpoint);

- init_raw_breakpoint (b, gdbarch, sal, bptype, NULL);
+ init_raw_breakpoint (b, gdbarch, sal, bptype, &bkpt_ops);
add_to_breakpoint_chain (b);
return b;
}
@@ -7054,10 +6768,7 @@ hw_breakpoint_used_count (void)
{
/* Special types of hardware breakpoints may use more than
one register. */
- if (b->ops && b->ops->resources_needed)
- i += b->ops->resources_needed (bl);
- else
- i++;
+ i += b->ops->resources_needed (bl);
}
}

@@ -7082,10 +6793,7 @@ hw_watchpoint_used_count (enum bptype ty
{
/* Special types of hardware watchpoints may use more than
one register. */
- if (b->ops && b->ops->resources_needed)
- i += b->ops->resources_needed (bl);
- else
- i++;
+ i += b->ops->resources_needed (bl);
}
else if (is_hardware_watchpoint (b))
*other_type_used = 1;
@@ -7267,162 +6975,7 @@ set_momentary_breakpoint_at_pc (struct g
static void
mention (struct breakpoint *b)
{
- int say_where = 0;
- struct cleanup *ui_out_chain;
- struct value_print_options opts;
-
- get_user_print_options (&opts);
-
- if (b->ops != NULL && b->ops->print_mention != NULL)
- b->ops->print_mention (b);
- else
- switch (b->type)
- {
- case bp_none:
- printf_filtered (_("(apparently deleted?) Eventpoint %d: "),
- b->number);
- break;
- case bp_watchpoint:
- ui_out_text (uiout, "Watchpoint ");
- ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
- ui_out_field_int (uiout, "number", b->number);
- ui_out_text (uiout, ": ");
- ui_out_field_string (uiout, "exp", b->exp_string);
- do_cleanups (ui_out_chain);
- break;
- case bp_hardware_watchpoint:
- ui_out_text (uiout, "Hardware watchpoint ");
- ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
- ui_out_field_int (uiout, "number", b->number);
- ui_out_text (uiout, ": ");
- ui_out_field_string (uiout, "exp", b->exp_string);
- do_cleanups (ui_out_chain);
- break;
- case bp_read_watchpoint:
- ui_out_text (uiout, "Hardware read watchpoint ");
- ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
- ui_out_field_int (uiout, "number", b->number);
- ui_out_text (uiout, ": ");
- ui_out_field_string (uiout, "exp", b->exp_string);
- do_cleanups (ui_out_chain);
- break;
- case bp_access_watchpoint:
- ui_out_text (uiout, "Hardware access (read/write) watchpoint ");
- ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
- ui_out_field_int (uiout, "number", b->number);
- ui_out_text (uiout, ": ");
- ui_out_field_string (uiout, "exp", b->exp_string);
- do_cleanups (ui_out_chain);
- break;
- case bp_breakpoint:
- case bp_gnu_ifunc_resolver:
- if (ui_out_is_mi_like_p (uiout))
- {
- say_where = 0;
- break;
- }
- 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"));
- say_where = 1;
- break;
- case bp_hardware_breakpoint:
- if (ui_out_is_mi_like_p (uiout))
- {
- say_where = 0;
- break;
- }
- printf_filtered (_("Hardware assisted breakpoint %d"), b->number);
- say_where = 1;
- break;
- case bp_tracepoint:
- if (ui_out_is_mi_like_p (uiout))
- {
- say_where = 0;
- break;
- }
- printf_filtered (_("Tracepoint"));
- printf_filtered (_(" %d"), b->number);
- say_where = 1;
- break;
- case bp_fast_tracepoint:
- if (ui_out_is_mi_like_p (uiout))
- {
- say_where = 0;
- break;
- }
- printf_filtered (_("Fast tracepoint"));
- printf_filtered (_(" %d"), b->number);
- say_where = 1;
- break;
- case bp_static_tracepoint:
- if (ui_out_is_mi_like_p (uiout))
- {
- say_where = 0;
- break;
- }
- printf_filtered (_("Static tracepoint"));
- printf_filtered (_(" %d"), b->number);
- say_where = 1;
- break;
-
- case bp_until:
- case bp_finish:
- case bp_longjmp:
- case bp_longjmp_resume:
- case bp_exception:
- case bp_exception_resume:
- case bp_step_resume:
- case bp_hp_step_resume:
- case bp_call_dummy:
- case bp_std_terminate:
- case bp_watchpoint_scope:
- case bp_shlib_event:
- case bp_thread_event:
- case bp_overlay_event:
- case bp_jit_event:
- case bp_longjmp_master:
- case bp_std_terminate_master:
- case bp_exception_master:
- case bp_gnu_ifunc_resolver_return:
- break;
- }
-
- if (say_where)
- {
- /* 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->source_file == NULL)
- {
- printf_filtered (" at ");
- fputs_filtered (paddress (b->loc->gdbarch, b->loc->address),
- gdb_stdout);
- }
- if (b->source_file)
- printf_filtered (": file %s, line %d.",
- b->source_file, b->line_number);
-
- if (b->loc->next)
- {
- struct bp_location *loc = b->loc;
- int n = 0;
- for (; loc; loc = loc->next)
- ++n;
- printf_filtered (" (%d locations)", n);
- }
-
- }
- }
+ b->ops->print_mention (b);
if (ui_out_is_mi_like_p (uiout))
return;
printf_filtered ("\n");
@@ -7496,8 +7049,6 @@ bp_loc_is_permanent (struct bp_location
return retval;
}

-
-
/* Create a breakpoint with SAL as location. Use ADDR_STRING
as textual description of the location, and COND_STRING
as condition expression. */
@@ -10799,127 +10350,801 @@ bpstat_remove_breakpoint_callback (struc
return 0;
}

-/* Delete a breakpoint and clean up all traces of it in the data
- structures. */
+/* Default breakpoint_ops methods. */

-void
-delete_breakpoint (struct breakpoint *bpt)
+static void
+bkpt_dtor (struct breakpoint *self)
{
- struct breakpoint *b;
-
- gdb_assert (bpt != NULL);
+ decref_counted_command_line (&self->commands);
+ xfree (self->cond_string);
+ xfree (self->cond_exp);
+ xfree (self->addr_string);
+ xfree (self->addr_string_range_end);
+ xfree (self->exp);
+ xfree (self->exp_string);
+ xfree (self->exp_string_reparse);
+ value_free (self->val);
+ xfree (self->source_file);
+}

- /* Has this bp already been deleted? This can happen because
- multiple lists can hold pointers to bp's. bpstat lists are
- especial culprits.
+static struct bp_location *
+bkpt_allocate_location (struct breakpoint *self)
+{
+ struct bp_location *loc;

- One example of this happening is a watchpoint's scope bp. When
- the scope bp triggers, we notice that the watchpoint is out of
- scope, and delete it. We also delete its scope bp. But the
- scope bp is marked "auto-deleting", and is already on a bpstat.
- That bpstat is then checked for auto-deleting bp's, which are
- deleted.
+ loc = XNEW (struct bp_location);
+ init_bp_location (loc, NULL, bpt);
+ return loc;
+}

- A real solution to this problem might involve reference counts in
- bp's, and/or giving them pointers back to their referencing
- bpstat's, and teaching delete_breakpoint to only free a bp's
- storage when no more references were extent. A cheaper bandaid
- was chosen. */
- if (bpt->type == bp_none)
- return;
+static enum print_stop_action
+bkpt_print_it (bpstat bs)
+{
+ return print_it_typical (bs);
+}

- /* At least avoid this stale reference until the reference counting
- of breakpoints gets resolved. */
- if (bpt->related_breakpoint != bpt)
- {
- struct breakpoint *related;
+static int
+bkpt_breakpoint_hit (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr)
+{
+ struct breakpoint *b = bl->owner;

- if (bpt->type == bp_watchpoint_scope)
- watchpoint_del_at_next_stop (bpt->related_breakpoint);
- else if (bpt->related_breakpoint->type == bp_watchpoint_scope)
- watchpoint_del_at_next_stop (bpt);
+ /* By definition, the inferior does not report stops at
+ tracepoints. */
+ if (is_tracepoint (b))
+ return 0;

- /* Unlink bpt from the bpt->related_breakpoint ring. */
- for (related = bpt; related->related_breakpoint != bpt;
- related = related->related_breakpoint);
- related->related_breakpoint = bpt->related_breakpoint;
- bpt->related_breakpoint = bpt;
+ if (!is_watchpoint (b)
+ && b->type != bp_hardware_breakpoint
+ && b->type != bp_catchpoint) /* a non-watchpoint bp */
+ {
+ 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;
}

- /* watch_command_1 creates a watchpoint but only sets its number if
- update_watchpoint succeeds in creating its bp_locations. If there's
- a problem in that process, we'll be asked to delete the half-created
- watchpoint. In that case, don't announce the deletion. */
- if (bpt->number)
- observer_notify_breakpoint_deleted (bpt);
+ /* 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 (breakpoint_chain == bpt)
- breakpoint_chain = bpt->next;
+ if (is_hardware_watchpoint (b)
+ && b->watchpoint_triggered == watch_triggered_no)
+ return 0;

- ALL_BREAKPOINTS (b)
- if (b->next == bpt)
+ if (b->type == bp_hardware_breakpoint)
{
- b->next = bpt->next;
- break;
+ 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;
}

- if (bpt->ops != NULL && bpt->ops->dtor != NULL)
- bpt->ops->dtor (bpt);
-
- decref_counted_command_line (&bpt->commands);
- xfree (bpt->cond_string);
- xfree (bpt->cond_exp);
- xfree (bpt->addr_string);
- xfree (bpt->addr_string_range_end);
- xfree (bpt->exp);
- xfree (bpt->exp_string);
- xfree (bpt->exp_string_reparse);
- value_free (bpt->val);
- xfree (bpt->source_file);
-
-
- /* Be sure no bpstat's are pointing at the breakpoint after it's
- been freed. */
- /* FIXME, how can we find all bpstat's? We just check stop_bpstat
- in all threeds for now. Note that we cannot just remove bpstats
- pointing at bpt from the stop_bpstat list entirely, as breakpoint
- commands are associated with the bpstat; if we remove it here,
- then the later call to bpstat_do_actions (&stop_bpstat); in
- event-top.c won't do anything, and temporary breakpoints with
- commands won't work. */
-
- iterate_over_threads (bpstat_remove_breakpoint_callback, bpt);
-
- /* Now that breakpoint is removed from breakpoint list, update the
- global location list. This will remove locations that used to
- belong to 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);
-
+ return 1;
+}

- /* 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;
+static int
+bkpt_check_status (bpstat bs)
+{
+ struct breakpoint *b = bs->breakpoint_at;

- xfree (bpt);
+ if (is_watchpoint (b))
+ bpstat_check_watchpoint (bs);
+ else if (b->type == bp_thread_event
+ || b->type == bp_overlay_event
+ || b->type == bp_longjmp_master
+ || b->type == bp_std_terminate_master
+ || b->type == bp_exception_master)
+ /* We do not stop for these. */
+ bs->stop = 0;
}

static void
-do_delete_breakpoint_cleanup (void *b)
+bkpt_print_one (struct breakpoint *self,
+ struct bp_location *loc,
+ int header_of_multiple,
+ int part_of_multiple,
+ struct bp_location **last_loc)
{
- delete_breakpoint (b);
-}
+ struct value_print_options opts;

-struct cleanup *
-make_cleanup_delete_breakpoint (struct breakpoint *b)
-{
- return make_cleanup (do_delete_breakpoint_cleanup, b);
+ get_user_print_options (&opts);
}

-/* Iterator function to call a user-provided callback function once
- for each of B and its related breakpoints. */
+/* Implement the "print_one_detail" breakpoint_ops method for regular
+ breakpoints. */
+
+static void
+bkpt_print_one_detail (const struct breakpoint *self,
+ struct ui_out *uiout)
+{
+ if (self->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",
+ self->static_trace_marker_id);
+ ui_out_text (uiout, "\n");
+ }
+}
+
+static int
+bkpt_resources_needed (struct bp_location *bl)
+{
+ gdb_assert (bl->owner->type == bp_hardware_breakpoint
+ || is_hardware_watchpoint (bl->owner));
+
+ return 1;
+}
+
+static int
+bkpt_print_mention (struct breakpoint *b)
+{
+ struct cleanup *ui_out_chain;
+ struct value_print_options opts;
+ int say_where = 0;
+
+ get_user_print_options (&opts);
+
+ switch (b->type)
+ {
+ case bp_none:
+ printf_filtered (_("(apparently deleted?) Eventpoint %d: "),
+ b->number);
+ break;
+ case bp_watchpoint:
+ ui_out_text (uiout, "Watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+ ui_out_field_int (uiout, "number", b->number);
+ ui_out_text (uiout, ": ");
+ ui_out_field_string (uiout, "exp", b->exp_string);
+ do_cleanups (ui_out_chain);
+ break;
+ case bp_hardware_watchpoint:
+ ui_out_text (uiout, "Hardware watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+ ui_out_field_int (uiout, "number", b->number);
+ ui_out_text (uiout, ": ");
+ ui_out_field_string (uiout, "exp", b->exp_string);
+ do_cleanups (ui_out_chain);
+ break;
+ case bp_read_watchpoint:
+ ui_out_text (uiout, "Hardware read watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+ ui_out_field_int (uiout, "number", b->number);
+ ui_out_text (uiout, ": ");
+ ui_out_field_string (uiout, "exp", b->exp_string);
+ do_cleanups (ui_out_chain);
+ break;
+ case bp_access_watchpoint:
+ ui_out_text (uiout, "Hardware access (read/write) watchpoint ");
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+ ui_out_field_int (uiout, "number", b->number);
+ ui_out_text (uiout, ": ");
+ ui_out_field_string (uiout, "exp", b->exp_string);
+ do_cleanups (ui_out_chain);
+ break;
+ case bp_breakpoint:
+ case bp_gnu_ifunc_resolver:
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ say_where = 0;
+ break;
+ }
+ 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"));
+ say_where = 1;
+ break;
+ case bp_hardware_breakpoint:
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ say_where = 0;
+ break;
+ }
+ printf_filtered (_("Hardware assisted breakpoint %d"), b->number);
+ say_where = 1;
+ break;
+ case bp_tracepoint:
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ say_where = 0;
+ break;
+ }
+ printf_filtered (_("Tracepoint"));
+ printf_filtered (_(" %d"), b->number);
+ say_where = 1;
+ break;
+ case bp_fast_tracepoint:
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ say_where = 0;
+ break;
+ }
+ printf_filtered (_("Fast tracepoint"));
+ printf_filtered (_(" %d"), b->number);
+ say_where = 1;
+ break;
+ case bp_static_tracepoint:
+ if (ui_out_is_mi_like_p (uiout))
+ {
+ say_where = 0;
+ break;
+ }
+ printf_filtered (_("Static tracepoint"));
+ printf_filtered (_(" %d"), b->number);
+ say_where = 1;
+ break;
+
+ case bp_until:
+ case bp_finish:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
+ case bp_step_resume:
+ case bp_hp_step_resume:
+ case bp_call_dummy:
+ case bp_std_terminate:
+ case bp_watchpoint_scope:
+ case bp_shlib_event:
+ case bp_thread_event:
+ case bp_overlay_event:
+ case bp_jit_event:
+ case bp_longjmp_master:
+ case bp_std_terminate_master:
+ case bp_exception_master:
+ case bp_gnu_ifunc_resolver_return:
+ break;
+ }
+
+ if (say_where)
+ {
+ /* 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->source_file == NULL)
+ {
+ printf_filtered (" at ");
+ fputs_filtered (paddress (b->loc->gdbarch, b->loc->address),
+ gdb_stdout);
+ }
+ if (b->source_file)
+ printf_filtered (": file %s, line %d.",
+ b->source_file, b->line_number);
+
+ if (b->loc->next)
+ {
+ struct bp_location *loc = b->loc;
+ int n = 0;
+ for (; loc; loc = loc->next)
+ ++n;
+ printf_filtered (" (%d locations)", n);
+ }
+
+ }
+ }
+}
+
+static int
+bkpt_re_set (struct breakpoint *b)
+{
+ switch (b->type)
+ {
+ case bp_none:
+ warning (_("attempted to reset apparently deleted breakpoint #%d?"),
+ b->number);
+ return 0;
+ case bp_breakpoint:
+ case bp_hardware_breakpoint:
+ case bp_tracepoint:
+ case bp_fast_tracepoint:
+ case bp_static_tracepoint:
+ case bp_gnu_ifunc_resolver:
+ /* Do not attempt to re-set breakpoints disabled during startup. */
+ if (b->enable_state == bp_startup_disabled)
+ return 0;
+
+ if (b->addr_string == NULL)
+ {
+ /* Anything without a string can't be re-set. */
+ delete_breakpoint (b);
+ return 0;
+ }
+
+ breakpoint_re_set_default (b);
+ }
+ break;
+
+ case bp_watchpoint:
+ case bp_hardware_watchpoint:
+ case bp_read_watchpoint:
+ case bp_access_watchpoint:
+ /* Watchpoint can be either on expression using entirely global
+ variables, or it can be on local variables.
+
+ Watchpoints of the first kind are never auto-deleted, and
+ even persist across program restarts. Since they can use
+ variables from shared libraries, we need to reparse
+ expression as libraries are loaded and unloaded.
+
+ Watchpoints on local variables can also change meaning as
+ result of solib event. For example, if a watchpoint uses
+ both a local and a global variables in expression, it's a
+ local watchpoint, but unloading of a shared library will make
+ the expression invalid. This is not a very common use case,
+ but we still re-evaluate expression, to avoid surprises to
+ the user.
+
+ Note that for local watchpoints, we re-evaluate it only if
+ watchpoints frame id is still valid. If it's not, it means
+ the watchpoint is out of scope and will be deleted soon. In
+ fact, I'm not sure we'll ever be called in this case.
+
+ If a local watchpoint's frame id is still valid, then
+ b->exp_valid_block is likewise valid, and we can safely use it.
+
+ Don't do anything about disabled watchpoints, since they will
+ be reevaluated again when enabled. */
+ update_watchpoint (b, 1 /* reparse */);
+ break;
+ /* We needn't really do anything to reset these, since the mask
+ that requests them is unaffected by e.g., new libraries being
+ loaded. */
+ case bp_catchpoint:
+ break;
+
+ default:
+ printf_filtered (_("Deleting unknown breakpoint type %d\n"), b->type);
+ /* fall through */
+ /* 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:
+
+ /* 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. */
+ case bp_until:
+ case bp_finish:
+ case bp_watchpoint_scope:
+ case bp_call_dummy:
+ case bp_std_terminate:
+ case bp_step_resume:
+ case bp_hp_step_resume:
+ case bp_longjmp:
+ case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
+ case bp_jit_event:
+ case bp_gnu_ifunc_resolver_return:
+ break;
+ }
+}
+
+static void
+bkpt_print_recreate (struct breakpoint *tp, struct ui_file *fp)
+{
+ if (tp->type == bp_fast_tracepoint)
+ fprintf_unfiltered (fp, "ftrace");
+ if (tp->type == bp_static_tracepoint)
+ fprintf_unfiltered (fp, "strace");
+ else if (tp->type == bp_tracepoint)
+ fprintf_unfiltered (fp, "trace");
+ else if (tp->type == bp_breakpoint && tp->disposition == disp_del)
+ fprintf_unfiltered (fp, "tbreak");
+ else if (tp->type == bp_breakpoint)
+ fprintf_unfiltered (fp, "break");
+ else if (tp->type == bp_hardware_breakpoint
+ && tp->disposition == disp_del)
+ fprintf_unfiltered (fp, "thbreak");
+ else if (tp->type == bp_hardware_breakpoint)
+ fprintf_unfiltered (fp, "hbreak");
+ else if (tp->type == bp_watchpoint)
+ fprintf_unfiltered (fp, "watch");
+ else if (tp->type == bp_hardware_watchpoint)
+ fprintf_unfiltered (fp, "watch");
+ else if (tp->type == bp_read_watchpoint)
+ fprintf_unfiltered (fp, "rwatch");
+ else if (tp->type == bp_access_watchpoint)
+ fprintf_unfiltered (fp, "awatch");
+ else
+ internal_error (__FILE__, __LINE__,
+ _("unhandled breakpoint type %d"), (int) tp->type);
+
+ if (tp->exp_string)
+ fprintf_unfiltered (fp, " %s", tp->exp_string);
+ else if (tp->addr_string)
+ fprintf_unfiltered (fp, " %s", tp->addr_string);
+ else
+ {
+ char tmp[40];
+
+ sprintf_vma (tmp, tp->loc->address);
+ fprintf_unfiltered (fp, " *0x%s", tmp);
+ }
+}
+
+static int
+bkpt_works_in_software_mode (const struct breakpoint *b)
+{
+ gdb_assert_unreachable ("");
+}
+
+static int
+bkpt_insert_location (struct bp_location *bl)
+{
+ if (bl->loc_type == bp_loc_software_breakpoint
+ || bl->loc_type == bp_loc_hardware_breakpoint)
+ {
+ if (bl->owner->type != bp_hardware_breakpoint)
+ {
+ /* If the explicitly specified breakpoint type
+ is not hardware breakpoint, check the memory map to see
+ if the breakpoint address is in read only memory or not.
+
+ Two important cases are:
+ - location type is not hardware breakpoint, memory
+ is readonly. We change the type of the location to
+ hardware breakpoint.
+ - location type is hardware breakpoint, memory is
+ read-write. This means we've previously made the
+ location hardware one, but then the memory map changed,
+ so we undo.
+
+ When breakpoints are removed, remove_breakpoints will use
+ location types we've just set here, the only possible
+ problem is that memory map has changed during running
+ program, but it's not going to work anyway with current
+ gdb. */
+ struct mem_region *mr
+ = lookup_mem_region (bl->target_info.placed_address);
+
+ if (mr)
+ {
+ if (automatic_hardware_breakpoints)
+ {
+ enum bp_loc_type new_type;
+
+ if (mr->attrib.mode != MEM_RW)
+ new_type = bp_loc_hardware_breakpoint;
+ else
+ new_type = bp_loc_software_breakpoint;
+
+ if (new_type != bl->loc_type)
+ {
+ static int said = 0;
+
+ bl->loc_type = new_type;
+ if (!said)
+ {
+ fprintf_filtered (gdb_stdout,
+ _("Note: automatically using "
+ "hardware breakpoints for "
+ "read-only addresses.\n"));
+ said = 1;
+ }
+ }
+ }
+ else if (bl->loc_type == bp_loc_software_breakpoint
+ && mr->attrib.mode != MEM_RW)
+ warning (_("cannot set software breakpoint "
+ "at readonly address %s"),
+ paddress (bl->gdbarch, bl->address));
+ }
+ }
+
+ /* First check to see if we have to handle an overlay. */
+ if (overlay_debugging == ovly_off
+ || bl->section == NULL
+ || !(section_is_overlay (bl->section)))
+ {
+ /* No overlay handling: just set the breakpoint. */
+
+ if (bl->loc_type == bp_loc_hardware_breakpoint)
+ val = target_insert_hw_breakpoint (bl->gdbarch,
+ &bl->target_info);
+ else
+ val = target_insert_breakpoint (bl->gdbarch,
+ &bl->target_info);
+ }
+ else
+ {
+ /* This breakpoint is in an overlay section.
+ Shall we set a breakpoint at the LMA? */
+ if (!overlay_events_enabled)
+ {
+ /* Yes -- overlay event support is not active,
+ so we must try to set a breakpoint at the LMA.
+ This will not work for a hardware breakpoint. */
+ if (bl->loc_type == bp_loc_hardware_breakpoint)
+ warning (_("hardware breakpoint %d not supported in overlay!"),
+ bl->owner->number);
+ else
+ {
+ CORE_ADDR addr = overlay_unmapped_address (bl->address,
+ bl->section);
+ /* Set a software (trap) breakpoint at the LMA. */
+ bl->overlay_target_info = bl->target_info;
+ bl->overlay_target_info.placed_address = addr;
+ val = target_insert_breakpoint (bl->gdbarch,
+ &bl->overlay_target_info);
+ if (val != 0)
+ fprintf_unfiltered (tmp_error_stream,
+ "Overlay breakpoint %d "
+ "failed: in ROM?\n",
+ bl->owner->number);
+ }
+ }
+ /* Shall we set a breakpoint at the VMA? */
+ if (section_is_mapped (bl->section))
+ {
+ /* Yes. This overlay section is mapped into memory. */
+ if (bl->loc_type == bp_loc_hardware_breakpoint)
+ val = target_insert_hw_breakpoint (bl->gdbarch,
+ &bl->target_info);
+ else
+ val = target_insert_breakpoint (bl->gdbarch,
+ &bl->target_info);
+ }
+ else
+ {
+ /* No. This breakpoint will not be inserted.
+ No error, but do not mark the bp as 'inserted'. */
+ return 0;
+ }
+ }
+
+ return val;
+ }
+}
+
+static int
+bkpt_remove_location (struct bp_location *bl)
+{
+ int val;
+
+ if (bl->loc_type == bp_loc_software_breakpoint
+ || bl->loc_type == bp_loc_hardware_breakpoint)
+ {
+ /* "Normal" instruction breakpoint: either the standard
+ trap-instruction bp (bp_breakpoint), or a
+ bp_hardware_breakpoint. */
+
+ /* First check to see if we have to handle an overlay. */
+ if (overlay_debugging == ovly_off
+ || bl->section == NULL
+ || !(section_is_overlay (bl->section)))
+ {
+ /* No overlay handling: just remove the breakpoint. */
+
+ if (bl->loc_type == bp_loc_hardware_breakpoint)
+ val = target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
+ else
+ val = target_remove_breakpoint (bl->gdbarch, &bl->target_info);
+ }
+ else
+ {
+ /* This breakpoint is in an overlay section.
+ Did we set a breakpoint at the LMA? */
+ if (!overlay_events_enabled)
+ {
+ /* Yes -- overlay event support is not active, so we
+ should have set a breakpoint at the LMA. Remove it.
+ */
+ /* Ignore any failures: if the LMA is in ROM, we will
+ have already warned when we failed to insert it. */
+ if (bl->loc_type == bp_loc_hardware_breakpoint)
+ target_remove_hw_breakpoint (bl->gdbarch,
+ &bl->overlay_target_info);
+ else
+ target_remove_breakpoint (bl->gdbarch,
+ &bl->overlay_target_info);
+ }
+ /* Did we set a breakpoint at the VMA?
+ If so, we will have marked the breakpoint 'inserted'. */
+ if (bl->inserted)
+ {
+ /* Yes -- remove it. Previously we did not bother to
+ remove the breakpoint if the section had been
+ unmapped, but let's not rely on that being safe. We
+ don't know what the overlay manager might do. */
+ if (bl->loc_type == bp_loc_hardware_breakpoint)
+ val = target_remove_hw_breakpoint (bl->gdbarch,
+ &bl->target_info);
+
+ /* However, we should remove *software* breakpoints only
+ if the section is still mapped, or else we overwrite
+ wrong code with the saved shadow contents. */
+ else if (section_is_mapped (bl->section))
+ val = target_remove_breakpoint (bl->gdbarch,
+ &bl->target_info);
+ else
+ val = 0;
+ }
+ else
+ {
+ /* No -- not inserted, so no need to remove. No error. */
+ val = 0;
+ }
+ }
+
+ /* In some cases, we might not be able to remove a breakpoint
+ in a shared library that has already been removed, but we
+ have not yet processed the shlib unload event. */
+ if (val && solib_name_from_address (bl->pspace, bl->address))
+ val = 0;
+ }
+
+ return val;
+}
+
+/* The breakpoint_ops structure to be used in regular breakpoints. */
+
+static struct breakpoint_ops bkpt_ops =
+{
+ bkpt_dtor,
+ bkpt_allocate_location,
+ bkpt_re_set,
+ bkpt_insert,
+ bkpt_remove,
+ bkpt_breakpoint_hit,
+ bkpt_check_status,
+ bkpt_resources_needed,
+ bkpt_works_in_software_mode,
+ bkpt_print_it,
+ bkpt_print_one,
+ bkpt_print_one_detailk,
+ bkpt_print_mention,
+ bkpt_print_recreate
+};
+
+/* Default bp_location_ops methods. */
+
+static void
+bp_location_dtor (struct bp_location *self)
+{
+ xfree (self->cond);
+ xfree (self->function_name);
+}
+
+/* Delete a breakpoint and clean up all traces of it in the data
+ structures. */
+
+void
+delete_breakpoint (struct breakpoint *bpt)
+{
+ struct breakpoint *b;
+
+ gdb_assert (bpt != NULL);
+
+ /* Has this bp already been deleted? This can happen because
+ multiple lists can hold pointers to bp's. bpstat lists are
+ especial culprits.
+
+ One example of this happening is a watchpoint's scope bp. When
+ the scope bp triggers, we notice that the watchpoint is out of
+ scope, and delete it. We also delete its scope bp. But the
+ scope bp is marked "auto-deleting", and is already on a bpstat.
+ That bpstat is then checked for auto-deleting bp's, which are
+ deleted.
+
+ A real solution to this problem might involve reference counts in
+ bp's, and/or giving them pointers back to their referencing
+ bpstat's, and teaching delete_breakpoint to only free a bp's
+ storage when no more references were extent. A cheaper bandaid
+ was chosen. */
+ if (bpt->type == bp_none)
+ return;
+
+ /* At least avoid this stale reference until the reference counting
+ of breakpoints gets resolved. */
+ if (bpt->related_breakpoint != bpt)
+ {
+ struct breakpoint *related;
+
+ if (bpt->type == bp_watchpoint_scope)
+ watchpoint_del_at_next_stop (bpt->related_breakpoint);
+ else if (bpt->related_breakpoint->type == bp_watchpoint_scope)
+ watchpoint_del_at_next_stop (bpt);
+
+ /* Unlink bpt from the bpt->related_breakpoint ring. */
+ for (related = bpt; related->related_breakpoint != bpt;
+ related = related->related_breakpoint);
+ related->related_breakpoint = bpt->related_breakpoint;
+ bpt->related_breakpoint = bpt;
+ }
+
+ /* watch_command_1 creates a watchpoint but only sets its number if
+ update_watchpoint succeeds in creating its bp_locations. If there's
+ a problem in that process, we'll be asked to delete the half-created
+ watchpoint. In that case, don't announce the deletion. */
+ if (bpt->number)
+ observer_notify_breakpoint_deleted (bpt);
+
+ if (breakpoint_chain == bpt)
+ breakpoint_chain = bpt->next;
+
+ ALL_BREAKPOINTS (b)
+ if (b->next == bpt)
+ {
+ b->next = bpt->next;
+ break;
+ }
+
+ /* Be sure no bpstat's are pointing at the breakpoint after it's
+ been freed. */
+ /* FIXME, how can we find all bpstat's? We just check stop_bpstat
+ in all threeds for now. Note that we cannot just remove bpstats
+ pointing at bpt from the stop_bpstat list entirely, as breakpoint
+ commands are associated with the bpstat; if we remove it here,
+ then the later call to bpstat_do_actions (&stop_bpstat); in
+ event-top.c won't do anything, and temporary breakpoints with
+ commands won't work. */
+
+ iterate_over_threads (bpstat_remove_breakpoint_callback, bpt);
+
+ /* Now that breakpoint is removed from breakpoint list, update the
+ global location list. This will remove locations that used to
+ belong to 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);
+
+ bpt->ops->dtor (bpt);
+ /* 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;
+ xfree (bpt);
+}
+
+static void
+do_delete_breakpoint_cleanup (void *b)
+{
+ delete_breakpoint (b);
+}
+
+struct cleanup *
+make_cleanup_delete_breakpoint (struct breakpoint *b)
+{
+ return make_cleanup (do_delete_breakpoint_cleanup, b);
+}
+
+/* Iterator function to call a user-provided callback function once
+ for each of B and its related breakpoints. */

static void
iterate_over_related_breakpoints (struct breakpoint *b,
@@ -11473,129 +11698,11 @@ breakpoint_re_set_one (void *bint)
{
/* Get past catch_errs. */
struct breakpoint *b = (struct breakpoint *) bint;
+ struct cleanup *cleanups;

- if (b->ops != NULL && b->ops->re_set != NULL)
- {
- struct cleanup *cleanups;
-
- cleanups = prepare_re_set_context (b);
- b->ops->re_set (b);
- do_cleanups (cleanups);
-
- return 0;
- }
-
- switch (b->type)
- {
- case bp_none:
- warning (_("attempted to reset apparently deleted breakpoint #%d?"),
- b->number);
- return 0;
- case bp_breakpoint:
- case bp_hardware_breakpoint:
- case bp_tracepoint:
- case bp_fast_tracepoint:
- case bp_static_tracepoint:
- case bp_gnu_ifunc_resolver:
- /* Do not attempt to re-set breakpoints disabled during startup. */
- if (b->enable_state == bp_startup_disabled)
- return 0;
-
- if (b->addr_string == NULL)
- {
- /* Anything without a string can't be re-set. */
- delete_breakpoint (b);
- return 0;
- }
-
- {
- struct cleanup *cleanups;
-
- cleanups = prepare_re_set_context (b);
- breakpoint_re_set_default (b);
- do_cleanups (cleanups);
- }
- break;
-
- case bp_watchpoint:
- case bp_hardware_watchpoint:
- case bp_read_watchpoint:
- case bp_access_watchpoint:
- /* Watchpoint can be either on expression using entirely global
- variables, or it can be on local variables.
-
- Watchpoints of the first kind are never auto-deleted, and
- even persist across program restarts. Since they can use
- variables from shared libraries, we need to reparse
- expression as libraries are loaded and unloaded.
-
- Watchpoints on local variables can also change meaning as
- result of solib event. For example, if a watchpoint uses
- both a local and a global variables in expression, it's a
- local watchpoint, but unloading of a shared library will make
- the expression invalid. This is not a very common use case,
- but we still re-evaluate expression, to avoid surprises to
- the user.
-
- Note that for local watchpoints, we re-evaluate it only if
- watchpoints frame id is still valid. If it's not, it means
- the watchpoint is out of scope and will be deleted soon. In
- fact, I'm not sure we'll ever be called in this case.
-
- If a local watchpoint's frame id is still valid, then
- b->exp_valid_block is likewise valid, and we can safely use it.
-
- Don't do anything about disabled watchpoints, since they will
- be reevaluated again when enabled. */
- update_watchpoint (b, 1 /* reparse */);
- break;
- /* We needn't really do anything to reset these, since the mask
- that requests them is unaffected by e.g., new libraries being
- loaded. */
- case bp_catchpoint:
- break;
-
- default:
- printf_filtered (_("Deleting unknown breakpoint type %d\n"), b->type);
- /* fall through */
- /* 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:
-
- /* 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. */
- case bp_until:
- case bp_finish:
- case bp_watchpoint_scope:
- case bp_call_dummy:
- case bp_std_terminate:
- case bp_step_resume:
- case bp_hp_step_resume:
- case bp_longjmp:
- case bp_longjmp_resume:
- case bp_exception:
- case bp_exception_resume:
- case bp_jit_event:
- case bp_gnu_ifunc_resolver_return:
- break;
- }
-
+ cleanups = prepare_re_set_context (b);
+ b->ops->re_set (b);
+ do_cleanups (cleanups);
return 0;
}

@@ -12774,49 +12881,7 @@ save_breakpoints (char *filename, int fr
if (filter && !filter (tp))
continue;

- if (tp->ops != NULL && tp->ops->print_recreate != NULL)
- (tp->ops->print_recreate) (tp, fp);
- else
- {
- if (tp->type == bp_fast_tracepoint)
- fprintf_unfiltered (fp, "ftrace");
- if (tp->type == bp_static_tracepoint)
- fprintf_unfiltered (fp, "strace");
- else if (tp->type == bp_tracepoint)
- fprintf_unfiltered (fp, "trace");
- else if (tp->type == bp_breakpoint && tp->disposition == disp_del)
- fprintf_unfiltered (fp, "tbreak");
- else if (tp->type == bp_breakpoint)
- fprintf_unfiltered (fp, "break");
- else if (tp->type == bp_hardware_breakpoint
- && tp->disposition == disp_del)
- fprintf_unfiltered (fp, "thbreak");
- else if (tp->type == bp_hardware_breakpoint)
- fprintf_unfiltered (fp, "hbreak");
- else if (tp->type == bp_watchpoint)
- fprintf_unfiltered (fp, "watch");
- else if (tp->type == bp_hardware_watchpoint)
- fprintf_unfiltered (fp, "watch");
- else if (tp->type == bp_read_watchpoint)
- fprintf_unfiltered (fp, "rwatch");
- else if (tp->type == bp_access_watchpoint)
- fprintf_unfiltered (fp, "awatch");
- else
- internal_error (__FILE__, __LINE__,
- _("unhandled breakpoint type %d"), (int) tp->type);
-
- if (tp->exp_string)
- fprintf_unfiltered (fp, " %s", tp->exp_string);
- else if (tp->addr_string)
- fprintf_unfiltered (fp, " %s", tp->addr_string);
- else
- {
- char tmp[40];
-
- sprintf_vma (tmp, tp->loc->address);
- fprintf_unfiltered (fp, " *0x%s", tmp);
- }
- }
+ tp->ops->print_recreate (tp, fp);

if (tp->thread != -1)
fprintf_unfiltered (fp, " thread %d", tp->thread);