diff options
-rw-r--r-- | gdb/NEWS | 7 | ||||
-rw-r--r-- | gdb/ada-lang.c | 6 | ||||
-rw-r--r-- | gdb/break-catch-throw.c | 6 | ||||
-rw-r--r-- | gdb/breakpoint.c | 287 | ||||
-rw-r--r-- | gdb/breakpoint.h | 37 | ||||
-rw-r--r-- | gdb/testsuite/gdb.mi/new-ui-bp-deleted.exp | 8 | ||||
-rw-r--r-- | gdb/testsuite/gdb.mi/user-selected-context-sync.exp | 14 | ||||
-rw-r--r-- | gdb/testsuite/gdb.multi/bp-thread-specific.exp | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.multi/inferior-specific-bp.exp | 12 | ||||
-rw-r--r-- | gdb/testsuite/gdb.multi/multi-target-continue.exp | 2 | ||||
-rw-r--r-- | gdb/testsuite/gdb.multi/multi-target-ping-pong-next.exp | 4 | ||||
-rw-r--r-- | gdb/testsuite/gdb.multi/pending-bp-del-inferior.exp | 6 | ||||
-rw-r--r-- | gdb/testsuite/gdb.multi/pending-bp.exp | 206 | ||||
-rw-r--r-- | gdb/testsuite/gdb.multi/tids.exp | 6 |
14 files changed, 497 insertions, 111 deletions
@@ -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" } } |