From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id sBdqM5eEZmnSnwEAWB0awg (envelope-from ) for ; Tue, 13 Jan 2026 12:44:55 -0500 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=JAcqp7i8; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id C1FA61E0BA; Tue, 13 Jan 2026 12:44:55 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 710E71E08D for ; Tue, 13 Jan 2026 12:44:54 -0500 (EST) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id EABB74BA2E2E for ; Tue, 13 Jan 2026 17:44:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org EABB74BA2E2E 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=JAcqp7i8 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 C08A54BA2E1C for ; Tue, 13 Jan 2026 17:44:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C08A54BA2E1C 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 C08A54BA2E1C 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=1768326265; cv=none; b=nBidDSp22RMkuY0puRRMpI4avGXqWAehzt9b5on04YbFblmWoeuRqTNYWprydjiyF2VpK8sSWa+wzKsJEAAbDZHaLz1WFl1ete/4cOXUdogsMUpN7dFawQ5cvX2Vbs8xQf0o9ZXvr2SKQAU4LmvA2w2u0QLM7/nC2SQlomo+pmE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1768326265; c=relaxed/simple; bh=2wASPJhNUGuddIjWnM+TiX5h/rA/4M69FP9Zd421c4U=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Ao582i2mjPWHrailbMLZIkVBkF7/2Yi+SkOOeyVYb/lk8rfBPVzUyTo5MIYEQ2O5+KoTHAZlRqbXLwkCRa+qmxw70XliX6ABGvvg1+Y/kXBs6AdaRCoDebX6RqcBfu773+VgNArZyvCetNtlxlE8Bl7ZhZ/eCPWpnVy2RInkCD8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C08A54BA2E1C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1768326265; 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; bh=yzC0upLlm0XY3dwmQcfymz2TL6/bb0wlTPIPd97UUwI=; b=JAcqp7i886X6O+em12E6IrnQ0mJdGEqWyjgQ1jgdAPzOV1+EtNQeuvP3YKx9fu5GyTq5Jo sM+cc//WmEiV2EupduyLD65WrYQ+MoPWj5U/9o83e3S3UiL5nNlvDKVRY/B6Ni+tdzZNFj ARXni+c0FNAvr2QiBEkiPa37zoTj8z0= 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-657-LJo7t1DNMRe7UGP0sBZaNw-1; Tue, 13 Jan 2026 12:44:23 -0500 X-MC-Unique: LJo7t1DNMRe7UGP0sBZaNw-1 X-Mimecast-MFC-AGG-ID: LJo7t1DNMRe7UGP0sBZaNw_1768326263 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 E20E518005B6 for ; Tue, 13 Jan 2026 17:44:22 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.113]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 867DE19560B2; Tue, 13 Jan 2026 17:44:21 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH v7] gdb: Print linker namespace when showing a frame Date: Tue, 13 Jan 2026 14:43:41 -0300 Message-ID: <20260113174341.3532973-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: PTT9ZA99DWzujLq9gpVpOToNRb6HTa43G8eX0I9v4YM_1768326263 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true 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~public-inbox=simark.ca@sourceware.org When a user is stopped in a private linker namespace, the only way for them to realize that is using the _linker_namespace convenience variable. While serviceable, this is a sub-optimal solution, as most users are unaware of convenience variables. This commit introduces a new way for users to be informed of the linker namespace of a function, by printing it along with the function name. This is done by using the proposed syntax for symbols and locations, like so: #0 [[0]]::main () This is done by introducing a new method to general_symbol_info, which uses part of the functionality behind the _linker_namespace variable , namely, find the linker namespace that contains the given address on the given program space. The reason print_name was not changed to do this is that the old method returns a "const char *", but the new one needs to return a string, and the refactor was very complicated, so the new method is introduced. The namespace ID is only printed if multiple namespaces are active, otherwise no change in behavior is expected. This commit also updates the test gdb.base/dlmopen-ns-ids.exp to test this functionality. --- gdb/NEWS | 4 +++ gdb/doc/gdb.texinfo | 9 ++++++ gdb/solib.c | 29 ++++++++++------- gdb/solib.h | 8 +++++ gdb/stack.c | 9 ++++-- gdb/symtab.c | 15 +++++++++ gdb/symtab.h | 13 ++++++-- .../gdb.base/dlmopen-ns-ids-framefilter.py | 31 +++++++++++++++++++ gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 25 +++++++++++++-- gdb/testsuite/gdb.mi/mi-dlmopen.exp | 2 +- 10 files changed, 125 insertions(+), 20 deletions(-) create mode 100644 gdb/testsuite/gdb.base/dlmopen-ns-ids-framefilter.py diff --git a/gdb/NEWS b/gdb/NEWS index cd0303fa199..80dfc25f824 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -54,6 +54,10 @@ on the index. Any existing indexes should be regenerated. * Support for Floating Point Mode Register (FPMR) in AArch64. +* When debugging an inferior with multiple linker namespaces, functions + will be printed like so [[N]]::foo, where N is the namespace that + contains foo. For example [[0]]::main. + * New targets GNU/Linux/MicroBlaze (gdbserver) microblazeel-*linux* diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 7059f73935c..d18710ca273 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -22406,6 +22406,15 @@ possibility that those objects may cross-talk. Each set of isolated shared objects is said to belong to a ``namespace'', and linker related actions such as relocations do not cross namespace boundaries. +When multiple linker namespaces are active, @value{GDBN} will print the +identifier of the namespace that contains the function, when a function +is printed. It will look like this: + +@smallexample +#0 [[1]]::inc (n=0) at dlmopen-ns-ids-lib.c +#1 0x0000000000400591 in [[0]]::main () at dlmopen-ns-ids-main.c +@end smallexample + @kindex info dll @item info dll @var{regex} This is an alias of @code{info sharedlibrary}. diff --git a/gdb/solib.c b/gdb/solib.c index 492ff5580c9..a3e40940ddd 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -1825,6 +1825,22 @@ solib_linker_namespace_count (program_space *pspace) return 0; } +/* See solib.h. */ + +int +linker_namespace_for_addr (CORE_ADDR addr, program_space *pspace) +{ + for (const solib &so : pspace->solibs ()) + if (solib_contains_address_p (so, addr)) + { + if (so.ops().supports_namespaces ()) + return so.ops ().find_solib_ns (so); + break; + } + + return 0; +} + /* Implementation of the linker_namespace convenience variable. This returns the GDB internal identifier of the linker namespace, @@ -1833,19 +1849,10 @@ solib_linker_namespace_count (program_space *pspace) static value * linker_namespace_make_value (gdbarch *gdbarch, internalvar *var, - void *ignore) + void *ignore) { - int nsid = 0; CORE_ADDR curr_pc = get_frame_pc (get_selected_frame ()); - - for (const solib &so : current_program_space->solibs ()) - if (solib_contains_address_p (so, curr_pc)) - { - if (so.ops ().supports_namespaces ()) - nsid = so.ops ().find_solib_ns (so); - - break; - } + int nsid = linker_namespace_for_addr (curr_pc, current_program_space); /* If the PC is not in an SO, or the solib_ops doesn't support linker namespaces, the inferior is in the default namespace. */ diff --git a/gdb/solib.h b/gdb/solib.h index 4709669c54e..48cc709f2de 100644 --- a/gdb/solib.h +++ b/gdb/solib.h @@ -335,6 +335,14 @@ extern const char *solib_name_from_address (struct program_space *, CORE_ADDR); extern bool solib_contains_address_p (const solib &, CORE_ADDR); +/* Given the address ADDR, return which linker namespace contains + this address in PSPACE. If ADDR is present in multiple namespaces, + an arbitrary one is returned. If ADDR is not present in any + namespace, or if the target doesn't support linker namespaces, + returns 0. */ + +extern int linker_namespace_for_addr (CORE_ADDR addr, program_space *pspace); + /* Return whether the data starting at VADDR, size SIZE, must be kept in a core file for shared libraries loaded before "gcore" is used to be handled correctly when the core file is loaded. This only diff --git a/gdb/stack.c b/gdb/stack.c index 9d8e9da6aa8..bdfd41b7827 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -1276,7 +1276,9 @@ find_frame_funname (const frame_info_ptr &frame, enum language *funlang, func = get_frame_function (frame); if (func) { - const char *print_name = func->print_name (); + std::string print_name + = func->print_name_with_namespace (get_frame_pc_if_available (frame), + get_frame_program_space (frame)); *funlang = func->language (); if (funcp) @@ -1288,13 +1290,13 @@ find_frame_funname (const frame_info_ptr &frame, enum language *funlang, stored in the symbol table, but we stored a version with DMGL_PARAMS turned on, and here we don't want to display parameters. So remove the parameters. */ - funname = cp_remove_params (print_name); + funname = cp_remove_params (print_name.c_str ()); } /* If we didn't hit the C++ case above, set *funname here. */ if (funname == NULL) - funname.reset (xstrdup (print_name)); + funname.reset (xstrdup (print_name.c_str ())); } else { @@ -1362,6 +1364,7 @@ print_frame (struct ui_out *uiout, annotate_frame_function_name (); string_file stb; + gdb_puts (funname ? funname.get () : "??", &stb); uiout->field_stream ("func", stb, function_name_style.style ()); uiout->wrap_hint (3); diff --git a/gdb/symtab.c b/gdb/symtab.c index 63505a94d41..bf4c3c7183f 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -756,6 +756,21 @@ gdb_mangle_name (struct type *type, int method_id, int signature_id) /* See symtab.h. */ +std::string +general_symbol_info::print_name_with_namespace (std::optional pc, + program_space *pspace) +{ + std::string name = print_name (); + if (pc.has_value () + && solib_linker_namespace_count (pspace) > 1) + return string_printf + ("[[%d]]::%s", linker_namespace_for_addr (*pc, pspace), + name.c_str ()); + return name; +} + +/* See symtab.h. */ + void general_symbol_info::set_demangled_name (const char *name, struct obstack *obstack) diff --git a/gdb/symtab.h b/gdb/symtab.h index b771851f03a..4b0e21c4cee 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -448,9 +448,10 @@ struct general_symbol_info /* Short version as to when to use which name accessor: Use natural_name () to refer to the name of the symbol in the original source code. Use linkage_name () if you want to know what the linker - thinks the symbol's name is. Use print_name () for output. Use - demangled_name () if you specifically need to know whether natural_name () - and linkage_name () are different. */ + thinks the symbol's name is. Use print_name_with_namespace () for most + output. Use print_name () if you have a reason to always omit the + namespace identifier. Use demangled_name () if you specifically need + to know whether natural_name () and linkage_name () are different. */ const char *linkage_name () const { return m_name; } @@ -470,6 +471,12 @@ struct general_symbol_info const char *print_name () const { return demangle ? natural_name () : linkage_name (); } + /* Similar to print_name, but may prefix the name of the symbol with the + linker namespace identifier, if the target supports it and the inferior + has more than one identifier loaded. */ + std::string print_name_with_namespace + (std::optional pc, program_space *pspace); + /* Return the demangled name for a symbol based on the language for that symbol. If no demangled name exists, return NULL. */ const char *demangled_name () const; diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-framefilter.py b/gdb/testsuite/gdb.base/dlmopen-ns-ids-framefilter.py new file mode 100644 index 00000000000..11d96fcfbc4 --- /dev/null +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-framefilter.py @@ -0,0 +1,31 @@ +# Copyright (C) 2026 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# This file is part of the GDB testsuite. It tests if printing the +# linker namespace id is affected by a null frame filter + +import gdb + + +class NullFilter: + def __init__(self): + self.name = "null filter" + self.priority = 100 + self.enabled = True + gdb.frame_filters[self.name] = self + + def filter(self, iterator): + return iterator diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp index e40bc213454..e9832664566 100644 --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp @@ -21,7 +21,7 @@ require allow_dlmopen_tests -standard_testfile -main.c -lib.c +standard_testfile -main.c -lib.c -framefilter.py set srcfile_lib $srcfile2 set so_name dlmopen-lib.so @@ -192,6 +192,11 @@ proc_with_prefix test_conv_vars {} { gdb_test "print \$_linker_namespace" ".* = 0" \ "Still in the default namespace" + # There should be no namespace ID visible, since there's + # only one namespace loaded. + gdb_test "backtrace" "\#0\\s+main .*" \ + "No namespace ID in backtrace" + gdb_breakpoint "inc" allow-pending gdb_breakpoint [gdb_get_line_number "TAG: first dlclose"] @@ -200,14 +205,30 @@ proc_with_prefix test_conv_vars {} { gdb_test "print \$_linker_namespace" ".* = $dl" \ "Verify we're in namespace $dl" + + gdb_test "frame" "\#0\\s+\\\[\\\[$dl\\\]\\\]::inc.*" \ + "Namespace ID in the frame" } # Check that we display the namespace of the selected # frame, not the lowermost one. - gdb_test "up" "\#1.*in main.*" + gdb_test "up" "\#1.*in \\\[\\\[0\\\]\\\]::main.*" gdb_test "print \$_linker_namespace" ".* = 0" \ "print namespace of selected frame" + gdb_test "backtrace" [multi_line \ + "\#0\\s+\\\[\\\[1\\\]\\\]::inc \[^\r\n\]*" \ + "\#1\\s+$::hex in \\\[\\\[0\\\]\\\]::main \[^\r\n\]*" ] \ + "raw backtrace" + + set remote_python_file [gdb_remote_download host \ + $::srcdir/$::subdir/$::srcfile3] + gdb_test_no_output "source $remote_python_file" "load frame filter" + gdb_test "backtrace" [multi_line \ + "\#0\\s+\\\[\\\[1\\\]\\\]::inc \[^\r\n\]*" \ + "\#1\\s+$::hex in \\\[\\\[0\\\]\\\]::main \[^\r\n\]*" ] \ + "With null frame filter" + gdb_continue_to_breakpoint "first dlclose" gdb_test "print \$_linker_namespace_count" "4" "all SOs loaded" diff --git a/gdb/testsuite/gdb.mi/mi-dlmopen.exp b/gdb/testsuite/gdb.mi/mi-dlmopen.exp index ff854ac7dd4..832c6ea6fe6 100644 --- a/gdb/testsuite/gdb.mi/mi-dlmopen.exp +++ b/gdb/testsuite/gdb.mi/mi-dlmopen.exp @@ -156,7 +156,7 @@ proc check_solib_unload_events {} { -disp keep -func main -file ".*$::srcfile" -line $::bp_main # Run past all the dlopen and dlmopen calls. - mi_execute_to "exec-continue" "breakpoint-hit" main "" ".*" $::bp_loaded \ + mi_execute_to "exec-continue" "breakpoint-hit" {\[\[0\]\]::main} "" ".*" $::bp_loaded \ {"" "disp=\"keep\""} "continue until all libraries are loaded" # Check that the dynamic linker has now been loaded multiple times. base-commit: 6b8fb74a9403092c4e4813c728e20ed10a84676f -- 2.52.0