aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/NEWS7
-rw-r--r--gdb/ada-lang.c6
-rw-r--r--gdb/break-catch-throw.c6
-rw-r--r--gdb/breakpoint.c287
-rw-r--r--gdb/breakpoint.h37
-rw-r--r--gdb/testsuite/gdb.mi/new-ui-bp-deleted.exp8
-rw-r--r--gdb/testsuite/gdb.mi/user-selected-context-sync.exp14
-rw-r--r--gdb/testsuite/gdb.multi/bp-thread-specific.exp7
-rw-r--r--gdb/testsuite/gdb.multi/inferior-specific-bp.exp12
-rw-r--r--gdb/testsuite/gdb.multi/multi-target-continue.exp2
-rw-r--r--gdb/testsuite/gdb.multi/multi-target-ping-pong-next.exp4
-rw-r--r--gdb/testsuite/gdb.multi/pending-bp-del-inferior.exp6
-rw-r--r--gdb/testsuite/gdb.multi/pending-bp.exp206
-rw-r--r--gdb/testsuite/gdb.multi/tids.exp6
14 files changed, 497 insertions, 111 deletions
diff --git a/gdb/NEWS b/gdb/NEWS
index 3ee6a61..fa57b56 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -14,6 +14,13 @@
'thread' or 'task' keywords are parsed at the time the breakpoint is
created, rather than at the time the breakpoint becomes non-pending.
+* Thread-specific breakpoints are only inserted into the program space
+ in which the thread of interest is running. In most cases program
+ spaces are unique for each inferior, so this means that
+ thread-specific breakpoints will usually only be inserted for the
+ inferior containing the thread of interest. The breakpoint will
+ be hit no less than before.
+
* Python API
** Added gdb.record.clear. Clears the trace data of the current recording.
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 1e2ee45..14d6abd 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -12073,11 +12073,11 @@ struct ada_catchpoint : public code_breakpoint
enable_state = enabled ? bp_enabled : bp_disabled;
language = language_ada;
- re_set ();
+ re_set (pspace);
}
struct bp_location *allocate_location () override;
- void re_set () override;
+ void re_set (program_space *pspace) override;
void check_status (struct bpstat *bs) override;
enum print_stop_action print_it (const bpstat *bs) const override;
bool print_one (const bp_location **) const override;
@@ -12122,7 +12122,7 @@ static struct symtab_and_line ada_exception_sal
catchpoint kinds. */
void
-ada_catchpoint::re_set ()
+ada_catchpoint::re_set (program_space *pspace)
{
std::vector<symtab_and_line> sals;
try
diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
index b7e29a7..c1c88d9 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -81,10 +81,10 @@ struct exception_catchpoint : public code_breakpoint
_("invalid type-matching regexp")))
{
pspace = current_program_space;
- re_set ();
+ re_set (pspace);
}
- void re_set () override;
+ void re_set (program_space *pspace) override;
enum print_stop_action print_it (const bpstat *bs) const override;
bool print_one (const bp_location **) const override;
void print_mention () const override;
@@ -197,7 +197,7 @@ exception_catchpoint::check_status (struct bpstat *bs)
/* Implement the 're_set' method. */
void
-exception_catchpoint::re_set ()
+exception_catchpoint::re_set (program_space *pspace)
{
std::vector<symtab_and_line> sals;
struct program_space *filter_pspace = current_program_space;
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8860ec4..7fd50ba 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -91,9 +91,12 @@
static void map_breakpoint_numbers (const char *,
gdb::function_view<void (breakpoint *)>);
-static void
- create_sals_from_location_spec_default (location_spec *locspec,
- linespec_result *canonical);
+static void parse_breakpoint_sals (location_spec *locspec,
+ linespec_result *canonical,
+ program_space *search_pspace);
+
+static void breakpoint_re_set_one (breakpoint *b,
+ program_space *filter_pspace);
static void create_breakpoints_sal (struct gdbarch *,
struct linespec_result *,
@@ -283,11 +286,12 @@ static bool strace_marker_p (struct breakpoint *b);
static void bkpt_probe_create_sals_from_location_spec
(location_spec *locspec,
- struct linespec_result *canonical);
+ struct linespec_result *canonical,
+ struct program_space *search_pspace);
const struct breakpoint_ops code_breakpoint_ops =
{
- create_sals_from_location_spec_default,
+ parse_breakpoint_sals,
create_breakpoints_sal,
};
@@ -352,7 +356,7 @@ struct internal_breakpoint : public code_breakpoint
disposition = disp_donttouch;
}
- void re_set () override;
+ void re_set (program_space *pspace) override;
void check_status (struct bpstat *bs) override;
enum print_stop_action print_it (const bpstat *bs) const override;
void print_mention () const override;
@@ -389,7 +393,7 @@ struct momentary_breakpoint : public code_breakpoint
gdb_assert (inferior == -1);
}
- void re_set () override;
+ void re_set (program_space *pspace) override;
void check_status (struct bpstat *bs) override;
enum print_stop_action print_it (const bpstat *bs) const override;
void print_mention () const override;
@@ -400,7 +404,7 @@ struct dprintf_breakpoint : public ordinary_breakpoint
{
using ordinary_breakpoint::ordinary_breakpoint;
- void re_set () override;
+ void re_set (program_space *pspace) override;
int breakpoint_hit (const struct bp_location *bl,
const address_space *aspace,
CORE_ADDR bp_addr,
@@ -1549,7 +1553,36 @@ breakpoint_set_thread (struct breakpoint *b, int thread)
int old_thread = b->thread;
b->thread = thread;
if (old_thread != thread)
- notify_breakpoint_modified (b);
+ {
+ /* If THREAD is in a different program_space than OLD_THREAD, or the
+ breakpoint has switched to or from being thread-specific, then we
+ need to re-set the locations of this breakpoint. First, figure
+ out the program_space for the old and new threads, use a value of
+ nullptr to indicate the breakpoint is in all program spaces. */
+ program_space *old_pspace = nullptr;
+ if (old_thread != -1)
+ {
+ struct thread_info *thr = find_thread_global_id (old_thread);
+ gdb_assert (thr != nullptr);
+ old_pspace = thr->inf->pspace;
+ }
+
+ program_space *new_pspace = nullptr;
+ if (thread != -1)
+ {
+ struct thread_info *thr = find_thread_global_id (thread);
+ gdb_assert (thr != nullptr);
+ new_pspace = thr->inf->pspace;
+ }
+
+ /* If the program space has changed for this breakpoint, then
+ re-evaluate it's locations. */
+ if (old_pspace != new_pspace)
+ breakpoint_re_set_one (b, new_pspace);
+
+ /* Let others know the breakpoint has changed. */
+ notify_breakpoint_modified (b);
+ }
}
/* See breakpoint.h. */
@@ -1568,7 +1601,34 @@ breakpoint_set_inferior (struct breakpoint *b, int inferior)
int old_inferior = b->inferior;
b->inferior = inferior;
if (old_inferior != inferior)
- notify_breakpoint_modified (b);
+ {
+ /* If INFERIOR is in a different program_space than OLD_INFERIOR, or
+ the breakpoint has switch to or from inferior-specific, then we
+ need to re-set the locations of this breakpoint. First, figure
+ out the program_space for the old and new inferiors, use a value
+ of nullptr to indicate the breakpoint is in all program
+ spaces. */
+ program_space *old_pspace = nullptr;
+ if (old_inferior != -1)
+ {
+ struct inferior *inf = find_inferior_id (old_inferior);
+ gdb_assert (inf != nullptr);
+ old_pspace = inf->pspace;
+ }
+
+ program_space *new_pspace = nullptr;
+ if (inferior != -1)
+ {
+ struct inferior *inf = find_inferior_id (inferior);
+ gdb_assert (inf != nullptr);
+ new_pspace = inf->pspace;
+ }
+
+ if (old_pspace != new_pspace)
+ breakpoint_re_set_one (b, new_pspace);
+
+ notify_breakpoint_modified (b);
+ }
}
/* See breakpoint.h. */
@@ -8124,11 +8184,16 @@ catchpoint::catchpoint (struct gdbarch *gdbarch, bool temp,
/* See breakpoint.h. */
void
-catchpoint::re_set ()
+catchpoint::re_set (program_space *filter_pspace)
{
/* All catchpoints are associated with a specific program_space. */
gdb_assert (pspace != nullptr);
+ /* If only a single program space changed, and it's not the program space
+ for which this catchpoint applies, then there's nothing to do. */
+ if (filter_pspace != nullptr && filter_pspace != pspace)
+ return;
+
/* Catchpoints have a single dummy location. */
gdb_assert (locations ().size () == 1);
bp_location &bl = m_locations.front ();
@@ -8852,7 +8917,8 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
static void
parse_breakpoint_sals (location_spec *locspec,
- struct linespec_result *canonical)
+ struct linespec_result *canonical,
+ struct program_space *search_pspace)
{
if (locspec->type () == LINESPEC_LOCATION_SPEC)
{
@@ -8916,7 +8982,7 @@ parse_breakpoint_sals (location_spec *locspec,
&& strchr ("+-", spec[0]) != NULL
&& spec[1] != '['))
{
- decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, NULL,
+ decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, search_pspace,
get_last_displayed_symtab (),
get_last_displayed_line (),
canonical, NULL, NULL);
@@ -8924,7 +8990,7 @@ parse_breakpoint_sals (location_spec *locspec,
}
}
- decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, NULL,
+ decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, search_pspace,
cursal.symtab, cursal.line, canonical, NULL, NULL);
}
@@ -9023,6 +9089,39 @@ breakpoint_ops_for_location_spec_type (enum location_spec_type locspec_type,
}
}
+/* Return the program space to use as a filter when searching for locations
+ of a breakpoint specific to THREAD or INFERIOR. If THREAD and INFERIOR
+ are both -1, meaning all threads/inferiors, then this function returns
+ nullptr, indicating no program space filtering should be performed.
+ Otherwise, this function returns the program space for the inferior that
+ contains THREAD (when THREAD is not -1), or the program space for
+ INFERIOR (when INFERIOR is not -1). */
+
+static struct program_space *
+find_program_space_for_breakpoint (int thread, int inferior)
+{
+ if (thread != -1)
+ {
+ gdb_assert (inferior == -1);
+
+ struct thread_info *thr = find_thread_global_id (thread);
+ gdb_assert (thr != nullptr);
+ gdb_assert (thr->inf != nullptr);
+ return thr->inf->pspace;
+ }
+ else if (inferior != -1)
+ {
+ gdb_assert (thread == -1);
+
+ struct inferior *inf = find_inferior_id (inferior);
+ gdb_assert (inf != nullptr);
+
+ return inf->pspace;
+ }
+
+ return nullptr;
+}
+
/* See breakpoint.h. */
const struct breakpoint_ops *
@@ -9124,7 +9223,10 @@ create_breakpoint (struct gdbarch *gdbarch,
try
{
- ops->create_sals_from_location_spec (locspec, &canonical);
+ struct program_space *search_pspace
+ = find_program_space_for_breakpoint (thread, inferior);
+ ops->create_sals_from_location_spec (locspec, &canonical,
+ search_pspace);
}
catch (const gdb_exception_error &e)
{
@@ -9597,7 +9699,7 @@ break_range_command (const char *arg, int from_tty)
arg_start = arg;
location_spec_up start_locspec
= string_to_location_spec (&arg, current_language);
- parse_breakpoint_sals (start_locspec.get (), &canonical_start);
+ parse_breakpoint_sals (start_locspec.get (), &canonical_start, nullptr);
if (arg[0] != ',')
error (_("Too few arguments."));
@@ -9698,7 +9800,7 @@ watchpoint_exp_is_const (const struct expression *exp)
/* Implement the "re_set" method for watchpoints. */
void
-watchpoint::re_set ()
+watchpoint::re_set (struct program_space *pspace)
{
/* Watchpoint can be either on expression using entirely global
variables, or it can be on local variables.
@@ -11810,7 +11912,7 @@ breakpoint::print_recreate (struct ui_file *fp) const
/* Default breakpoint_ops methods. */
void
-code_breakpoint::re_set ()
+code_breakpoint::re_set (struct program_space *pspace)
{
/* FIXME: is this still reachable? */
if (breakpoint_location_spec_empty_p (this))
@@ -11820,7 +11922,7 @@ code_breakpoint::re_set ()
return;
}
- re_set_default ();
+ re_set_default (pspace);
}
int
@@ -12026,7 +12128,7 @@ code_breakpoint::decode_location_spec (location_spec *locspec,
/* Virtual table for internal breakpoints. */
void
-internal_breakpoint::re_set ()
+internal_breakpoint::re_set (struct program_space *pspace)
{
switch (type)
{
@@ -12119,7 +12221,7 @@ internal_breakpoint::print_mention () const
/* Virtual table for momentary breakpoints */
void
-momentary_breakpoint::re_set ()
+momentary_breakpoint::re_set (struct program_space *pspace)
{
/* Keep temporary breakpoints, which can be encountered when we step
over a dlopen call and solib_add is resetting the breakpoints.
@@ -12160,12 +12262,13 @@ longjmp_breakpoint::~longjmp_breakpoint ()
static void
bkpt_probe_create_sals_from_location_spec (location_spec *locspec,
- struct linespec_result *canonical)
+ struct linespec_result *canonical,
+ struct program_space *search_pspace)
{
struct linespec_sals lsal;
- lsal.sals = parse_probes (locspec, NULL, canonical);
+ lsal.sals = parse_probes (locspec, search_pspace, canonical);
lsal.canonical = xstrdup (canonical->locspec->to_string ());
canonical->lsals.push_back (std::move (lsal));
}
@@ -12255,9 +12358,9 @@ tracepoint::print_recreate (struct ui_file *fp) const
}
void
-dprintf_breakpoint::re_set ()
+dprintf_breakpoint::re_set (struct program_space *pspace)
{
- re_set_default ();
+ re_set_default (pspace);
/* 1 - connect to target 1, that can run breakpoint commands.
2 - create a dprintf, which resolves fine.
@@ -12311,8 +12414,10 @@ dprintf_breakpoint::after_condition_true (struct bpstat *bs)
markers (`-m'). */
static void
-strace_marker_create_sals_from_location_spec (location_spec *locspec,
- struct linespec_result *canonical)
+strace_marker_create_sals_from_location_spec
+ (location_spec *locspec,
+ struct linespec_result *canonical,
+ struct program_space *search_pspace)
{
struct linespec_sals lsal;
const char *arg_start, *arg;
@@ -12836,12 +12941,32 @@ update_breakpoint_locations (code_breakpoint *b,
all locations are in the same shared library, that was unloaded.
We'd like to retain the location, so that when the library is
loaded again, we don't loose the enabled/disabled status of the
- individual locations. */
+ individual locations.
+
+ Thread specific breakpoints will also trigger this case if the thread
+ is changed to a different program space, and all of the old locations
+ go out of scope. In this case we do (currently) discard the old
+ locations -- we assume the change in thread is permanent and the old
+ locations will never come back into scope. */
if (all_locations_are_pending (b, filter_pspace) && sals.empty ())
- return;
+ {
+ if (b->thread != -1)
+ b->clear_locations ();
+ return;
+ }
bp_location_list existing_locations = b->steal_locations (filter_pspace);
+ /* If this is a thread-specific breakpoint then any locations left on the
+ breakpoint are for a program space in which the thread of interest
+ does not operate. This can happen when the user changes the thread of
+ a thread-specific breakpoint.
+
+ We assume that the change in thread is permanent, and that the old
+ locations will never be used again, so discard them now. */
+ if (b->thread != -1)
+ b->clear_locations ();
+
for (const auto &sal : sals)
{
struct bp_location *new_loc;
@@ -13007,40 +13132,45 @@ code_breakpoint::location_spec_to_sals (location_spec *locspec,
locations. */
void
-code_breakpoint::re_set_default ()
+code_breakpoint::re_set_default (struct program_space *filter_pspace)
{
- struct program_space *filter_pspace = current_program_space;
std::vector<symtab_and_line> expanded, expanded_end;
- int found;
- std::vector<symtab_and_line> sals = location_spec_to_sals (locspec.get (),
- filter_pspace,
- &found);
- if (found)
- expanded = std::move (sals);
-
- if (locspec_range_end != nullptr)
- {
- std::vector<symtab_and_line> sals_end
- = location_spec_to_sals (locspec_range_end.get (),
- filter_pspace, &found);
+ /* If this breakpoint is thread-specific then find the program space in
+ which the specific thread exists. Otherwise, for breakpoints that are
+ not thread-specific THREAD_PSPACE will be nullptr. */
+ program_space *bp_pspace
+ = find_program_space_for_breakpoint (this->thread, this->inferior);
+
+ /* If this is not a thread or inferior specific breakpoint, or it is a
+ thread or inferior specific breakpoint but we are looking for new
+ locations in the program space that the specific thread or inferior is
+ running, then look for new locations for this breakpoint. */
+ if (bp_pspace == nullptr || filter_pspace == bp_pspace)
+ {
+ int found;
+ std::vector<symtab_and_line> sals
+ = location_spec_to_sals (locspec.get (), filter_pspace, &found);
if (found)
- expanded_end = std::move (sals_end);
+ expanded = std::move (sals);
+
+ if (locspec_range_end != nullptr)
+ {
+ std::vector<symtab_and_line> sals_end
+ = location_spec_to_sals (locspec_range_end.get (),
+ filter_pspace, &found);
+ if (found)
+ expanded_end = std::move (sals_end);
+ }
}
+ /* Update the locations for this breakpoint. For thread-specific
+ breakpoints this will remove any old locations that are for the wrong
+ program space -- this can happen if the user changes the thread of a
+ thread-specific breakpoint. */
update_breakpoint_locations (this, filter_pspace, expanded, expanded_end);
}
-/* Default method for creating SALs from an address string. It basically
- calls parse_breakpoint_sals. Return 1 for success, zero for failure. */
-
-static void
-create_sals_from_location_spec_default (location_spec *locspec,
- struct linespec_result *canonical)
-{
- parse_breakpoint_sals (locspec, canonical);
-}
-
/* Re-set breakpoint locations for the current program space.
Locations bound to other program spaces are left untouched. */
@@ -13075,7 +13205,7 @@ breakpoint_re_set (void)
{
input_radix = b.input_radix;
set_language (b.language);
- b.re_set ();
+ b.re_set (current_program_space);
}
catch (const gdb_exception &ex)
{
@@ -13096,6 +13226,53 @@ breakpoint_re_set (void)
/* Now we can insert. */
update_global_location_list (UGLL_MAY_INSERT);
}
+
+/* Re-set locations for breakpoint B in FILTER_PSPACE. If FILTER_PSPACE is
+ nullptr then re-set locations for B in all program spaces. Locations
+ bound to program spaces other than FILTER_PSPACE are left untouched. */
+
+static void
+breakpoint_re_set_one (breakpoint *b, program_space *filter_pspace)
+{
+ {
+ scoped_restore_current_language save_language;
+ scoped_restore save_input_radix = make_scoped_restore (&input_radix);
+ scoped_restore_current_pspace_and_thread restore_pspace_thread;
+
+ /* To ::re_set each breakpoint we set the current_language to the
+ language of the breakpoint before re-evaluating the breakpoint's
+ location. This change can unfortunately get undone by accident if
+ the language_mode is set to auto, and we either switch frames, or
+ more likely in this context, we select the current frame.
+
+ We prevent this by temporarily turning the language_mode to
+ language_mode_manual. We restore it once all breakpoints
+ have been reset. */
+ scoped_restore save_language_mode = make_scoped_restore (&language_mode);
+ language_mode = language_mode_manual;
+
+ /* Note: we must not try to insert locations until after all
+ breakpoints have been re-set. Otherwise, e.g., when re-setting
+ breakpoint 1, we'd insert the locations of breakpoint 2, which
+ hadn't been re-set yet, and thus may have stale locations. */
+
+ try
+ {
+ input_radix = b->input_radix;
+ set_language (b->language);
+ b->re_set (filter_pspace);
+ }
+ catch (const gdb_exception &ex)
+ {
+ exception_fprintf (gdb_stderr, ex,
+ "Error in re-setting breakpoint %d: ",
+ b->number);
+ }
+ }
+
+ /* Now we can insert. */
+ update_global_location_list (UGLL_MAY_INSERT);
+}
/* Reset the thread number of this breakpoint:
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 77b754f..cef1d72 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -568,15 +568,15 @@ enum print_stop_action
struct breakpoint_ops
{
- /* Create SALs from location spec, storing the result in
- linespec_result.
-
- For an explanation about the arguments, see the function
- `create_sals_from_location_spec_default'.
+ /* Create SALs from LOCSPEC, storing the result in linespec_result
+ CANONICAL. If SEARCH_PSPACE is not nullptr then only results in the
+ corresponding program space are returned. If SEARCH_PSPACE is nullptr
+ then results for all program spaces are returned.
This function is called inside `create_breakpoint'. */
void (*create_sals_from_location_spec) (location_spec *locspec,
- struct linespec_result *canonical);
+ linespec_result *canonical,
+ program_space *search_pspace);
/* This method will be responsible for creating a breakpoint given its SALs.
Usually, it just calls `create_breakpoints_sal' (for ordinary
@@ -708,10 +708,19 @@ struct breakpoint : public intrusive_list_node<breakpoint>
/* Reevaluate a breakpoint. This is necessary after symbols change
(e.g., an executable or DSO was loaded, or the inferior just
- started). This is pure virtual as, at a minimum, each sub-class must
- recompute any cached condition expressions based off of the
- cond_string member variable. */
- virtual void re_set () = 0;
+ started).
+
+ If not nullptr, then FILTER_PSPACE is the program space in which
+ symbols may have changed, we only need to add new locations in
+ FILTER_PSPACE.
+
+ If FILTER_PSPACE is nullptr then all program spaces may have changed,
+ new locations need to be searched for in every program space.
+
+ This is pure virtual as, at a minimum, each sub-class must recompute
+ any cached condition expressions based off of the cond_string member
+ variable. */
+ virtual void re_set (program_space *filter_pspace) = 0;
/* Insert the breakpoint or watchpoint or activate the catchpoint.
Return 0 for success, 1 if the breakpoint, watchpoint or
@@ -952,7 +961,7 @@ struct code_breakpoint : public breakpoint
/* Add a location for SAL to this breakpoint. */
bp_location *add_location (const symtab_and_line &sal);
- void re_set () override;
+ void re_set (program_space *pspace) override;
int insert_location (struct bp_location *) override;
int remove_location (struct bp_location *,
enum remove_bp_reason reason) override;
@@ -974,7 +983,7 @@ protected:
struct program_space *search_pspace);
/* Helper method that does the basic work of re_set. */
- void re_set_default ();
+ void re_set_default (program_space *pspace);
/* Find the SaL locations corresponding to the given LOCATION.
On return, FOUND will be 1 if any SaL was found, zero otherwise. */
@@ -996,7 +1005,7 @@ struct watchpoint : public breakpoint
{
using breakpoint::breakpoint;
- void re_set () override;
+ void re_set (program_space *pspace) override;
int insert_location (struct bp_location *) override;
int remove_location (struct bp_location *,
enum remove_bp_reason reason) override;
@@ -1140,7 +1149,7 @@ struct catchpoint : public breakpoint
/* If the catchpoint has a condition set then recompute the cached
expression within the single dummy location. */
- void re_set () override;
+ void re_set (program_space *filter_pspace) override;
};
diff --git a/gdb/testsuite/gdb.mi/new-ui-bp-deleted.exp b/gdb/testsuite/gdb.mi/new-ui-bp-deleted.exp
index f736994..938e6de 100644
--- a/gdb/testsuite/gdb.mi/new-ui-bp-deleted.exp
+++ b/gdb/testsuite/gdb.mi/new-ui-bp-deleted.exp
@@ -76,8 +76,12 @@ foreach_mi_ui_mode mode {
set loc2 [make_bp_loc "$::decimal\\.2"]
# Create the inferior-specific breakpoint.
- mi_create_breakpoint_multi "-g i2 foo" "create breakpoint in inferior 2" \
- -inferior "2" -locations "\\\[$loc1,$loc2\\\]"
+ mi_create_breakpoint "-g i2 foo" "create breakpoint in inferior 2" \
+ -number "$decimal" \
+ -type "breakpoint" \
+ -enabled "y" \
+ -func "foo" \
+ -inferior "2"
set bpnum [mi_get_valueof "/d" "\$bpnum" "INVALID"]
if {$mode eq "separate"} {
diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
index 93b91b4..e168a5e 100644
--- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
+++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
@@ -364,15 +364,9 @@ proc test_continue_to_start { mode inf } {
# Consume MI output.
with_spawn_id $mi_spawn_id {
- if { $inf == 1} {
- mi_expect_stop "breakpoint-hit" "child_sub_function" \
- "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
- "thread $inf.2 stops MI"
- } else {
- mi_expect_stop "breakpoint-hit" "child_sub_function" \
- "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \
- "thread $inf.2 stops MI"
- }
+ mi_expect_stop "breakpoint-hit" "child_sub_function" \
+ "" "$srcfile" "$decimal" {"" "disp=\"del\""} \
+ "thread $inf.2 stops MI"
}
}
}
@@ -439,7 +433,7 @@ proc_with_prefix test_setup { mode } {
with_spawn_id $mi_spawn_id {
mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \
- {"" "disp=\"del\"" "locno=\"[0-9]+\""} "main stop"
+ {"" "disp=\"del\""} "main stop"
}
# Consume CLI output.
diff --git a/gdb/testsuite/gdb.multi/bp-thread-specific.exp b/gdb/testsuite/gdb.multi/bp-thread-specific.exp
index 7635e84..c1d8752 100644
--- a/gdb/testsuite/gdb.multi/bp-thread-specific.exp
+++ b/gdb/testsuite/gdb.multi/bp-thread-specific.exp
@@ -50,7 +50,7 @@ gdb_test "info threads" \
# locations ('foo' in both inferiors) even though only one of those
# locations will ever trigger ('foo' in inferior 2).
gdb_test "break foo thread 2.1" \
- "Breakpoint $decimal at $hex: foo\\. \\(2 locations\\)"
+ "Breakpoint $decimal at $hex: file \[^\r\n\]+$srcfile, line $decimal\\."
set bpnum [get_integer_valueof "\$bpnum" "INVALID"]
@@ -58,10 +58,7 @@ set bpnum [get_integer_valueof "\$bpnum" "INVALID"]
# earlier breakpoint. Check that the thread-id used when describing
# the earlier breakpoints is correct.
gdb_test "break foo thread 1.1" \
- [multi_line \
- "Note: breakpoint $bpnum \\(thread 2.1\\) also set at pc $hex\\." \
- "Note: breakpoint $bpnum \\(thread 2.1\\) also set at pc $hex\\." \
- "Breakpoint $decimal at $hex: foo\\. \\(2 locations\\)"]
+ "Breakpoint $decimal at $hex: file \[^\r\n\]+$srcfile, line $decimal\\."
# Save the breakpoints into a file.
if {[is_remote host]} {
diff --git a/gdb/testsuite/gdb.multi/inferior-specific-bp.exp b/gdb/testsuite/gdb.multi/inferior-specific-bp.exp
index 46efe6f..52f8418 100644
--- a/gdb/testsuite/gdb.multi/inferior-specific-bp.exp
+++ b/gdb/testsuite/gdb.multi/inferior-specific-bp.exp
@@ -105,16 +105,8 @@ proc check_info_breakpoints { testname bp_number expected_loc_count } {
# Create an inferior-specific breakpoint. Use gdb_test instead of
# gdb_breakpoint here as we want to check the breakpoint was placed in
# multiple locations.
-#
-# Currently GDB still places inferior specific breakpoints into every
-# inferior, just like it does with thread specific breakpoints.
-# Hopefully this will change in the future, at which point, this test
-# will need updating.
-#
-# Two of these locations are in inferior 1, while the third is in
-# inferior 2.
gdb_test "break foo inferior 1" \
- "Breakpoint $decimal at $hex: foo\\. \\(3 locations\\)"
+ "Breakpoint $decimal at $hex: foo\\. \\(2 locations\\)"
set bp_number [get_integer_valueof "\$bpnum" "INVALID" \
"get b/p number for inferior specific breakpoint"]
@@ -123,7 +115,7 @@ set location_count 0
set saw_inf_cond false
check_info_breakpoints "first check for inferior specific breakpoint" \
- $bp_number 3
+ $bp_number 2
# Create a multi-inferior breakpoint to stop at.
gdb_breakpoint "stop_breakpt" message
diff --git a/gdb/testsuite/gdb.multi/multi-target-continue.exp b/gdb/testsuite/gdb.multi/multi-target-continue.exp
index d220106..d4b2fc2 100644
--- a/gdb/testsuite/gdb.multi/multi-target-continue.exp
+++ b/gdb/testsuite/gdb.multi/multi-target-continue.exp
@@ -30,7 +30,7 @@ proc test_continue {non-stop} {
proc set_break {inf} {
gdb_test "break function${inf} thread ${inf}.1" \
- "Breakpoint .* function${inf}\\..*"
+ "Breakpoint ${::decimal} at ${::hex}: file .*, line ${::decimal}\\."
}
# Select inferior INF, and then run to a breakpoint on inferior
diff --git a/gdb/testsuite/gdb.multi/multi-target-ping-pong-next.exp b/gdb/testsuite/gdb.multi/multi-target-ping-pong-next.exp
index 0aff708..36f9d24 100644
--- a/gdb/testsuite/gdb.multi/multi-target-ping-pong-next.exp
+++ b/gdb/testsuite/gdb.multi/multi-target-ping-pong-next.exp
@@ -52,12 +52,12 @@ proc test_ping_pong_next {} {
gdb_test "thread 1.1" "Switching to thread 1.1 .*"
gdb_test "break $srcfile:$line1 thread 1.1" \
- "Breakpoint .*$srcfile:$line1\\..*"
+ "Breakpoint .*$srcfile, line $line1\\."
gdb_test "continue" "hit Breakpoint .*"
gdb_test "break $srcfile:$line2 thread 2.1" \
- "Breakpoint .*$srcfile:$line2\\..*"
+ "Breakpoint .*$srcfile, line $line2\\."
# Now block inferior 1 and issue "next". We should stop at the
# breakpoint for inferior 2, given schedlock off.
diff --git a/gdb/testsuite/gdb.multi/pending-bp-del-inferior.exp b/gdb/testsuite/gdb.multi/pending-bp-del-inferior.exp
index 5fcd1ef..12c0a84 100644
--- a/gdb/testsuite/gdb.multi/pending-bp-del-inferior.exp
+++ b/gdb/testsuite/gdb.multi/pending-bp-del-inferior.exp
@@ -129,10 +129,8 @@ proc do_bp_test { bp_type bp_pending } {
} else {
set bp_pattern_before \
[multi_line \
- "$bp_number\\s+breakpoint\\s+keep\\s+y\\s+<MULTIPLE>\\s*" \
- "\\s+stop only in [string_to_regexp $bp_restriction]" \
- "$bp_number\\.1\\s+y\\s+$::hex in $bp_func at \[^\r\n\]+ inf 1" \
- "$bp_number\\.2\\s+y\\s+$::hex in $bp_func at \[^\r\n\]+ inf 2"]
+ "$bp_number\\s+breakpoint\\s+keep\\s+y\\s+$::hex in $bp_func at \[^\r\n\]+ inf 1" \
+ "\\s+stop only in [string_to_regexp $bp_restriction]"]
set bp_pattern_after \
[multi_line \
diff --git a/gdb/testsuite/gdb.multi/pending-bp.exp b/gdb/testsuite/gdb.multi/pending-bp.exp
index 13f76f4..2a0644b 100644
--- a/gdb/testsuite/gdb.multi/pending-bp.exp
+++ b/gdb/testsuite/gdb.multi/pending-bp.exp
@@ -72,6 +72,48 @@ proc do_test_setup { inf_1_stop inf_2_stop } {
return true
}
+# Create a breakpoint on the function 'foo' in THREAD. It is expected
+# that the breakpoint created will be pending, this is checked by
+# running the 'info breakpoints' command.
+#
+# Returns the number for the newly created breakpoint.
+proc do_create_pending_foo_breakpoint { {thread "1.1"} } {
+ gdb_test "break foo thread $thread" \
+ [multi_line \
+ "Function \"foo\" not defined\\." \
+ "Breakpoint $::decimal \\(foo\\) pending\."] \
+ "set pending thread-specific breakpoint"
+ set bpnum [get_integer_valueof "\$bpnum" "*INVALID*" \
+ "get number for thread-specific breakpoint on foo"]
+ gdb_test "info breakpoints $bpnum" \
+ [multi_line \
+ "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+<PENDING>\\s+foo" \
+ "\\s+stop only in thread [string_to_regexp $thread]"] \
+ "check thread-specific breakpoint is initially pending"
+
+ return $bpnum
+}
+
+# Create a breakpoint on the function 'foo' in THREAD. It is expected
+# that the breakpoint created will not be pending, this is checked by
+# running the 'info breakpoints' command.
+#
+# Returns the number for the newly created breakpoint.
+proc do_create_foo_breakpoint { {thread "1.1"} } {
+ gdb_test "break foo thread $thread" \
+ "Breakpoint $::decimal at $::hex" \
+ "set thread-specific breakpoint"
+ set bpnum [get_integer_valueof "\$bpnum" "*INVALID*" \
+ "get number for thread-specific breakpoint on foo"]
+ gdb_test "info breakpoints $bpnum" \
+ [multi_line \
+ "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+$::hex\\s+<foo\[^>\]*> inf $::decimal" \
+ "\\s+stop only in thread [string_to_regexp $thread]"] \
+ "check thread-specific breakpoint is initially pending"
+
+ return $bpnum
+}
+
# Check that when a breakpoint is in the pending state, but that breakpoint
# does have some locations (those locations themselves are pending), GDB
# doesn't display the inferior list in the 'info breakpoints' output.
@@ -122,5 +164,169 @@ proc_with_prefix test_no_inf_display {} {
"check info breakpoints while breakpoint is pending"
}
+# Setup two inferiors. In #1 the symbol 'foo' has not yet been
+# loaded, while in #2 the symbol 'foo' has been loaded.
+#
+# Create a thread-specific breakpoint on 'foo' tied to a thread in
+# inferior #1, the breakpoint should be pending -- 'foo' is not yet
+# loaded in #1.
+#
+# Now move inferior #1 forward until 'foo' is loaded, check the
+# breakpoint is no longer pending.
+#
+# Move inferior #1 forward more until 'foo' is unloaded, check that
+# the breakpoint returns to the pending state.
+proc_with_prefix test_pending_toggle { } {
+
+ do_test_setup "Break before open" "Break before close"
+
+ set bpnum [do_create_pending_foo_breakpoint]
+
+ # Now return to inferior 1 and continue until the shared library is
+ # loaded, the breakpoint should become non-pending.
+ gdb_test "inferior 1" "Switching to inferior 1 .*" \
+ "switch back to inferior 1"
+ gdb_continue_to_breakpoint "stop in foo in inferior 1" "foo \\(\\) .*"
+
+ gdb_test "info breakpoint $bpnum" \
+ [multi_line \
+ "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+$::hex <foo\[^>\]*> inf 1" \
+ "\\s+stop only in thread 1\\.1" \
+ "\\s+breakpoint already hit 1 time"] \
+ "check thread-specific breakpoint is no longer pending"
+
+ gdb_breakpoint [gdb_get_line_number "Break after close"] temporary
+ gdb_continue_to_breakpoint "close library"
+ gdb_test "info breakpoints $bpnum" \
+ [multi_line \
+ "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+<PENDING>\\s+foo" \
+ "\\s+stop only in thread 1\\.1" \
+ "\\s+breakpoint already hit 1 time"] \
+ "check thread-specific breakpoint is pending again"
+}
+
+# Create a Python variable VAR and set it to the gdb.Breakpoint object
+# corresponding to the breakpoint numbered BPNUM. If THREAD is not
+# the empty string then THREAD should be an integer, check that
+# gdb.Breakpoint.thread is set to the value of THREAD. Otherwise, if
+# THREAD is the empty string, check that gdb.Breakpoint.thread is set
+# to None.
+proc py_find_breakpoint { var bpnum {thread ""} } {
+ gdb_test_no_output \
+ "python ${var}=\[b for b in gdb.breakpoints() if b.number == $bpnum\]\[0\]" \
+ "find Python gdb.Breakpoint object"
+ if { $thread ne "" } {
+ gdb_test_no_output "python assert(${var}.thread == ${thread})" \
+ "check thread attribute is currently correct"
+ } else {
+ gdb_test_no_output "python assert(${var}.thread is None)" \
+ "check thread attribute is currently correct"
+ }
+}
+
+# Setup two inferiors. In #1 the symbol 'foo' has not yet been
+# loaded, while in #2 the symbol 'foo' has been loaded.
+#
+# Create a thread-specific breakpoint on 'foo' tied to a thread in
+# inferior #1, the breakpoint should be pending -- 'foo' is not yet
+# loaded in #1.
+#
+# Use Python to change the thread of the thread-specific breakpoint to
+# a thread in inferior #2, at this point the thread should gain a
+# location and become non-pending.
+#
+# Set the thread back to a thread in inferior #1, the breakpoint
+# should return to the pending state.
+proc_with_prefix py_test_toggle_thread {} {
+ do_test_setup "Break before open" "Break after open"
+
+ set bpnum [do_create_pending_foo_breakpoint]
+
+ py_find_breakpoint "bp" $bpnum 1
+
+ gdb_test_no_output "python bp.thread = 2" \
+ "change thread on thread-specific breakpoint"
+ gdb_test "info breakpoint $bpnum" \
+ [multi_line \
+ "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+$::hex <foo\[^>\]*> inf 2" \
+ "\\s+stop only in thread 2\\.1"] \
+ "check thread-specific breakpoint now has a location"
+
+ gdb_test_no_output "set call_count = 2" "set call_count in inferior 2"
+ gdb_continue_to_breakpoint "stop at foo in inferior 2" "foo \\(\\) .*"
+
+ gdb_test_no_output "python bp.thread = 1" \
+ "restore thread on thread-specific breakpoint"
+ gdb_test "info breakpoints $bpnum" \
+ [multi_line \
+ "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+<PENDING>\\s+foo" \
+ "\\s+stop only in thread 1\\.1" \
+ "\\s+breakpoint already hit 1 time"] \
+ "check thread-specific breakpoint has returned to pending"
+
+ gdb_breakpoint [gdb_get_line_number "Break after close"] temporary
+ gdb_continue_to_breakpoint "stop after close in inferior 2" \
+ ".* Break after close\\. .*"
+
+ gdb_test "inferior 1" "Switching to inferior 1 .*" \
+ "switch to inferior 1"
+ gdb_continue_to_breakpoint "stop at foo in inferior 1" "foo \\(\\) .*"
+}
+
+# Setup two inferiors. Both inferiors have the symbol 'foo'
+# available.
+#
+# Create a thread-specific breakpoint on 'foo' tied to a thread in
+# inferior #1, the breakpoint should not be pending, but will only
+# have a single location, the location in inferior #1.
+#
+# Use Python to change the thread of the thread-specific breakpoint to
+# None. At this point the breakpoint should gain a second location, a
+# location in inferior #2.
+proc_with_prefix py_test_clear_thread {} {
+ do_test_setup "Break after open" "Break after open"
+
+ set bpnum [do_create_foo_breakpoint]
+
+ py_find_breakpoint "bp" $bpnum 1
+
+ gdb_test_no_output "python bp.thread = None" \
+ "clear thread on thread-specific breakpoint"
+ gdb_test "info breakpoints $bpnum" \
+ [multi_line \
+ "${bpnum}\\s+breakpoint\\s+keep y\\s+<MULTIPLE>\\s*" \
+ "${bpnum}\\.1\\s+y\\s+${::hex}\\s+<foo\[^>\]*> inf $::decimal" \
+ "${bpnum}\\.2\\s+y\\s+${::hex}\\s+<foo\[^>\]*> inf $::decimal"] \
+ "check for a location in both inferiors"
+
+ gdb_continue_to_breakpoint "stop at foo in inferior 2" "foo \\(\\) .*"
+ gdb_test_no_output "set call_count = 2" "set call_count in inferior 2"
+
+ gdb_test "inferior 1" "Switching to inferior 1 .*" \
+ "switch to inferior 1"
+ gdb_continue_to_breakpoint "stop at foo in inferior 1" "foo \\(\\) .*"
+ gdb_test_no_output "set call_count = 2" "set call_count in inferior 1"
+
+ gdb_test_no_output "python bp.thread = 2"
+ gdb_test "info breakpoints $bpnum" \
+ [multi_line \
+ "${bpnum}\\s+breakpoint\\s+keep y\\s+${::hex}\\s+<foo\[^>\]*> inf 2" \
+ "\\s+stop only in thread 2\\.1" \
+ "\\s+breakpoint already hit 2 times"] \
+ "check for a location only in inferior 2"
+
+ gdb_breakpoint [gdb_get_line_number "Break after close"] temporary
+ gdb_continue_to_breakpoint "stop after close in inferior 1" \
+ ".* Break after close\\. .*"
+
+ gdb_test "inferior 2" "Switching to inferior 2 .*" \
+ "switch back to inferior 2"
+ gdb_continue_to_breakpoint "stop at foo again in inferior 2" \
+ "foo \\(\\) .*"
+}
+
# Run all the tests.
test_no_inf_display
+test_pending_toggle
+py_test_toggle_thread
+py_test_clear_thread
diff --git a/gdb/testsuite/gdb.multi/tids.exp b/gdb/testsuite/gdb.multi/tids.exp
index 573b02f..4f78884 100644
--- a/gdb/testsuite/gdb.multi/tids.exp
+++ b/gdb/testsuite/gdb.multi/tids.exp
@@ -433,11 +433,13 @@ if { [allow_python_tests] } {
gdb_py_test_silent_cmd "python bp = gdb.breakpoints()\[0\]" \
"get python breakpoint" 0
- gdb_test "python bp.thread = 6" "thread = 6" \
+ gdb_test_no_output "python bp.thread = 6" \
"make breakpoint thread-specific with python"
# Check that the inferior-qualified ID is correct.
gdb_test "info breakpoint" \
- "stop only in thread 1.3\r\n.*" \
+ [multi_line \
+ "$decimal\\s+\[^\r\n\]+ in thread_function1 at \[^\r\n\]+" \
+ "\\s+stop only in thread 1\\.3"] \
"thread specific breakpoint right thread"
}
}