#include "progspace-and-thread.h"
#include "gdbsupport/array-view.h"
#include "gdbsupport/gdb_optional.h"
+#include "gdbsupport/common-utils.h"
/* Prototypes for local functions. */
gdb::unique_xmalloc_ptr<char>,
gdb::unique_xmalloc_ptr<char>,
enum bptype,
- enum bpdisp, int, int,
+ enum bpdisp, int, int, int,
int,
int, int, int, unsigned);
UGLL_INSERT
};
+/* Return a textual version of INSERT_MODE. */
+
+static const char *
+ugll_insert_mode_text (ugll_insert_mode insert_mode)
+{
+/* Make sure the compiler warns if a new ugll_insert_mode enumerator is added
+ but not handled here. */
+DIAGNOSTIC_PUSH
+DIAGNOSTIC_ERROR_SWITCH
+ switch (insert_mode)
+ {
+ case UGLL_DONT_INSERT:
+ return "UGLL_DONT_INSERT";
+ case UGLL_MAY_INSERT:
+ return "UGLL_MAY_INSERT";
+ case UGLL_INSERT:
+ return "UGLL_INSERT";
+ }
+DIAGNOSTIC_POP
+
+ gdb_assert_not_reached ("must handle all enum values");
+}
+
+/* Return a textual version of REASON. */
+
+static const char *
+remove_bp_reason_str (remove_bp_reason reason)
+{
+/* Make sure the compiler warns if a new remove_bp_reason enumerator is added
+ but not handled here. */
+DIAGNOSTIC_PUSH
+DIAGNOSTIC_ERROR_SWITCH
+ switch (reason)
+ {
+ case REMOVE_BREAKPOINT:
+ return "regular remove";
+ case DETACH_BREAKPOINT:
+ return "detach";
+ }
+DIAGNOSTIC_POP
+
+ gdb_assert_not_reached ("must handle all enum values");
+}
+
+/* Return a textual version of breakpoint location BL describing number,
+ location and address. */
+
+static std::string
+breakpoint_location_address_str (const bp_location *bl)
+{
+ std::string str = string_printf ("Breakpoint %d (%s) at address %s",
+ bl->owner->number,
+ host_address_to_string (bl),
+ paddress (bl->gdbarch, bl->address));
+
+ std::string loc_string = bl->to_string ();
+ if (!loc_string.empty ())
+ str += string_printf (" %s", loc_string.c_str ());
+
+ return str;
+}
+
static void update_global_location_list (enum ugll_insert_mode);
static void update_global_location_list_nothrow (enum ugll_insert_mode);
disposition = disp_donttouch;
frame_id = frame_id_;
thread = thread_;
+
+ /* The inferior should have been set by the parent constructor. */
+ gdb_assert (inferior == -1);
}
void re_set () override;
value);
}
+/* True if breakpoint debug output is enabled. */
+static bool debug_breakpoint = false;
+
+/* Print a "breakpoint" debug statement. */
+#define breakpoint_debug_printf(fmt, ...) \
+ debug_prefixed_printf_cond (debug_breakpoint, "breakpoint", fmt, \
+ ##__VA_ARGS__)
+
+/* "show debug breakpoint" implementation. */
+static void
+show_debug_breakpoint (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ gdb_printf (file, _("Breakpoint location debugging is %s.\n"), value);
+}
+
/* See breakpoint.h. */
int
/* Chains of all breakpoints defined. */
-static struct breakpoint *breakpoint_chain;
+static intrusive_list<breakpoint> breakpoint_chain;
/* See breakpoint.h. */
breakpoint_range
all_breakpoints ()
{
- return breakpoint_range (breakpoint_chain);
+ return breakpoint_range (breakpoint_chain.begin (), breakpoint_chain.end ());
}
/* See breakpoint.h. */
tracepoint_range
all_tracepoints ()
{
- return tracepoint_range (breakpoint_chain);
+ return tracepoint_range (tracepoint_iterator (breakpoint_chain.begin ()),
+ tracepoint_iterator (breakpoint_chain.end ()));
}
/* Array is sorted by bp_location_is_less_than - primarily by the ADDRESS. */
void
clear_breakpoint_hit_counts (void)
{
- for (breakpoint *b : all_breakpoints ())
- b->hit_count = 0;
+ for (breakpoint &b : all_breakpoints ())
+ b.hit_count = 0;
}
\f
struct breakpoint *
get_breakpoint (int num)
{
- for (breakpoint *b : all_breakpoints ())
- if (b->number == num)
- return b;
+ for (breakpoint &b : all_breakpoints ())
+ if (b.number == num)
+ return &b;
return nullptr;
}
static bool
has_multiple_locations (int num)
{
- for (breakpoint *b : all_breakpoints ())
- if (b->number == num)
- return b->has_multiple_locations ();
+ for (breakpoint &b : all_breakpoints ())
+ if (b.number == num)
+ return b.has_multiple_locations ();
return false;
}
error (_("Garbage '%s' follows condition"), cond_string);
}
+/* See breakpoint.h. */
+
+void
+notify_breakpoint_modified (breakpoint *b)
+{
+ interps_notify_breakpoint_modified (b);
+ gdb::observers::breakpoint_modified.notify (b);
+}
+
void
set_breakpoint_condition (struct breakpoint *b, const char *exp,
int from_tty, bool force)
}
mark_breakpoint_modified (b);
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (b);
}
/* See breakpoint.h. */
set_breakpoint_condition (int bpnum, const char *exp, int from_tty,
bool force)
{
- for (breakpoint *b : all_breakpoints ())
- if (b->number == bpnum)
+ for (breakpoint &b : all_breakpoints ())
+ if (b.number == bpnum)
{
/* Check if this breakpoint has a "stop" method implemented in an
extension language. This method and conditions entered into GDB
from the CLI are mutually exclusive. */
const struct extension_language_defn *extlang
- = get_breakpoint_cond_ext_lang (b, EXT_LANG_NONE);
+ = get_breakpoint_cond_ext_lang (&b, EXT_LANG_NONE);
if (extlang != NULL)
{
" a %s stop condition defined for this breakpoint."),
ext_lang_capitalized_name (extlang));
}
- set_breakpoint_condition (b, exp, from_tty, force);
+ set_breakpoint_condition (&b, exp, from_tty, force);
- if (is_breakpoint (b))
+ if (is_breakpoint (&b))
update_global_location_list (UGLL_MAY_INSERT);
return;
/* We're completing the breakpoint number. */
len = strlen (text);
- for (breakpoint *b : all_breakpoints ())
+ for (breakpoint &b : all_breakpoints ())
{
char number[50];
- xsnprintf (number, sizeof (number), "%d", b->number);
+ xsnprintf (number, sizeof (number), "%d", b.number);
if (strncmp (number, text, len) == 0)
tracker.add_completion (make_unique_xstrdup (number));
{
std::vector<breakpoint *> found;
- for (breakpoint *b : all_breakpoints ())
- if (b->type == bp_static_tracepoint
- || b->type == bp_static_marker_tracepoint)
+ for (breakpoint &b : all_breakpoints ())
+ if (b.type == bp_static_tracepoint
+ || b.type == bp_static_marker_tracepoint)
{
- for (bp_location &loc : b->locations ())
+ for (bp_location &loc : b.locations ())
if (loc.address == addr)
- found.push_back (b);
+ found.push_back (&b);
}
return found;
validate_commands_for_breakpoint (b, commands.get ());
b->commands = std::move (commands);
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (b);
}
/* Set the internal `silent' flag on the breakpoint. Note that this
b->silent = silent;
if (old_silent != silent)
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (b);
}
/* See breakpoint.h. */
void
breakpoint_set_thread (struct breakpoint *b, int thread)
{
- /* It is invalid to set the thread field to anything other than -1 (which
- means no thread restriction) if a task restriction is already in
- place. */
- gdb_assert (thread == -1 || b->task == -1);
+ /* THREAD should be -1, meaning no thread restriction, or it should be a
+ valid global thread-id, which are greater than zero. */
+ gdb_assert (thread == -1 || thread > 0);
- int old_thread = b->thread;
+ /* It is not valid to set a thread restriction for a breakpoint that
+ already has task or inferior restriction. */
+ gdb_assert (thread == -1 || (b->task == -1 && b->inferior == -1));
+ int old_thread = b->thread;
b->thread = thread;
if (old_thread != thread)
+ notify_breakpoint_modified (b);
+}
+
+/* See breakpoint.h. */
+
+void
+breakpoint_set_inferior (struct breakpoint *b, int inferior)
+{
+ /* INFERIOR should be -1, meaning no inferior restriction, or it should
+ be a valid inferior number, which are greater than zero. */
+ gdb_assert (inferior == -1 || inferior > 0);
+
+ /* It is not valid to set an inferior restriction for a breakpoint that
+ already has a task or thread restriction. */
+ gdb_assert (inferior == -1 || (b->task == -1 && b->thread == -1));
+
+ int old_inferior = b->inferior;
+ b->inferior = inferior;
+ if (old_inferior != inferior)
gdb::observers::breakpoint_modified.notify (b);
}
void
breakpoint_set_task (struct breakpoint *b, int task)
{
- /* It is invalid to set the task field to anything other than -1 (which
- means no task restriction) if a thread restriction is already in
- place. */
- gdb_assert (task == -1 || b->thread == -1);
+ /* TASK should be -1, meaning no task restriction, or it should be a
+ valid task-id, which are greater than zero. */
+ gdb_assert (task == -1 || task > 0);
- int old_task = b->task;
+ /* It is not valid to set a task restriction for a breakpoint that
+ already has a thread or inferior restriction. */
+ gdb_assert (task == -1 || (b->thread == -1 && b->inferior == -1));
+ int old_task = b->task;
b->task = task;
if (old_task != task)
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (b);
}
static void
{
validate_commands_for_breakpoint (b, cmd.get ());
b->commands = cmd;
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (b);
}
});
}
/* No NULL conditions or failed bytecode generation. Build a
condition list for this location's address. If we have software
and hardware locations at the same address, they aren't
- considered duplicates, but we still marge all the conditions
+ considered duplicates, but we still merge all the conditions
anyway, as it's simpler, and doesn't really make a practical
difference. */
for (bp_location *loc : loc_range)
if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
return 0;
+ breakpoint_debug_printf ("%s", breakpoint_location_address_str (bl).c_str ());
+
/* Note we don't initialize bl->target_info, as that wipes out
the breakpoint location's shadow_contents if the breakpoint
is still inserted at that location. This in turn breaks
{
/* See also: disable_breakpoints_in_shlibs. */
bl->shlib_disabled = 1;
- gdb::observers::breakpoint_modified.notify (bl->owner);
+ notify_breakpoint_modified (bl->owner);
if (!*disabled_breaks)
{
gdb_printf (tmp_error_stream,
breakpoint_program_space_exit (struct program_space *pspace)
{
/* Remove any breakpoint that was set through this program space. */
- for (breakpoint *b : all_breakpoints_safe ())
- if (b->pspace == pspace)
- delete_breakpoint (b);
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (b.pspace == pspace)
+ delete_breakpoint (&b);
/* Breakpoints set through other program spaces could have locations
bound to PSPACE as well. Remove those. */
void
insert_breakpoints (void)
{
- for (breakpoint *bpt : all_breakpoints ())
- if (is_hardware_watchpoint (bpt))
+ for (breakpoint &bpt : all_breakpoints ())
+ if (is_hardware_watchpoint (&bpt))
{
- struct watchpoint *w = (struct watchpoint *) bpt;
+ watchpoint &w = gdb::checked_static_cast<watchpoint &> (bpt);
- update_watchpoint (w, false /* don't reparse. */);
+ update_watchpoint (&w, false /* don't reparse. */);
}
/* Updating watchpoints creates new locations, so update the global
&& !valid_global_thread_id (bl->owner->thread))
continue;
+ /* Or inferior specific breakpoints if the inferior no longer
+ exists. */
+ if (bl->owner->inferior != -1
+ && !valid_global_inferior_id (bl->owner->inferior))
+ continue;
+
switch_to_program_space_and_thread (bl->pspace);
/* For targets that support global breakpoints, there's no need
/* If we failed to insert all locations of a watchpoint, remove
them, as half-inserted watchpoint is of limited use. */
- for (breakpoint *bpt : all_breakpoints ())
+ for (breakpoint &bpt : all_breakpoints ())
{
bool some_failed = false;
- if (!is_hardware_watchpoint (bpt))
+ if (!is_hardware_watchpoint (&bpt))
continue;
- if (!breakpoint_enabled (bpt))
+ if (!breakpoint_enabled (&bpt))
continue;
- if (bpt->disposition == disp_del_at_next_stop)
+ if (bpt.disposition == disp_del_at_next_stop)
continue;
- for (bp_location &loc : bpt->locations ())
+ for (bp_location &loc : bpt.locations ())
if (!loc.inserted && should_be_inserted (&loc))
{
some_failed = true;
if (some_failed)
{
- for (bp_location &loc : bpt->locations ())
+ for (bp_location &loc : bpt.locations ())
if (loc.inserted)
remove_breakpoint (&loc);
hw_breakpoint_error = 1;
tmp_error_stream.printf ("Could not insert "
"hardware watchpoint %d.\n",
- bpt->number);
+ bpt.number);
error_flag = -1;
}
}
static void
remove_threaded_breakpoints (struct thread_info *tp, int silent)
{
- for (breakpoint *b : all_breakpoints_safe ())
+ for (breakpoint &b : all_breakpoints_safe ())
{
- if (b->thread == tp->global_num && user_breakpoint_p (b))
+ if (b.thread == tp->global_num && user_breakpoint_p (&b))
{
gdb_printf (_("\
Thread-specific breakpoint %d deleted - thread %s no longer in the thread list.\n"),
- b->number, print_thread_id (tp));
- delete_breakpoint (b);
+ b.number, print_thread_id (tp));
+ delete_breakpoint (&b);
+ }
+ }
+}
+
+/* Called when inferior INF has been removed from GDB. Remove associated
+ per-inferior breakpoints. */
+
+static void
+remove_inferior_breakpoints (struct inferior *inf)
+{
+ for (breakpoint &b : all_breakpoints_safe ())
+ {
+ if (b.inferior == inf->num && user_breakpoint_p (&b))
+ {
+ /* Tell the user the breakpoint has been deleted. But only for
+ breakpoints that would not normally have been deleted at the
+ next stop anyway. */
+ if (b.disposition != disp_del
+ && b.disposition != disp_del_at_next_stop)
+ gdb_printf (_("\
+Inferior-specific breakpoint %d deleted - inferior %d has been removed.\n"),
+ b.number, inf->num);
+ delete_breakpoint (&b);
}
}
}
{
int val;
+ breakpoint_debug_printf ("inf->num = %d", inf->num);
+
for (bp_location *bl : all_bp_locations ())
{
if (bl->pspace != inf->pspace)
if (bploc->pspace == current_program_space)
gdb_assert (!bploc->inserted);
- for (breakpoint *b : all_breakpoints_safe ())
+ for (breakpoint &b : all_breakpoints_safe ())
{
- if (b->pspace != current_program_space)
+ if (b.pspace != current_program_space)
continue;
/* Solib breakpoints must be explicitly reset after an exec(). */
- if (b->type == bp_shlib_event)
+ if (b.type == bp_shlib_event)
{
- delete_breakpoint (b);
+ delete_breakpoint (&b);
continue;
}
/* JIT breakpoints must be explicitly reset after an exec(). */
- if (b->type == bp_jit_event)
+ if (b.type == bp_jit_event)
{
- delete_breakpoint (b);
+ delete_breakpoint (&b);
continue;
}
/* 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_exception_master)
+ 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)
{
- delete_breakpoint (b);
+ delete_breakpoint (&b);
continue;
}
/* Step-resume breakpoints are meaningless after an exec(). */
- if (b->type == bp_step_resume || b->type == bp_hp_step_resume)
+ if (b.type == bp_step_resume || b.type == bp_hp_step_resume)
{
- delete_breakpoint (b);
+ delete_breakpoint (&b);
continue;
}
/* Just like single-step breakpoints. */
- if (b->type == bp_single_step)
+ if (b.type == bp_single_step)
{
- delete_breakpoint (b);
+ 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
- || b->type == bp_longjmp_call_dummy
- || b->type == bp_exception || b->type == bp_exception_resume)
+ if (b.type == bp_longjmp || b.type == bp_longjmp_resume
+ || b.type == bp_longjmp_call_dummy
+ || b.type == bp_exception || b.type == bp_exception_resume)
{
- delete_breakpoint (b);
+ delete_breakpoint (&b);
continue;
}
- if (b->type == bp_catchpoint)
+ if (b.type == bp_catchpoint)
{
/* For now, none of the bp_catchpoint breakpoints need to
do anything at this point. In the future, if some of
address is probably bogus in the new a.out, unlike e.g., the
solib breakpoints.) */
- if (b->type == bp_finish)
+ if (b.type == bp_finish)
{
continue;
}
/* Without a symbolic address, we have little hope of the
pre-exec() address meaning the same thing in the post-exec()
a.out. */
- if (breakpoint_location_spec_empty_p (b))
+ if (breakpoint_location_spec_empty_p (&b))
{
- delete_breakpoint (b);
+ delete_breakpoint (&b);
continue;
}
}
static int
remove_breakpoint_1 (struct bp_location *bl, enum remove_bp_reason reason)
{
+ breakpoint_debug_printf ("%s due to %s",
+ breakpoint_location_address_str (bl).c_str (),
+ remove_bp_reason_str (reason));
+
int val;
/* BL is never in moribund_locations by our callers. */
mark_breakpoints_out ();
- for (breakpoint *b : all_breakpoints_safe ())
+ for (breakpoint &b : all_breakpoints_safe ())
{
- if (b->has_locations () && b->first_loc ().pspace != pspace)
+ if (b.has_locations () && b.first_loc ().pspace != pspace)
continue;
- switch (b->type)
+ switch (b.type)
{
case bp_call_dummy:
case bp_longjmp_call_dummy:
/* Also remove single-step breakpoints. */
- delete_breakpoint (b);
+ delete_breakpoint (&b);
break;
case bp_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
{
- struct watchpoint *w = (struct watchpoint *) b;
+ watchpoint &w = gdb::checked_static_cast<watchpoint &> (b);
/* Likewise for watchpoints on local expressions. */
- if (w->exp_valid_block != NULL)
- delete_breakpoint (b);
+ if (w.exp_valid_block != NULL)
+ delete_breakpoint (&b);
else
{
/* Get rid of existing locations, which are no longer
update_watchpoint, when the inferior is restarted.
The next update_global_location_list call will
garbage collect them. */
- b->clear_locations ();
+ b.clear_locations ();
if (context == inf_starting)
{
/* Reset val field to force reread of starting value in
insert_breakpoints. */
- w->val.reset (nullptr);
- w->val_valid = false;
+ w.val.reset (nullptr);
+ w.val_valid = false;
}
}
}
hardware_watchpoint_inserted_in_range (const address_space *aspace,
CORE_ADDR addr, ULONGEST len)
{
- for (breakpoint *bpt : all_breakpoints ())
+ for (breakpoint &bpt : all_breakpoints ())
{
- if (bpt->type != bp_hardware_watchpoint
- && bpt->type != bp_access_watchpoint)
+ if (bpt.type != bp_hardware_watchpoint
+ && bpt.type != bp_access_watchpoint)
continue;
- if (!breakpoint_enabled (bpt))
+ if (!breakpoint_enabled (&bpt))
continue;
- for (bp_location &loc : bpt->locations ())
+ for (bp_location &loc : bpt.locations ())
if (loc.pspace->aspace == aspace && loc.inserted)
{
CORE_ADDR l, h;
{
/* We were not stopped by a watchpoint. Mark all watchpoints
as not triggered. */
- for (breakpoint *b : all_breakpoints ())
- if (is_hardware_watchpoint (b))
+ for (breakpoint &b : all_breakpoints ())
+ if (is_hardware_watchpoint (&b))
{
- struct watchpoint *w = (struct watchpoint *) b;
+ watchpoint &w = gdb::checked_static_cast<watchpoint &> (b);
- w->watchpoint_triggered = watch_triggered_no;
+ w.watchpoint_triggered = watch_triggered_no;
}
return 0;
{
/* We were stopped by a watchpoint, but we don't know where.
Mark all watchpoints as unknown. */
- for (breakpoint *b : all_breakpoints ())
- if (is_hardware_watchpoint (b))
+ for (breakpoint &b : all_breakpoints ())
+ if (is_hardware_watchpoint (&b))
{
- struct watchpoint *w = (struct watchpoint *) b;
+ watchpoint &w = gdb::checked_static_cast<watchpoint &> (b);
- w->watchpoint_triggered = watch_triggered_unknown;
+ w.watchpoint_triggered = watch_triggered_unknown;
}
return 1;
affected by this data address as triggered, and all others as not
triggered. */
- for (breakpoint *b : all_breakpoints ())
- if (is_hardware_watchpoint (b))
+ for (breakpoint &b : all_breakpoints ())
+ if (is_hardware_watchpoint (&b))
{
- struct watchpoint *w = (struct watchpoint *) b;
+ watchpoint &w = gdb::checked_static_cast<watchpoint &> (b);
- w->watchpoint_triggered = watch_triggered_no;
- for (bp_location &loc : b->locations ())
+ w.watchpoint_triggered = watch_triggered_no;
+ for (bp_location &loc : b.locations ())
{
- if (is_masked_watchpoint (b))
+ if (is_masked_watchpoint (&b))
{
- CORE_ADDR newaddr = addr & w->hw_wp_mask;
- CORE_ADDR start = loc.address & w->hw_wp_mask;
+ CORE_ADDR newaddr = addr & w.hw_wp_mask;
+ CORE_ADDR start = loc.address & w.hw_wp_mask;
if (newaddr == start)
{
- w->watchpoint_triggered = watch_triggered_yes;
+ w.watchpoint_triggered = watch_triggered_yes;
break;
}
}
(current_inferior ()->top_target (), addr, loc.address,
loc.length))
{
- w->watchpoint_triggered = watch_triggered_yes;
+ w.watchpoint_triggered = watch_triggered_yes;
break;
}
}
if (bl->watchpoint_type == hw_read)
{
- for (breakpoint *other_b : all_breakpoints ())
- if (other_b->type == bp_hardware_watchpoint
- || other_b->type == bp_access_watchpoint)
+ for (breakpoint &other_b : all_breakpoints ())
+ if (other_b.type == bp_hardware_watchpoint
+ || other_b.type == bp_access_watchpoint)
{
- struct watchpoint *other_w =
- (struct watchpoint *) other_b;
+ watchpoint &other_w =
+ gdb::checked_static_cast<watchpoint &> (other_b);
- if (other_w->watchpoint_triggered
+ if (other_w.watchpoint_triggered
== watch_triggered_yes)
{
other_write_watchpoint = 1;
evaluating the condition if this isn't the specified
thread/task. */
if ((b->thread != -1 && b->thread != thread->global_num)
+ || (b->inferior != -1 && b->inferior != thread->inf->num)
|| (b->task != -1 && b->task != ada_get_task_number (thread)))
{
infrun_debug_printf ("incorrect thread or task, not stopping");
else
within_current_scope = false;
}
- CORE_ADDR pc_before_check = get_frame_pc (get_selected_frame (nullptr));
if (within_current_scope)
{
try
}
catch (const gdb_exception_error &ex)
{
- exception_fprintf (gdb_stderr, ex,
- "Error in testing condition for breakpoint %d:\n",
- b->number);
-
- /* If the pc value changed as a result of evaluating the
- condition then we probably stopped within an inferior
- function call due to some unexpected stop, e.g. the thread
- hit another breakpoint, or the thread received an
- unexpected signal. In this case we don't want to also
- print the information about this breakpoint. */
- CORE_ADDR pc_after_check
- = get_frame_pc (get_selected_frame (nullptr));
- if (pc_before_check != pc_after_check)
- bs->print = 0;
+ int locno = bpstat_locno (bs);
+ if (locno != 0)
+ exception_fprintf
+ (gdb_stderr, ex,
+ "Error in testing condition for breakpoint %d.%d:\n",
+ b->number, locno);
+ else
+ exception_fprintf
+ (gdb_stderr, ex,
+ "Error in testing condition for breakpoint %d:\n",
+ b->number);
}
}
else
bs->stop = false;
/* Increase the hit count even though we don't stop. */
++(b->hit_count);
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (b);
return;
}
{
bpstat *bs_head = nullptr, **bs_link = &bs_head;
- for (breakpoint *b : all_breakpoints ())
+ for (breakpoint &b : all_breakpoints ())
{
- if (!breakpoint_enabled (b))
+ if (!breakpoint_enabled (&b))
continue;
- for (bp_location &bl : b->locations ())
+ for (bp_location &bl : b.locations ())
{
/* For hardware watchpoints, we look only at the first
location. The watchpoint_check function will work on the
entire expression, not the individual locations. For
read watchpoints, the watchpoints_triggered function has
checked all locations already. */
- if (b->type == bp_hardware_watchpoint && &bl != &b->first_loc ())
+ if (b.type == bp_hardware_watchpoint && &bl != &b.first_loc ())
break;
if (!bl.enabled || bl.disabled_by_cond || bl.shlib_disabled)
watchpoint as triggered so that we will handle the
out-of-scope event. We'll get to the watchpoint next
iteration. */
- if (b->type == bp_watchpoint_scope && b->related_breakpoint != b)
+ if (b.type == bp_watchpoint_scope && b.related_breakpoint != &b)
{
- struct watchpoint *w = (struct watchpoint *) b->related_breakpoint;
+ struct watchpoint *w = (struct watchpoint *) b.related_breakpoint;
w->watchpoint_triggered = watch_triggered_yes;
}
b->enable_state = bp_disabled;
removed_any = 1;
}
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (b);
if (b->silent)
bs->print = false;
bs->commands = b->commands;
bool
bpstat_should_step ()
{
- for (breakpoint *b : all_breakpoints ())
- if (breakpoint_enabled (b)
- && b->type == bp_watchpoint
- && b->has_locations ())
+ for (breakpoint &b : all_breakpoints ())
+ if (breakpoint_enabled (&b)
+ && b.type == bp_watchpoint
+ && b.has_locations ())
return true;
return false;
uiout->field_signed ("thread", b->thread);
else if (b->task != -1)
uiout->field_signed ("task", b->task);
+ else if (b->inferior != -1)
+ uiout->field_signed ("inferior", b->inferior);
}
uiout->text ("\n");
uiout->text ("\n");
}
+ if (!part_of_multiple && b->inferior != -1)
+ {
+ uiout->text ("\tstop only in inferior ");
+ uiout->field_signed ("inferior", b->inferior);
+ uiout->text ("\n");
+ }
+
if (!part_of_multiple)
{
if (b->hit_count)
/* Compute the number of rows in the table, as well as the size
required for address fields. */
nr_printable_breakpoints = 0;
- for (breakpoint *b : all_breakpoints ())
+ for (breakpoint &b : all_breakpoints ())
{
/* If we have a filter, only list the breakpoints it accepts. */
- if (filter && !filter (b))
+ if (filter && !filter (&b))
continue;
/* If we have a BP_NUM_LIST string, it is a list of breakpoints to
accept. Skip the others. */
if (bp_num_list != NULL && *bp_num_list != '\0')
{
- if (show_internal && parse_and_eval_long (bp_num_list) != b->number)
+ if (show_internal && parse_and_eval_long (bp_num_list) != b.number)
continue;
- if (!show_internal && !number_is_in_list (bp_num_list, b->number))
+ if (!show_internal && !number_is_in_list (bp_num_list, b.number))
continue;
}
- if (show_internal || user_breakpoint_p (b))
+ if (show_internal || user_breakpoint_p (&b))
{
int addr_bit, type_len;
- addr_bit = breakpoint_address_bits (b);
+ addr_bit = breakpoint_address_bits (&b);
if (addr_bit > print_address_bits)
print_address_bits = addr_bit;
- type_len = strlen (bptype_string (b->type));
+ type_len = strlen (bptype_string (b.type));
if (type_len > print_type_col_width)
print_type_col_width = type_len;
if (nr_printable_breakpoints > 0)
annotate_breakpoints_table ();
- for (breakpoint *b : all_breakpoints ())
+ for (breakpoint &b : all_breakpoints ())
{
QUIT;
/* If we have a filter, only list the breakpoints it accepts. */
- if (filter && !filter (b))
+ if (filter && !filter (&b))
continue;
/* If we have a BP_NUM_LIST string, it is a list of breakpoints to
{
if (show_internal) /* maintenance info breakpoint */
{
- if (parse_and_eval_long (bp_num_list) != b->number)
+ if (parse_and_eval_long (bp_num_list) != b.number)
continue;
}
else /* all others */
{
- if (!number_is_in_list (bp_num_list, b->number))
+ if (!number_is_in_list (bp_num_list, b.number))
continue;
}
}
/* We only print out user settable breakpoints unless the
show_internal is set. */
- if (show_internal || user_breakpoint_p (b))
+ if (show_internal || user_breakpoint_p (&b))
{
- print_one_breakpoint (b, &last_loc, show_internal);
- for (bp_location &loc : b->locations ())
+ print_one_breakpoint (&b, &last_loc, show_internal);
+ for (bp_location &loc : b.locations ())
if (loc.disabled_by_cond)
has_disabled_by_cond_location = true;
}
{
int others = 0;
- for (breakpoint *b : all_breakpoints ())
- others += (user_breakpoint_p (b)
- && breakpoint_has_pc (b, pspace, pc, section));
+ for (breakpoint &b : all_breakpoints ())
+ others += (user_breakpoint_p (&b)
+ && breakpoint_has_pc (&b, pspace, pc, section));
if (others > 0)
{
gdb_printf (_("Note: breakpoint "));
else /* if (others == ???) */
gdb_printf (_("Note: breakpoints "));
- for (breakpoint *b : all_breakpoints ())
- if (user_breakpoint_p (b) && breakpoint_has_pc (b, pspace, pc, section))
+ for (breakpoint &b : all_breakpoints ())
+ if (user_breakpoint_p (&b)
+ && breakpoint_has_pc (&b, pspace, pc, section))
{
others--;
- gdb_printf ("%d", b->number);
- if (b->thread == -1 && thread != -1)
+ gdb_printf ("%d", b.number);
+ if (b.thread == -1 && thread != -1)
gdb_printf (" (all threads)");
- else if (b->thread != -1)
+ else if (b.thread != -1)
{
- struct thread_info *thr = find_thread_global_id (b->thread);
+ struct thread_info *thr = find_thread_global_id (b.thread);
gdb_printf (" (thread %s)", print_thread_id (thr));
}
- else if (b->task != -1)
- gdb_printf (" (task %d)", b->task);
+ else if (b.task != -1)
+ gdb_printf (" (task %d)", b.task);
gdb_printf ("%s%s ",
- ((b->enable_state == bp_disabled
- || b->enable_state == bp_call_disabled)
+ ((b.enable_state == bp_disabled
+ || b.enable_state == bp_call_disabled)
? " (disabled)"
: ""),
(others > 1) ? ","
{
}
+/* See breakpoint.h. */
+
+std::string
+bp_location::to_string () const
+{
+ string_file stb;
+ ui_out_redirect_pop redir (current_uiout, &stb);
+ print_breakpoint_location (this->owner, this);
+ return stb.string ();
+}
+
/* Decrement reference count. If the reference count reaches 0,
destroy the bp_location. Sets *BLP to NULL. */
static breakpoint *
add_to_breakpoint_chain (std::unique_ptr<breakpoint> &&b)
{
- struct breakpoint *b1;
- struct breakpoint *result = b.get ();
-
/* Add this breakpoint to the end of the chain so that a list of
breakpoints will come out in order of increasing numbers. */
- b1 = breakpoint_chain;
- if (b1 == 0)
- breakpoint_chain = b.release ();
- else
- {
- while (b1->next)
- b1 = b1->next;
- b1->next = b.release ();
- }
+ breakpoint_chain.push_back (*b.release ());
- return result;
+ return &breakpoint_chain.back ();
}
/* Initialize loc->function_name. */
we maintain a list of continually-inserted but always disabled
longjmp "master" breakpoints. Here, we simply create momentary
clones of those and enable them for the requested thread. */
- for (breakpoint *b : all_breakpoints_safe ())
- if (b->pspace == current_program_space
- && (b->type == bp_longjmp_master
- || b->type == bp_exception_master))
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (b.pspace == current_program_space
+ && (b.type == bp_longjmp_master
+ || b.type == bp_exception_master))
{
- enum bptype type = b->type == bp_longjmp_master ? bp_longjmp : bp_exception;
+ bptype type = b.type == bp_longjmp_master ? bp_longjmp : bp_exception;
/* longjmp_breakpoint_ops ensures INITIATING_FRAME is cleared again
after their removal. */
- momentary_breakpoint_from_master (b, type, 1, thread);
+ momentary_breakpoint_from_master (&b, type, 1, thread);
}
tp->initiating_frame = frame;
void
delete_longjmp_breakpoint (int thread)
{
- for (breakpoint *b : all_breakpoints_safe ())
- if (b->type == bp_longjmp || b->type == bp_exception)
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (b.type == bp_longjmp || b.type == bp_exception)
{
- if (b->thread == thread)
- delete_breakpoint (b);
+ if (b.thread == thread)
+ {
+ gdb_assert (b.inferior == -1);
+ delete_breakpoint (&b);
+ }
}
}
void
delete_longjmp_breakpoint_at_next_stop (int thread)
{
- for (breakpoint *b : all_breakpoints_safe ())
- if (b->type == bp_longjmp || b->type == bp_exception)
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (b.type == bp_longjmp || b.type == bp_exception)
{
- if (b->thread == thread)
- b->disposition = disp_del_at_next_stop;
+ if (b.thread == thread)
+ {
+ gdb_assert (b.inferior == -1);
+ b.disposition = disp_del_at_next_stop;
+ }
}
}
{
breakpoint *retval = nullptr;
- for (breakpoint *b : all_breakpoints ())
- if (b->pspace == current_program_space && b->type == bp_longjmp_master)
+ for (breakpoint &b : all_breakpoints ())
+ if (b.pspace == current_program_space && b.type == bp_longjmp_master)
{
int thread = inferior_thread ()->global_num;
breakpoint *new_b
- = momentary_breakpoint_from_master (b, bp_longjmp_call_dummy,
+ = momentary_breakpoint_from_master (&b, bp_longjmp_call_dummy,
1, thread);
/* Link NEW_B into the chain of RETVAL breakpoints. */
Save all breakpoints to delete in that set and delete them at the end. */
std::unordered_set<breakpoint *> to_delete;
- for (struct breakpoint *b : all_breakpoints ())
+ for (struct breakpoint &b : all_breakpoints ())
{
- if (b->type == bp_longjmp_call_dummy && b->thread == tp->global_num)
+ if (b.type == bp_longjmp_call_dummy && b.thread == tp->global_num)
{
- struct breakpoint *dummy_b = b->related_breakpoint;
+ gdb_assert (b.inferior == -1);
+ struct breakpoint *dummy_b = b.related_breakpoint;
/* Find the bp_call_dummy breakpoint in the list of breakpoints
chained off b->related_breakpoint. */
- while (dummy_b != b && dummy_b->type != bp_call_dummy)
+ while (dummy_b != &b && dummy_b->type != bp_call_dummy)
dummy_b = dummy_b->related_breakpoint;
/* If there was no bp_call_dummy breakpoint then there's nothing
dummy_frame_discard (dummy_b->frame_id, tp);
- for (breakpoint *related_breakpoint = b->related_breakpoint;
- related_breakpoint != b;
+ for (breakpoint *related_breakpoint = b.related_breakpoint;
+ related_breakpoint != &b;
related_breakpoint = related_breakpoint->related_breakpoint)
- to_delete.insert (b->related_breakpoint);
+ to_delete.insert (b.related_breakpoint);
- to_delete.insert (b);
+ to_delete.insert (&b);
}
}
void
enable_overlay_breakpoints (void)
{
- for (breakpoint *b : all_breakpoints ())
- if (b->type == bp_overlay_event)
+ for (breakpoint &b : all_breakpoints ())
+ if (b.type == bp_overlay_event)
{
- b->enable_state = bp_enabled;
+ b.enable_state = bp_enabled;
update_global_location_list (UGLL_MAY_INSERT);
overlay_events_enabled = 1;
}
void
disable_overlay_breakpoints (void)
{
- for (breakpoint *b : all_breakpoints ())
- if (b->type == bp_overlay_event)
+ for (breakpoint &b : all_breakpoints ())
+ if (b.type == bp_overlay_event)
{
- b->enable_state = bp_disabled;
+ b.enable_state = bp_disabled;
update_global_location_list (UGLL_DONT_INSERT);
overlay_events_enabled = 0;
}
void
set_std_terminate_breakpoint (void)
{
- for (breakpoint *b : all_breakpoints_safe ())
- if (b->pspace == current_program_space
- && b->type == bp_std_terminate_master)
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (b.pspace == current_program_space
+ && b.type == bp_std_terminate_master)
{
- momentary_breakpoint_from_master (b, bp_std_terminate, 1,
+ momentary_breakpoint_from_master (&b, bp_std_terminate, 1,
inferior_thread ()->global_num);
}
}
void
delete_std_terminate_breakpoint (void)
{
- for (breakpoint *b : all_breakpoints_safe ())
- if (b->type == bp_std_terminate)
- delete_breakpoint (b);
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (b.type == bp_std_terminate)
+ delete_breakpoint (&b);
}
struct breakpoint *
void
remove_jit_event_breakpoints (void)
{
- for (breakpoint *b : all_breakpoints_safe ())
- if (b->type == bp_jit_event
- && b->first_loc ().pspace == current_program_space)
- delete_breakpoint (b);
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (b.type == bp_jit_event
+ && b.first_loc ().pspace == current_program_space)
+ delete_breakpoint (&b);
}
void
remove_solib_event_breakpoints (void)
{
- for (breakpoint *b : all_breakpoints_safe ())
- if (b->type == bp_shlib_event
- && b->first_loc ().pspace == current_program_space)
- delete_breakpoint (b);
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (b.type == bp_shlib_event
+ && b.first_loc ().pspace == current_program_space)
+ delete_breakpoint (&b);
}
/* See breakpoint.h. */
void
remove_solib_event_breakpoints_at_next_stop (void)
{
- for (breakpoint *b : all_breakpoints_safe ())
- if (b->type == bp_shlib_event
- && b->first_loc ().pspace == current_program_space)
- b->disposition = disp_del_at_next_stop;
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (b.type == bp_shlib_event
+ && b.first_loc ().pspace == current_program_space)
+ b.disposition = disp_del_at_next_stop;
}
/* Helper for create_solib_event_breakpoint /
loc->inserted = 0;
/* This may cause duplicate notifications for the same breakpoint. */
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (b);
if (!disabled_shlib_breaks)
{
|| (objfile->flags & OBJF_USERLOADED) == 0)
return;
- for (breakpoint *b : all_breakpoints ())
+ for (breakpoint &b : all_breakpoints ())
{
bool bp_modified = false;
- if (!is_breakpoint (b) && !is_tracepoint (b))
+ if (!is_breakpoint (&b) && !is_tracepoint (&b))
continue;
- for (bp_location &loc : b->locations ())
+ for (bp_location &loc : b.locations ())
{
CORE_ADDR loc_addr = loc.address;
}
if (bp_modified)
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (&b);
}
}
pspace = current_program_space;
}
+/* Notify interpreters and observers that breakpoint B was created. */
+
+static void
+notify_breakpoint_created (breakpoint *b)
+{
+ interps_notify_breakpoint_created (b);
+ gdb::observers::breakpoint_created.notify (b);
+}
+
breakpoint *
install_breakpoint (int internal, std::unique_ptr<breakpoint> &&arg, int update_gll)
{
set_tracepoint_count (breakpoint_count);
if (!internal)
mention (b);
- gdb::observers::breakpoint_created.notify (b);
+
+ notify_breakpoint_created (b);
if (update_gll)
update_global_location_list (UGLL_MAY_INSERT);
{
int i = 0;
- for (breakpoint *b : all_breakpoints ())
- if (b->type == bp_hardware_breakpoint && breakpoint_enabled (b))
- for (bp_location &bl : b->locations ())
+ for (breakpoint &b : all_breakpoints ())
+ if (b.type == bp_hardware_breakpoint && breakpoint_enabled (&b))
+ for (bp_location &bl : b.locations ())
{
/* Special types of hardware breakpoints may use more than
one register. */
- i += b->resources_needed (&bl);
+ i += b.resources_needed (&bl);
}
return i;
int i = 0;
*other_type_used = 0;
- for (breakpoint *b : all_breakpoints ())
+ for (breakpoint &b : all_breakpoints ())
{
- if (b == except)
+ if (&b == except)
continue;
- if (!breakpoint_enabled (b))
+ if (!breakpoint_enabled (&b))
continue;
- if (b->type == type)
- i += hw_watchpoint_use_count (b);
- else if (is_hardware_watchpoint (b))
+ if (b.type == type)
+ i += hw_watchpoint_use_count (&b);
+ else if (is_hardware_watchpoint (&b))
*other_type_used = 1;
}
void
disable_watchpoints_before_interactive_call_start (void)
{
- for (breakpoint *b : all_breakpoints ())
- if (is_watchpoint (b) && breakpoint_enabled (b))
+ for (breakpoint &b : all_breakpoints ())
+ if (is_watchpoint (&b) && breakpoint_enabled (&b))
{
- b->enable_state = bp_call_disabled;
+ b.enable_state = bp_call_disabled;
update_global_location_list (UGLL_DONT_INSERT);
}
}
void
enable_watchpoints_after_interactive_call_stop (void)
{
- for (breakpoint *b : all_breakpoints ())
- if (is_watchpoint (b) && b->enable_state == bp_call_disabled)
+ for (breakpoint &b : all_breakpoints ())
+ if (is_watchpoint (&b) && b.enable_state == bp_call_disabled)
{
- b->enable_state = bp_enabled;
+ b.enable_state = bp_enabled;
update_global_location_list (UGLL_MAY_INSERT);
}
}
update_dprintf_commands (const char *args, int from_tty,
struct cmd_list_element *c)
{
- for (breakpoint *b : all_breakpoints ())
- if (b->type == bp_dprintf)
- update_dprintf_command_list (b);
+ for (breakpoint &b : all_breakpoints ())
+ if (b.type == bp_dprintf)
+ update_dprintf_command_list (&b);
}
code_breakpoint::code_breakpoint (struct gdbarch *gdbarch_,
gdb::unique_xmalloc_ptr<char> cond_string_,
gdb::unique_xmalloc_ptr<char> extra_string_,
enum bpdisp disposition_,
- int thread_, int task_, int ignore_count_,
+ int thread_, int task_, int inferior_,
+ int ignore_count_,
int from_tty,
int enabled_, unsigned flags,
int display_canonical_)
gdb_assert (!sals.empty ());
- /* At most one of thread or task can be set on any breakpoint. */
- gdb_assert (thread == -1 || task == -1);
+ /* At most one of thread, task, or inferior can be set on any breakpoint. */
+ gdb_assert (((thread == -1 ? 0 : 1)
+ + (task == -1 ? 0 : 1)
+ + (inferior == -1 ? 0 : 1)) <= 1);
+
thread = thread_;
task = task_;
+ inferior = inferior_;
cond_string = std::move (cond_string_);
extra_string = std::move (extra_string_);
gdb::unique_xmalloc_ptr<char> cond_string,
gdb::unique_xmalloc_ptr<char> extra_string,
enum bptype type, enum bpdisp disposition,
- int thread, int task, int ignore_count,
+ int thread, int task, int inferior, int ignore_count,
int from_tty,
int enabled, int internal, unsigned flags,
int display_canonical)
std::move (cond_string),
std::move (extra_string),
disposition,
- thread, task, ignore_count,
+ thread, task, inferior, ignore_count,
from_tty,
enabled, flags,
display_canonical);
gdb::unique_xmalloc_ptr<char> cond_string,
gdb::unique_xmalloc_ptr<char> extra_string,
enum bptype type, enum bpdisp disposition,
- int thread, int task, int ignore_count,
+ int thread, int task, int inferior,
+ int ignore_count,
int from_tty,
int enabled, int internal, unsigned flags)
{
std::move (cond_string),
std::move (extra_string),
type, disposition,
- thread, task, ignore_count,
+ thread, task, inferior, ignore_count,
from_tty, enabled, internal, flags,
canonical->special_display);
}
}
}
-/* Given TOK, a string specification of condition and thread, as
- accepted by the 'break' command, extract the condition
- string and thread number and set *COND_STRING and *THREAD.
- PC identifies the context at which the condition should be parsed.
- If no condition is found, *COND_STRING is set to NULL.
- If no thread is found, *THREAD is set to -1. */
+/* Given TOK, a string specification of condition and thread, as accepted
+ by the 'break' command, extract the condition string into *COND_STRING.
+ If no condition string is found then *COND_STRING is set to nullptr.
+
+ If the breakpoint specification has an associated thread, task, or
+ inferior, these are extracted into *THREAD, *TASK, and *INFERIOR
+ respectively, otherwise these arguments are set to -1 (for THREAD and
+ INFERIOR) or 0 (for TASK).
+
+ PC identifies the context at which the condition should be parsed. */
static void
find_condition_and_thread (const char *tok, CORE_ADDR pc,
gdb::unique_xmalloc_ptr<char> *cond_string,
- int *thread, int *task,
+ int *thread, int *inferior, int *task,
gdb::unique_xmalloc_ptr<char> *rest)
{
cond_string->reset ();
*thread = -1;
+ *inferior = -1;
*task = -1;
rest->reset ();
bool force = false;
if ((*tok == '"' || *tok == ',') && rest)
{
rest->reset (savestring (tok, strlen (tok)));
- return;
+ break;
}
end_tok = skip_to_space (tok);
if (*task != -1)
error (_("You can specify only one of thread or task."));
+ if (*inferior != -1)
+ error (_("You can specify only one of inferior or thread."));
+
tok = end_tok + 1;
thr = parse_thread_id (tok, &tmptok);
if (tok == tmptok)
*thread = thr->global_num;
tok = tmptok;
}
+ else if (toklen >= 1 && strncmp (tok, "inferior", toklen) == 0)
+ {
+ if (*inferior != -1)
+ error(_("You can specify only one inferior."));
+
+ if (*task != -1)
+ error (_("You can specify only one of inferior or task."));
+
+ if (*thread != -1)
+ error (_("You can specify only one of inferior or thread."));
+
+ char *tmptok;
+ tok = end_tok + 1;
+ *inferior = strtol (tok, &tmptok, 0);
+ if (tok == tmptok)
+ error (_("Junk after inferior keyword."));
+ if (!valid_global_inferior_id (*inferior))
+ error (_("Unknown inferior number %d."), *inferior);
+ tok = tmptok;
+ }
else if (toklen >= 1 && strncmp (tok, "task", toklen) == 0)
{
char *tmptok;
if (*thread != -1)
error (_("You can specify only one of thread or task."));
+ if (*inferior != -1)
+ error (_("You can specify only one of inferior or task."));
+
tok = end_tok + 1;
*task = strtol (tok, &tmptok, 0);
if (tok == tmptok)
else if (rest)
{
rest->reset (savestring (tok, strlen (tok)));
- return;
+ break;
}
else
error (_("Junk at end of arguments."));
find_condition_and_thread_for_sals (const std::vector<symtab_and_line> &sals,
const char *input,
gdb::unique_xmalloc_ptr<char> *cond_string,
- int *thread, int *task,
+ int *thread, int *inferior, int *task,
gdb::unique_xmalloc_ptr<char> *rest)
{
int num_failures = 0;
{
gdb::unique_xmalloc_ptr<char> cond;
int thread_id = -1;
+ int inferior_id = -1;
int task_id = -1;
gdb::unique_xmalloc_ptr<char> remaining;
try
{
find_condition_and_thread (input, sal.pc, &cond, &thread_id,
- &task_id, &remaining);
+ &inferior_id, &task_id, &remaining);
*cond_string = std::move (cond);
- /* At most one of thread or task can be set. */
- gdb_assert (thread_id == -1 || task_id == -1);
+ /* A value of -1 indicates that these fields are unset. At most
+ one of these fields should be set (to a value other than -1)
+ at this point. */
+ gdb_assert (((thread_id == -1 ? 1 : 0)
+ + (task_id == -1 ? 1 : 0)
+ + (inferior_id == -1 ? 1 : 0)) >= 2);
*thread = thread_id;
+ *inferior = inferior_id;
*task = task_id;
*rest = std::move (remaining);
break;
create_breakpoint (struct gdbarch *gdbarch,
location_spec *locspec,
const char *cond_string,
- int thread, const char *extra_string,
+ int thread, int inferior,
+ const char *extra_string,
bool force_condition, int parse_extra,
int tempflag, enum bptype type_wanted,
int ignore_count,
int task = -1;
int prev_bkpt_count = breakpoint_count;
+ gdb_assert (thread == -1 || thread > 0);
+ gdb_assert (inferior == -1 || inferior > 0);
+ gdb_assert (thread == -1 || inferior == -1);
+
gdb_assert (ops != NULL);
/* If extra_string isn't useful, set it to NULL. */
const linespec_sals &lsal = canonical.lsals[0];
find_condition_and_thread_for_sals (lsal.sals, extra_string,
- &cond, &thread, &task, &rest);
+ &cond, &thread, &inferior,
+ &task, &rest);
cond_string_copy = std::move (cond);
extra_string_copy = std::move (rest);
}
std::move (extra_string_copy),
type_wanted,
tempflag ? disp_del : disp_donttouch,
- thread, task, ignore_count,
+ thread, task, inferior, ignore_count,
from_tty, enabled, internal, flags);
}
else
create_breakpoint (get_current_arch (),
locspec.get (),
- NULL, 0, arg, false, 1 /* parse arg */,
+ NULL,
+ -1 /* thread */, -1 /* inferior */,
+ arg, false, 1 /* parse arg */,
tempflag, type_wanted,
0 /* Ignore count */,
pending_break_support,
create_breakpoint (get_current_arch (),
locspec.get (),
- NULL, 0, arg, false, 1 /* parse arg */,
+ NULL, -1, -1,
+ arg, false, 1 /* parse arg */,
0, bp_dprintf,
0 /* Ignore count */,
pending_break_support,
const char *cond_end = NULL;
enum bptype bp_type;
int thread = -1;
+ int inferior = -1;
/* Flag to indicate whether we are going to use masks for
the hardware watchpoint. */
bool use_mask = false;
if (task != -1)
error (_("You can specify only one of thread or task."));
+ if (inferior != -1)
+ error (_("You can specify only one of inferior or thread."));
+
/* Extract the thread ID from the next token. */
thr = parse_thread_id (value_start, &endp);
-
- /* Check if the user provided a valid thread ID. */
- if (*endp != ' ' && *endp != '\t' && *endp != '\0')
- invalid_thread_id_error (value_start);
+ if (value_start == endp)
+ error (_("Junk after thread keyword."));
thread = thr->global_num;
}
if (thread != -1)
error (_("You can specify only one of thread or task."));
+ if (inferior != -1)
+ error (_("You can specify only one of inferior or task."));
+
task = strtol (value_start, &tmp, 0);
if (tmp == value_start)
error (_("Junk after task keyword."));
if (!valid_task_id (task))
error (_("Unknown task %d."), task);
}
+ else if (toklen == 8 && startswith (tok, "inferior"))
+ {
+ /* Support for watchpoints will be added in a later commit. */
+ error (_("Cannot use 'inferior' keyword with watchpoints"));
+ }
else if (toklen == 4 && startswith (tok, "mask"))
{
/* We've found a "mask" token, which means the user wants to
/* At most one of thread or task can be set on a watchpoint. */
gdb_assert (thread == -1 || task == -1);
w->thread = thread;
+ w->inferior = inferior;
w->task = task;
w->disposition = disp_donttouch;
w->pspace = current_program_space;
? NULL : symtab_to_fullname (sal.symtab));
/* Find all matching breakpoints and add them to 'found'. */
- for (breakpoint *b : all_breakpoints ())
+ for (breakpoint &b : all_breakpoints ())
{
int match = 0;
/* Are we going to delete b? */
- if (b->type != bp_none && !is_watchpoint (b)
- && user_breakpoint_p (b))
+ if (b.type != bp_none && !is_watchpoint (&b)
+ && user_breakpoint_p (&b))
{
- for (bp_location &loc : b->locations ())
+ for (bp_location &loc : b.locations ())
{
/* If the user specified file:line, don't allow a PC
match. This matches historical gdb behavior. */
}
if (match)
- found.push_back (b);
+ found.push_back (&b);
}
}
&& bs->stop)
delete_breakpoint (bs->breakpoint_at);
- for (breakpoint *b : all_breakpoints_safe ())
- if (b->disposition == disp_del_at_next_stop)
- delete_breakpoint (b);
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (b.disposition == disp_del_at_next_stop)
+ delete_breakpoint (&b);
}
/* A comparison function for bp_location AP and BP being interfaced to
std::sort. Sort elements primarily by their ADDRESS (no matter what
bl_address_is_meaningful says), secondarily by ordering first
- permanent elements and terciarily just ensuring the array is sorted
+ permanent elements and tertiarily just ensuring the array is sorted
stable way despite std::sort being an unstable algorithm. */
static int
scoped_restore_current_pspace_and_thread restore_pspace_thread;
- for (breakpoint *b : all_tracepoints ())
+ for (breakpoint &b : all_tracepoints ())
{
- struct tracepoint *t;
bool bp_location_downloaded = false;
- if ((b->type == bp_fast_tracepoint
+ if ((b.type == bp_fast_tracepoint
? !may_insert_fast_tracepoints
: !may_insert_tracepoints))
continue;
if (can_download_tracepoint == TRIBOOL_FALSE)
break;
- for (bp_location &bl : b->locations ())
+ for (bp_location &bl : b.locations ())
{
/* In tracepoint, locations are _never_ duplicated, so
should_be_inserted is equivalent to
bl.inserted = 1;
bp_location_downloaded = true;
}
- t = (struct tracepoint *) b;
- t->number_on_target = b->number;
+
+ tracepoint &t = gdb::checked_static_cast<tracepoint &> (b);
+ t.number_on_target = b.number;
if (bp_location_downloaded)
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (&b);
}
}
/* Last breakpoint location program space that was marked for update. */
int last_pspace_num = -1;
+ breakpoint_debug_printf ("insert_mode = %s",
+ ugll_insert_mode_text (insert_mode));
+
/* Used in the duplicates detection below. When iterating over all
bp_locations, points to the first bp_location of a given address.
Breakpoints and watchpoints of different types are never
std::vector<bp_location *> old_locations = std::move (bp_locations);
bp_locations.clear ();
- for (breakpoint *b : all_breakpoints ())
- for (bp_location &loc : b->locations ())
+ for (breakpoint &b : all_breakpoints ())
+ for (bp_location &loc : b.locations ())
bp_locations.push_back (&loc);
/* See if we need to "upgrade" a software breakpoint to a hardware
enum bptype type_wanted,
enum bpdisp disposition,
int thread,
- int task, int ignore_count,
+ int task, int inferior,
+ int ignore_count,
int from_tty, int enabled,
int internal, unsigned flags)
{
std::move (cond_string),
std::move (extra_string),
disposition,
- thread, task, ignore_count,
+ thread, task, inferior, ignore_count,
from_tty, enabled, flags,
canonical->special_display));
return b->type == bp_static_marker_tracepoint;
}
+/* Notify interpreters and observers that breakpoint B was deleted. */
+
+static void
+notify_breakpoint_deleted (breakpoint *b)
+{
+ interps_notify_breakpoint_deleted (b);
+ gdb::observers::breakpoint_deleted.notify (b);
+}
+
/* Delete a breakpoint and clean up all traces of it in the data
structures. */
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)
- gdb::observers::breakpoint_deleted.notify (bpt);
+ notify_breakpoint_deleted (bpt);
- if (breakpoint_chain == bpt)
- breakpoint_chain = bpt->next;
-
- for (breakpoint *b : all_breakpoints ())
- if (b->next == bpt)
- {
- b->next = bpt->next;
- break;
- }
+ breakpoint_chain.erase (breakpoint_chain.iterator_to (*bpt));
/* Be sure no bpstat's are pointing at the breakpoint after it's
been freed. */
/* Delete all breakpoints if no argument. Do not delete
internal breakpoints, these have to be deleted with an
explicit breakpoint number argument. */
- for (breakpoint *b : all_breakpoints ())
- if (user_breakpoint_p (b))
+ for (breakpoint &b : all_breakpoints ())
+ if (user_breakpoint_p (&b))
{
breaks_to_delete = 1;
break;
/* Ask user only if there are some breakpoints to delete. */
if (!from_tty
|| (breaks_to_delete && query (_("Delete all breakpoints? "))))
- for (breakpoint *b : all_breakpoints_safe ())
- if (user_breakpoint_p (b))
- delete_breakpoint (b);
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (user_breakpoint_p (&b))
+ delete_breakpoint (&b);
}
else
map_breakpoint_numbers
}
if (!locations_are_equal (existing_locations, b->locations ()))
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (b);
}
/* Find the SaL locations corresponding to the given LOCSPEC.
if (condition_not_parsed && extra_string != NULL)
{
gdb::unique_xmalloc_ptr<char> local_cond, local_extra;
- int local_thread, local_task;
+ int local_thread, local_task, local_inferior;
find_condition_and_thread_for_sals (sals, extra_string.get (),
&local_cond, &local_thread,
+ &local_inferior,
&local_task, &local_extra);
gdb_assert (cond_string == nullptr);
if (local_cond != nullptr)
breakpoint 1, we'd insert the locations of breakpoint 2, which
hadn't been re-set yet, and thus may have stale locations. */
- for (breakpoint *b : all_breakpoints_safe ())
+ for (breakpoint &b : all_breakpoints_safe ())
{
try
{
- breakpoint_re_set_one (b);
+ breakpoint_re_set_one (&b);
}
catch (const gdb_exception &ex)
{
exception_fprintf (gdb_stderr, ex,
"Error in re-setting breakpoint %d: ",
- b->number);
+ b.number);
}
}
if (count < 0)
count = 0;
- for (breakpoint *b : all_breakpoints ())
- if (b->number == bptnum)
+ for (breakpoint &b : all_breakpoints ())
+ if (b.number == bptnum)
{
- if (is_tracepoint (b))
+ if (is_tracepoint (&b))
{
if (from_tty && count != 0)
gdb_printf (_("Ignore count ignored for tracepoint %d."),
return;
}
- b->ignore_count = count;
+ b.ignore_count = count;
if (from_tty)
{
if (count == 0)
"crossings of breakpoint %d."),
count, bptnum);
}
- gdb::observers::breakpoint_modified.notify (b);
+ notify_breakpoint_modified (&b);
return;
}
{
bool match = false;
- for (breakpoint *b : all_breakpoints_safe ())
- if (b->number == i)
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (b.number == i)
{
match = true;
- function (b);
+ function (&b);
break;
}
if (!match)
}
update_global_location_list (UGLL_DONT_INSERT);
- gdb::observers::breakpoint_modified.notify (loc->owner);
+ notify_breakpoint_modified (loc->owner);
}
/* Calculates LOC_NUM for LOC by traversing the bp_location chain of LOC's
target_disable_tracepoint (loc);
update_global_location_list (UGLL_DONT_INSERT);
- gdb::observers::breakpoint_modified.notify (loc->owner);
+ notify_breakpoint_modified (loc->owner);
}
/* Enable or disable a range of breakpoint locations. BP_NUM is the
update_global_location_list (UGLL_DONT_INSERT);
- gdb::observers::breakpoint_modified.notify (bpt);
+ notify_breakpoint_modified (bpt);
}
/* Enable or disable the breakpoint(s) or breakpoint location(s)
{
if (args == 0)
{
- for (breakpoint *bpt : all_breakpoints ())
- if (user_breakpoint_p (bpt))
+ for (breakpoint &bpt : all_breakpoints ())
+ if (user_breakpoint_p (&bpt))
{
if (enable)
- enable_breakpoint (bpt);
+ enable_breakpoint (&bpt);
else
- disable_breakpoint (bpt);
+ disable_breakpoint (&bpt);
}
}
else
bpt->enable_count = count;
update_global_location_list (UGLL_MAY_INSERT);
- gdb::observers::breakpoint_modified.notify (bpt);
+ notify_breakpoint_modified (bpt);
}
CORE_ADDR addr, ssize_t len,
const bfd_byte *data)
{
- for (breakpoint *bp : all_breakpoints ())
- if (bp->enable_state == bp_enabled
- && bp->type == bp_hardware_watchpoint)
+ for (breakpoint &bp : all_breakpoints ())
+ if (bp.enable_state == bp_enabled
+ && bp.type == bp_hardware_watchpoint)
{
- struct watchpoint *wp = (struct watchpoint *) bp;
+ watchpoint &wp = gdb::checked_static_cast<watchpoint &> (bp);
- if (wp->val_valid && wp->val != nullptr)
+ if (wp.val_valid && wp.val != nullptr)
{
- for (bp_location &loc : bp->locations ())
+ for (bp_location &loc : bp.locations ())
if (loc.loc_type == bp_loc_hardware_watchpoint
&& loc.address + loc.length > addr
&& addr + len > loc.address)
{
- wp->val = NULL;
- wp->val_valid = false;
+ wp.val = NULL;
+ wp.val_valid = false;
}
}
}
single_step_breakpoint_inserted_here_p (const address_space *aspace,
CORE_ADDR pc)
{
- for (breakpoint *bpt : all_breakpoints ())
+ for (breakpoint &bpt : all_breakpoints ())
{
- if (bpt->type == bp_single_step
- && breakpoint_has_location_inserted_here (bpt, aspace, pc))
+ if (bpt.type == bp_single_step
+ && breakpoint_has_location_inserted_here (&bpt, aspace, pc))
return 1;
}
return 0;
create_breakpoint (get_current_arch (),
locspec.get (),
- NULL, 0, arg, false, 1 /* parse arg */,
+ NULL, -1, -1, arg, false, 1 /* parse arg */,
0 /* tempflag */,
bp_tracepoint /* type_wanted */,
0 /* Ignore count */,
current_language);
create_breakpoint (get_current_arch (),
locspec.get (),
- NULL, 0, arg, false, 1 /* parse arg */,
+ NULL, -1, -1, arg, false, 1 /* parse arg */,
0 /* tempflag */,
bp_fast_tracepoint /* type_wanted */,
0 /* Ignore count */,
create_breakpoint (get_current_arch (),
locspec.get (),
- NULL, 0, arg, false, 1 /* parse arg */,
+ NULL, -1, -1, arg, false, 1 /* parse arg */,
0 /* tempflag */,
type /* type_wanted */,
0 /* Ignore count */,
current_language);
if (!create_breakpoint (get_current_arch (),
locspec.get (),
- utp->cond_string.get (), -1, addr_str,
+ utp->cond_string.get (), -1, -1, addr_str,
false /* force_condition */,
0 /* parse cond/thread */,
0 /* tempflag */,
Do not delete internal or call-dummy breakpoints, these
have to be deleted with an explicit breakpoint number
argument. */
- for (breakpoint *tp : all_tracepoints ())
- if (is_tracepoint (tp) && user_breakpoint_p (tp))
+ for (breakpoint &tp : all_tracepoints ())
+ if (is_tracepoint (&tp) && user_breakpoint_p (&tp))
{
breaks_to_delete = 1;
break;
if (!from_tty
|| (breaks_to_delete && query (_("Delete all tracepoints? "))))
{
- for (breakpoint *b : all_breakpoints_safe ())
- if (is_tracepoint (b) && user_breakpoint_p (b))
- delete_breakpoint (b);
+ for (breakpoint &b : all_breakpoints_safe ())
+ if (is_tracepoint (&b) && user_breakpoint_p (&b))
+ delete_breakpoint (&b);
}
}
else
trace_pass_set_count (struct tracepoint *tp, int count, int from_tty)
{
tp->pass_count = count;
- gdb::observers::breakpoint_modified.notify (tp);
+ notify_breakpoint_modified (tp);
if (from_tty)
gdb_printf (_("Setting tracepoint %d's passcount to %d\n"),
tp->number, count);
static void
trace_pass_command (const char *args, int from_tty)
{
- struct tracepoint *t1;
ULONGEST count;
if (args == 0 || *args == 0)
if (*args)
error (_("Junk at end of arguments."));
- for (breakpoint *b : all_tracepoints ())
+ for (breakpoint &b : all_tracepoints ())
{
- t1 = (struct tracepoint *) b;
- trace_pass_set_count (t1, count, from_tty);
+ tracepoint &t1 = gdb::checked_static_cast<tracepoint &> (b);
+ trace_pass_set_count (&t1, count, from_tty);
}
}
else if (*args == '\0')
{
- t1 = get_tracepoint_by_number (&args, NULL);
+ tracepoint *t1 = get_tracepoint_by_number (&args, NULL);
if (t1)
trace_pass_set_count (t1, count, from_tty);
}
number_or_range_parser parser (args);
while (!parser.finished ())
{
- t1 = get_tracepoint_by_number (&args, &parser);
+ tracepoint *t1 = get_tracepoint_by_number (&args, &parser);
if (t1)
trace_pass_set_count (t1, count, from_tty);
}
struct tracepoint *
get_tracepoint (int num)
{
- for (breakpoint *t : all_tracepoints ())
- if (t->number == num)
- return (struct tracepoint *) t;
+ for (breakpoint &t : all_tracepoints ())
+ if (t.number == num)
+ return gdb::checked_static_cast<tracepoint *> (&t);
return NULL;
}
struct tracepoint *
get_tracepoint_by_number_on_target (int num)
{
- for (breakpoint *b : all_tracepoints ())
+ for (breakpoint &b : all_tracepoints ())
{
- struct tracepoint *t = (struct tracepoint *) b;
+ tracepoint &t = gdb::checked_static_cast<tracepoint &> (b);
- if (t->number_on_target == num)
- return t;
+ if (t.number_on_target == num)
+ return &t;
}
return NULL;
return NULL;
}
- for (breakpoint *t : all_tracepoints ())
- if (t->number == tpnum)
- return (struct tracepoint *) t;
+ for (breakpoint &t : all_tracepoints ())
+ if (t.number == tpnum)
+ return gdb::checked_static_cast<tracepoint *> (&t);
gdb_printf ("No tracepoint number %d.\n", tpnum);
return NULL;
error (_("Argument required (file name in which to save)"));
/* See if we have anything to save. */
- for (breakpoint *tp : all_breakpoints ())
+ for (breakpoint &tp : all_breakpoints ())
{
/* Skip internal and momentary breakpoints. */
- if (!user_breakpoint_p (tp))
+ if (!user_breakpoint_p (&tp))
continue;
/* If we have a filter, only save the breakpoints it accepts. */
- if (filter && !filter (tp))
+ if (filter && !filter (&tp))
continue;
any = true;
- if (is_tracepoint (tp))
+ if (is_tracepoint (&tp))
{
extra_trace_bits = 1;
if (extra_trace_bits)
save_trace_state_variables (&fp);
- for (breakpoint *tp : all_breakpoints ())
+ for (breakpoint &tp : all_breakpoints ())
{
/* Skip internal and momentary breakpoints. */
- if (!user_breakpoint_p (tp))
+ if (!user_breakpoint_p (&tp))
continue;
/* If we have a filter, only save the breakpoints it accepts. */
- if (filter && !filter (tp))
+ if (filter && !filter (&tp))
continue;
- tp->print_recreate (&fp);
+ tp.print_recreate (&fp);
/* Note, we can't rely on tp->number for anything, as we can't
assume the recreated breakpoint numbers will match. Use $bpnum
instead. */
- if (tp->cond_string)
- fp.printf (" condition $bpnum %s\n", tp->cond_string.get ());
+ if (tp.cond_string)
+ fp.printf (" condition $bpnum %s\n", tp.cond_string.get ());
- if (tp->ignore_count)
- fp.printf (" ignore $bpnum %d\n", tp->ignore_count);
+ if (tp.ignore_count)
+ fp.printf (" ignore $bpnum %d\n", tp.ignore_count);
- if (tp->type != bp_dprintf && tp->commands)
+ if (tp.type != bp_dprintf && tp.commands)
{
fp.puts (" commands\n");
ui_out_redirect_pop redir (current_uiout, &fp);
- print_command_lines (current_uiout, tp->commands.get (), 2);
+ print_command_lines (current_uiout, tp.commands.get (), 2);
fp.puts (" end\n");
}
- if (tp->enable_state == bp_disabled)
+ if (tp.enable_state == bp_disabled)
fp.puts ("disable $bpnum\n");
/* If this is a multi-location breakpoint, check if the locations
should be individually disabled. Watchpoint locations are
special, and not user visible. */
- if (!is_watchpoint (tp) && tp->has_multiple_locations ())
+ if (!is_watchpoint (&tp) && tp.has_multiple_locations ())
{
int n = 1;
- for (bp_location &loc : tp->locations ())
+ for (bp_location &loc : tp.locations ())
{
if (!loc.enabled)
fp.printf ("disable $bpnum.%d\n", n);
pc_at_non_inline_function (const address_space *aspace, CORE_ADDR pc,
const target_waitstatus &ws)
{
- for (breakpoint *b : all_breakpoints ())
+ for (breakpoint &b : all_breakpoints ())
{
- if (!is_non_inline_function (b))
+ if (!is_non_inline_function (&b))
continue;
- for (bp_location &bl : b->locations ())
+ for (bp_location &bl : b.locations ())
{
if (!bl.shlib_disabled
&& bpstat_check_location (&bl, aspace, pc, ws))
gdb::observers::memory_changed.attach (invalidate_bp_value_on_memory_change,
"breakpoint");
- breakpoint_chain = 0;
/* Don't bother to call set_breakpoint_count. $bpnum isn't useful
before a breakpoint is set. */
breakpoint_count = 0;
&breakpoint_set_cmdlist,
&breakpoint_show_cmdlist);
+ add_setshow_boolean_cmd ("breakpoint", class_maintenance,
+ &debug_breakpoint, _("\
+Set breakpoint location debugging."), _("\
+Show breakpoint location debugging."), _("\
+When on, breakpoint location specific debugging is enabled."),
+ NULL,
+ show_debug_breakpoint,
+ &setdebuglist, &showdebuglist);
+
add_setshow_enum_cmd ("condition-evaluation", class_breakpoint,
condition_evaluation_enums,
&condition_evaluation_mode_1, _("\
"breakpoint");
gdb::observers::thread_exit.attach (remove_threaded_breakpoints,
"breakpoint");
+ gdb::observers::inferior_removed.attach (remove_inferior_breakpoints,
+ "breakpoint");
}