From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 71D483858D34 for ; Wed, 6 Mar 2024 14:11:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 71D483858D34 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 71D483858D34 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709734294; cv=none; b=b9PEgkAs3fgAE/W5wr1ZUkCrUBdH1N5UBXKrRZy3xAsIlObIhXKfMZ8PFpVJ2nAl8cGeZtmMNk8GWrL2/uPuDIHnOTp+5FeFJ6x8R+ykKwL31UdGR94cu+42zarNWgP1vOfjcavpadX/L15iFlUf0hd567A4kLVr/6TlClx+BXo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709734294; c=relaxed/simple; bh=c4G2qO03rZzobq74RYC46mbFHC7wJ7YzIJp+4NVcusM=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=xhoa/CRZuqdIgpYsh550nUMAJXFLs6Jk9/YXbch5dLnEtM3At0/VXXmxZ/+e/w6ctZgWQYxiGuCQaFMrSCuHZvvWv9kdk9wEqOb4r5+m9djzmV3FeBrLlZbUBWJmdL1nHwIKeLRbu4U5TYf+zMCtLK4vrgwzgHwbPQUu+MpgJfA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1709734288; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j0/mkIzBEwkR8qgBcLkfxLJWXAByXUuFhnbt69Avowg=; b=bvNLkAa1iheFn0sn+ztiQKcmzLypOtFmHE8dQdC0g0xtZARxdPbkB9XXyfVUoeLzvUuK7O mEj4Vhh9BoF75bcpylQsrR48a4O2UBdh3bJWGAulSGiBfgi/bWyiXxmC75l6OD5fgeCQM0 PpqzzYXPSfP+rIEwk5rhxgMZG799CW4= Received: from mail-ej1-f70.google.com (mail-ej1-f70.google.com [209.85.218.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-497-CFQyKuf0MHeWHZ5-MFu9kA-1; Wed, 06 Mar 2024 09:11:25 -0500 X-MC-Unique: CFQyKuf0MHeWHZ5-MFu9kA-1 Received: by mail-ej1-f70.google.com with SMTP id a640c23a62f3a-a3fcf5b93faso451332966b.2 for ; Wed, 06 Mar 2024 06:11:25 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1709734283; x=1710339083; h=content-transfer-encoding:mime-version:message-id:date:references :in-reply-to:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=SpuVW9J+N8O0+H0tNvuJ3szqYF45WEyf+rZ9MAVVAyU=; b=TV4m3kM4aZJA6dSX5MCqGh5qAQjs3SSQ7YppQpMY5aIfrJwp2nuIGUpApMMDFFOHKv lXAwjxEkyieCHyftxW3gn8bfNH3Lftexe+9nvfjQTvd720RIiuYvQAr/CeMt8PQbvjoG poGbSw7gIfBEUuVoj+OatI4LG93z87Bc2vb4jQRAhy1XvMa880Pd1WUK2zhVV/pxcIq7 PC86fRUQO3bWPzo+TtvaS3JNuIYuC4184COu+DGh3UXSZfelAPOVF8EazCStqQF1NCCl 9XMFUzYU2qiptWTbnbsapgbtl3HtJ+cpg83kpK2TtcKGHYacKeKxOPM4mAKbuK7CZOVy gjgQ== X-Forwarded-Encrypted: i=1; AJvYcCU8lYWPTguplo2gZwI7ireM9tNce5VOSOP/As2mVL0JkUfSIQiiUxQZYBgNh0c30mPHb9vfOZvg5CIRvP24e3ELOeF2DtQ+GCJyag== X-Gm-Message-State: AOJu0YyXpzEY8SmnFIY4rhH1jghd3GcCWaqTPA2/T1gddwLMLQPxWxU5 ynvfisrJcEnYBv7v1S8Jj8kf2nXsiUF37og903DAKBhVHIdDQjasEdeR7djdVTn5QeG7nbr6f4v Kjtu6JzIcJ7t42KIN1D0mscCSLl0rJA7yjsVjbrnYUZDnbygYuMtk2RJgjRvLFL+681k= X-Received: by 2002:a17:906:3c17:b0:a43:d853:98f1 with SMTP id h23-20020a1709063c1700b00a43d85398f1mr10297376ejg.17.1709734283028; Wed, 06 Mar 2024 06:11:23 -0800 (PST) X-Google-Smtp-Source: AGHT+IE1TQCT0/QbdbXFE9+iDP1hhCve6vUEKdui4eMjcLNggWFJCeleVWlY0SXlKTZ5xPIHMSpZaw== X-Received: by 2002:a17:906:3c17:b0:a43:d853:98f1 with SMTP id h23-20020a1709063c1700b00a43d85398f1mr10297352ejg.17.1709734282121; Wed, 06 Mar 2024 06:11:22 -0800 (PST) Received: from localhost (185.223.159.143.dyn.plus.net. [143.159.223.185]) by smtp.gmail.com with ESMTPSA id w17-20020a170906d21100b00a457a55b814sm2802894ejz.73.2024.03.06.06.11.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 Mar 2024 06:11:21 -0800 (PST) From: Andrew Burgess To: "Willgerodt, Felix" , "gdb-patches@sourceware.org" Cc: Eli Zaretskii Subject: RE: [PATCHv9 14/14] gdb: only insert thread-specific breakpoints in the relevant inferior In-Reply-To: References: <3a2b295e10626cf03ce54b1d32c9175eba725f0c.1709651994.git.aburgess@redhat.com> Date: Wed, 06 Mar 2024 14:11:20 +0000 Message-ID: <87r0gna1rr.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-12.2 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: "Willgerodt, Felix" writes: >> -----Original Message----- >> From: Andrew Burgess >> Sent: Dienstag, 5. M=C3=A4rz 2024 16:22 >> To: gdb-patches@sourceware.org >> Cc: Andrew Burgess ; Eli Zaretskii >> Subject: [PATCHv9 14/14] gdb: only insert thread-specific breakpoints in= the >> relevant inferior >>=20 >> This commit updates GDB so that thread or inferior specific >> breakpoints are only inserted into the program space in which the >> specific thread or inferior is running. >>=20 >> In terms of implementation, getting this basically working is easy >> enough, now that a breakpoint's thread or inferior field is setup >> prior to GDB looking for locations, we can easily use this information >> to find a suitable program_space and pass this to as a filter when >> creating the sals. >>=20 >> Or we could if breakpoint_ops::create_sals_from_location_spec allowed >> us to pass in a filter program_space. >>=20 >> So, this commit extends breakpoint_ops::create_sals_from_location_spec >> to take a program_space argument, and uses this to filter the set of >> returned sals. This accounts for about half the change in this patch. >>=20 >> The second set of changes starts from breakpoint_set_thread and >> breakpoint_set_inferior, this is called when the thread or inferior >> for a breakpoint changes, e.g. from the Python API. >>=20 >> Previously this call would never result in the locations of a >> breakpoint changing, after all, locations were inserted in every >> program space, and we just use the thread or inferior variable to >> decide when we should stop. Now though, changing a breakpoint's >> thread or inferior can mean we need to figure out a new set of >> breakpoint locations. >>=20 >> To support this I've added a new breakpoint_re_set_one function, which >> is like breakpoint_re_set, but takes a single breakpoint, and just >> updates the locations for that one breakpoint. We only need to call >> this function if the program_space in which a breakpoint's thread (or >> inferior) is running actually changes. If the program_space does >> change then we call the new breakpoint_re_set_one function passing in >> the program_space which should be used to filter the new locations (or >> nullptr to indicate we should set locations in all program spaces). >> This filter program_space needs to propagate down to all the re_set >> methods, this accounts for the remaining half of the changes in this >> patch. >>=20 >> There were a couple of existing tests that created thread or inferior >> specific breakpoints and then checked the 'info breakpoints' output, >> these needed updating. These were: >>=20 >> gdb.mi/user-selected-context-sync.exp >> gdb.multi/bp-thread-specific.exp >> gdb.multi/multi-target-continue.exp >> gdb.multi/multi-target-ping-pong-next.exp >> gdb.multi/tids.exp >> gdb.mi/new-ui-bp-deleted.exp >> gdb.multi/inferior-specific-bp.exp >> gdb.multi/pending-bp-del-inferior.exp >>=20 >> I've also added some additional tests to: >>=20 >> gdb.multi/pending-bp.exp >>=20 >> I've updated the documentation and added a NEWS entry. >>=20 >> Reviewed-By: Eli Zaretskii >> --- >> gdb/NEWS | 7 + >> gdb/ada-lang.c | 6 +- >> gdb/break-catch-throw.c | 6 +- >> gdb/breakpoint.c | 280 ++++++++++++++---- >> gdb/breakpoint.h | 29 +- >> gdb/testsuite/gdb.mi/new-ui-bp-deleted.exp | 8 +- >> .../gdb.mi/user-selected-context-sync.exp | 4 +- >> .../gdb.multi/bp-thread-specific.exp | 7 +- >> .../gdb.multi/inferior-specific-bp.exp | 12 +- >> .../gdb.multi/multi-target-continue.exp | 2 +- >> .../gdb.multi/multi-target-ping-pong-next.exp | 4 +- >> .../gdb.multi/pending-bp-del-inferior.exp | 6 +- >> gdb/testsuite/gdb.multi/pending-bp.exp | 206 +++++++++++++ >> gdb/testsuite/gdb.multi/tids.exp | 6 +- >> 14 files changed, 484 insertions(+), 99 deletions(-) >>=20 >> diff --git a/gdb/NEWS b/gdb/NEWS >> index c170385a50e..2a888d64e4d 100644 >> --- a/gdb/NEWS >> +++ b/gdb/NEWS >> @@ -17,6 +17,13 @@ >> 'thread' or 'task' keywords are parsed at the time the breakpoint is >> created, rather than at the time the breakpoint becomes non-pending. >>=20 >> +* 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. >> + >> * Changed commands >>=20 >> disassemble >> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c >> index 1c26ebf7b30..c88acdf4035 100644 >> --- a/gdb/ada-lang.c >> +++ b/gdb/ada-lang.c >> @@ -12010,11 +12010,11 @@ struct ada_catchpoint : public >> code_breakpoint >> enable_state =3D enabled ? bp_enabled : bp_disabled; >> language =3D language_ada; >>=20 >> - re_set (); >> + re_set (pspace); >> } >>=20 >> 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; >> @@ -12059,7 +12059,7 @@ static struct symtab_and_line ada_exception_sal >> catchpoint kinds. */ >>=20 >> void >> -ada_catchpoint::re_set () >> +ada_catchpoint::re_set (program_space *pspace) >> { >> std::vector sals; >> try >> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c >> index d053bd5fbe0..7191d1b38fa 100644 >> --- a/gdb/break-catch-throw.c >> +++ b/gdb/break-catch-throw.c >> @@ -82,10 +82,10 @@ struct exception_catchpoint : public code_breakpoint >> =09=09=09=09 _("invalid type-matching regexp"))) >> { >> pspace =3D current_program_space; >> - re_set (); >> + re_set (pspace); >> } >>=20 >> - 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; >> @@ -198,7 +198,7 @@ exception_catchpoint::check_status (struct bpstat >> *bs) >> /* Implement the 're_set' method. */ >>=20 >> void >> -exception_catchpoint::re_set () >> +exception_catchpoint::re_set (program_space *pspace) >> { >> std::vector sals; >> struct program_space *filter_pspace =3D current_program_space; >> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c >> index e1efde66feb..a190f2a78bf 100644 >> --- a/gdb/breakpoint.c >> +++ b/gdb/breakpoint.c >> @@ -91,9 +91,12 @@ >> static void map_breakpoint_numbers (const char *, >> =09=09=09=09 gdb::function_view); >>=20 >> -static void >> - create_sals_from_location_spec_default (location_spec *locspec, >> -=09=09=09=09=09 linespec_result *canonical); >> +static void parse_breakpoint_sals (location_spec *locspec, >> +=09=09=09=09 linespec_result *canonical, >> +=09=09=09=09 program_space *search_pspace); >> + >> +static void breakpoint_re_set_one (breakpoint *b, >> +=09=09=09=09 program_space *filter_pspace); >>=20 >> static void create_breakpoints_sal (struct gdbarch *, >> =09=09=09=09 struct linespec_result *, >> @@ -283,11 +286,12 @@ static bool strace_marker_p (struct breakpoint *b)= ; >>=20 >> 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); >>=20 >> const struct breakpoint_ops code_breakpoint_ops =3D >> { >> - create_sals_from_location_spec_default, >> + parse_breakpoint_sals, >> create_breakpoints_sal, >> }; >>=20 >> @@ -352,7 +356,7 @@ struct internal_breakpoint : public code_breakpoint >> disposition =3D disp_donttouch; >> } >>=20 >> - 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 =3D=3D -1); >> } >>=20 >> - 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; >>=20 >> - void re_set () override; >> + void re_set (program_space *pspace) override; >> int breakpoint_hit (const struct bp_location *bl, >> =09=09 const address_space *aspace, >> =09=09 CORE_ADDR bp_addr, >> @@ -1549,7 +1553,36 @@ breakpoint_set_thread (struct breakpoint *b, int >> thread) >> int old_thread =3D b->thread; >> b->thread =3D thread; >> if (old_thread !=3D thread) >> - notify_breakpoint_modified (b); >> + { >> + /* If THREAD is in a different program_space than OLD_THREAD, or = the >> +=09 breakpoint has switched to or from being thread-specific, then we >> +=09 need to re-set the locations of this breakpoint. First, figure >> +=09 out the program_space for the old and new threads, use a value of >> +=09 nullptr to indicate the breakpoint is in all program spaces. */ >> + program_space *old_pspace =3D nullptr; >> + if (old_thread !=3D -1) >> +=09{ >> +=09 struct thread_info *thr =3D find_thread_global_id (old_thread); >> +=09 gdb_assert (thr !=3D nullptr); >> +=09 old_pspace =3D thr->inf->pspace; >> +=09} >> + >> + program_space *new_pspace =3D nullptr; >> + if (thread !=3D -1) >> +=09{ >> +=09 struct thread_info *thr =3D find_thread_global_id (thread); >> +=09 gdb_assert (thr !=3D nullptr); >> +=09 new_pspace =3D thr->inf->pspace; >> +=09} >> + >> + /* If the program space has changed for this breakpoint, then >> +=09 re-evaluate it's locations. */ >> + if (old_pspace !=3D new_pspace) >> +=09breakpoint_re_set_one (b, new_pspace); >> + >> + /* Let others know the breakpoint has changed. */ >> + notify_breakpoint_modified (b); >> + } >> } >>=20 >> /* See breakpoint.h. */ >> @@ -1568,7 +1601,34 @@ breakpoint_set_inferior (struct breakpoint *b, in= t >> inferior) >> int old_inferior =3D b->inferior; >> b->inferior =3D inferior; >> if (old_inferior !=3D inferior) >> - notify_breakpoint_modified (b); >> + { >> + /* If INFERIOR is in a different program_space than OLD_INFERIOR,= or >> +=09 the breakpoint has switch to or from inferior-specific, then we >> +=09 need to re-set the locations of this breakpoint. First, figure >> +=09 out the program_space for the old and new inferiors, use a value >> +=09 of nullptr to indicate the breakpoint is in all program >> +=09 spaces. */ >> + program_space *old_pspace =3D nullptr; >> + if (old_inferior !=3D -1) >> +=09{ >> +=09 struct inferior *inf =3D find_inferior_id (old_inferior); >> +=09 gdb_assert (inf !=3D nullptr); >> +=09 old_pspace =3D inf->pspace; >> +=09} >> + >> + program_space *new_pspace =3D nullptr; >> + if (inferior !=3D -1) >> +=09{ >> +=09 struct inferior *inf =3D find_inferior_id (inferior); >> +=09 gdb_assert (inf !=3D nullptr); >> +=09 new_pspace =3D inf->pspace; >> +=09} >> + >> + if (old_pspace !=3D new_pspace) >> +=09breakpoint_re_set_one (b, new_pspace); >> + >> + notify_breakpoint_modified (b); >> + } >> } >>=20 >> /* See breakpoint.h. */ >> @@ -8799,7 +8859,8 @@ create_breakpoints_sal (struct gdbarch *gdbarch, >>=20 >> static void >> parse_breakpoint_sals (location_spec *locspec, >> -=09=09 struct linespec_result *canonical) >> +=09=09 struct linespec_result *canonical, >> +=09=09 struct program_space *search_pspace) >> { >> struct symtab_and_line cursal; >>=20 >> @@ -8864,7 +8925,7 @@ parse_breakpoint_sals (location_spec *locspec, >> =09 && strchr ("+-", spec[0]) !=3D NULL >> =09 && spec[1] !=3D '[')) >> =09{ >> -=09 decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, NULL, >> +=09 decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, >> search_pspace, >> =09=09=09 get_last_displayed_symtab (), >> =09=09=09 get_last_displayed_line (), >> =09=09=09 canonical, NULL, NULL); >> @@ -8872,7 +8933,7 @@ parse_breakpoint_sals (location_spec *locspec, >> =09} >> } >>=20 >> - decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, NULL, >> + decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, search_pspace, >> =09=09 cursal.symtab, cursal.line, canonical, NULL, NULL); >> } >>=20 >> @@ -8971,6 +9032,39 @@ breakpoint_ops_for_location_spec_type (enum >> location_spec_type locspec_type, >> } >> } >>=20 >> +/* Return the program space to use as a filter when searching for locat= ions >> + of a breakpoint specific to THREAD or INFERIOR. If THREAD and INFER= IOR >> + are both -1, meaning all threads/inferiors, then this function retur= ns >> + 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 !=3D -1) >> + { >> + gdb_assert (inferior =3D=3D -1); >> + >> + struct thread_info *thr =3D find_thread_global_id (thread); >> + gdb_assert (thr !=3D nullptr); >> + gdb_assert (thr->inf !=3D nullptr); >> + return thr->inf->pspace; >> + } >> + else if (inferior !=3D -1) >> + { >> + gdb_assert (thread =3D=3D -1); >> + >> + struct inferior *inf =3D find_inferior_id (inferior); >> + gdb_assert (inf !=3D nullptr); >> + >> + return inf->pspace; >> + } >> + >> + return nullptr; >> +} >> + >> /* See breakpoint.h. */ >>=20 >> const struct breakpoint_ops * >> @@ -9072,7 +9166,10 @@ create_breakpoint (struct gdbarch *gdbarch, >>=20 >> try >> { >> - ops->create_sals_from_location_spec (locspec, &canonical); >> + struct program_space *search_pspace >> +=09=3D find_program_space_for_breakpoint (thread, inferior); >> + ops->create_sals_from_location_spec (locspec, &canonical, >> +=09=09=09=09=09 search_pspace); >> } >> catch (const gdb_exception_error &e) >> { >> @@ -9545,7 +9642,7 @@ break_range_command (const char *arg, int >> from_tty) >> arg_start =3D arg; >> location_spec_up start_locspec >> =3D string_to_location_spec (&arg, current_language); >> - parse_breakpoint_sals (start_locspec.get (), &canonical_start); >> + parse_breakpoint_sals (start_locspec.get (), &canonical_start, nullpt= r); >>=20 >> if (arg[0] !=3D ',') >> error (_("Too few arguments.")); >> @@ -9646,7 +9743,7 @@ watchpoint_exp_is_const (const struct expression >> *exp) >> /* Implement the "re_set" method for watchpoints. */ >>=20 >> 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. >> @@ -11757,7 +11854,7 @@ breakpoint::print_recreate (struct ui_file *fp) >> const >> /* Default breakpoint_ops methods. */ >>=20 >> 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)) >> @@ -11767,7 +11864,7 @@ code_breakpoint::re_set () >> return; >> } >>=20 >> - re_set_default (); >> + re_set_default (pspace); >> } >>=20 >> int >> @@ -11973,7 +12070,7 @@ code_breakpoint::decode_location_spec >> (location_spec *locspec, >> /* Virtual table for internal breakpoints. */ >>=20 >> void >> -internal_breakpoint::re_set () >> +internal_breakpoint::re_set (struct program_space *pspace) >> { >> switch (type) >> { >> @@ -12066,7 +12163,7 @@ internal_breakpoint::print_mention () const >> /* Virtual table for momentary breakpoints */ >>=20 >> 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. >> @@ -12107,12 +12204,13 @@ longjmp_breakpoint::~longjmp_breakpoint () >>=20 >> static void >> bkpt_probe_create_sals_from_location_spec (location_spec *locspec, >> -=09=09=09=09=09 struct linespec_result *canonical) >> +=09=09=09=09=09 struct linespec_result *canonical, >> +=09=09=09=09=09 struct program_space >> *search_pspace) >>=20 >> { >> struct linespec_sals lsal; >>=20 >> - lsal.sals =3D parse_probes (locspec, NULL, canonical); >> + lsal.sals =3D parse_probes (locspec, search_pspace, canonical); >> lsal.canonical =3D xstrdup (canonical->locspec->to_string ()); >> canonical->lsals.push_back (std::move (lsal)); >> } >> @@ -12202,9 +12300,9 @@ tracepoint::print_recreate (struct ui_file *fp) >> const >> } >>=20 >> void >> -dprintf_breakpoint::re_set () >> +dprintf_breakpoint::re_set (struct program_space *pspace) >> { >> - re_set_default (); >> + re_set_default (pspace); >>=20 >> /* 1 - connect to target 1, that can run breakpoint commands. >> 2 - create a dprintf, which resolves fine. >> @@ -12258,8 +12356,10 @@ dprintf_breakpoint::after_condition_true >> (struct bpstat *bs) >> markers (`-m'). */ >>=20 >> static void >> -strace_marker_create_sals_from_location_spec (location_spec *locspec, >> -=09=09=09=09=09 struct linespec_result *canonical) >> +strace_marker_create_sals_from_location_spec >> +=09(location_spec *locspec, >> +=09 struct linespec_result *canonical, >> +=09 struct program_space *search_pspace) >> { >> struct linespec_sals lsal; >> const char *arg_start, *arg; >> @@ -12776,12 +12876,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 thr= ead >> + is changed to a different program space, and all of the old locati= ons >> + go out of scope. In this case we do (currently) discard the old >> + locations -- we assume the change in thread is permanent and the o= ld >> + locations will never come back into scope. */ >> if (all_locations_are_pending (b, filter_pspace) && sals.empty ()) >> - return; >> + { >> + if (b->thread !=3D -1) >> +=09b->clear_locations (); >> + return; >> + } >>=20 >> bp_location_list existing_locations =3D b->steal_locations (filter_ps= pace); >>=20 >> + /* 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 threa= d 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 !=3D -1) >> + b->clear_locations (); >> + >> for (const auto &sal : sals) >> { >> struct bp_location *new_loc; >> @@ -12947,40 +13067,45 @@ code_breakpoint::location_spec_to_sals >> (location_spec *locspec, >> locations. */ >>=20 >> void >> -code_breakpoint::re_set_default () >> +code_breakpoint::re_set_default (struct program_space *filter_pspace) >> { >> - struct program_space *filter_pspace =3D current_program_space; >> std::vector expanded, expanded_end; >>=20 >> - int found; >> - std::vector sals =3D location_spec_to_sals (locspec.= get (), >> -=09=09=09=09=09=09=09 filter_pspace, >> -=09=09=09=09=09=09=09 &found); >> - if (found) >> - expanded =3D std::move (sals); >> - >> - if (locspec_range_end !=3D nullptr) >> - { >> - std::vector sals_end >> -=09=3D location_spec_to_sals (locspec_range_end.get (), >> -=09=09=09=09 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 >> + =3D 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 inferio= r is >> + running, then look for new locations for this breakpoint. */ >> + if (bp_pspace =3D=3D nullptr || filter_pspace =3D=3D bp_pspace) >> + { >> + int found; >> + std::vector sals >> +=09=3D location_spec_to_sals (locspec.get (), filter_pspace, &found); >> if (found) >> -=09expanded_end =3D std::move (sals_end); >> +=09expanded =3D std::move (sals); >> + >> + if (locspec_range_end !=3D nullptr) >> +=09{ >> +=09 std::vector sals_end >> +=09 =3D location_spec_to_sals (locspec_range_end.get (), >> +=09=09=09=09 filter_pspace, &found); >> +=09 if (found) >> +=09 expanded_end =3D std::move (sals_end); >> +=09} >> } >>=20 >> + /* Update the locations for this breakpoint. For thread-specific >> + breakpoints this will remove any old locations that are for the wr= ong >> + 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); >> } >>=20 >> -/* Default method for creating SALs from an address string. It basical= ly >> - calls parse_breakpoint_sals. Return 1 for success, zero for failure= . */ >> - >> -static void >> -create_sals_from_location_spec_default (location_spec *locspec, >> -=09=09=09=09=09struct 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. */ >>=20 >> @@ -13015,7 +13140,7 @@ breakpoint_re_set (void) >> =09 { >> =09 input_radix =3D b.input_radix; >> =09 set_language (b.language); >> -=09 b.re_set (); >> +=09 b.re_set (current_program_space); >> =09 } >> =09catch (const gdb_exception &ex) >> =09 { >> @@ -13036,6 +13161,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_PSPAC= E is >> + nullptr then re-set locations for B in all program spaces. Location= s >> + 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 =3D make_scoped_restore (&input_rad= ix); >> + 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, o= r >> + 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 =3D make_scoped_restore >> (&language_mode); >> + language_mode =3D 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 >> + { >> +=09input_radix =3D b->input_radix; >> +=09set_language (b->language); >> +=09b->re_set (filter_pspace); >> + } >> + catch (const gdb_exception &ex) >> + { >> +=09exception_fprintf (gdb_stderr, ex, >> +=09=09=09 "Error in re-setting breakpoint %d: ", >> +=09=09=09 b->number); >> + } >> + } >> + >> + /* Now we can insert. */ >> + update_global_location_list (UGLL_MAY_INSERT); >> +} >>=20 >>=20 >>=20 >> /* Reset the thread number of this breakpoint: >>=20 >> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h >> index 42b49144e79..dea55deb314 100644 >> --- a/gdb/breakpoint.h >> +++ b/gdb/breakpoint.h >> @@ -570,15 +570,15 @@ enum print_stop_action >>=20 >> 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 t= he >> + corresponding program space are returned. If SEARCH_PSPACE is nul= lptr >> + then results for all program spaces are returned. >>=20 >> This function is called inside `create_breakpoint'. */ >> void (*create_sals_from_location_spec) (location_spec *locspec, >> -=09=09=09=09=09 struct linespec_result *canonical); >> +=09=09=09=09=09 linespec_result *canonical, >> +=09=09=09=09=09 program_space *search_pspace); >>=20 >> /* This method will be responsible for creating a breakpoint given it= s SALs. >> Usually, it just calls `create_breakpoints_sal' (for ordinary >> @@ -710,8 +710,15 @@ struct breakpoint : public >> intrusive_list_node >>=20 >> /* Reevaluate a breakpoint. This is necessary after symbols change >> (e.g., an executable or DSO was loaded, or the inferior just >> - started). */ >> - virtual void re_set () >> + 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 chang= ed, >> + new locations need to be searched for in every program space. */ >> + virtual void re_set (program_space *filter_pspace) >> { >> /* Nothing to re-set. */ >> } >> @@ -955,7 +962,7 @@ struct code_breakpoint : public breakpoint >> /* Add a location for SAL to this breakpoint. */ >> bp_location *add_location (const symtab_and_line &sal); >>=20 >> - void re_set () override; >> + void re_set (program_space *pspace) override; >> int insert_location (struct bp_location *) override; >> int remove_location (struct bp_location *, >> =09=09 enum remove_bp_reason reason) override; >> @@ -977,7 +984,7 @@ struct code_breakpoint : public breakpoint >> struct program_space *search_pspace); >>=20 >> /* Helper method that does the basic work of re_set. */ >> - void re_set_default (); >> + void re_set_default (program_space *pspace); >>=20 >> /* Find the SaL locations corresponding to the given LOCATION. >> On return, FOUND will be 1 if any SaL was found, zero otherwise. = */ >> @@ -999,7 +1006,7 @@ struct watchpoint : public breakpoint >> { >> using breakpoint::breakpoint; >>=20 >> - void re_set () override; >> + void re_set (program_space *pspace) override; >> int insert_location (struct bp_location *) override; >> int remove_location (struct bp_location *, >> =09=09 enum remove_bp_reason reason) override; >> diff --git a/gdb/testsuite/gdb.mi/new-ui-bp-deleted.exp >> b/gdb/testsuite/gdb.mi/new-ui-bp-deleted.exp >> index f736994d234..938e6deec05 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"] >>=20 >> # Create the inferior-specific breakpoint. >> - mi_create_breakpoint_multi "-g i2 foo" "create breakpoint in inferi= or 2" \ >> -=09-inferior "2" -locations "\\\[$loc1,$loc2\\\]" >> + mi_create_breakpoint "-g i2 foo" "create breakpoint in inferior 2" = \ >> +=09-number "$decimal" \ >> +=09-type "breakpoint" \ >> +=09-enabled "y" \ >> +=09-func "foo" \ >> +=09-inferior "2" >> set bpnum [mi_get_valueof "/d" "\$bpnum" "INVALID"] >>=20 >> 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 93b91b42f92..ed331aff873 100644 >> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp >> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp >> @@ -370,7 +370,7 @@ proc test_continue_to_start { mode inf } { >> =09=09=09 "thread $inf.2 stops MI" >> =09=09 } else { >> =09=09=09mi_expect_stop "breakpoint-hit" >> "child_sub_function" \ >> -=09=09=09 "" "$srcfile" "$decimal" {"" "disp=3D\"del\"" >> "locno=3D\"[0-9]+\""} \ >> +=09=09=09 "" "$srcfile" "$decimal" {"" "disp=3D\"del\""} \ >> =09=09=09 "thread $inf.2 stops MI" >> =09=09 } > > Hi Andrew, > > For what it is worth: At some point I had backported your v8 on the > gdb 14 branch to play around with it and see if it fixes a downstream > problem I had. It didn't, but I tested your v8 a bit and didn't find any > issues with it on gdb 14. If your downstream issue is in the same area, do you think this indicates an oversight / issue with this series as it currently stands? You say downstream issue, so I guess it doesn't impact upstream GDB. So there's likely no easy way I could investigate to see if this series could be made to help you? > While doing that I saw that we probably can just get rid of the > if else in this testcase here now. Sorry for not commenting this > earlier. Good catch. The updated patch is below. Thanks, Andrew --- commit 81af4bd48799027180954a1ff9483b8c9aa77023 Author: Andrew Burgess Date: Fri Mar 3 19:03:15 2023 +0000 gdb: only insert thread-specific breakpoints in the relevant inferior =20 This commit updates GDB so that thread or inferior specific breakpoints are only inserted into the program space in which the specific thread or inferior is running. =20 In terms of implementation, getting this basically working is easy enough, now that a breakpoint's thread or inferior field is setup prior to GDB looking for locations, we can easily use this information to find a suitable program_space and pass this to as a filter when creating the sals. =20 Or we could if breakpoint_ops::create_sals_from_location_spec allowed us to pass in a filter program_space. =20 So, this commit extends breakpoint_ops::create_sals_from_location_spec to take a program_space argument, and uses this to filter the set of returned sals. This accounts for about half the change in this patch. =20 The second set of changes starts from breakpoint_set_thread and breakpoint_set_inferior, this is called when the thread or inferior for a breakpoint changes, e.g. from the Python API. =20 Previously this call would never result in the locations of a breakpoint changing, after all, locations were inserted in every program space, and we just use the thread or inferior variable to decide when we should stop. Now though, changing a breakpoint's thread or inferior can mean we need to figure out a new set of breakpoint locations. =20 To support this I've added a new breakpoint_re_set_one function, which is like breakpoint_re_set, but takes a single breakpoint, and just updates the locations for that one breakpoint. We only need to call this function if the program_space in which a breakpoint's thread (or inferior) is running actually changes. If the program_space does change then we call the new breakpoint_re_set_one function passing in the program_space which should be used to filter the new locations (or nullptr to indicate we should set locations in all program spaces). This filter program_space needs to propagate down to all the re_set methods, this accounts for the remaining half of the changes in this patch. =20 There were a couple of existing tests that created thread or inferior specific breakpoints and then checked the 'info breakpoints' output, these needed updating. These were: =20 gdb.mi/user-selected-context-sync.exp gdb.multi/bp-thread-specific.exp gdb.multi/multi-target-continue.exp gdb.multi/multi-target-ping-pong-next.exp gdb.multi/tids.exp gdb.mi/new-ui-bp-deleted.exp gdb.multi/inferior-specific-bp.exp gdb.multi/pending-bp-del-inferior.exp =20 I've also added some additional tests to: =20 gdb.multi/pending-bp.exp =20 I've updated the documentation and added a NEWS entry. =20 Reviewed-By: Eli Zaretskii diff --git a/gdb/NEWS b/gdb/NEWS index c170385a50e..2a888d64e4d 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -17,6 +17,13 @@ 'thread' or 'task' keywords are parsed at the time the breakpoint is created, rather than at the time the breakpoint becomes non-pending. =20 +* 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. + * Changed commands =20 disassemble diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 1c26ebf7b30..c88acdf4035 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -12010,11 +12010,11 @@ struct ada_catchpoint : public code_breakpoint enable_state =3D enabled ? bp_enabled : bp_disabled; language =3D language_ada; =20 - re_set (); + re_set (pspace); } =20 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; @@ -12059,7 +12059,7 @@ static struct symtab_and_line ada_exception_sal catchpoint kinds. */ =20 void -ada_catchpoint::re_set () +ada_catchpoint::re_set (program_space *pspace) { std::vector sals; try diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c index d053bd5fbe0..7191d1b38fa 100644 --- a/gdb/break-catch-throw.c +++ b/gdb/break-catch-throw.c @@ -82,10 +82,10 @@ struct exception_catchpoint : public code_breakpoint =09=09=09=09 _("invalid type-matching regexp"))) { pspace =3D current_program_space; - re_set (); + re_set (pspace); } =20 - 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; @@ -198,7 +198,7 @@ exception_catchpoint::check_status (struct bpstat *bs) /* Implement the 're_set' method. */ =20 void -exception_catchpoint::re_set () +exception_catchpoint::re_set (program_space *pspace) { std::vector sals; struct program_space *filter_pspace =3D current_program_space; diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index e1efde66feb..a190f2a78bf 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -91,9 +91,12 @@ static void map_breakpoint_numbers (const char *, =09=09=09=09 gdb::function_view); =20 -static void - create_sals_from_location_spec_default (location_spec *locspec, -=09=09=09=09=09 linespec_result *canonical); +static void parse_breakpoint_sals (location_spec *locspec, +=09=09=09=09 linespec_result *canonical, +=09=09=09=09 program_space *search_pspace); + +static void breakpoint_re_set_one (breakpoint *b, +=09=09=09=09 program_space *filter_pspace); =20 static void create_breakpoints_sal (struct gdbarch *, =09=09=09=09 struct linespec_result *, @@ -283,11 +286,12 @@ static bool strace_marker_p (struct breakpoint *b); =20 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); =20 const struct breakpoint_ops code_breakpoint_ops =3D { - create_sals_from_location_spec_default, + parse_breakpoint_sals, create_breakpoints_sal, }; =20 @@ -352,7 +356,7 @@ struct internal_breakpoint : public code_breakpoint disposition =3D disp_donttouch; } =20 - 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 =3D=3D -1); } =20 - 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; =20 - void re_set () override; + void re_set (program_space *pspace) override; int breakpoint_hit (const struct bp_location *bl, =09=09 const address_space *aspace, =09=09 CORE_ADDR bp_addr, @@ -1549,7 +1553,36 @@ breakpoint_set_thread (struct breakpoint *b, int thr= ead) int old_thread =3D b->thread; b->thread =3D thread; if (old_thread !=3D thread) - notify_breakpoint_modified (b); + { + /* If THREAD is in a different program_space than OLD_THREAD, or the +=09 breakpoint has switched to or from being thread-specific, then we +=09 need to re-set the locations of this breakpoint. First, figure +=09 out the program_space for the old and new threads, use a value of +=09 nullptr to indicate the breakpoint is in all program spaces. */ + program_space *old_pspace =3D nullptr; + if (old_thread !=3D -1) +=09{ +=09 struct thread_info *thr =3D find_thread_global_id (old_thread); +=09 gdb_assert (thr !=3D nullptr); +=09 old_pspace =3D thr->inf->pspace; +=09} + + program_space *new_pspace =3D nullptr; + if (thread !=3D -1) +=09{ +=09 struct thread_info *thr =3D find_thread_global_id (thread); +=09 gdb_assert (thr !=3D nullptr); +=09 new_pspace =3D thr->inf->pspace; +=09} + + /* If the program space has changed for this breakpoint, then +=09 re-evaluate it's locations. */ + if (old_pspace !=3D new_pspace) +=09breakpoint_re_set_one (b, new_pspace); + + /* Let others know the breakpoint has changed. */ + notify_breakpoint_modified (b); + } } =20 /* See breakpoint.h. */ @@ -1568,7 +1601,34 @@ breakpoint_set_inferior (struct breakpoint *b, int i= nferior) int old_inferior =3D b->inferior; b->inferior =3D inferior; if (old_inferior !=3D inferior) - notify_breakpoint_modified (b); + { + /* If INFERIOR is in a different program_space than OLD_INFERIOR, or +=09 the breakpoint has switch to or from inferior-specific, then we +=09 need to re-set the locations of this breakpoint. First, figure +=09 out the program_space for the old and new inferiors, use a value +=09 of nullptr to indicate the breakpoint is in all program +=09 spaces. */ + program_space *old_pspace =3D nullptr; + if (old_inferior !=3D -1) +=09{ +=09 struct inferior *inf =3D find_inferior_id (old_inferior); +=09 gdb_assert (inf !=3D nullptr); +=09 old_pspace =3D inf->pspace; +=09} + + program_space *new_pspace =3D nullptr; + if (inferior !=3D -1) +=09{ +=09 struct inferior *inf =3D find_inferior_id (inferior); +=09 gdb_assert (inf !=3D nullptr); +=09 new_pspace =3D inf->pspace; +=09} + + if (old_pspace !=3D new_pspace) +=09breakpoint_re_set_one (b, new_pspace); + + notify_breakpoint_modified (b); + } } =20 /* See breakpoint.h. */ @@ -8799,7 +8859,8 @@ create_breakpoints_sal (struct gdbarch *gdbarch, =20 static void parse_breakpoint_sals (location_spec *locspec, -=09=09 struct linespec_result *canonical) +=09=09 struct linespec_result *canonical, +=09=09 struct program_space *search_pspace) { struct symtab_and_line cursal; =20 @@ -8864,7 +8925,7 @@ parse_breakpoint_sals (location_spec *locspec, =09 && strchr ("+-", spec[0]) !=3D NULL =09 && spec[1] !=3D '[')) =09{ -=09 decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, NULL, +=09 decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, search_pspace, =09=09=09 get_last_displayed_symtab (), =09=09=09 get_last_displayed_line (), =09=09=09 canonical, NULL, NULL); @@ -8872,7 +8933,7 @@ parse_breakpoint_sals (location_spec *locspec, =09} } =20 - decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, NULL, + decode_line_full (locspec, DECODE_LINE_FUNFIRSTLINE, search_pspace, =09=09 cursal.symtab, cursal.line, canonical, NULL, NULL); } =20 @@ -8971,6 +9032,39 @@ breakpoint_ops_for_location_spec_type (enum location= _spec_type locspec_type, } } =20 +/* Return the program space to use as a filter when searching for location= s + 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 tha= t + 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 !=3D -1) + { + gdb_assert (inferior =3D=3D -1); + + struct thread_info *thr =3D find_thread_global_id (thread); + gdb_assert (thr !=3D nullptr); + gdb_assert (thr->inf !=3D nullptr); + return thr->inf->pspace; + } + else if (inferior !=3D -1) + { + gdb_assert (thread =3D=3D -1); + + struct inferior *inf =3D find_inferior_id (inferior); + gdb_assert (inf !=3D nullptr); + + return inf->pspace; + } + + return nullptr; +} + /* See breakpoint.h. */ =20 const struct breakpoint_ops * @@ -9072,7 +9166,10 @@ create_breakpoint (struct gdbarch *gdbarch, =20 try { - ops->create_sals_from_location_spec (locspec, &canonical); + struct program_space *search_pspace +=09=3D find_program_space_for_breakpoint (thread, inferior); + ops->create_sals_from_location_spec (locspec, &canonical, +=09=09=09=09=09 search_pspace); } catch (const gdb_exception_error &e) { @@ -9545,7 +9642,7 @@ break_range_command (const char *arg, int from_tty) arg_start =3D arg; location_spec_up start_locspec =3D string_to_location_spec (&arg, current_language); - parse_breakpoint_sals (start_locspec.get (), &canonical_start); + parse_breakpoint_sals (start_locspec.get (), &canonical_start, nullptr); =20 if (arg[0] !=3D ',') error (_("Too few arguments.")); @@ -9646,7 +9743,7 @@ watchpoint_exp_is_const (const struct expression *exp= ) /* Implement the "re_set" method for watchpoints. */ =20 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. @@ -11757,7 +11854,7 @@ breakpoint::print_recreate (struct ui_file *fp) con= st /* Default breakpoint_ops methods. */ =20 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)) @@ -11767,7 +11864,7 @@ code_breakpoint::re_set () return; } =20 - re_set_default (); + re_set_default (pspace); } =20 int @@ -11973,7 +12070,7 @@ code_breakpoint::decode_location_spec (location_spe= c *locspec, /* Virtual table for internal breakpoints. */ =20 void -internal_breakpoint::re_set () +internal_breakpoint::re_set (struct program_space *pspace) { switch (type) { @@ -12066,7 +12163,7 @@ internal_breakpoint::print_mention () const /* Virtual table for momentary breakpoints */ =20 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. @@ -12107,12 +12204,13 @@ longjmp_breakpoint::~longjmp_breakpoint () =20 static void bkpt_probe_create_sals_from_location_spec (location_spec *locspec, -=09=09=09=09=09 struct linespec_result *canonical) +=09=09=09=09=09 struct linespec_result *canonical, +=09=09=09=09=09 struct program_space *search_pspace) =20 { struct linespec_sals lsal; =20 - lsal.sals =3D parse_probes (locspec, NULL, canonical); + lsal.sals =3D parse_probes (locspec, search_pspace, canonical); lsal.canonical =3D xstrdup (canonical->locspec->to_string ()); canonical->lsals.push_back (std::move (lsal)); } @@ -12202,9 +12300,9 @@ tracepoint::print_recreate (struct ui_file *fp) con= st } =20 void -dprintf_breakpoint::re_set () +dprintf_breakpoint::re_set (struct program_space *pspace) { - re_set_default (); + re_set_default (pspace); =20 /* 1 - connect to target 1, that can run breakpoint commands. 2 - create a dprintf, which resolves fine. @@ -12258,8 +12356,10 @@ dprintf_breakpoint::after_condition_true (struct b= pstat *bs) markers (`-m'). */ =20 static void -strace_marker_create_sals_from_location_spec (location_spec *locspec, -=09=09=09=09=09 struct linespec_result *canonical) +strace_marker_create_sals_from_location_spec +=09(location_spec *locspec, +=09 struct linespec_result *canonical, +=09 struct program_space *search_pspace) { struct linespec_sals lsal; const char *arg_start, *arg; @@ -12776,12 +12876,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 !=3D -1) +=09b->clear_locations (); + return; + } =20 bp_location_list existing_locations =3D b->steal_locations (filter_pspac= e); =20 + /* If this is a thread-specific breakpoint then any locations left on th= e + breakpoint are for a program space in which the thread of interest + does not operate. This can happen when the user changes the thread o= f + 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 !=3D -1) + b->clear_locations (); + for (const auto &sal : sals) { struct bp_location *new_loc; @@ -12947,40 +13067,45 @@ code_breakpoint::location_spec_to_sals (location_= spec *locspec, locations. */ =20 void -code_breakpoint::re_set_default () +code_breakpoint::re_set_default (struct program_space *filter_pspace) { - struct program_space *filter_pspace =3D current_program_space; std::vector expanded, expanded_end; =20 - int found; - std::vector sals =3D location_spec_to_sals (locspec.get= (), -=09=09=09=09=09=09=09 filter_pspace, -=09=09=09=09=09=09=09 &found); - if (found) - expanded =3D std::move (sals); - - if (locspec_range_end !=3D nullptr) - { - std::vector sals_end -=09=3D location_spec_to_sals (locspec_range_end.get (), -=09=09=09=09 filter_pspace, &found); + /* If this breakpoint is thread-specific then find the program space in + which the specific thread exists. Otherwise, for breakpoints that ar= e + not thread-specific THREAD_PSPACE will be nullptr. */ + program_space *bp_pspace + =3D 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 i= s + running, then look for new locations for this breakpoint. */ + if (bp_pspace =3D=3D nullptr || filter_pspace =3D=3D bp_pspace) + { + int found; + std::vector sals +=09=3D location_spec_to_sals (locspec.get (), filter_pspace, &found); if (found) -=09expanded_end =3D std::move (sals_end); +=09expanded =3D std::move (sals); + + if (locspec_range_end !=3D nullptr) +=09{ +=09 std::vector sals_end +=09 =3D location_spec_to_sals (locspec_range_end.get (), +=09=09=09=09 filter_pspace, &found); +=09 if (found) +=09 expanded_end =3D std::move (sals_end); +=09} } =20 + /* 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= ); } =20 -/* 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, -=09=09=09=09=09struct 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. */ =20 @@ -13015,7 +13140,7 @@ breakpoint_re_set (void) =09 { =09 input_radix =3D b.input_radix; =09 set_language (b.language); -=09 b.re_set (); +=09 b.re_set (current_program_space); =09 } =09catch (const gdb_exception &ex) =09 { @@ -13036,6 +13161,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 i= s + 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 =3D 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 =3D make_scoped_restore (&language_m= ode); + language_mode =3D 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 + { +=09input_radix =3D b->input_radix; +=09set_language (b->language); +=09b->re_set (filter_pspace); + } + catch (const gdb_exception &ex) + { +=09exception_fprintf (gdb_stderr, ex, +=09=09=09 "Error in re-setting breakpoint %d: ", +=09=09=09 b->number); + } + } + + /* Now we can insert. */ + update_global_location_list (UGLL_MAY_INSERT); +} =0C /* Reset the thread number of this breakpoint: =20 diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 42b49144e79..dea55deb314 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -570,15 +570,15 @@ enum print_stop_action =20 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 nullpt= r + then results for all program spaces are returned. =20 This function is called inside `create_breakpoint'. */ void (*create_sals_from_location_spec) (location_spec *locspec, -=09=09=09=09=09 struct linespec_result *canonical); +=09=09=09=09=09 linespec_result *canonical, +=09=09=09=09=09 program_space *search_pspace); =20 /* This method will be responsible for creating a breakpoint given its S= ALs. Usually, it just calls `create_breakpoints_sal' (for ordinary @@ -710,8 +710,15 @@ struct breakpoint : public intrusive_list_node =20 /* Reevaluate a breakpoint. This is necessary after symbols change (e.g., an executable or DSO was loaded, or the inferior just - started). */ - virtual void re_set () + 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. */ + virtual void re_set (program_space *filter_pspace) { /* Nothing to re-set. */ } @@ -955,7 +962,7 @@ struct code_breakpoint : public breakpoint /* Add a location for SAL to this breakpoint. */ bp_location *add_location (const symtab_and_line &sal); =20 - void re_set () override; + void re_set (program_space *pspace) override; int insert_location (struct bp_location *) override; int remove_location (struct bp_location *, =09=09 enum remove_bp_reason reason) override; @@ -977,7 +984,7 @@ struct code_breakpoint : public breakpoint struct program_space *search_pspace); =20 /* Helper method that does the basic work of re_set. */ - void re_set_default (); + void re_set_default (program_space *pspace); =20 /* Find the SaL locations corresponding to the given LOCATION. On return, FOUND will be 1 if any SaL was found, zero otherwise. */ @@ -999,7 +1006,7 @@ struct watchpoint : public breakpoint { using breakpoint::breakpoint; =20 - void re_set () override; + void re_set (program_space *pspace) override; int insert_location (struct bp_location *) override; int remove_location (struct bp_location *, =09=09 enum remove_bp_reason reason) override; diff --git a/gdb/testsuite/gdb.mi/new-ui-bp-deleted.exp b/gdb/testsuite/gdb= .mi/new-ui-bp-deleted.exp index f736994d234..938e6deec05 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"] =20 # Create the inferior-specific breakpoint. - mi_create_breakpoint_multi "-g i2 foo" "create breakpoint in inferior = 2" \ -=09-inferior "2" -locations "\\\[$loc1,$loc2\\\]" + mi_create_breakpoint "-g i2 foo" "create breakpoint in inferior 2" \ +=09-number "$decimal" \ +=09-type "breakpoint" \ +=09-enabled "y" \ +=09-func "foo" \ +=09-inferior "2" set bpnum [mi_get_valueof "/d" "\$bpnum" "INVALID"] =20 if {$mode eq "separate"} { diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/test= suite/gdb.mi/user-selected-context-sync.exp index 93b91b42f92..e168a5eee45 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 } { =20 =09=09# Consume MI output. =09=09with_spawn_id $mi_spawn_id { -=09=09 if { $inf =3D=3D 1} { -=09=09=09mi_expect_stop "breakpoint-hit" "child_sub_function" \ -=09=09=09 "" "$srcfile" "$decimal" {"" "disp=3D\"del\""} \ -=09=09=09 "thread $inf.2 stops MI" -=09=09 } else { -=09=09=09mi_expect_stop "breakpoint-hit" "child_sub_function" \ -=09=09=09 "" "$srcfile" "$decimal" {"" "disp=3D\"del\"" "locno=3D\"[0-9= ]+\""} \ -=09=09=09 "thread $inf.2 stops MI" -=09=09 } +=09=09 mi_expect_stop "breakpoint-hit" "child_sub_function" \ +=09=09=09"" "$srcfile" "$decimal" {"" "disp=3D\"del\""} \ +=09=09=09"thread $inf.2 stops MI" =09=09} =09 } =09} @@ -439,7 +433,7 @@ proc_with_prefix test_setup { mode } { =20 =09with_spawn_id $mi_spawn_id { =09 mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \ -=09=09{"" "disp=3D\"del\"" "locno=3D\"[0-9]+\""} "main stop" +=09=09{"" "disp=3D\"del\""} "main stop" =09} =20 =09# Consume CLI output. diff --git a/gdb/testsuite/gdb.multi/bp-thread-specific.exp b/gdb/testsuite= /gdb.multi/bp-thread-specific.exp index 7635e84b913..c1d87521ee9 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\\= ." =20 set bpnum [get_integer_valueof "\$bpnum" "INVALID"] =20 @@ -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 \ -=09 "Note: breakpoint $bpnum \\(thread 2.1\\) also set at pc $hex\\." \ -=09 "Note: breakpoint $bpnum \\(thread 2.1\\) also set at pc $hex\\." \ -=09 "Breakpoint $decimal at $hex: foo\\. \\(2 locations\\)"] + "Breakpoint $decimal at $hex: file \[^\r\n\]+$srcfile, line $decimal\\= ." =20 # Save the breakpoints into a file. if {[is_remote host]} { diff --git a/gdb/testsuite/gdb.multi/inferior-specific-bp.exp b/gdb/testsui= te/gdb.multi/inferior-specific-bp.exp index 46efe6f54bc..52f84183589 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 expec= ted_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" \ =09=09 "get b/p number for inferior specific breakpoint"] =20 @@ -123,7 +115,7 @@ set location_count 0 set saw_inf_cond false =20 check_info_breakpoints "first check for inferior specific breakpoint" \ - $bp_number 3 + $bp_number 2 =20 # 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/testsu= ite/gdb.multi/multi-target-continue.exp index d2201061713..d4b2fc28133 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} { =20 proc set_break {inf} { =09gdb_test "break function${inf} thread ${inf}.1" \ -=09"Breakpoint .* function${inf}\\..*" +=09 "Breakpoint ${::decimal} at ${::hex}: file .*, line ${::decimal}\\.= " } =20 # 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 0aff708c0f3..36f9d24a917 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 .*" =20 gdb_test "break $srcfile:$line1 thread 1.1" \ -=09"Breakpoint .*$srcfile:$line1\\..*" +=09"Breakpoint .*$srcfile, line $line1\\." =20 gdb_test "continue" "hit Breakpoint .*" =20 gdb_test "break $srcfile:$line2 thread 2.1" \ -=09"Breakpoint .*$srcfile:$line2\\..*" +=09"Breakpoint .*$srcfile, line $line2\\." =20 # 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/test= suite/gdb.multi/pending-bp-del-inferior.exp index 5fcd1ef2e39..12c0a84bb02 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 { =09set bp_pattern_before \ =09 [multi_line \ -=09=09 "$bp_number\\s+breakpoint\\s+keep\\s+y\\s+\\s*" \ -=09=09 "\\s+stop only in [string_to_regexp $bp_restriction]" \ -=09=09 "$bp_number\\.1\\s+y\\s+$::hex in $bp_func at \[^\r\n\]+ inf 1" \ -=09=09 "$bp_number\\.2\\s+y\\s+$::hex in $bp_func at \[^\r\n\]+ inf 2"] +=09=09 "$bp_number\\s+breakpoint\\s+keep\\s+y\\s+$::hex in $bp_func at \[^= \r\n\]+ inf 1" \ +=09=09 "\\s+stop only in [string_to_regexp $bp_restriction]"] =20 =09set bp_pattern_after \ =09 [multi_line \ diff --git a/gdb/testsuite/gdb.multi/pending-bp.exp b/gdb/testsuite/gdb.mul= ti/pending-bp.exp index 478d8d7c037..aeb8c2c886e 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 } =20 +# 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" \ +=09[multi_line \ +=09 "Function \"foo\" not defined\\." \ +=09 "Breakpoint $::decimal \\(foo\\) pending\."] \ +=09"set pending thread-specific breakpoint" + set bpnum [get_integer_valueof "\$bpnum" "*INVALID*" \ +=09=09 "get number for thread-specific breakpoint on foo"] + gdb_test "info breakpoints $bpnum" \ +=09[multi_line \ +=09 "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+\\s+foo" \ +=09 "\\s+stop only in thread [string_to_regexp $thread]"] \ +=09"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" \ +=09"Breakpoint $::decimal at $::hex" \ +=09"set thread-specific breakpoint" + set bpnum [get_integer_valueof "\$bpnum" "*INVALID*" \ +=09=09 "get number for thread-specific breakpoint on foo"] + gdb_test "info breakpoints $bpnum" \ +=09[multi_line \ +=09 "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+$::hex\\s+\]*> inf $= ::decimal" \ +=09 "\\s+stop only in thread [string_to_regexp $thread]"] \ +=09"check thread-specific breakpoint is initially pending" + + return $bpnum +} + # Check that when a breakpoint is in the pending state, but that breakpoin= t # 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 {} { =09"check info breakpoints while breakpoint is pending" } =20 +# 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 .*" \ +=09"switch back to inferior 1" + gdb_continue_to_breakpoint "stop in foo in inferior 1" "foo \\(\\) .*" + + gdb_test "info breakpoint $bpnum" \ +=09[multi_line \ +=09 "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+$::hex \]*> inf 1" \ +=09 "\\s+stop only in thread 1\\.1" \ +=09 "\\s+breakpoint already hit 1 time"] \ +=09"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" \ +=09[multi_line \ +=09 "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+\\s+foo" \ +=09 "\\s+stop only in thread 1\\.1" \ +=09 "\\s+breakpoint already hit 1 time"] \ +=09"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 \ +=09"python ${var}=3D\[b for b in gdb.breakpoints() if b.number =3D=3D $bpn= um\]\[0\]" \ +=09"find Python gdb.Breakpoint object" + if { $thread ne "" } { +=09gdb_test_no_output "python assert(${var}.thread =3D=3D ${thread})" \ +=09 "check thread attribute is currently correct" + } else { +=09gdb_test_no_output "python assert(${var}.thread is None)" \ +=09 "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 =3D 2" \ +=09"change thread on thread-specific breakpoint" + gdb_test "info breakpoint $bpnum" \ +=09[multi_line \ +=09 "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+$::hex \]*> inf 2" \ +=09 "\\s+stop only in thread 2\\.1"] \ +=09"check thread-specific breakpoint now has a location" + + gdb_test_no_output "set call_count =3D 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 =3D 1" \ +=09"restore thread on thread-specific breakpoint" + gdb_test "info breakpoints $bpnum" \ +=09[multi_line \ +=09 "$bpnum\\s+breakpoint\\s+keep\\s+y\\s+\\s+foo" \ +=09 "\\s+stop only in thread 1\\.1" \ +=09 "\\s+breakpoint already hit 1 time"] \ +=09"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" \ +=09".* Break after close\\. .*" + + gdb_test "inferior 1" "Switching to inferior 1 .*" \ +=09"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 =3D None" \ +=09"clear thread on thread-specific breakpoint" + gdb_test "info breakpoints $bpnum" \ +=09[multi_line \ +=09 "${bpnum}\\s+breakpoint\\s+keep y\\s+\\s*" \ +=09 "${bpnum}\\.1\\s+y\\s+${::hex}\\s+\]*> inf $::decimal" \ +=09 "${bpnum}\\.2\\s+y\\s+${::hex}\\s+\]*> inf $::decimal"] \ +=09"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 =3D 2" "set call_count in inferior = 2" + + gdb_test "inferior 1" "Switching to inferior 1 .*" \ +=09"switch to inferior 1" + gdb_continue_to_breakpoint "stop at foo in inferior 1" "foo \\(\\) .*" + gdb_test_no_output "set call_count =3D 2" "set call_count in inferior = 1" + + gdb_test_no_output "python bp.thread =3D 2" + gdb_test "info breakpoints $bpnum" \ +=09[multi_line \ +=09 "${bpnum}\\s+breakpoint\\s+keep y\\s+${::hex}\\s+\]*> inf = 2" \ +=09 "\\s+stop only in thread 2\\.1" \ +=09 "\\s+breakpoint already hit 2 times"] \ +=09"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" \ +=09".* Break after close\\. .*" + + gdb_test "inferior 2" "Switching to inferior 2 .*" \ +=09"switch back to inferior 2" + gdb_continue_to_breakpoint "stop at foo again in inferior 2" \ +=09"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/tid= s.exp index 573b02fdd42..4f788844ee4 100644 --- a/gdb/testsuite/gdb.multi/tids.exp +++ b/gdb/testsuite/gdb.multi/tids.exp @@ -433,11 +433,13 @@ if { [allow_python_tests] } { =20 =09gdb_py_test_silent_cmd "python bp =3D gdb.breakpoints()\[0\]" \ =09 "get python breakpoint" 0 -=09gdb_test "python bp.thread =3D 6" "thread =3D 6" \ +=09gdb_test_no_output "python bp.thread =3D 6" \ =09 "make breakpoint thread-specific with python" =09# Check that the inferior-qualified ID is correct. =09gdb_test "info breakpoint" \ -=09 "stop only in thread 1.3\r\n.*" \ +=09 [multi_line \ +=09=09 "$decimal\\s+\[^\r\n\]+ in thread_function1 at \[^\r\n\]+" \ +=09=09 "\\s+stop only in thread 1\\.3"] \ =09 "thread specific breakpoint right thread" } }