Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH v7] gdb: Print linker namespace when showing a frame
@ 2026-01-13 17:43 Guinevere Larsen
  2026-01-13 20:08 ` Eli Zaretskii
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Guinevere Larsen @ 2026-01-13 17:43 UTC (permalink / raw)
  To: gdb-patches; +Cc: Guinevere Larsen

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 <CORE_ADDR> 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 <CORE_ADDR> 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 <http://www.gnu.org/licenses/>.
+
+
+# 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


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v7] gdb: Print linker namespace when showing a frame
  2026-01-13 17:43 [PATCH v7] gdb: Print linker namespace when showing a frame Guinevere Larsen
@ 2026-01-13 20:08 ` Eli Zaretskii
  2026-03-05 12:18 ` [PING][PATCH " Guinevere Larsen
  2026-04-20 16:28 ` [PATCH " Andrew Burgess
  2 siblings, 0 replies; 5+ messages in thread
From: Eli Zaretskii @ 2026-01-13 20:08 UTC (permalink / raw)
  To: Guinevere Larsen; +Cc: gdb-patches

> From: Guinevere Larsen <guinevere@redhat.com>
> Cc: Guinevere Larsen <guinevere@redhat.com>
> Date: Tue, 13 Jan 2026 14:43:41 -0300
> 
> 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

OK for the documentation parts, thanks.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PING][PATCH v7] gdb: Print linker namespace when showing a frame
  2026-01-13 17:43 [PATCH v7] gdb: Print linker namespace when showing a frame Guinevere Larsen
  2026-01-13 20:08 ` Eli Zaretskii
@ 2026-03-05 12:18 ` Guinevere Larsen
  2026-04-20 16:28 ` [PATCH " Andrew Burgess
  2 siblings, 0 replies; 5+ messages in thread
From: Guinevere Larsen @ 2026-03-05 12:18 UTC (permalink / raw)
  To: gdb-patches, Guinevere Larsen

Ping :)

On 1/13/26 2:43 PM, Guinevere Larsen wrote:
> 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 <CORE_ADDR> 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 <CORE_ADDR> 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 <http://www.gnu.org/licenses/>.
> +
> +
> +# 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


-- 
Cheers,
Guinevere Larsen
It/she


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v7] gdb: Print linker namespace when showing a frame
  2026-01-13 17:43 [PATCH v7] gdb: Print linker namespace when showing a frame Guinevere Larsen
  2026-01-13 20:08 ` Eli Zaretskii
  2026-03-05 12:18 ` [PING][PATCH " Guinevere Larsen
@ 2026-04-20 16:28 ` Andrew Burgess
  2026-05-06 20:07   ` Guinevere Larsen
  2 siblings, 1 reply; 5+ messages in thread
From: Andrew Burgess @ 2026-04-20 16:28 UTC (permalink / raw)
  To: Guinevere Larsen, gdb-patches; +Cc: Guinevere Larsen

Guinevere Larsen <guinevere@redhat.com> writes:

> 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 ())

Missing space after 'ops'.

> +	  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 ());

Does this work?  The PRINT_NAME will have the namepsace prefix in place,
but doesn't cp_remove_params parse the name as a C++ symbol, so will
this correctly find and remove the parameters?

I haven't looked at the earlier versions, but I have a suspicion that
this might be me causing problems, as I think originally you were adding
the namespace-id as a prefix, and I pushed you to write
print_name_with_namespace.

Anyway, I think you should write a test to cover this case (C++ symbol
in a namespace) and see if this works, if not, then you might need to go
back to something more like your original approach, adding the namespace
prefix.

>  	}
>  
>        /* 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
>      {

This 'else' block looks up the funname via lookup_minimal_symbol_by_pc,
but doesn't add the namespace-id.  If we had code without debug in a
namespace, I think this is the path it would take, should we not be
displaying the id in this case?

This might be a good new test to add.

> @@ -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 <CORE_ADDR> pc,

GDB style is not to place a space before the template arguments.

> +						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;
> +}

Following on from an earlier thought, maybe this was a bad suggestion.
Maybe better would be just a function like 'linker_namespace_prefix_str'
which would return a std::string, either empty (no namespaces in use) or
'[[N]]::'.  Then this could be used though out GDB wherever we wish to
print the namespace?

> +
> +/* 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 <CORE_ADDR> pc, program_space *pspace);

Space before template arguments again.

> +
>    /* 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 <http://www.gnu.org/licenses/>.
> +
> +
> +# 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"

This change worries me a little.  The hope here is that having the [[0]]
appear will not cause problems for any MI consumers.  What if existing
MI frontends are looking up the function by name?

One possibility would be to add a new field to the stop event,
e.g. linker_nsid or similar.  How feasible do you think this might be?

>  
>      # Check that the dynamic linker has now been loaded multiple times.
>
> base-commit: 6b8fb74a9403092c4e4813c728e20ed10a84676f
> -- 
> 2.52.0

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v7] gdb: Print linker namespace when showing a frame
  2026-04-20 16:28 ` [PATCH " Andrew Burgess
@ 2026-05-06 20:07   ` Guinevere Larsen
  0 siblings, 0 replies; 5+ messages in thread
From: Guinevere Larsen @ 2026-05-06 20:07 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 2422 bytes --]

On 4/20/26 1:28 PM, Andrew Burgess wrote:
>> @@ -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 ());
> Does this work?  The PRINT_NAME will have the namepsace prefix in place,
> but doesn't cp_remove_params parse the name as a C++ symbol, so will
> this correctly find and remove the parameters?
>
> I haven't looked at the earlier versions, but I have a suspicion that
> this might be me causing problems, as I think originally you were adding
> the namespace-id as a prefix, and I pushed you to write
> print_name_with_namespace.
>
> Anyway, I think you should write a test to cover this case (C++ symbol
> in a namespace) and see if this works, if not, then you might need to go
> back to something more like your original approach, adding the namespace
> prefix.

You're correct, this does not work. However, I thought about it some 
more, and I think this is the wrong place to make this change anyway. I 
don't think we want to say that the function *name* includes the prefix.

So instead, I added a function that calculates and returns the 
identifier, then identified the callers that print the name directly, 
and made them call the function. This way, also, the python symbol.name 
and the guile equivalent won't be polluted by the linker namespace.

>
>>   	}
>>   
>>         /* 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
>>       {
> This 'else' block looks up the funname via lookup_minimal_symbol_by_pc,
> but doesn't add the namespace-id.  If we had code without debug in a
> namespace, I think this is the path it would take, should we not be
> displaying the id in this case?
>
> This might be a good new test to add.

Now that print_frame is calling it, instead of find_frame_funname, I 
don't think the existence of debug symbols no longer matters, so I won't 
be adding this test case, as it is redundant. v8 should be arriving on 
the list soon enough

-- 
Cheers,
Guinevere Larsen
It/she

[-- Attachment #2: Type: text/html, Size: 3261 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-05-06 20:08 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-13 17:43 [PATCH v7] gdb: Print linker namespace when showing a frame Guinevere Larsen
2026-01-13 20:08 ` Eli Zaretskii
2026-03-05 12:18 ` [PING][PATCH " Guinevere Larsen
2026-04-20 16:28 ` [PATCH " Andrew Burgess
2026-05-06 20:07   ` Guinevere Larsen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox