From patchwork Mon Jun 1 19:22:47 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 136205 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EB5984BA5439 for ; Mon, 1 Jun 2026 19:24:32 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org EB5984BA5439 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=MiphIAWg X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 649AF4BA5439 for ; Mon, 1 Jun 2026 19:23:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 649AF4BA5439 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 649AF4BA5439 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780341826; cv=none; b=Y9jfYbKKcUbm2I0jNkPAh1Ay6CNcNY+mPI+p6gNxQjR2Lc/lu/eT5HM8S31jPuZfkSvw0CvulsHHzRNxmrNYBMh0zWSX0sykXhhDGP0YRH5Tho1TrM94dYIKLST57SdQFJdbLFvYr5yQFhpr3z22byCJe+gtgznteUN8jY97I6c= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780341826; c=relaxed/simple; bh=fVrNQcpKV4r22zO/Xcl+RiUwxd5pdz8na7aLHUYZIMA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=eMp3U7mze5ArHo8tOVCRdMtbeCMnT3RW92p0Pnszv6iMhl45+1+vMkxDynUmJs3N5FA58aVeKHoQyP13aYuFvqPYJiEhBH2dki4g62q9MbEzOI1LcA25WoIzHCfAlyWCVQpQACgWxNnX9ogoCbSayEoEG9Q7Bp23GHVjcCplWHQ= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=MiphIAWg DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 649AF4BA5439 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780341826; 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=SNiROKT3ghO6+prBK44NVFHPCj0Jum6SS2ox7Xpn13Y=; b=MiphIAWg4Qvl+LW2tnWriE4alqg/s6bQR1503d2pdrACJia6VPfh3cXU1HnhMpnutSsF7+ HHm6lNukTRh5rBGjd5nx6Mx+9Wj0IN/cykOc0qTfni6cFBQmiGaY+dlxDmb2O2pHwCXpKg +Vv6qMtEngiRTDrZKlEZllP46GStoR4= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-13-98k5RVW3NyuJkzYIM76CmQ-1; Mon, 01 Jun 2026 15:23:45 -0400 X-MC-Unique: 98k5RVW3NyuJkzYIM76CmQ-1 X-Mimecast-MFC-AGG-ID: 98k5RVW3NyuJkzYIM76CmQ_1780341824 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 941D31955E8D for ; Mon, 1 Jun 2026 19:23:36 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.144]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id E58FD19560A7; Mon, 1 Jun 2026 19:23:34 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH v7 1/5] gdb: Create helper function for the current namespace Date: Mon, 1 Jun 2026 16:22:47 -0300 Message-ID: <20260601192251.60958-2-guinevere@redhat.com> In-Reply-To: <20260601192251.60958-1-guinevere@redhat.com> References: <20260601192251.60958-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: ca-rdlhbxIJSApNCCWlIimXQ_kGiFT7XpWaH3XoO2fw_1780341824 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-10.1 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_BLOCKED, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org More code is needing to access the linker namespace of the selected frame, so it makes sense to create a helper function that calculates the current namespace, and make the internalvar use that helper instead. This commit introduces this helper function. --- gdb/solib.c | 26 +++++++++++++++++--------- gdb/solib.h | 4 ++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/gdb/solib.c b/gdb/solib.c index d92d0dd9a3d..dbb69ef7678 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -1793,15 +1793,10 @@ solib_linker_namespace_count (program_space *pspace) return 0; } -/* Implementation of the linker_namespace convenience variable. - - This returns the GDB internal identifier of the linker namespace, - for the selected frame, as an integer. If the inferior doesn't support - linker namespaces, this always returns 0. */ +/* See solib.h. */ -static value * -linker_namespace_make_value (gdbarch *gdbarch, internalvar *var, - void *ignore) +int +get_current_linker_namespace () { int nsid = 0; CORE_ADDR curr_pc = get_frame_pc (get_selected_frame ()); @@ -1815,9 +1810,22 @@ linker_namespace_make_value (gdbarch *gdbarch, internalvar *var, break; } + return nsid; +} + +/* Implementation of the linker_namespace convenience variable. + This returns the GDB internal identifier of the linker namespace, + for the selected frame, as an integer. If the inferior doesn't support + linker namespaces, this always returns 0. */ + +static value * +linker_namespace_make_value (gdbarch *gdbarch, internalvar *var, + void *ignore) +{ /* If the PC is not in an SO, or the solib_ops doesn't support linker namespaces, the inferior is in the default namespace. */ - return value_from_longest (builtin_type (gdbarch)->builtin_int, nsid); + return value_from_longest (builtin_type (gdbarch)->builtin_int, + get_current_linker_namespace ()); } /* Implementation of `$_linker_namespace' variable. */ diff --git a/gdb/solib.h b/gdb/solib.h index 9e6c3f7346e..e52eef53df8 100644 --- a/gdb/solib.h +++ b/gdb/solib.h @@ -412,4 +412,8 @@ extern void handle_solib_event (void); extern int solib_linker_namespace_count (program_space *pspace); +/* Calculate the linker namespace for the currently selected frame. */ + +int get_current_linker_namespace (); + #endif /* GDB_SOLIB_H */ From patchwork Mon Jun 1 19:22:48 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 136206 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 66ED04BA5436 for ; Mon, 1 Jun 2026 19:25:17 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 66ED04BA5436 Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=NxSBmAUo X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id A1A1E4BA2E0C for ; Mon, 1 Jun 2026 19:23:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A1A1E4BA2E0C Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 A1A1E4BA2E0C Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780341826; cv=none; b=hFjpHdCPOknfBdkFfEGQf3v37G0/8M9VjYyDiZNNLMsDZV9kUkdUNYRZu4B8/gnUA+Dou3VwH/sy/cvM1GYpcOJMb9/wRQ/bm47/RjjFSg5LmscCPr6iuE2HNy+5MPu8PStdoTNRSc86Lmkr7+mFYzgoibBJCunhaiF3vtQEaqM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780341826; c=relaxed/simple; bh=TvDuzHvNcfSJlbARxqEiuIMxgXRCns9BzC73B4t1UjA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=MwoPKb99m7Dfgmuky+KbqhBi1StQa3CWrFk52asc9l+20y0UFxrLcMjD05knokNUM8hJYFhQgCv7yI2350ZBdWwH62EnhYH9bZRUWUn6hI3agnfyCpLpIVpQdG+r6iPQJp5VSj+QDx817JDfQN5jqGlRQI+fudQ8lUKUJfHTEJs= ARC-Authentication-Results: i=1; sourceware.org; dkim=fail (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=NxSBmAUo reason="signature verification failed" DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A1A1E4BA2E0C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780341826; 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=fPNyW09Wvx8KoZQqUtaGANFEiNtOW3ekTZAcO29lZOc=; b=NxSBmAUo+jrkepxRKVf1uV76G+GqKj4AhaohEXKfZuSWdA8kvMlrraCVe94J/PwV3xnY6C v66xxWyyoUe5B6LdwIOA/p3B/N2BWrmp4THcCUb7C0wxH+GaTL3ZGiFO9F/PKT1R/nqiQA zTlShOb8QE85bXI8sqKz8ihCSZ4Wu1A= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-452-U8sI8v4ZNZKsbFrYa3FaDQ-1; Mon, 01 Jun 2026 15:23:45 -0400 X-MC-Unique: U8sI8v4ZNZKsbFrYa3FaDQ-1 X-Mimecast-MFC-AGG-ID: U8sI8v4ZNZKsbFrYa3FaDQ_1780341824 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 411F41956053 for ; Mon, 1 Jun 2026 19:23:39 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.144]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6218819560A3; Mon, 1 Jun 2026 19:23:36 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH v7 2/5] gdb: make lookup_minimal_symbol_linkage work with linker namespaces Date: Mon, 1 Jun 2026 16:22:48 -0300 Message-ID: <20260601192251.60958-3-guinevere@redhat.com> In-Reply-To: <20260601192251.60958-1-guinevere@redhat.com> References: <20260601192251.60958-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: ZetEfGTYxQmrGSXgyVtneC8_3fy9-DsW_-2hYOoOos4_1780341824 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, GIT_PATCH_0, KAM_DMARC_QUARANTINE, KAM_DMARC_STATUS, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_HOSTKARMA_W, RCVD_IN_SBL_CSS, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org When a symbol found by GDB may have copy relocation, GDB calculates the address of the symbol by checking all the objfiles in the current program space for another instance of the same symbol, and returns the address of the first instance found. This works well when linker namespaces are not involved, but fails when a symbol is present in more than one namespace. That's because copy relocations respect linker namespace boundaries, and so if we're trying to find the symbol in namespace N, the symbol from a different namespace M may be returned, if the SO containing the symbol was loaded in M before N. To make the search work correctly, lookup_minimal_symbol_linkage would need to also respect linker namespace boundaries. However, to avoid leaking solib knowledge to minsyms, and because of how little information is passed to the function, this commit instead makes the function take a vector of objfiles to search, in place of the program space. This makes it so symbol::get_maybe_copied_address (and the equivalent of minimal_symbol) need to request the objfiles for the correct namespace, since they have enough context to figure out the namespace. Creating the vector is left as a function in solib.c Since minimal_symbol::get_maybe_copied_address only searches main_file objfiles, if we can guarantee that only one is loaded for each program space, we could avoid the work of constructing an std::vector that will be mostly ignored. However, I couldn't convince myself that that is the case, so I decided to keep the behavior exactly as is. Ideally, lookup_minimal_symbol_linkage would receive an iterator instead of a vector, but that would either require that we either make a generic iterator to manage program_space::objfiles_range iterator and a vector iterator, or we find a way to filter the objfiles based on the linker namespace, but this has quadratic complexity, over the linear complexity of creating a new vector, to avoid even worse performance. Finally, as some minor refactoring, find_solib_for_objfile is moved to solib.c to simplify looking for which namespace contains the objfile where we found the symbol the user was looking for. As Andrew noted, this function is flawed, but as the bug was already here and this refactor only exposes it further, so the commit adds comment explaining the issue. --- gdb/dwarf2/ada-imported.c | 8 +++- gdb/minsyms.c | 15 ++++--- gdb/minsyms.h | 13 +++--- gdb/solib-svr4.c | 20 ---------- gdb/solib.c | 84 +++++++++++++++++++++++++++++++++++++++ gdb/solib.h | 25 ++++++++++++ gdb/symtab.c | 13 +++++- 7 files changed, 143 insertions(+), 35 deletions(-) diff --git a/gdb/dwarf2/ada-imported.c b/gdb/dwarf2/ada-imported.c index 7cdaffef886..31782803c73 100644 --- a/gdb/dwarf2/ada-imported.c +++ b/gdb/dwarf2/ada-imported.c @@ -36,9 +36,13 @@ static struct value * ada_imported_read_variable (struct symbol *symbol, const frame_info_ptr &frame) { const char *name = get_imported_name (symbol); + + std::vector objfiles_to_search; + for (objfile &objf : symbol->objfile ()->pspace ()->objfiles ()) + objfiles_to_search.push_back (&objf); + bound_minimal_symbol minsym - = lookup_minimal_symbol_linkage (symbol->objfile ()->pspace (), name, - true, false); + = lookup_minimal_symbol_linkage (objfiles_to_search, name, true, false); if (minsym.minsym == nullptr) error (_("could not find imported name %s"), name); return value_at (symbol->type (), minsym.value_address ()); diff --git a/gdb/minsyms.c b/gdb/minsyms.c index 4eafc789047..b3538a9284a 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -54,6 +54,7 @@ #include "gdbsupport/cxx-thread.h" #include "gdbsupport/parallel-for.h" #include "inferior.h" +#include "solib.h" /* Return true if MINSYM is a cold clone symbol. Recognize f.i. these symbols (mangled/demangled): @@ -588,19 +589,21 @@ lookup_minimal_symbol_linkage (const char *name, struct objfile *objf, /* See minsyms.h. */ bound_minimal_symbol -lookup_minimal_symbol_linkage (program_space *pspace, const char *name, - bool match_static_type, bool only_main) +lookup_minimal_symbol_linkage (gdb::array_view objfiles_to_search, + const char *name, bool match_static_type, + bool only_main) { - for (objfile &objfile : pspace->objfiles ()) + for (objfile *objfile : objfiles_to_search) { - if (objfile.separate_debug_objfile_backlink != nullptr) + if (objfile == nullptr + || objfile->separate_debug_objfile_backlink != nullptr) continue; - if (only_main && (objfile.flags & OBJF_MAINLINE) == 0) + if (only_main && (objfile->flags & OBJF_MAINLINE) == 0) continue; bound_minimal_symbol minsym - = lookup_minimal_symbol_linkage (name, &objfile, match_static_type); + = lookup_minimal_symbol_linkage (name, objfile, match_static_type); if (minsym.minsym != nullptr) return minsym; } diff --git a/gdb/minsyms.h b/gdb/minsyms.h index c44d5b20aec..03d05b6e328 100644 --- a/gdb/minsyms.h +++ b/gdb/minsyms.h @@ -215,13 +215,16 @@ extern bound_minimal_symbol lookup_minimal_symbol_linkage (const char *name, struct objfile *objf, bool match_static_type) ATTRIBUTE_NONNULL (1) ATTRIBUTE_NONNULL (2); -/* A variant of lookup_minimal_symbol_linkage that iterates over all - objfiles of PSPACE. If ONLY_MAIN is true, then only an objfile with - OBJF_MAINLINE will be considered. */ +/* A variant of lookup_minimal_symbol_linkage that iterates over the + objfiles in OBJFILES_TO_SEARCH. If ONLY_MAIN is true, then only an + objfile with OBJF_MAINLINE will be considered. This function should + receive a program_space::objfile_ranges instead, but we can't include + progspace.h here, nor can we do forward declarations of nested types, + so std::vector will waste a bit of memory to work around that issue. */ extern bound_minimal_symbol lookup_minimal_symbol_linkage - (program_space *pspace, const char *name, bool match_static_type, - bool only_main) ATTRIBUTE_NONNULL (1); + (gdb::array_view objfiles_to_search, const char *name, + bool match_static_type, bool only_main); /* Look through all the current minimal symbol tables and find the first minimal symbol that matches NAME and PC. If OBJF is non-NULL, diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 8e3de4d3ea1..394b1237096 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -3592,26 +3592,6 @@ lp64_svr4_solib_ops::fetch_link_map_offsets () const } -/* Return the DSO matching OBJFILE or nullptr if none can be found. */ - -static const solib * -find_solib_for_objfile (struct objfile *objfile) -{ - if (objfile == nullptr) - return nullptr; - - /* If OBJFILE is a separate debug object file, look for the original - object file. */ - if (objfile->separate_debug_objfile_backlink != nullptr) - objfile = objfile->separate_debug_objfile_backlink; - - for (const solib &so : current_program_space->solibs ()) - if (so.objfile == objfile) - return &so; - - return nullptr; -} - /* Return the address of the r_debug object for the namespace containing SOLIB or zero if it cannot be found. This may happen when symbol files are added manually, for example, or with the main executable. diff --git a/gdb/solib.c b/gdb/solib.c index dbb69ef7678..ca68b5c93c1 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -1795,6 +1795,90 @@ solib_linker_namespace_count (program_space *pspace) /* See solib.h. */ +const solib * +find_solib_for_objfile (struct objfile *objfile) +{ + if (objfile == nullptr) + return nullptr; + + /* If OBJFILE is a separate debug object file, look for the original + object file. */ + if (objfile->separate_debug_objfile_backlink != nullptr) + objfile = objfile->separate_debug_objfile_backlink; + + for (const solib &so : objfile->pspace ()->solibs ()) + if (so.objfile == objfile) + return &so; + + return nullptr; +} + +/* See solib.h. */ + +std::vector +get_objfiles_in_linker_namespace (int nsid, program_space *pspace) +{ + std::vector objfiles_in_ns; + const solib_ops *ops = pspace->solib_ops (); + + gdb_assert (ops->supports_namespaces ()); + + /* If we're looking at the default namespace, we also need + to add the mainline objfiles by hand, since there is no + solib associated with those files. We add them first + because if we're searching for copy relocations, they + should be in the main file, so we'll find it faster. */ + if (nsid == 0) + for (objfile &objf : pspace->objfiles ()) + if ((objf.flags & OBJF_MAINLINE) != 0) + objfiles_in_ns.push_back (&objf); + + std::vector solibs = ops->get_solibs_in_ns (nsid); + /* Reserve for efficiency. */ + objfiles_in_ns.reserve (solibs.size () + objfiles_in_ns.size ()); + for (const solib *so : solibs) + objfiles_in_ns.push_back (so->objfile); + + return objfiles_in_ns; +} + +/* See solib.h. */ + +std::vector +get_objfiles_in_linker_namespace (objfile *objfile) +{ + program_space *pspace = objfile->pspace (); + const solib_ops *ops = pspace->solib_ops (); + const solib *so = find_solib_for_objfile (objfile); + + /* If the inferior hasn't started yet, the solib_ops won't be + set for the program space. Since namespaces only make sense + when the inferior has already created some, we can just skip + it here. */ + if (ops != nullptr && ops->supports_namespaces () + /* If we're searching for a symbol from the linker, we'll reach here + before having any namespaces. Return all objfiles since the + boundaries haven't been setup yet. */ + && ops->num_active_namespaces () > 0 + /* When trying to load libthread_db, we can search for a symbol in an + objfile with no associated solib. In that case, again, we should + return all objfiles. */ + && so != nullptr) + { + return get_objfiles_in_linker_namespace (ops->find_solib_ns (*so), + pspace); + } + + /* If any of the previous conditions isn't satisfied, we return + the full list of objfiles in the inferior. */ + std::vector found_objfiles; + for (struct objfile &objf : objfile->pspace ()->objfiles ()) + found_objfiles.push_back (&objf); + + return found_objfiles; +} + +/* See solib.h. */ int get_current_linker_namespace () { diff --git a/gdb/solib.h b/gdb/solib.h index e52eef53df8..493a2086f24 100644 --- a/gdb/solib.h +++ b/gdb/solib.h @@ -20,6 +20,9 @@ #ifndef GDB_SOLIB_H #define GDB_SOLIB_H +/* Forward decl's for prototypes */ +struct objfile; + #include "gdb_bfd.h" #include "gdbsupport/function-view.h" #include "gdbsupport/intrusive_list.h" @@ -416,4 +419,26 @@ extern int solib_linker_namespace_count (program_space *pspace); int get_current_linker_namespace (); +/* Return a vector with pointers of all objfiles in the namespace + NSID. This version assumes that the inferior supports namespaces. */ + +std::vector get_objfiles_in_linker_namespace + (int nsid, program_space *pspace); + +/* Return a vector with pointers of all objfiles in the same namespace + as OBJFILE. If the inferior doesn't support namespaces, return all + objfiles in the program_space. */ + +std::vector get_objfiles_in_linker_namespace (objfile *objfile); + +/* Return the DSO matching OBJFILE or nullptr if none can be found. + NOTE: This function has the flawed assumption that the objfile <-> solib + relationship as a 1 to 1, but it is in fact 1 to many. For now, this + function is only used to find an objfile's namespace, meaning the bug + will only return a possibly incorrect value when the objfile belongs + to something present in multiple namespaces, which is only the linker + namespace as far as I know. Keep this in mind, if using this function. */ + +const solib *find_solib_for_objfile (struct objfile *objfile); + #endif /* GDB_SOLIB_H */ diff --git a/gdb/symtab.c b/gdb/symtab.c index 3c10e1fd750..95287ab42f7 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -74,6 +74,7 @@ #include "gdbsupport/common-utils.h" #include #include "gdbsupport/unordered_set.h" +#include "solib.h" /* Forward declarations for local functions. */ @@ -6598,8 +6599,12 @@ symbol::get_maybe_copied_address () const gdb_assert (this->loc_class () == LOC_STATIC); const char *linkage_name = this->linkage_name (); + + std::vector objfiles_to_search + (get_objfiles_in_linker_namespace (this->objfile ())); + bound_minimal_symbol minsym - = lookup_minimal_symbol_linkage (this->objfile ()->pspace (), linkage_name, + = lookup_minimal_symbol_linkage (objfiles_to_search, linkage_name, false, false); if (minsym.minsym != nullptr) return minsym.value_address (); @@ -6638,8 +6643,12 @@ minimal_symbol::get_maybe_copied_address (objfile *objf) const gdb_assert ((objf->flags & OBJF_MAINLINE) == 0); const char *linkage_name = this->linkage_name (); + + std::vector objfiles_to_search + (get_objfiles_in_linker_namespace (objf)); + bound_minimal_symbol found - = lookup_minimal_symbol_linkage (objf->pspace (), linkage_name, + = lookup_minimal_symbol_linkage (objfiles_to_search, linkage_name, false, true); if (found.minsym != nullptr) return found.value_address (); From patchwork Mon Jun 1 19:22:49 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 136208 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2D5314BA2E2C for ; Mon, 1 Jun 2026 19:26:38 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2D5314BA2E2C Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=I9BEwSu4 X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id F03354BA2E12 for ; Mon, 1 Jun 2026 19:23:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F03354BA2E12 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 F03354BA2E12 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780341827; cv=none; b=LhbR0AslUVPl4NMfakPYm+EgFi3pJc1zlGEcsgLxYnkVpxLwhmssJGgr1vzG2+hBHLjiDO+dyinnrPkzdAEWjhEwYKDdNa2+A95CyRqLsfykE/iRLjSPwH9ev3lshtJXNnmRKG5O1NmBxACujiehn2V8oeL5KoRbpDYWqjy8IdM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780341827; c=relaxed/simple; bh=uPq3uOxtdWnYWuUJKv6b67OkCyDREJ5H6GqxEhXum+4=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=T7NfucgIjWj41Jl/Ns9mMa2dBa/q4qvzLIVIzBplrCf9ifts6KsqsxsePRb5MMFA7j8YUtVqy5SMc5EigeI73XWFO/Qk1ZunnN+95UaRzee2FwHI+SgJ0lU4vhpPoJsuNZ2+/8pkKJeF/mU0io8ai9Zg6S9GNt7EYK+kHE1/5HY= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=I9BEwSu4 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F03354BA2E12 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780341826; 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=vLHvV1JUPMb7yj7rDzpg7Xp5uN32iHMIdDwI85R9SIg=; b=I9BEwSu4jehuoIjoE34lcdAGGVLlpXrXWmQjRhzWJ04yCLiFxGvdVEdZp2WXDaBVHlD/Eh coYirTm2CEoaH7OPUgQW24MKfVWG42bYOFwEQx+LU1DjgK4uacQY6B2nB1vDo+shgmllkY Z0pK+hnEGW+cknEVtcwLrgCsaxc7cQ4= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-170-eiK3MPbuOMWwqqjY442L7g-1; Mon, 01 Jun 2026 15:23:45 -0400 X-MC-Unique: eiK3MPbuOMWwqqjY442L7g-1 X-Mimecast-MFC-AGG-ID: eiK3MPbuOMWwqqjY442L7g_1780341824 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 966CA19560AF; Mon, 1 Jun 2026 19:23:41 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.144]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id E61BE19560A3; Mon, 1 Jun 2026 19:23:39 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen , Eli Zaretskii Subject: [PATCH v7 3/5] gdb: Make the parser recognize the [[N]] syntax for variables Date: Mon, 1 Jun 2026 16:22:49 -0300 Message-ID: <20260601192251.60958-4-guinevere@redhat.com> In-Reply-To: <20260601192251.60958-1-guinevere@redhat.com> References: <20260601192251.60958-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: rZskMvwG0nZU4Rh3V-dKuR1osASOKhk-0XX00_66tpY_1780341824 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-10.6 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_STOCKGEN, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This commit adds a couple new rules to the YACC parser, that will allow GDB to recognize expressions like [[N]]::var. This new syntax reuses the existing rules for searching for "block"s, because it allows, with minimal changes to the .y file as a whole, while also allowing [[N]]::function::symbol work. Notably, [[N]]::'file.c'::var does not work yet, as this code change is also involved and would pollute the current commit, so will be done in a separate one in the same series. To restrict the search to a desired namespace, a new function is introduced, lookup_symbol_in_linker_namespace. This function will only perform the symbol lookup in the objfiles that belong to the requested namespace. This commit also changes the error message when "print var" if "var" is only present in namespaces other than the current one. Before this commit, lookup_minimal_symbol would find them as "external" symbols with incomplete information - outputting " has incomplete information, cast it to its declared type." - which could be confusing for the users. This commit changes the parser rule "variable: name_not_typename" so that, if multiple namespaces are active, we'll look for minimal symbols only in the current namespace. Known limitations: * When using [[N]]::foo::var, if that specific foo version is not on the stack, the error will be unable to include the linker namespace requested. So if a user sees "foo" in the stack this could be confusing, but it should be mitigated when a future patch adds the namespace ID to the backtrace where applicable. * Completion is not supported. That's because the function used to complete symbols expects only text in the form "file.c:symbol", so can't handle the double colon. This isn't unique to linker namespaces, though, since func::var will also not complete, it is just a quirk of how :: completion work at this point. * The expression that parses [[N]] only takes an integer. That's because there aren't many expressions that would make sense in there, and the work of accepting an arbitrary expression felt too much for little gain. Reviewed-By: Eli Zaretskii --- gdb/NEWS | 5 + gdb/c-exp.y | 72 ++++++++--- gdb/doc/gdb.texinfo | 6 + gdb/minsyms.c | 122 ++++++++++++------- gdb/minsyms.h | 8 ++ gdb/parser-defs.h | 13 ++ gdb/symtab.c | 40 ++++++ gdb/symtab.h | 8 ++ gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c | 14 +++ gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 + gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 53 ++++++++ 11 files changed, 280 insertions(+), 64 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 7c8cf9af4c2..256af323844 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -421,6 +421,11 @@ info threads [-gid] [-stopped] [-running] [ID]... These new flags can be useful to get a reduced list when there is a large number of threads. +print + The print command now accepts the following syntax to print values + from a specific linker namespace: `[[N]]::foo'. N is the namespace + identifier as understood by GDB. + * GDB-internal Thread Local Storage (TLS) support ** Linux targets for the x86_64, aarch64, ppc64, s390x, and riscv diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 2829d8bccba..8e405e4dc41 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -175,7 +175,7 @@ using namespace expr; struct ttype tsym; struct symtoken ssym; int voidval; - const struct block *bval; + struct bval_type bval; enum exp_opcode opcode; struct stoken_vector svec; @@ -263,6 +263,7 @@ static void c_print_token (FILE *file, int type, YYSTYPE value); %token TYPEOF %token DECLTYPE %token TYPEID +%token DOUBLESQUAREOPEN DOUBLESQUARECLOSE /* Special type cases, put in to allow the parser to distinguish different legal basetypes. */ @@ -1058,31 +1059,43 @@ exp : FALSEKEYWORD block : BLOCKNAME { - if ($1.sym.symbol) - $$ = $1.sym.symbol->value_block (); - else + if ($1.sym.symbol == nullptr) error (_("No file or function \"%s\"."), copy_name ($1.stoken).c_str ()); + $$.search_namespace = false; + $$.b_val = $1.sym.symbol->value_block (); } | FILENAME { $$ = $1; } + | DOUBLESQUAREOPEN INT DOUBLESQUARECLOSE + { + $$.search_namespace = true; + $$.namespace_val = $2.val; + } ; block : block COLONCOLON name { std::string copy = copy_name ($3); - struct symbol *tem - = lookup_symbol (copy.c_str (), $1, - SEARCH_FUNCTION_DOMAIN, - nullptr).symbol; + struct block_symbol tem; - if (tem == nullptr) + if ($1.search_namespace) + tem = lookup_symbol_in_linker_namespace + (copy.c_str (), $1.namespace_val, SEARCH_FUNCTION_DOMAIN); + else + tem = lookup_symbol (copy.c_str (), $1.b_val, + SEARCH_FUNCTION_DOMAIN, + nullptr); + + if (tem.symbol == nullptr) error (_("No function \"%ps\" in specified context."), styled_string (function_name_style.style (), copy.c_str ())); - $$ = tem->value_block (); } + $$.b_val = tem.symbol->value_block (); + $$.search_namespace = false; + } ; variable: name_not_typename ENTRY @@ -1101,9 +1114,15 @@ variable: name_not_typename ENTRY variable: block COLONCOLON name { std::string copy = copy_name ($3); - struct block_symbol sym - = lookup_symbol (copy.c_str (), $1, - SEARCH_VFT, NULL); + struct block_symbol sym; + + if ($1.search_namespace) + sym = lookup_symbol_in_linker_namespace + (copy.c_str (), $1.namespace_val, + SEARCH_VFT); + else + sym = lookup_symbol (copy.c_str (), $1.b_val, + SEARCH_VFT, NULL); if (sym.symbol == 0) error (_("No symbol \"%s\" in specified context."), @@ -1199,8 +1218,17 @@ variable: name_not_typename { std::string arg = copy_name ($1.stoken); - bound_minimal_symbol msymbol - = lookup_minimal_symbol (current_program_space, arg.c_str ()); + int active_linker_nss + = solib_linker_namespace_count + (current_program_space); + bound_minimal_symbol msymbol; + + if (active_linker_nss > 1) + msymbol = lookup_minimal_symbol_in_linker_namespace + (current_program_space, arg.c_str ()); + else + msymbol = lookup_minimal_symbol + (current_program_space, arg.c_str ()); if (msymbol.minsym == NULL) { if (!current_program_space->has_full_symbols () @@ -1208,6 +1236,9 @@ variable: name_not_typename error (_("No symbol table is loaded. Use the \"%ps\" command."), styled_string (command_style.style (), "file")); + else if (active_linker_nss > 1) + error (_("No symbol \"%s\" in the current linker namespace."), + arg.c_str ()); else error (_("No symbol \"%s\" in current context."), arg.c_str ()); @@ -2545,7 +2576,9 @@ static const struct c_token tokentab2[] = {"!=", NOTEQUAL, OP_NULL, 0}, {"<=", LEQ, OP_NULL, 0}, {">=", GEQ, OP_NULL, 0}, - {".*", DOT_STAR, OP_NULL, FLAG_CXX} + {".*", DOT_STAR, OP_NULL, FLAG_CXX}, + {"[[", DOUBLESQUAREOPEN, OP_NULL, 0}, + {"]]", DOUBLESQUARECLOSE, OP_NULL, 0}, }; /* Identifier-like tokens. Only type-specifiers than can appear in @@ -3177,8 +3210,9 @@ classify_name (struct parser_state *par_state, const struct block *block, if (auto symtab = lookup_symtab (current_program_space, copy.c_str ()); symtab != nullptr) { - yylval.bval + yylval.bval.b_val = symtab->compunit ()->blockvector ()->static_block (); + yylval.bval.search_namespace = false; return FILENAME; } @@ -3428,7 +3462,7 @@ yylex (void) name_obstack.clear (); checkpoint = 0; if (current.token == FILENAME) - search_block = current.value.bval; + search_block = current.value.bval.b_val; else if (current.token == COLONCOLON) search_block = NULL; else @@ -3612,7 +3646,7 @@ c_print_token (FILE *file, int type, YYSTYPE value) break; case FILENAME: - parser_fprintf (file, "bval<%s>", host_address_to_string (value.bval)); + parser_fprintf (file, "bval<%s>", host_address_to_string (value.bval.b_val)); break; } } diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index a698b2b8451..ce67eb28a26 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -10775,6 +10775,12 @@ you can choose a different format by specifying @samp{/@var{f}}, where @var{f} is a letter specifying the format; see @ref{Output Formats,,Output Formats}. +Additionally, if the inferior supports linker namespaces, @value{GDBN} +has implemented the following syntax to allow users to resolve symbols +to a specific namespace: @samp{[[@var{n}]]::@var{symbol}}. Here @var{n} +is @value{GDBN}'s namespace identifier, which may be different from the +inferior's identifier. + @anchor{print options} The @code{print} command supports a number of options that allow overriding relevant global print settings as set by @code{set print} diff --git a/gdb/minsyms.c b/gdb/minsyms.c index b3538a9284a..5de058fa1ef 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -324,7 +324,10 @@ lookup_minimal_symbol_demangled (const lookup_name_info &lookup_name, } } -/* Look through all the current minimal symbol tables and find the +/* Main implementation for the lookup_minimal_symbol function. + Receives a list of objfiles in which to look for the symbol. + + Look through all the current minimal symbol tables and find the first minimal symbol that matches NAME. If OBJF is non-NULL, limit the search to that objfile. If SFILE is non-NULL, the only file-scope symbols considered will be from that source file (global symbols are @@ -344,9 +347,9 @@ lookup_minimal_symbol_demangled (const lookup_name_info &lookup_name, Obviously, there must be distinct mangled names for each of these, but the demangled names are all the same: S::S or S::~S. */ -bound_minimal_symbol -lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf, - const char *sfile) +static bound_minimal_symbol +lookup_minimal_symbol_in_objfiles (std::vector objfile_list, + const char *name, const char *sfile) { found_minimal_symbols found; @@ -362,53 +365,48 @@ lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf, lookup_name_info lookup_name (name, symbol_name_match_type::FULL); - for (objfile &objfile : pspace->objfiles ()) + for (objfile *objfile : objfile_list) { if (found.external_symbol.minsym != NULL) break; - if (objf == NULL || objf == &objfile - || objf == objfile.separate_debug_objfile_backlink) + symbol_lookup_debug_printf ("lookup_minimal_symbol (%s, %s, %s)", + name, sfile != NULL ? sfile : "NULL", + objfile_debug_name (objfile)); + + /* Do two passes: the first over the ordinary hash table, + and the second over the demangled hash table. */ + lookup_minimal_symbol_mangled (name, sfile, objfile, + objfile->per_bfd->msymbol_hash, + mangled_hash, mangled_cmp, found); + + /* If not found, try the demangled hash table. */ + if (found.external_symbol.minsym == NULL) { - symbol_lookup_debug_printf ("lookup_minimal_symbol (%s, %s, %s, %s)", - host_address_to_string (pspace), - name, sfile != NULL ? sfile : "NULL", - objfile_debug_name (&objfile)); - - /* Do two passes: the first over the ordinary hash table, - and the second over the demangled hash table. */ - lookup_minimal_symbol_mangled (name, sfile, &objfile, - objfile.per_bfd->msymbol_hash, - mangled_hash, mangled_cmp, found); - - /* If not found, try the demangled hash table. */ - if (found.external_symbol.minsym == NULL) + /* Once for each language in the demangled hash names + table (usually just zero or one languages). */ + for (unsigned iter = 0; iter < nr_languages; ++iter) { - /* Once for each language in the demangled hash names - table (usually just zero or one languages). */ - for (unsigned iter = 0; iter < nr_languages; ++iter) - { - if (!objfile.per_bfd->demangled_hash_languages.test (iter)) - continue; - enum language lang = (enum language) iter; - - unsigned int hash - = (lookup_name.search_name_hash (lang) - % MINIMAL_SYMBOL_HASH_SIZE); - - symbol_name_matcher_ftype *match - = language_def (lang)->get_symbol_name_matcher - (lookup_name); - struct minimal_symbol **msymbol_demangled_hash - = objfile.per_bfd->msymbol_demangled_hash; - - lookup_minimal_symbol_demangled (lookup_name, sfile, &objfile, - msymbol_demangled_hash, - hash, match, found); - - if (found.external_symbol.minsym != NULL) - break; - } + if (!objfile->per_bfd->demangled_hash_languages.test (iter)) + continue; + enum language lang = (enum language) iter; + + unsigned int hash + = (lookup_name.search_name_hash (lang) + % MINIMAL_SYMBOL_HASH_SIZE); + + symbol_name_matcher_ftype *match + = language_def (lang)->get_symbol_name_matcher + (lookup_name); + struct minimal_symbol **msymbol_demangled_hash + = objfile->per_bfd->msymbol_demangled_hash; + + lookup_minimal_symbol_demangled (lookup_name, sfile, objfile, + msymbol_demangled_hash, + hash, match, found); + + if (found.external_symbol.minsym != NULL) + break; } } } @@ -461,6 +459,40 @@ lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf, return {}; } +/* See minsyms.h. */ + +bound_minimal_symbol +lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf, + const char *sfile) +{ + std::vector search_objfiles; + if (objf != nullptr) + { + search_objfiles.push_back (objf); + if (objf->separate_debug_objfile_backlink != nullptr) + search_objfiles.push_back (objf->separate_debug_objfile_backlink); + } + else + { + for (objfile &objfile : pspace->objfiles ()) + search_objfiles.push_back (&objfile); + } + + return lookup_minimal_symbol_in_objfiles (search_objfiles, name, sfile); +} + +/* See minsyms.h. */ + +bound_minimal_symbol +lookup_minimal_symbol_in_linker_namespace (program_space *pspace, + const char *name) +{ + return lookup_minimal_symbol_in_objfiles + (get_objfiles_in_linker_namespace (get_current_linker_namespace (), + pspace), + name, nullptr); +} + /* See gdbsupport/symbol.h. */ int diff --git a/gdb/minsyms.h b/gdb/minsyms.h index 03d05b6e328..b8cd639a4d4 100644 --- a/gdb/minsyms.h +++ b/gdb/minsyms.h @@ -191,6 +191,14 @@ bound_minimal_symbol lookup_minimal_symbol (program_space *pspace, objfile *obj = nullptr, const char *sfile = nullptr); +/* Same as above, but only look for a minimal symbol in the objfiles that + belong to the current linker namespace. This function is only meant to + be called when attempting to resolve a symbol from a user command, and + there are multiple linker namespaces available to resolve it in. */ + +bound_minimal_symbol lookup_minimal_symbol_in_linker_namespace + (program_space *pspace, const char *name); + /* Look through all the minimal symbol tables in PSPACE and find the first minimal symbol that matches NAME and has text type. If OBJF is non-NULL, limit the search to that objfile. Returns a bound diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h index cfa9d9c111d..a424f0c7b6f 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -362,6 +362,19 @@ struct ttype struct type *type; }; +/* A struct to hold all the necessary information when finding a block, + or finding symbols inside a block. */ +struct bval_type + { + /* Whether we are explicitly searching a block in a namespace. */ + bool search_namespace; + /* This is where the result of the search will be stored. */ + const struct block *b_val; + /* If this block, or a parent one, were searched for in a specific + namespace, this is where the namespace is stored. */ + LONGEST namespace_val; + }; + struct symtoken { struct stoken stoken; diff --git a/gdb/symtab.c b/gdb/symtab.c index 95287ab42f7..5eab8ad600a 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -2588,6 +2588,46 @@ lookup_static_symbol (const char *name, const domain_search_flags domain) /* See symtab.h. */ +struct block_symbol +lookup_symbol_in_linker_namespace (const char *name, LONGEST nsid, + const domain_search_flags domain) +{ + if (!current_program_space->solib_ops ()->supports_namespaces ()) + error (_("Linker namespaces are not supported by the inferior.")); + + std::vector objfiles_in_namespace + = get_objfiles_in_linker_namespace (nsid, current_program_space); + + if (objfiles_in_namespace.size () == 0) + error (_("Namespace [[%s]] is inactive"), plongest (nsid)); + + symbol_lookup_debug_printf ("lookup_symbol_in_linker_namespace (%s, %s, %s)", + plongest (nsid), name, domain_name (domain).c_str ()); + demangle_result_storage storage; + const char *demangled_name + = demangle_for_lookup (name, current_language->la_language, storage); + + /* We look for both global and static symbols in here, the order + is arbitrary. */ + for (objfile *objf : objfiles_in_namespace) + { + struct block_symbol bsym + = lookup_global_symbol_from_objfile (objf, GLOBAL_BLOCK, + demangled_name, domain); + if (bsym.symbol != nullptr) + return bsym; + + bsym = lookup_global_symbol_from_objfile (objf, STATIC_BLOCK, + demangled_name, domain); + if (bsym.symbol != nullptr) + return bsym; + } + + return {}; +} + +/* See symtab.h. */ + struct block_symbol lookup_global_symbol (const char *name, const struct block *block, diff --git a/gdb/symtab.h b/gdb/symtab.h index 0a7ad3668b4..3feac5fcf6c 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -2735,6 +2735,14 @@ extern struct block_symbol const char *name, const domain_search_flags domain); +/* Lookup symbol NAME from DOMAIN in the linker namespace NSID. + This generates a list of all objfiles in NSID, then searches + those objfiles for the given symbol. Searches for both global or + static symbols. */ +extern struct block_symbol + lookup_symbol_in_linker_namespace (const char *name, LONGEST nsid, + const domain_search_flags domain); + extern unsigned int symtab_create_debug; /* Print a "symtab-create" debug statement. */ diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c index 99846fe0f96..ae74cab61bf 100644 --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c @@ -26,3 +26,17 @@ inc (int n) int amount = gdb_dlmopen_glob; return n + amount; /* bp.inc. */ } + +static int +change_global (int n) +{ + gdb_dlmopen_glob += n; + return n; +} + +__attribute__((visibility ("default"))) +int +func_with_other_call (int n) +{ + return change_global (n + 1); +} diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c index 4f08a5135b2..02b2bbe6417 100644 --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c @@ -47,6 +47,9 @@ main (void) fun (dl); } + fun = dlsym (handle[0], "func_with_other_call"); + fun (0); + dlclose (handle[0]); /* TAG: first dlclose */ dlclose (handle[1]); /* TAG: second dlclose */ dlclose (handle[2]); /* TAG: third dlclose */ diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp index e40bc213454..72b92304325 100644 --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp @@ -123,6 +123,10 @@ proc get_first_so_ns {} { return $ns } +proc ns_id_for_command {ns} { + return "\[\[$ns\]\]" +} + # Run the tests relating to the command "info sharedlibrary", to # verify that the namespace ID is consistent. proc test_info_shared {} { @@ -311,6 +315,55 @@ proc test_info_linker_namespaces {} { ".*" ] "print namespaces with no argument" } +# Test that we can use the [[N]]::symbol syntax, and its variations +# like [[N]]::func::symbol. +proc_with_prefix test_print_namespace_symbol {} { + clean_restart + gdb_load $::binfile + + set ns1 [ns_id_for_command 1] + set ns2 [ns_id_for_command 2] + + if { ![runto_main] } { + return + } + + gdb_breakpoint [gdb_get_line_number "TAG: first dlclose"] + gdb_breakpoint "change_global" allow-pending + + # Test printing variables for non-existent namespace. + gdb_test "print ${ns1}::gdb_dlmopen_glob" "Namespace ..1.. is inactive" \ + "Before loading namespaces" + + gdb_continue_to_breakpoint "change_global" + + # Test finding location of variables. + gdb_test "print ${ns1}::gdb_dlmopen_glob" ".* = 0" "before changing" + gdb_test_no_output "set ${ns1}::gdb_dlmopen_glob = 1" + gdb_test "print ${ns1}::gdb_dlmopen_glob" ".* = 1" "after changing" + gdb_test "print ${ns2}::gdb_dlmopen_glob" ".* = 0" "other namespace" + + gdb_test "print gdb_dlmopen_glob" ".* = 1" "changed the right variable" + + # Test finding functions in specific namespaces. + gdb_test "print ${ns1}::inc (2)" ".* = 3" + gdb_test "print ${ns2}::inc (2)" ".* = 2" + + # Test finding a specific block in the backtrace. + gdb_test "print n" ".* = 1" + gdb_test "print ${ns1}::func_with_other_call::n" ".* = 0" + gdb_test "print ${ns2}::func_with_other_call::n" \ + "No frame is currently executing in block func_with_other_call." + + # Leave to default namespace. + gdb_continue_to_breakpoint "TAG: first dlclose" + # This global doesn't exist in the default namespace. Rather than + # returning a random one, we just say we didn't find one. + gdb_test "print gdb_dlmopen_glob" \ + "No symbol .gdb_dlmopen_glob. in the current linker namespace." +} + test_info_shared test_conv_vars test_info_linker_namespaces +test_print_namespace_symbol From patchwork Mon Jun 1 19:22:50 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 136204 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 43F224BA2E30 for ; Mon, 1 Jun 2026 19:24:30 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 43F224BA2E30 Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=cn+p5sdL X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id D70F04BA2E0E for ; Mon, 1 Jun 2026 19:23:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D70F04BA2E0E Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 D70F04BA2E0E Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780341827; cv=none; b=BO9GAONZhMhcV67aM06LWexkhV77FwkD7t0KkA+si7Sa7QBkc1X+mxb6flVWqFFxQ8QVw/S0jDlAjj0zjafbxKDPeG8woBTbZckwLmvKKxwPElx73zyi/9ITaGPjiHkhiAN5usM+zCv/ee85dk2GFB1UsDlygEljBoEIgFpC/M4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780341827; c=relaxed/simple; bh=FxHdquZFRUe3QLGOtK4eS2Rh6avv9dK0HxoTxEBPMAA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=vv/3igEMPtSvDKSBf5Jr9xiXfYDNOxbhPpzy/YmbVeArBD59gp/6cW8Ttv0UMCDQiqgc2awtPBYDP02/HpAnBwYynNjJvuBkS7V1BEtZSGawTwq3hzUip6ZXFUmWdtkPM0eNGWr0fgKrY98Soc26fjn6NPNxcW1Q5MT2lQ8TXIw= ARC-Authentication-Results: i=1; sourceware.org; dkim=fail (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=cn+p5sdL reason="signature verification failed" DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D70F04BA2E0E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780341826; 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=9Hm+lo+buMdskH+Vk91a5WR9UQdnaDQyygq2w1LxXog=; b=cn+p5sdL4gOimYkCc4mWlxG14oETt2xDeqilXvCmBOGAzxgVUrcJtOXi9jHWoBmPROtPcx IhQtbiW7oQ9/42OTa++vqlSSTbUEogMe2hl94umAGHyYoefMxXZlB0uXOkKUtLxpaxcqPo L8YuvRI9k8U1wG9/58R8nz6F66n/8N4= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-486-sHNo4Bl8P4aCoo2lWWQ8lg-1; Mon, 01 Jun 2026 15:23:45 -0400 X-MC-Unique: sHNo4Bl8P4aCoo2lWWQ8lg-1 X-Mimecast-MFC-AGG-ID: sHNo4Bl8P4aCoo2lWWQ8lg_1780341824 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 612D819560B8 for ; Mon, 1 Jun 2026 19:23:43 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.144]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 2100B19560A6; Mon, 1 Jun 2026 19:23:41 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH v7 4/5] gdb: extend the [[N]]::foo syntax for files Date: Mon, 1 Jun 2026 16:22:50 -0300 Message-ID: <20260601192251.60958-5-guinevere@redhat.com> In-Reply-To: <20260601192251.60958-1-guinevere@redhat.com> References: <20260601192251.60958-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: AYX82CzX03Fiims7_xrL_tS2EKOoB9QRas8x6t2zrYw_1780341824 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, GIT_PATCH_0, KAM_DMARC_QUARANTINE, KAM_DMARC_STATUS, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This commit implements the missing support for [[N]]::'file.c'::var syntax that was skipped on the previous commit. This is done with a new rule, 'block: block COLONCOLON FILENAME', a few changes to classify_name and adding a value to the parser_state. classify_name now restricts its search for files to ones available in the provided linker namespace (if there was one), which is found in the parser_state. To explain why the search has to be restricted, imagine the following scenario: An inferior has 2 linker namespaces. In namespace 0, there is a library with the file 'foo' loaded; in namespace 1, there is a function 'foo', which is in the stack. If the user were to type [[1]]::foo::var, it could be possible that foo is mis-classified as a filename, then when executing the rule 'block: block COLONCOLON FILENAME' we search for the file with the filename restriction and error out because there are no files named that. Therefore, the safest way to ensure we're always classifying things correctly is to use the linker namespace in the classify_name function. And the reason the linker namespace must be in the parser_state is because, while running classify_name, we don't have access to the previous states to see if there was a LINKER_NAMESPACE token, so adding it to the global state is the only way to pass it along. The new rule only exists to make sure that it is only used in the intended syntax, instead of allowing for something like function::filename::variable. This commit also adds a link to the solib_ops relevant to the expression being parsed, as a way to identify if linker namespaces are supported; this could be achieved by guarding the search functions instead, but I think that this is more reliable. The new rule uses "block" rather than a linker namespace specific token, because if we allowed that token to also reduce into block, the new rule would never be triggered as the simple reduction would be preferred. If we didn't allow the linker namespace to reduce into block, the rest of the syntaxes for [[N]]::foo would be more involved, so the option in this commit seemed like the simplest solution. The rule "block: block COLONCOLON name" also had to be updated because, if a user tried to search for a file not present in the linker namespace, GDB would miscategorize it to 'name' instead of 'filename', and if no function of the same name was found, the error would only say "No function \"foo\" (...)" which could confuse a user. The new error says "Nothing named \"foo\" (...)" instead since it is impossible for us to disambiguate between filename or function name, and both would be valid in this code path. The parser_state changes were not used for the previous commit because the lookup_symbol calls would lead to an even more intrusive change for no real gain, since the search would be rerun any way. There is an argument to be made that the results could be different if only namespace had a type and another had a variable, but a situation where that significantly changes the result is quite unlikely, I think. --- gdb/c-exp.y | 23 ++++++++++-- gdb/linespec.c | 4 +-- gdb/parse.c | 3 +- gdb/parser-defs.h | 37 ++++++++++++++++++-- gdb/rust-parse.c | 3 +- gdb/symtab.c | 37 +++++++++++++------- gdb/symtab.h | 4 ++- gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 2 ++ gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 21 +++++++++++ 9 files changed, 112 insertions(+), 22 deletions(-) diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 8e405e4dc41..f152b1d53f0 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -1064,15 +1064,18 @@ block : BLOCKNAME copy_name ($1.stoken).c_str ()); $$.search_namespace = false; $$.b_val = $1.sym.symbol->value_block (); + pstate->reset_linker_namespace (); } | FILENAME { $$ = $1; + pstate->reset_linker_namespace (); } | DOUBLESQUAREOPEN INT DOUBLESQUARECLOSE { $$.search_namespace = true; $$.namespace_val = $2.val; + pstate->set_linker_namespace ($2.val); } ; @@ -1089,12 +1092,26 @@ block : block COLONCOLON name SEARCH_FUNCTION_DOMAIN, nullptr); - if (tem.symbol == nullptr) + if (tem.symbol == nullptr && !$1.search_namespace) error (_("No function \"%ps\" in specified context."), styled_string (function_name_style.style (), copy.c_str ())); + else if (tem.symbol == nullptr && $1.search_namespace) + /* COPY can be a function or a file. There is no way + to identify which the user intended, so emit a + generic warning instead. */ + error (_("Nothing named \"%s\" in specified context."), + copy.c_str ()); $$.b_val = tem.symbol->value_block (); $$.search_namespace = false; + pstate->reset_linker_namespace (); + } + | block COLONCOLON FILENAME + { + if (!$1.search_namespace) + error (_("Filename must be the first part of the expression")); + $$ = $3; + pstate->reset_linker_namespace (); } ; @@ -1131,6 +1148,7 @@ variable: block COLONCOLON name pstate->block_tracker->update (sym); pstate->push_new (sym); + pstate->reset_linker_namespace (); } ; @@ -3207,7 +3225,8 @@ classify_name (struct parser_state *par_state, const struct block *block, || is_quoted_name) { /* See if it's a file name. */ - if (auto symtab = lookup_symtab (current_program_space, copy.c_str ()); + if (auto symtab = lookup_symtab (current_program_space, copy.c_str (), + par_state->get_linker_namespace ()); symtab != nullptr) { yylval.bval.b_val diff --git a/gdb/linespec.c b/gdb/linespec.c index 5371d8426ae..38a30f04f77 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -3628,11 +3628,11 @@ collect_symtabs_from_filename (const char *file, if (pspace->executing_startup) continue; - for_each_symtab (pspace, file, collector); + for_each_symtab (pspace, file, -1, collector); } } else - for_each_symtab (search_pspace, file, collector); + for_each_symtab (search_pspace, file, -1, collector); /* It is tempting to use the unordered_dense 'extract' method here, and remove the separate vector -- but it's unclear if ordering diff --git a/gdb/parse.c b/gdb/parse.c index fd190d6e15e..2ed52d689a1 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -426,7 +426,8 @@ parse_exp_in_context (const char **stringptr, CORE_ADDR pc, parser_state ps (lang, get_current_arch (), expression_context_block, expression_context_pc, flags, *stringptr, - completer != nullptr, tracker); + completer != nullptr, tracker, + current_program_space->solib_ops ()); scoped_restore_current_language lang_saver (lang->la_language); diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h index a424f0c7b6f..299fd2b74af 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -26,6 +26,7 @@ #include "expression.h" #include "symtab.h" #include "expop.h" +#include "solib.h" struct block; struct language_defn; @@ -147,7 +148,8 @@ struct parser_state : public expr_builder parser_flags flags, const char *input, bool completion, - innermost_block_tracker *tracker) + innermost_block_tracker *tracker, + const solib_ops *ops) : expr_builder (lang, gdbarch), expression_context_block (context_block), expression_context_pc (context_pc), @@ -157,7 +159,8 @@ struct parser_state : public expr_builder comma_terminates ((flags & PARSER_COMMA_TERMINATES) != 0), parse_completion (completion), void_context_p ((flags & PARSER_VOID_CONTEXT) != 0), - debug ((flags & PARSER_DEBUG) != 0) + debug ((flags & PARSER_DEBUG) != 0), + m_solib_ops (ops) { } @@ -267,6 +270,26 @@ struct parser_state : public expr_builder push (expr::make_operation (std::move (lhs), std::move (rhs))); } + void set_linker_namespace (LONGEST ns_id) + { + if (m_solib_ops == nullptr) + error (_("Linker namespaces require an active inferior")); + if (m_solib_ops->supports_namespaces ()) + m_linker_namespace = ns_id; + else + error (_("Linker namespaces are not supported")); + } + + void reset_linker_namespace () + { + m_linker_namespace = -1; + } + + LONGEST get_linker_namespace () const + { + return m_linker_namespace; + } + /* Function called from the various parsers' yyerror functions to throw an error. The error will include a message identifying the location of the error within the current expression. */ @@ -327,6 +350,16 @@ struct parser_state : public expr_builder /* Stack of operations. */ std::vector m_operations; + + /* If the expression is being restricted to a specific namespace, this is + where that information is stored for the block lookup. It should be + accessed through setter/getters to ensure that the linker namespace is + only set when the gdbarch supports it. */ + LONGEST m_linker_namespace = -1; + + /* Used to figure out if an inferior is capable of handling linker + namespaces at all. */ + const solib_ops *m_solib_ops; }; /* A string token, either a char-string or bit-string. Char-strings are diff --git a/gdb/rust-parse.c b/gdb/rust-parse.c index 0c4f2a501ab..728fc88842b 100644 --- a/gdb/rust-parse.c +++ b/gdb/rust-parse.c @@ -2305,7 +2305,8 @@ rust_lex_tests (void) { /* Set up dummy "parser", so that rust_type works. */ parser_state ps (language_def (language_rust), current_inferior ()->arch (), - nullptr, 0, 0, nullptr, 0, nullptr); + nullptr, 0, 0, nullptr, 0, nullptr, + current_program_space->solib_ops ()); rust_parser parser (&ps); rust_lex_test_one (&parser, "", 0); diff --git a/gdb/symtab.c b/gdb/symtab.c index 5eab8ad600a..d7317a758b1 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -630,14 +630,11 @@ compare_filenames_for_search (const char *filename, const char *search_name) && STRIP_DRIVE_SPEC (filename) == &filename[len - search_len])); } -/* Return the first symtab in PSPACE matching NAME and for which - CALLBACK returns true. - - See documentation for for_each_symtab for how exactly NAME is matched. */ +/* See symtab.h. */ static symtab * find_symtab (program_space *pspace, const char *name, - find_symtab_callback_ftype callback) + LONGEST linker_ns, find_symtab_callback_ftype callback) { gdb::unique_xmalloc_ptr real_path; @@ -649,10 +646,23 @@ find_symtab (program_space *pspace, const char *name, gdb_assert (IS_ABSOLUTE_PATH (real_path.get ())); } - for (objfile &objfile : pspace->objfiles ()) + std::vector objfiles_to_search; + if (linker_ns >= 0) + { + gdb_assert (pspace->solib_ops ()->supports_namespaces ()); + objfiles_to_search + = get_objfiles_in_linker_namespace (linker_ns, pspace); + } + else + { + for (objfile &objf : pspace->objfiles ()) + objfiles_to_search.push_back (&objf); + } + + for (objfile *objfile : objfiles_to_search) if (symtab *result - = objfile.find_symtab_matching_filename (name, real_path.get (), - callback); + = objfile->find_symtab_matching_filename (name, real_path.get (), + callback); result != nullptr) return result; @@ -663,9 +673,9 @@ find_symtab (program_space *pspace, const char *name, void for_each_symtab (program_space *pspace, const char *name, - for_each_symtab_callback_ftype callback) + LONGEST linker_ns, for_each_symtab_callback_ftype callback) { - find_symtab (pspace, name, [&] (symtab *symtab) + find_symtab (pspace, name, linker_ns, [&] (symtab *symtab) { callback (symtab); return false; @@ -675,9 +685,10 @@ for_each_symtab (program_space *pspace, const char *name, /* See symtab.h. */ symtab * -lookup_symtab (program_space *pspace, const char *name) +lookup_symtab (program_space *pspace, const char *name, LONGEST linker_ns) { - return find_symtab (pspace, name, [&] (symtab *symtab) { return true; }); + return find_symtab (pspace, name, linker_ns, + [&] (symtab *symtab) { return true; }); } @@ -6192,7 +6203,7 @@ collect_file_symbol_completion_matches (completion_tracker &tracker, /* Go through symtabs for SRCFILE and check the externs and statics for symbols which match. */ - for_each_symtab (current_program_space, srcfile, [&] (symtab *s) + for_each_symtab (current_program_space, srcfile, -1, [&] (symtab *s) { add_symtab_completions (s->compunit (), tracker, mode, lookup_name, diff --git a/gdb/symtab.h b/gdb/symtab.h index 3feac5fcf6c..f73aedd9c02 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -2074,7 +2074,8 @@ const char *multiple_symbols_select_mode (void); /* Lookup a symbol table in PSPACE by source file name. */ -extern symtab *lookup_symtab (program_space *pspace, const char *name); +extern symtab *lookup_symtab (program_space *pspace, const char *name, + LONGEST linker_ns = -1); /* An object of this type is passed as the 'is_a_field_of_this' argument to lookup_symbol and lookup_symbol_in_language. */ @@ -2806,6 +2807,7 @@ using for_each_symtab_callback_ftype = std::function; Call CALLBACK with each symtab that is found. */ void for_each_symtab (program_space *pspace, const char *name, + LONGEST linker_ns, for_each_symtab_callback_ftype callback); /* Callback type for function find_symtab. */ diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c index 02b2bbe6417..35c5124a65e 100644 --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c @@ -24,6 +24,8 @@ #include #include +int global_main_file = 1312; + int main (void) { diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp index 72b92304325..78daed4518e 100644 --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp @@ -321,9 +321,15 @@ proc_with_prefix test_print_namespace_symbol {} { clean_restart gdb_load $::binfile + set ns0 [ns_id_for_command 0] set ns1 [ns_id_for_command 1] set ns2 [ns_id_for_command 2] + # Test printing variables before starting the inferior + gdb_test "print ${ns1}::gdb_dlmopen_glob" \ + "Linker namespaces require an active inferior" \ + "Before starting inferior" + if { ![runto_main] } { return } @@ -355,12 +361,27 @@ proc_with_prefix test_print_namespace_symbol {} { gdb_test "print ${ns2}::func_with_other_call::n" \ "No frame is currently executing in block func_with_other_call." + # Test that complex expressions work with multiple namespaces. + # At this point, the global in namespace 1 is 0, and in namespace 2 is 1 + # and the current namespace is 1. + gdb_test "print ${ns2}::gdb_dlmopen_glob + gdb_dlmopen_glob" ".* = 1" + gdb_test "print ${ns2}::'${::srcfile_lib}'::gdb_dlmopen_glob + gdb_dlmopen_glob" \ + ".* = 1" + gdb_test "print ${ns2}::'${::srcfile_lib}'::gdb_dlmopen_glob + '${::srcfile}'::global_main_file" \ + ".* = 1312" + # Leave to default namespace. gdb_continue_to_breakpoint "TAG: first dlclose" # This global doesn't exist in the default namespace. Rather than # returning a random one, we just say we didn't find one. gdb_test "print gdb_dlmopen_glob" \ "No symbol .gdb_dlmopen_glob. in the current linker namespace." + + # Minimal testing for finding files in namespaces. + gdb_test "print ${ns1}::'${::srcfile_lib}'::gdb_dlmopen_glob" \ + ".* = 2" + gdb_test "print ${ns0}::'${::srcfile_lib}'::gdb_dlmopen_glob" \ + "Nothing named .${::srcfile_lib}. in specified context." } test_info_shared From patchwork Mon Jun 1 19:22:51 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 136207 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CC39D4BA2E27 for ; Mon, 1 Jun 2026 19:25:55 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CC39D4BA2E27 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=eNTXcMmN X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id E9E824BA5439 for ; Mon, 1 Jun 2026 19:23:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E9E824BA5439 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 E9E824BA5439 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780341829; cv=none; b=WtY99CIt4mBDQWKzklOnfZ/1g4829ZSpojm+xYzy6y0CksqVcRFtsB7QjgsNHsgkufyKrbAa/KxKhrH06eIDx1hOpONd8HY9GJZtI4PZtJuXIGXR8eOrwG2ZRpcNEK7MgybO7EfJu7Yan34pKRiLbWbpEK3LS21vT8+teJsSQQ4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780341829; c=relaxed/simple; bh=i78crdmJNXtiGyrgNijpT3D1vc9wcFJbmS/qj/FIGtE=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=ktIYQCD1wOiJ81ga+YwtQmboJTec9F1+vHG5usWa4oVG9d7ymEZDucxPK6Ktw2D7ENr5MdiuyU7kifSeNq5A4LV/m4VUyLFSBHbxhjMrKKZn9fDhq7A0iFBNISD+MO2ovLioCAJisp3lC1nZmejMPJ0iB04KQIDzBXG2wHgxAu4= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=eNTXcMmN DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E9E824BA5439 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780341828; 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=lRVmCNVraIZeQNz/ai0nXmv9uaOcm9xDLalXCrZVLoU=; b=eNTXcMmN1hv4o8p9CJO5ZoYTEKADEnc0+aXYuGBORO9amnzcYcPDJebjy1Q/FhS7CckJfL o3yVcwYUfTaqlHKU7qPhicTkxjDK2m6DiXbebES0VuvDCkubaIMNDLsfK7QqNov/g++EpP FfAEdWllZG4btUc8wXC+bn/B7/ZH8nE= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-36-du1nv7IJNnq6J94syP4mdA-1; Mon, 01 Jun 2026 15:23:46 -0400 X-MC-Unique: du1nv7IJNnq6J94syP4mdA-1 X-Mimecast-MFC-AGG-ID: du1nv7IJNnq6J94syP4mdA_1780341825 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 966B918005B6 for ; Mon, 1 Jun 2026 19:23:45 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.144]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 3BA2A19560A6; Mon, 1 Jun 2026 19:23:43 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH v7 5/5] gdb: prefer symtabs for the current linker namespace Date: Mon, 1 Jun 2026 16:22:51 -0300 Message-ID: <20260601192251.60958-6-guinevere@redhat.com> In-Reply-To: <20260601192251.60958-1-guinevere@redhat.com> References: <20260601192251.60958-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: nWSeCvWc2LQ4cQel6NMuH-oqZBCO6bW5RFmcC6P9wlY_1780341825 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-12.8 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_BLOCKED, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org When a user uses the syntax 'filename'::expression, GDB will search symtabs in the order they were loaded by the inferior. This can lead to situations where the following happens: (gdb) p $_linker_namespace $1 = 3 (gdb) p [[1]]::gdb_dlmopen_glob = 1 $2 = 1 (gdb) p [[2]]::gdb_dlmopen_glob = 2 $3 = 2 (gdb) p [[3]]::gdb_dlmopen_glob = 3 $4 = 3 (gdb) p gdb_dlmopen_glob == 'dlmopen-ns-ids-lib.c'::gdb_dlmopen_glob $5 = 0 (gdb) p gdb_dlmopen_glob $6 = 3 (gdb) p 'dlmopen-ns-ids-lib.c'::gdb_dlmopen_glob $7 = 1 As a user, I would expect the expressions with and without the filename returned the exact same variable. As mentioned, because the library was loaded on namespace 1 first, that symtab is loaded first. This commit solves that issue by placing a copy of all symtabs in the current namespace first, and then adding all solibs. This can lead to a performance loss if the user is in namespace N and the symtab they are looking for is after all symtabs in namespace N, because all those symtabs will be searched first. However, I believe this is not a big concern, as I imagine most of the times that this syntax will be used, the user will either search for a symtab in the current namespace or the default one, meaning there is little chance that this will be very noticeable. This could be avoided by creating a set of the symtabs on the current namespace, and then when adding all symtabs, not re-adding ones that were there already, but this seems like too much complexity for an edge case. --- gdb/symtab.c | 4 ++++ gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 +++ gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 9 +++++++++ 3 files changed, 16 insertions(+) diff --git a/gdb/symtab.c b/gdb/symtab.c index d7317a758b1..b5ef0ddc147 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -655,6 +655,10 @@ find_symtab (program_space *pspace, const char *name, } else { + if (pspace->solib_ops ()->supports_namespaces ()) + objfiles_to_search + = get_objfiles_in_linker_namespace (get_current_linker_namespace (), + pspace); for (objfile &objf : pspace->objfiles ()) objfiles_to_search.push_back (&objf); } diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c index 35c5124a65e..012decc25e5 100644 --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c @@ -52,6 +52,9 @@ main (void) fun = dlsym (handle[0], "func_with_other_call"); fun (0); + fun = dlsym (handle[2], "func_with_other_call"); + fun (0); + dlclose (handle[0]); /* TAG: first dlclose */ dlclose (handle[1]); /* TAG: second dlclose */ dlclose (handle[2]); /* TAG: third dlclose */ diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp index 78daed4518e..9c9f97e6887 100644 --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp @@ -370,6 +370,15 @@ proc_with_prefix test_print_namespace_symbol {} { gdb_test "print ${ns2}::'${::srcfile_lib}'::gdb_dlmopen_glob + '${::srcfile}'::global_main_file" \ ".* = 1312" + gdb_continue_to_breakpoint "change_global in namespace 2" + # GDB would find symtabs in load order, ignoring the current linker namespace. + # This test ensures that we prefer the symtabs in the namespace in the current + # point of execution instead. + gdb_test "print gdb_dlmopen_glob == '${::srcfile_lib}'::gdb_dlmopen_glob" \ + ".* = 1" "symtab prioritizes the current namespace" + gdb_test "print &gdb_dlmopen_glob == &'${::srcfile_lib}'::gdb_dlmopen_glob" \ + ".* = 1" "Double checking with addresses" + # Leave to default namespace. gdb_continue_to_breakpoint "TAG: first dlclose" # This global doesn't exist in the default namespace. Rather than