static int breakpoint_1 (int, int, int (*) (const struct breakpoint *));
-static bpstat bpstat_alloc (struct bp_location *, bpstat);
-
static int breakpoint_cond_eval (void *);
static void cleanup_executing_breakpoints (void *);
/* Assuming we're creating a static tracepoint, does S look like a
static tracepoint marker spec ("-m MARKER_ID")? */
#define is_marker_spec(s) \
- (strncmp (s, "-m", 2) == 0 && ((s)[2] == ' ' || (s)[2] == '\t'))
+ (s != NULL && strncmp (s, "-m", 2) == 0 && ((s)[2] == ' ' || (s)[2] == '\t'))
/* A reference-counted struct command_line. This lets multiple
breakpoints share a single command list. */
static int internal_breakpoint_number = -1;
+/* Set the breakpoint number of B, depending on the value of INTERNAL.
+ If INTERNAL is non-zero, the breakpoint number will be populated
+ from internal_breakpoint_number and that variable decremented.
+ Otherwis the breakpoint number will be populated from
+ breakpoint_count and that value incremented. Internal breakpoints
+ do not set the internal var bpnum. */
+static void
+set_breakpoint_number (int internal, struct breakpoint *b)
+{
+ if (internal)
+ b->number = internal_breakpoint_number--;
+ else
+ {
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ }
+}
+
static struct breakpoint *
create_internal_breakpoint (struct gdbarch *gdbarch,
CORE_ADDR address, enum bptype type)
do_cleanups (old_chain);
}
+/* Install a master breakpoint on the unwinder's debug hook. */
+
+void
+create_exception_master_breakpoint (void)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ struct minimal_symbol *debug_hook;
+
+ debug_hook = lookup_minimal_symbol ("_Unwind_DebugHook", NULL, objfile);
+ if (debug_hook != NULL)
+ {
+ struct breakpoint *b;
+ CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (debug_hook);
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
+ addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
+ ¤t_target);
+ b = create_internal_breakpoint (gdbarch, addr, bp_exception_master);
+ b->addr_string = xstrdup ("_Unwind_DebugHook");
+ b->enable_state = bp_disabled;
+ }
+ }
+
+ update_global_location_list (1);
+}
+
void
update_breakpoints_after_exec (void)
{
/* Thread event breakpoints must be set anew after an exec(),
as must overlay event and longjmp master breakpoints. */
if (b->type == bp_thread_event || b->type == bp_overlay_event
- || b->type == bp_longjmp_master || b->type == bp_std_terminate_master)
+ || b->type == bp_longjmp_master || b->type == bp_std_terminate_master
+ || b->type == bp_exception_master)
{
delete_breakpoint (b);
continue;
/* Longjmp and longjmp-resume breakpoints are also meaningless
after an exec. */
- if (b->type == bp_longjmp || b->type == bp_longjmp_resume)
+ if (b->type == bp_longjmp || b->type == bp_longjmp_resume
+ || b->type == bp_exception || b->type == bp_exception_resume)
{
delete_breakpoint (b);
continue;
create_longjmp_master_breakpoint ("siglongjmp");
create_longjmp_master_breakpoint ("_siglongjmp");
create_std_terminate_master_breakpoint ("std::terminate()");
+ create_exception_master_breakpoint ();
}
int
interrupt the command list. When the call finishes
successfully, the inferior will be standing at the same
breakpoint as if nothing happened. */
- if (tp->in_infcall)
+ if (tp->control.in_infcall)
return;
}
and only return when it is stopped at the next breakpoint, we
keep doing breakpoint actions until it returns false to
indicate the inferior was not resumed. */
- if (!bpstat_do_actions_1 (&inferior_thread ()->stop_bpstat))
+ if (!bpstat_do_actions_1 (&inferior_thread ()->control.stop_bpstat))
break;
}
result = PRINT_NOTHING;
break;
+ case bp_exception_master:
+ /* These should never be enabled. */
+ printf_filtered (_("Exception Master Breakpoint: gdb should not stop!\n"));
+ result = PRINT_NOTHING;
+ break;
+
case bp_watchpoint:
case bp_hardware_watchpoint:
annotate_watchpoint (b->number);
case bp_none:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
return i;
}
-/* Allocate a new bpstat and chain it to the current one. */
+/* Allocate a new bpstat. Link it to the FIFO list by BS_LINK_POINTER. */
static bpstat
-bpstat_alloc (struct bp_location *bl, bpstat cbs /* Current "bs" value */ )
+bpstat_alloc (struct bp_location *bl, bpstat **bs_link_pointer)
{
bpstat bs;
bs = (bpstat) xmalloc (sizeof (*bs));
- cbs->next = bs;
+ bs->next = NULL;
+ **bs_link_pointer = bs;
+ *bs_link_pointer = &bs->next;
bs->breakpoint_at = bl->owner;
bs->bp_location_at = bl;
incref_bp_location (bl);
struct breakpoint *b = NULL;
struct bp_location *bl;
struct bp_location *loc;
- /* Root of the chain of bpstat's */
- struct bpstats root_bs[1];
+ /* First item of allocated bpstat's. */
+ bpstat bs_head = NULL, *bs_link = &bs_head;
/* Pointer to the last thing in the chain currently. */
- bpstat bs = root_bs;
+ bpstat bs;
int ix;
int need_remove_insert;
int removed_any;
/* Come here if it's a watchpoint, or if the break address matches */
- bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */
+ bs = bpstat_alloc (bl, &bs_link); /* Alloc a bpstat to explain stop */
/* Assume we stop. Should we find a watchpoint that is not
actually triggered, or if the condition of the breakpoint
if (breakpoint_address_match (loc->pspace->aspace, loc->address,
aspace, bp_addr))
{
- bs = bpstat_alloc (loc, bs);
+ bs = bpstat_alloc (loc, &bs_link);
/* For hits of moribund locations, we should just proceed. */
bs->stop = 0;
bs->print = 0;
}
}
- /* Terminate the chain. */
- bs->next = NULL;
-
/* Now go through the locations that caused the target to stop, and
check whether we're interested in reporting this stop to higher
layers, or whether we should resume the target transparently. */
removed_any = 0;
- for (bs = root_bs->next; bs != NULL; bs = bs->next)
+ for (bs = bs_head; bs != NULL; bs = bs->next)
{
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_std_terminate_master
+ || b->type == bp_exception_master)
/* We do not stop for these. */
bs->stop = 0;
else
watching may have. Don't bother if we're stopping; this will get
done later. */
need_remove_insert = 0;
- if (! bpstat_causes_stop (root_bs->next))
- for (bs = root_bs->next; bs != NULL; bs = bs->next)
+ if (! bpstat_causes_stop (bs_head))
+ for (bs = bs_head; bs != NULL; bs = bs->next)
if (!bs->stop
&& bs->breakpoint_at
&& is_hardware_watchpoint (bs->breakpoint_at))
else if (removed_any)
update_global_location_list (0);
- return root_bs->next;
+ return bs_head;
}
static void
retval.main_action = BPSTAT_WHAT_KEEP_CHECKING;
retval.call_dummy = STOP_NONE;
+ retval.is_longjmp = 0;
for (; bs != NULL; bs = bs->next)
{
}
break;
case bp_longjmp:
+ case bp_exception:
this_action = BPSTAT_WHAT_SET_LONGJMP_RESUME;
+ retval.is_longjmp = bptype == bp_longjmp;
break;
case bp_longjmp_resume:
+ case bp_exception_resume:
this_action = BPSTAT_WHAT_CLEAR_LONGJMP_RESUME;
+ retval.is_longjmp = bptype == bp_longjmp_resume;
break;
case bp_step_resume:
if (bs->stop)
case bp_overlay_event:
case bp_longjmp_master:
case bp_std_terminate_master:
+ case bp_exception_master:
this_action = BPSTAT_WHAT_SINGLE;
break;
case bp_catchpoint:
{bp_access_watchpoint, "acc watchpoint"},
{bp_longjmp, "longjmp"},
{bp_longjmp_resume, "longjmp resume"},
+ {bp_exception, "exception"},
+ {bp_exception_resume, "exception resume"},
{bp_step_resume, "step resume"},
{bp_watchpoint_scope, "watchpoint scope"},
{bp_call_dummy, "call dummy"},
{bp_overlay_event, "overlay events"},
{bp_longjmp_master, "longjmp master"},
{bp_std_terminate_master, "std::terminate master"},
+ {bp_exception_master, "exception master"},
{bp_catchpoint, "catchpoint"},
{bp_tracepoint, "tracepoint"},
{bp_fast_tracepoint, "fast tracepoint"},
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_overlay_event:
case bp_longjmp_master:
case bp_std_terminate_master:
+ case bp_exception_master:
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_static_tracepoint:
if (filter && !filter (b))
continue;
- if (allflag || user_settable_breakpoint (b))
+ if (allflag || (user_settable_breakpoint (b)
+ && b->number > 0))
{
int addr_bit, type_len;
/* We only print out user settable breakpoints unless the
allflag is set. */
- if (allflag || user_settable_breakpoint (b))
+ if (allflag || (user_settable_breakpoint (b)
+ && b->number > 0))
print_one_breakpoint (b, &last_loc, print_address_bits, allflag);
}
}
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_jit_event:
case bp_longjmp_master:
case bp_std_terminate_master:
+ case bp_exception_master:
loc->loc_type = bp_loc_software_breakpoint;
break;
case bp_hardware_breakpoint:
static void
decref_bp_location (struct bp_location **blp)
{
+ gdb_assert ((*blp)->refc > 0);
+
if (--(*blp)->refc == 0)
free_bp_location (*blp);
*blp = NULL;
b->syscalls_to_be_caught = NULL;
b->ops = NULL;
b->condition_not_parsed = 0;
+ b->py_bp_object = NULL;
/* Add this breakpoint to the end of the chain
so that a list of breakpoints will come out in order
}
/* Call this routine when stepping and nexting to enable a breakpoint
- if we do a longjmp() in THREAD. When we hit that breakpoint, call
- set_longjmp_resume_breakpoint() to figure out where we are going. */
+ if we do a longjmp() or 'throw' in TP. FRAME is the frame which
+ initiated the operation. */
void
-set_longjmp_breakpoint (int thread)
+set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame)
{
struct breakpoint *b, *temp;
+ int thread = tp->num;
/* To avoid having to rescan all objfile symbols at every step,
we maintain a list of continually-inserted but always disabled
clones of those and enable them for the requested thread. */
ALL_BREAKPOINTS_SAFE (b, temp)
if (b->pspace == current_program_space
- && b->type == bp_longjmp_master)
+ && (b->type == bp_longjmp_master
+ || b->type == bp_exception_master))
{
struct breakpoint *clone = clone_momentary_breakpoint (b);
- clone->type = bp_longjmp;
+ clone->type = b->type == bp_longjmp_master ? bp_longjmp : bp_exception;
clone->thread = thread;
}
+
+ tp->initiating_frame = frame;
}
/* Delete all longjmp breakpoints from THREAD. */
struct breakpoint *b, *temp;
ALL_BREAKPOINTS_SAFE (b, temp)
- if (b->type == bp_longjmp)
+ if (b->type == bp_longjmp || b->type == bp_exception)
{
if (b->thread == thread)
delete_breakpoint (b);
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_call_dummy:
case bp_std_terminate:
case bp_jit_event:
case bp_longjmp_master:
case bp_std_terminate_master:
+ case bp_exception_master:
break;
}
char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
- struct breakpoint_ops *ops, int from_tty, int enabled)
+ struct breakpoint_ops *ops, int from_tty,
+ int enabled, int internal)
{
struct breakpoint *b = NULL;
int i;
if (i == 0)
{
b = set_raw_breakpoint (gdbarch, sal, type);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
+ set_breakpoint_number (internal, b);
b->thread = thread;
b->task = task;
= xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
b->ops = ops;
- mention (b);
+ if (internal)
+ /* Do not mention breakpoints with a negative number, but do
+ notify observers. */
+ observer_notify_breakpoint_created (b->number);
+ else
+ mention (b);
}
/* Remove element at INDEX_TO_REMOVE from SAL, shifting other
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
struct breakpoint_ops *ops, int from_tty,
- int enabled)
+ int enabled, int internal)
{
int i;
create_breakpoint_sal (gdbarch, expanded, addr_string[i],
cond_string, type, disposition,
- thread, task, ignore_count, ops, from_tty, enabled);
+ thread, task, ignore_count, ops,
+ from_tty, enabled, internal);
}
}
parameter. If non-zero, the function will parse arg, extracting
breakpoint location, address and thread. Otherwise, ARG is just the
location of breakpoint, with condition and thread specified by the
- COND_STRING and THREAD parameters. Returns true if any breakpoint
- was created; false otherwise. */
+ COND_STRING and THREAD parameters. If INTERNAL is non-zero, the
+ breakpoint number will be allocated from the internal breakpoint
+ count. Returns true if any breakpoint was created; false
+ otherwise. */
int
create_breakpoint (struct gdbarch *gdbarch,
int ignore_count,
enum auto_boolean pending_break_support,
struct breakpoint_ops *ops,
- int from_tty,
- int enabled)
+ int from_tty, int enabled, int internal)
{
struct gdb_exception e;
struct symtabs_and_lines sals;
/* If pending breakpoint support is auto query and the user
selects no, then simply return the error code. */
if (pending_break_support == AUTO_BOOLEAN_AUTO
- && !nquery ("Make breakpoint pending on future shared library load? "))
+ && !nquery (_("Make breakpoint pending on future shared library load? ")))
return 0;
/* At this point, either the user was queried about setting
cond_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
- from_tty, enabled);
+ from_tty, enabled, internal);
do_cleanups (old_chain);
/* Get the tracepoint we just created. */
- tp = get_breakpoint (breakpoint_count);
+ if (internal)
+ tp = get_breakpoint (internal_breakpoint_number);
+ else
+ tp = get_breakpoint (breakpoint_count);
gdb_assert (tp != NULL);
/* Given that its possible to have multiple markers with
create_breakpoints_sal (gdbarch, sals, addr_string, cond_string,
type_wanted, tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops, from_tty,
- enabled);
+ enabled, internal);
}
else
{
make_cleanup (xfree, copy_arg);
b = set_raw_breakpoint_without_location (gdbarch, type_wanted);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
+ set_breakpoint_number (internal, b);
b->thread = -1;
b->addr_string = addr_string[0];
b->cond_string = NULL;
b->ops = ops;
b->enable_state = enabled ? bp_enabled : bp_disabled;
b->pspace = current_program_space;
+ b->py_bp_object = NULL;
if (enabled && b->pspace->executing_startup
&& (b->type == bp_breakpoint
|| b->type == bp_hardware_breakpoint))
b->enable_state = bp_startup_disabled;
- mention (b);
+ if (internal)
+ /* Do not mention breakpoints with a negative number,
+ but do notify observers. */
+ observer_notify_breakpoint_created (b->number);
+ else
+ mention (b);
}
if (sals.nelts > 1)
pending_break_support,
NULL /* breakpoint_ops */,
from_tty,
- 1 /* enabled */);
+ 1 /* enabled */,
+ 0 /* internal */);
}
hw_read: watch read,
hw_access: watch access (read or write) */
static void
-watch_command_1 (char *arg, int accessflag, int from_tty, int just_location)
+watch_command_1 (char *arg, int accessflag, int from_tty,
+ int just_location, int internal)
{
struct breakpoint *b, *scope_breakpoint = NULL;
struct expression *exp;
struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL;
- struct value *val, *mark;
+ struct value *val, *mark, *result;
struct frame_info *frame;
char *exp_start = NULL;
char *exp_end = NULL;
exp_valid_block = innermost_block;
mark = value_mark ();
- fetch_subexp_value (exp, &pc, &val, NULL, NULL);
+ fetch_subexp_value (exp, &pc, &val, &result, NULL);
if (just_location)
{
exp_valid_block = NULL;
- val = value_addr (val);
+ val = value_addr (result);
release_value (val);
value_free_to_mark (mark);
}
/* Now set up the breakpoint. */
b = set_raw_breakpoint_without_location (NULL, bp_type);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
+ set_breakpoint_number (internal, b);
b->thread = thread;
b->disposition = disp_donttouch;
b->exp = exp;
/* Finally update the new watchpoint. This creates the locations
that should be inserted. */
update_watchpoint (b, 1);
-
- mention (b);
+ if (internal)
+ /* Do not mention breakpoints with a negative number, but do
+ notify observers. */
+ observer_notify_breakpoint_created (b->number);
+ else
+ mention (b);
update_global_location_list (1);
}
{
if (VALUE_LVAL (v) == lval_memory)
{
- if (value_lazy (v))
- /* A lazy memory lvalue is one that GDB never needed to fetch;
- we either just used its address (e.g., `a' in `a.b') or
- we never needed it at all (e.g., `a' in `a,b'). */
+ if (v != head && value_lazy (v))
+ /* A lazy memory lvalue in the chain is one that GDB never
+ needed to fetch; we either just used its address (e.g.,
+ `a' in `a.b') or we never needed it at all (e.g., `a'
+ in `a,b'). This doesn't apply to HEAD; if that is
+ lazy then it was not readable, but watch it anyway. */
;
else
{
}
void
-watch_command_wrapper (char *arg, int from_tty)
+watch_command_wrapper (char *arg, int from_tty, int internal)
{
- watch_command_1 (arg, hw_write, from_tty, 0);
+ watch_command_1 (arg, hw_write, from_tty, 0, internal);
}
/* A helper function that looks for an argument at the start of a
just_location = 1;
}
- watch_command_1 (arg, accessflag, from_tty, just_location);
+ watch_command_1 (arg, accessflag, from_tty, just_location, 0);
}
static void
}
void
-rwatch_command_wrapper (char *arg, int from_tty)
+rwatch_command_wrapper (char *arg, int from_tty, int internal)
{
- watch_command_1 (arg, hw_read, from_tty, 0);
+ watch_command_1 (arg, hw_read, from_tty, 0, internal);
}
static void
}
void
-awatch_command_wrapper (char *arg, int from_tty)
+awatch_command_wrapper (char *arg, int from_tty, int internal)
{
- watch_command_1 (arg, hw_access, from_tty, 0);
+ watch_command_1 (arg, hw_access, from_tty, 0, internal);
}
static void
{
struct breakpoint *breakpoint;
struct breakpoint *breakpoint2;
+ int thread_num;
};
/* This function is called by fetch_inferior_event via the
delete_breakpoint (a->breakpoint);
if (a->breakpoint2)
delete_breakpoint (a->breakpoint2);
+ delete_longjmp_breakpoint (a->thread_num);
}
void
struct breakpoint *breakpoint;
struct breakpoint *breakpoint2 = NULL;
struct cleanup *old_chain;
+ int thread;
+ struct thread_info *tp;
clear_proceed_status ();
old_chain = make_cleanup_delete_breakpoint (breakpoint);
+ tp = inferior_thread ();
+ thread = tp->num;
+
/* Keep within the current frame, or in frames called by the current
one. */
frame_unwind_caller_id (frame),
bp_until);
make_cleanup_delete_breakpoint (breakpoint2);
+
+ set_longjmp_breakpoint (tp, frame_unwind_caller_id (frame));
+ make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
}
proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
args->breakpoint = breakpoint;
args->breakpoint2 = breakpoint2;
+ args->thread_num = thread;
discard_cleanups (old_chain);
add_continuation (inferior_thread (),
0,
AUTO_BOOLEAN_TRUE /* pending */,
&gnu_v3_exception_catchpoint_ops, from_tty,
- 1 /* enabled */);
+ 1 /* enabled */,
+ 0 /* internal */);
return 1;
}
{
struct breakpoint *bpt = data;
- bpstat_remove_bp_location (th->stop_bpstat, bpt);
+ bpstat_remove_bp_location (th->control.stop_bpstat, bpt);
return 0;
}
&& b->type != bp_overlay_event
&& b->type != bp_longjmp_master
&& b->type != bp_std_terminate_master
+ && b->type != bp_exception_master
&& b->number >= 0)
{
breaks_to_delete = 1;
&& b->type != bp_overlay_event
&& b->type != bp_longjmp_master
&& b->type != bp_std_terminate_master
+ && b->type != bp_exception_master
&& b->number >= 0)
delete_breakpoint (b);
}
case bp_overlay_event:
case bp_longjmp_master:
case bp_std_terminate_master:
+ case bp_exception_master:
delete_breakpoint (b);
break;
case bp_step_resume:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_jit_event:
break;
}
create_longjmp_master_breakpoint ("siglongjmp");
create_longjmp_master_breakpoint ("_siglongjmp");
create_std_terminate_master_breakpoint ("std::terminate()");
+ create_exception_master_breakpoint ();
}
\f
/* Reset the thread number of this breakpoint:
pending_break_support,
NULL,
from_tty,
- 1 /* enabled */))
+ 1 /* enabled */,
+ 0 /* internal */))
set_tracepoint_count (breakpoint_count);
}
pending_break_support,
NULL,
from_tty,
- 1 /* enabled */))
+ 1 /* enabled */,
+ 0 /* internal */))
set_tracepoint_count (breakpoint_count);
}
pending_break_support,
NULL,
from_tty,
- 1 /* enabled */))
+ 1 /* enabled */,
+ 0 /* internal */))
set_tracepoint_count (breakpoint_count);
}
pending_break_support,
NULL,
0 /* from_tty */,
- utp->enabled /* enabled */))
+ utp->enabled /* enabled */,
+ 0 /* internal */))
return NULL;
set_tracepoint_count (breakpoint_count);
ALL_BREAKPOINTS (tp)
{
/* Skip internal and momentary breakpoints. */
- if (!user_settable_breakpoint (tp))
+ if (!user_settable_breakpoint (tp) || tp->number < 0)
continue;
/* If we have a filter, only save the breakpoints it accepts. */
ALL_BREAKPOINTS (tp)
{
/* Skip internal and momentary breakpoints. */
- if (!user_settable_breakpoint (tp))
+ if (!user_settable_breakpoint (tp) || tp->number < 0)
continue;
/* If we have a filter, only save the breakpoints it accepts. */
fprintf_unfiltered (fp, " commands\n");
ui_out_redirect (uiout, fp);
- TRY_CATCH (ex, RETURN_MASK_ERROR)
+ TRY_CATCH (ex, RETURN_MASK_ALL)
{
print_command_lines (uiout, tp->commands->commands, 2);
}
help_list (save_cmdlist, "save ", -1, gdb_stdout);
}
+struct breakpoint *
+iterate_over_breakpoints (int (*callback) (struct breakpoint *, void *),
+ void *data)
+{
+ struct breakpoint *b, *temp;
+
+ ALL_BREAKPOINTS_SAFE (b, temp)
+ {
+ if ((*callback) (b, data))
+ return b;
+ }
+
+ return NULL;
+}
+
void
_initialize_breakpoint (void)
{