Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution
@ 2026-02-13  5:38 simon.marchi
  2026-02-13  5:38 ` [PATCH 2/4] gdb/elfread: replace ifunc htab_t with gdb::unordered_map simon.marchi
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: simon.marchi @ 2026-02-13  5:38 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@polymtl.ca>

Add some debug prints throughout the ifunc resolution code, to be able
to better understand what GDB does.  Add the new "set debug gnu-ifunc"
knob to control it.

Add the debug_prefixed_printf_cond_func macro to implement
gnu_ifunc_debug_printf_func, that takes an explicit function name.  This
is needed to avoid showing "operator()" as the function name in the
debug message.

Here is a sample session with the new debug output enabled.

    (gdb) b the_function
    [gnu-ifunc] elf_gnu_ifunc_resolve_name: resolving name "the_function"
    [gnu-ifunc] elf_gnu_ifunc_resolve_by_cache: resolving "the_function" by cache
    [gnu-ifunc] elf_gnu_ifunc_resolve_by_cache: cache miss for "the_function"
    [gnu-ifunc] elf_gnu_ifunc_resolve_by_got: resolving "the_function" by GOT
    [gnu-ifunc] elf_gnu_ifunc_resolve_by_got: GOT entry "the_function@got.plt" points to 0x7ffff7fb7036
    [gnu-ifunc] elf_gnu_ifunc_record_cache: recording cache entry for "the_function" at 0x7ffff7fb7036
    [gnu-ifunc] elf_gnu_ifunc_record_cache: minimal symbol "the_function@plt" at 0x7ffff7fb7030 does not match addr 0x7ffff7fb7036, not caching
    [gnu-ifunc] elf_gnu_ifunc_resolve_by_got: GOT entry "the_function@got.plt" points to 0x7ffff7fb2036
    [gnu-ifunc] elf_gnu_ifunc_record_cache: recording cache entry for "the_function" at 0x7ffff7fb2036
    [gnu-ifunc] elf_gnu_ifunc_record_cache: minimal symbol "the_function@plt" at 0x7ffff7fb2030 does not match addr 0x7ffff7fb2036, not caching
    [gnu-ifunc] elf_gnu_ifunc_resolve_by_got: failed to resolve "the_function" by GOT
    [gnu-ifunc] elf_gnu_ifunc_resolve_name: failed to resolve name "the_function"
    Breakpoint 2 at gnu-indirect-function resolver at 0x7ffff7fa80e9
    (gdb) c
    Continuing.
    [gnu-ifunc] elf_gnu_ifunc_resolver_stop: stop on resolver for "the_function"
    [gnu-ifunc] elf_gnu_ifunc_resolver_stop: created resolver return breakpoint at 0x7ffff7fd7186
    [gnu-ifunc] elf_gnu_ifunc_resolver_return_stop: stop on resolver return
    [gnu-ifunc] elf_gnu_ifunc_resolver_return_stop: resolver for "the_function" returned resolved address=0x7ffff7fad0e9, resolved pc=0x7ffff7fad0e9
    [gnu-ifunc] elf_gnu_ifunc_record_cache: recording cache entry for "the_function" at 0x7ffff7fad0e9
    [gnu-ifunc] elf_gnu_ifunc_record_cache: cached "the_function" -> 0x7ffff7fad0e9 in objfile /home/simark/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/ifunc-resolver/libimpl.so

    Breakpoint 2, the_function_impl_0 (caller_id=1) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.base/ifunc-resolver-libimpl.c:25
    25        the_function_last_caller_id = caller_id; /* break-in-impl */

Change-Id: I64f667e3457feaedfe9bb530de58faaf22545fa5
---
 gdb/NEWS                  |   4 ++
 gdb/doc/gdb.texinfo       |   6 +++
 gdb/elfread.c             | 110 +++++++++++++++++++++++++++++++++++---
 gdbsupport/common-debug.h |   9 ++++
 4 files changed, 123 insertions(+), 6 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index fa6e7ca61219..1957e63eae44 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -85,6 +85,10 @@ maintenance test-remote-args ARGS
   Test splitting and joining of inferior arguments ARGS as they would
   be split and joined when being passed to a remote target.
 
+set debug gnu-ifunc on|off
+show debug gnu-ifunc
+  Turn on or off debug messages related to GNU ifunc resolution.
+
 set progress-bars enabled on|off
 show progress-bars enabled
   Allows the progress bars, used when debuginfod is downloading
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5169be1965c5..c614e93b812e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -29331,6 +29331,12 @@ default is off.
 Displays the current state of displaying @value{GDBN} frame debugging
 info.
 
+@cindex GNU ifunc debug messages
+@item set debug gnu-ifunc
+Turn on or off debugging messages related to GNU ifunc resolution.
+@item show debug gnu-ifunc
+Show the current state of GNU ifunc resolution debugging messages.
+
 @item set debug gnu-nat
 @cindex @sc{gnu}/Hurd debug messages
 Turn on or off debugging messages from the @sc{gnu}/Hurd debug support.
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 722f21bf7753..61dd8ad260ba 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -47,6 +47,23 @@
 /* Whether ctf should always be read, or only if no dwarf is present.  */
 static bool always_read_ctf;
 
+/* Value of the 'set debug gnu-ifunc' configuration variable.  */
+static bool debug_gnu_ifunc;
+
+static void
+show_debug_gnu_ifunc (struct ui_file *file, int from_tty,
+		      struct cmd_list_element *c, const char *value)
+{
+  gdb_printf (file, _("gnu-ifunc debugging is %s.\n"), value);
+}
+
+#define gnu_ifunc_debug_printf(fmt, ...) \
+  debug_prefixed_printf_cond (debug_gnu_ifunc, "gnu-ifunc", fmt, ##__VA_ARGS__)
+
+#define gnu_ifunc_debug_printf_func(func, fmt, ...)			    \
+  debug_prefixed_printf_cond_func (debug_gnu_ifunc, "gnu-ifunc", func, fmt, \
+				   ##__VA_ARGS__)
+
 /* The struct elfinfo is available only during ELF symbol table and
    psymtab reading.  It is destroyed at the completion of psymtab-reading.
    It's local to elf_symfile_read.  */
@@ -695,11 +712,28 @@ elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr)
   struct elf_gnu_ifunc_cache entry_local, *entry_p;
   void **slot;
 
+  gnu_ifunc_debug_printf ("recording cache entry for \"%s\" at %s",
+			  name, paddress (current_inferior ()->arch (), addr));
+
   bound_minimal_symbol msym = lookup_minimal_symbol_by_pc (addr);
   if (msym.minsym == NULL)
-    return 0;
+    {
+      gnu_ifunc_debug_printf ("no minimal symbol found at %s, not caching",
+			      paddress (current_inferior ()->arch (), addr));
+      return 0;
+    }
+
   if (msym.value_address () != addr)
-    return 0;
+    {
+      gnu_ifunc_debug_printf ("minimal symbol \"%s\" at %s does not match "
+			      "addr %s, not caching",
+			      msym.minsym->linkage_name (),
+			      paddress (current_inferior ()->arch (),
+					msym.value_address ()),
+			      paddress (current_inferior ()->arch (), addr));
+      return 0;
+    }
+
   objfile = msym.objfile;
 
   /* If .plt jumps back to .plt the symbol is still deferred for later
@@ -711,10 +745,18 @@ elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr)
      symbol is in the .plt section because some systems have @plt
      symbols in the .text section.  */
   if (len > 4 && strcmp (target_name + len - 4, "@plt") == 0)
-    return 0;
+    {
+      gnu_ifunc_debug_printf ("target \"%s\" is a PLT stub, not caching",
+			      target_name);
+      return 0;
+    }
 
   if (strcmp (target_name, "_PROCEDURE_LINKAGE_TABLE_") == 0)
-    return 0;
+    {
+      gnu_ifunc_debug_printf ("target is _PROCEDURE_LINKAGE_TABLE_, "
+			      "not caching");
+      return 0;
+    }
 
   htab = elf_objfile_gnu_ifunc_cache_data.get (objfile);
   if (htab == NULL)
@@ -754,6 +796,9 @@ elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr)
     }
   *slot = entry_p;
 
+  gnu_ifunc_debug_printf ("cached \"%s\" -> %s in objfile %s",
+			  name, paddress (objfile->arch (), addr),
+			  objfile_name (objfile));
   return 1;
 }
 
@@ -767,6 +812,7 @@ elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr)
 static int
 elf_gnu_ifunc_resolve_by_cache (const char *name, CORE_ADDR *addr_p)
 {
+  gnu_ifunc_debug_printf ("resolving \"%s\" by cache", name);
   int found = 0;
 
   /* FIXME: we only search the initial namespace.
@@ -797,10 +843,17 @@ elf_gnu_ifunc_resolve_by_cache (const char *name, CORE_ADDR *addr_p)
 	 if (addr_p)
 	   *addr_p = entry_p->addr;
 
+	 gnu_ifunc_debug_printf ("cache hit for \"%s\" -> %s in objfile %s",
+				 name,
+				 paddress (objfile->arch (), entry_p->addr),
+				 objfile_name (objfile));
 	 found = 1;
 	 return 1;
        }, nullptr);
 
+  if (!found)
+    gnu_ifunc_debug_printf ("cache miss for \"%s\"", name);
+
   return found;
 }
 
@@ -815,9 +868,11 @@ elf_gnu_ifunc_resolve_by_cache (const char *name, CORE_ADDR *addr_p)
 static int
 elf_gnu_ifunc_resolve_by_got (const char *name, CORE_ADDR *addr_p)
 {
+  gnu_ifunc_debug_printf ("resolving \"%s\" by GOT", name);
   char *name_got_plt;
   const size_t got_suffix_len = strlen (SYMBOL_GOT_PLT_SUFFIX);
   int found = 0;
+  const char *func = __func__;
 
   name_got_plt = (char *) alloca (strlen (name) + got_suffix_len + 1);
   sprintf (name_got_plt, "%s" SYMBOL_GOT_PLT_SUFFIX, name);
@@ -827,7 +882,7 @@ elf_gnu_ifunc_resolve_by_got (const char *name, CORE_ADDR *addr_p)
      To search other namespaces, we would need to provide context, e.g. in
      form of an objfile in that namespace.  */
   current_program_space->iterate_over_objfiles_in_search_order
-    ([name, name_got_plt, &addr_p, &found] (struct objfile *objfile)
+    ([name, name_got_plt, &addr_p, &found, func] (struct objfile *objfile)
        {
 	 bfd *obfd = objfile->obfd.get ();
 	 struct gdbarch *gdbarch = objfile->arch ();
@@ -859,11 +914,16 @@ elf_gnu_ifunc_resolve_by_got (const char *name, CORE_ADDR *addr_p)
 	   (gdbarch, addr, current_inferior ()->top_target ());
 	 addr = gdbarch_addr_bits_remove (gdbarch, addr);
 
+	 gnu_ifunc_debug_printf_func (func, "GOT entry \"%s\" points to %s",
+				      name_got_plt, paddress (gdbarch, addr));
+
 	 if (elf_gnu_ifunc_record_cache (name, addr))
 	   {
 	     if (addr_p != NULL)
 	       *addr_p = addr;
 
+	     gnu_ifunc_debug_printf ("resolved \"%s\" via GOT to %s",
+				     name, paddress (gdbarch, addr));
 	     found = 1;
 	     return 1;
 	   }
@@ -871,6 +931,9 @@ elf_gnu_ifunc_resolve_by_got (const char *name, CORE_ADDR *addr_p)
 	 return 0;
        }, nullptr);
 
+  if (!found)
+    gnu_ifunc_debug_printf ("failed to resolve \"%s\" by GOT", name);
+
   return found;
 }
 
@@ -884,17 +947,20 @@ elf_gnu_ifunc_resolve_by_got (const char *name, CORE_ADDR *addr_p)
 static bool
 elf_gnu_ifunc_resolve_name (const char *name, CORE_ADDR *addr_p)
 {
+  gnu_ifunc_debug_printf ("resolving name \"%s\"", name);
+
   if (elf_gnu_ifunc_resolve_by_cache (name, addr_p))
     return true;
 
   if (elf_gnu_ifunc_resolve_by_got (name, addr_p))
     return true;
 
+  gnu_ifunc_debug_printf ("failed to resolve name \"%s\"", name);
   return false;
 }
 
 /* Call STT_GNU_IFUNC - a function returning address of a real function to
-   call.  PC is theSTT_GNU_IFUNC resolving function entry.  The value returned
+   call.  PC is the STT_GNU_IFUNC resolving function entry.  The value returned
    is the entry point of the resolved STT_GNU_IFUNC target function to call.
    */
 
@@ -908,6 +974,8 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
   CORE_ADDR hwcap = 0;
   struct value *hwcap_val;
 
+  gnu_ifunc_debug_printf ("resolving ifunc %s", paddress (gdbarch, pc));
+
   /* Try first any non-intrusive methods without an inferior call.  */
 
   if (find_pc_partial_function (pc, &name_at_pc, &start_at_pc, NULL)
@@ -919,6 +987,9 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
   else
     name_at_pc = NULL;
 
+  gnu_ifunc_debug_printf ("resolving via inferior call to resolver at %s",
+			  paddress (gdbarch, pc));
+
   function = value::allocate (func_func_type);
   function->set_lval (lval_memory);
   function->set_address (pc);
@@ -936,6 +1007,10 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
     (gdbarch, address, current_inferior ()->top_target ());
   address = gdbarch_addr_bits_remove (gdbarch, address);
 
+  gnu_ifunc_debug_printf ("resolver at %s returned %s",
+			  paddress (gdbarch, pc),
+			  paddress (gdbarch, address));
+
   if (name_at_pc)
     elf_gnu_ifunc_record_cache (name_at_pc, address);
 
@@ -953,6 +1028,9 @@ elf_gnu_ifunc_resolver_stop (code_breakpoint *b)
   CORE_ADDR prev_pc = get_frame_pc (prev_frame);
   int thread_id = inferior_thread ()->global_num;
 
+  gnu_ifunc_debug_printf ("stop on resolver for \"%s\"",
+			  b->locspec->to_string ());
+
   gdb_assert (b->type == bp_gnu_ifunc_resolver);
 
   for (b_return = b->related_breakpoint; b_return != b;
@@ -983,12 +1061,17 @@ elf_gnu_ifunc_resolver_stop (code_breakpoint *b)
 				    prev_frame_id,
 				    bp_gnu_ifunc_resolver_return).release ();
 
+      gnu_ifunc_debug_printf ("created resolver return breakpoint at %s",
+			      paddress (get_frame_arch (prev_frame), prev_pc));
 
       /* Add new b_return to the ring list b->related_breakpoint.  */
       gdb_assert (b_return->related_breakpoint == b_return);
       b_return->related_breakpoint = b->related_breakpoint;
       b->related_breakpoint = b_return;
     }
+  else
+    gnu_ifunc_debug_printf ("found existing resolver return breakpoint at %s",
+			    paddress (get_frame_arch (prev_frame), prev_pc));
 }
 
 /* Handle inferior hit of bp_gnu_ifunc_resolver_return, see its definition.  */
@@ -1005,6 +1088,8 @@ elf_gnu_ifunc_resolver_return_stop (code_breakpoint *b)
   struct value *value;
   CORE_ADDR resolved_address, resolved_pc;
 
+  gnu_ifunc_debug_printf ("stop on resolver return");
+
   gdb_assert (b->type == bp_gnu_ifunc_resolver_return);
 
   while (b->related_breakpoint != b)
@@ -1040,6 +1125,12 @@ elf_gnu_ifunc_resolver_return_stop (code_breakpoint *b)
     (gdbarch, resolved_address, current_inferior ()->top_target ());
   resolved_pc = gdbarch_addr_bits_remove (gdbarch, resolved_pc);
 
+  gnu_ifunc_debug_printf ("resolver for \"%s\" returned resolved address=%s, "
+			  "resolved pc=%s",
+			  b->locspec->to_string (),
+			  paddress (gdbarch, resolved_address),
+			  paddress (gdbarch, resolved_pc));
+
   gdb_assert (current_program_space == b->pspace || b->pspace == NULL);
   elf_gnu_ifunc_record_cache (b->locspec->to_string (), resolved_pc);
 
@@ -1343,6 +1434,13 @@ INIT_GDB_FILE (elfread)
 
   gnu_ifunc_fns_p = &elf_gnu_ifunc_fns;
 
+  add_setshow_boolean_cmd
+    ("gnu-ifunc", class_maintenance, &debug_gnu_ifunc,
+     _("Set GNU ifunc debugging."),
+     _("Show GNU ifunc debugging."),
+     _("When on, debug output for GNU ifunc resolution is displayed."),
+     nullptr, show_debug_gnu_ifunc, &setdebuglist, &showdebuglist);
+
   /* Add "set always-read-ctf on/off".  */
   add_setshow_boolean_cmd ("always-read-ctf", class_support, &always_read_ctf,
 			   _("\
diff --git a/gdbsupport/common-debug.h b/gdbsupport/common-debug.h
index f0edd49faead..206a7c96dc1a 100644
--- a/gdbsupport/common-debug.h
+++ b/gdbsupport/common-debug.h
@@ -71,6 +71,15 @@ extern void ATTRIBUTE_PRINTF (3, 0) debug_prefixed_vprintf
     } \
   while (0)
 
+#define debug_prefixed_printf_cond_func(debug_enabled_cond, mod, func, fmt, \
+					...) \
+  do \
+    { \
+      if (debug_enabled_cond) \
+	debug_prefixed_printf (mod, func, fmt, ##__VA_ARGS__); \
+    } \
+  while (0)
+
 #define debug_prefixed_printf_cond_nofunc(debug_enabled_cond, mod, fmt, ...) \
   do \
     { \

base-commit: 3a862dc6c3da4214aa12d36d5fbc45a420fb40d5
-- 
2.53.0


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

* [PATCH 2/4] gdb/elfread: replace ifunc htab_t with gdb::unordered_map
  2026-02-13  5:38 [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution simon.marchi
@ 2026-02-13  5:38 ` simon.marchi
  2026-02-13  5:38 ` [PATCH 3/4] gdbsupport: add gdb::unordered_string_map simon.marchi
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: simon.marchi @ 2026-02-13  5:38 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@efficios.com>

Replace this htab_t with gdb::unordered_map.  No functional change
expected.

Change-Id: Icad43938f761a032b6a6257f4be0f4ab5c60661c
---
 gdb/elfread.c | 120 ++++++++++++--------------------------------------
 1 file changed, 27 insertions(+), 93 deletions(-)

diff --git a/gdb/elfread.c b/gdb/elfread.c
index 61dd8ad260ba..010744639118 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -43,6 +43,7 @@
 #include <string_view>
 #include "dwarf2/public.h"
 #include "cli/cli-cmds.h"
+#include "gdbsupport/unordered_map.h"
 
 /* Whether ctf should always be read, or only if no dwarf is present.  */
 static bool always_read_ctf;
@@ -657,44 +658,12 @@ elf_rel_plt_read (minimal_symbol_reader &reader,
     }
 }
 
-/* The data pointer is htab_t for gnu_ifunc_record_cache_unchecked.  */
+/* Per-objfile cache mapping function names to resolved ifunc addresses.  */
 
-static const registry<objfile>::key<htab, htab_deleter>
-  elf_objfile_gnu_ifunc_cache_data;
-
-/* Map function names to CORE_ADDR in elf_objfile_gnu_ifunc_cache_data.  */
-
-struct elf_gnu_ifunc_cache
-{
-  /* This is always a function entry address, not a function descriptor.  */
-  CORE_ADDR addr;
-
-  char name[1];
-};
-
-/* htab_hash for elf_objfile_gnu_ifunc_cache_data.  */
-
-static hashval_t
-elf_gnu_ifunc_cache_hash (const void *a_voidp)
-{
-  const struct elf_gnu_ifunc_cache *a
-    = (const struct elf_gnu_ifunc_cache *) a_voidp;
-
-  return htab_hash_string (a->name);
-}
-
-/* htab_eq for elf_objfile_gnu_ifunc_cache_data.  */
-
-static int
-elf_gnu_ifunc_cache_eq (const void *a_voidp, const void *b_voidp)
-{
-  const struct elf_gnu_ifunc_cache *a
-    = (const struct elf_gnu_ifunc_cache *) a_voidp;
-  const struct elf_gnu_ifunc_cache *b
-    = (const struct elf_gnu_ifunc_cache *) b_voidp;
+using elf_gnu_ifunc_cache = gdb::unordered_map<std::string, CORE_ADDR>;
 
-  return strcmp (a->name, b->name) == 0;
-}
+static const registry<objfile>::key<elf_gnu_ifunc_cache>
+  elf_objfile_gnu_ifunc_cache_data;
 
 /* Record the target function address of a STT_GNU_IFUNC function NAME is the
    function entry address ADDR.  Return 1 if NAME and ADDR are considered as
@@ -707,13 +676,8 @@ elf_gnu_ifunc_cache_eq (const void *a_voidp, const void *b_voidp)
 static int
 elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr)
 {
-  struct objfile *objfile;
-  htab_t htab;
-  struct elf_gnu_ifunc_cache entry_local, *entry_p;
-  void **slot;
-
-  gnu_ifunc_debug_printf ("recording cache entry for \"%s\" at %s",
-			  name, paddress (current_inferior ()->arch (), addr));
+  gnu_ifunc_debug_printf ("recording cache entry for \"%s\" at %s", name,
+			  paddress (current_inferior ()->arch (), addr));
 
   bound_minimal_symbol msym = lookup_minimal_symbol_by_pc (addr);
   if (msym.minsym == NULL)
@@ -734,7 +698,7 @@ elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr)
       return 0;
     }
 
-  objfile = msym.objfile;
+  objfile *objfile = msym.objfile;
 
   /* If .plt jumps back to .plt the symbol is still deferred for later
      resolution and it has no use for GDB.  */
@@ -758,43 +722,23 @@ elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr)
       return 0;
     }
 
-  htab = elf_objfile_gnu_ifunc_cache_data.get (objfile);
-  if (htab == NULL)
-    {
-      htab = htab_create_alloc (1, elf_gnu_ifunc_cache_hash,
-				elf_gnu_ifunc_cache_eq,
-				NULL, xcalloc, xfree);
-      elf_objfile_gnu_ifunc_cache_data.set (objfile, htab);
-    }
+  elf_gnu_ifunc_cache &cache
+    = elf_objfile_gnu_ifunc_cache_data.try_emplace (objfile);
 
-  entry_local.addr = addr;
-  obstack_grow (&objfile->objfile_obstack, &entry_local,
-		offsetof (struct elf_gnu_ifunc_cache, name));
-  obstack_grow_str0 (&objfile->objfile_obstack, name);
-  entry_p
-    = (struct elf_gnu_ifunc_cache *) obstack_finish (&objfile->objfile_obstack);
-
-  slot = htab_find_slot (htab, entry_p, INSERT);
-  if (*slot != NULL)
+  auto [it, inserted] = cache.emplace (name, addr);
+  if (!inserted && it->second != addr)
     {
-      struct elf_gnu_ifunc_cache *entry_found_p
-	= (struct elf_gnu_ifunc_cache *) *slot;
+      /* This case indicates buggy inferior program, the resolved
+	 address should never change.  */
       struct gdbarch *gdbarch = objfile->arch ();
 
-      if (entry_found_p->addr != addr)
-	{
-	  /* This case indicates buggy inferior program, the resolved address
-	     should never change.  */
-
-	    warning (_("gnu-indirect-function \"%s\" has changed its resolved "
-		       "function_address from %s to %s"),
-		     name, paddress (gdbarch, entry_found_p->addr),
-		     paddress (gdbarch, addr));
-	}
+      warning (_("gnu-indirect-function \"%s\" has changed its "
+		 "resolved function_address from %s to %s"),
+	       name, paddress (gdbarch, it->second),
+	       paddress (gdbarch, addr));
 
-      /* New ENTRY_P is here leaked/duplicate in the OBJFILE obstack.  */
+      it->second = addr;
     }
-  *slot = entry_p;
 
   gnu_ifunc_debug_printf ("cached \"%s\" -> %s in objfile %s",
 			  name, paddress (objfile->arch (), addr),
@@ -822,30 +766,20 @@ elf_gnu_ifunc_resolve_by_cache (const char *name, CORE_ADDR *addr_p)
   current_program_space->iterate_over_objfiles_in_search_order
     ([name, &addr_p, &found] (struct objfile *objfile)
        {
-	 htab_t htab;
-	 elf_gnu_ifunc_cache *entry_p;
-	 void **slot;
-
-	 htab = elf_objfile_gnu_ifunc_cache_data.get (objfile);
-	 if (htab == NULL)
+	 elf_gnu_ifunc_cache *cache
+	   = elf_objfile_gnu_ifunc_cache_data.get (objfile);
+	 if (cache == nullptr)
 	   return 0;
 
-	 entry_p = ((elf_gnu_ifunc_cache *)
-		    alloca (sizeof (*entry_p) + strlen (name)));
-	 strcpy (entry_p->name, name);
-
-	 slot = htab_find_slot (htab, entry_p, NO_INSERT);
-	 if (slot == NULL)
+	 auto it = cache->find (name);
+	 if (it == cache->end ())
 	   return 0;
-	 entry_p = (elf_gnu_ifunc_cache *) *slot;
-	 gdb_assert (entry_p != NULL);
 
-	 if (addr_p)
-	   *addr_p = entry_p->addr;
+	 if (addr_p != nullptr)
+	   *addr_p = it->second;
 
 	 gnu_ifunc_debug_printf ("cache hit for \"%s\" -> %s in objfile %s",
-				 name,
-				 paddress (objfile->arch (), entry_p->addr),
+				 name, paddress (objfile->arch (), it->second),
 				 objfile_name (objfile));
 	 found = 1;
 	 return 1;
-- 
2.53.0


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

* [PATCH 3/4] gdbsupport: add gdb::unordered_string_map
  2026-02-13  5:38 [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution simon.marchi
  2026-02-13  5:38 ` [PATCH 2/4] gdb/elfread: replace ifunc htab_t with gdb::unordered_map simon.marchi
@ 2026-02-13  5:38 ` simon.marchi
  2026-02-13  5:38 ` [PATCH 4/4] gdb: use gdb::unordered_string_map throughout simon.marchi
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: simon.marchi @ 2026-02-13  5:38 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@efficios.com>

It occurred to me that when we use a

    gdb::unordered_map<std::string, T>

we construct a temporary std::string for each lookup from a
`const char *`, possibly doing dynamic allocation.  This is really
unnecessary, because it's easy to compare an existing `const char *` (or
std::string_view) with an std::string.  This can therefore be avoided by
having transparent hash and eq types.

Because this is a common enough case, add it to
gdbsupport/unordered_map.h, so it can easily be reused.  Define the
gdb::unordered_string_map type, which uses hash and eq types that work
on std::string_view.  Both `const char *` and `std::string` can
implicitly be converted to std::string_view, so this should be
sufficient.

Change-Id: Id93448d831696d25472f13c15212f13712ad8492
---
 gdbsupport/unordered_map.h | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/gdbsupport/unordered_map.h b/gdbsupport/unordered_map.h
index b615f2422f62..e0b97764d0b3 100644
--- a/gdbsupport/unordered_map.h
+++ b/gdbsupport/unordered_map.h
@@ -32,6 +32,40 @@ using unordered_map
       <Key, T, Hash, KeyEqual, std::allocator<std::pair<Key, T>>,
        ankerl::unordered_dense::bucket_type::standard>;
 
+/* An unordered_map with std::string keys that supports transparent
+   lookup from std::string_view, avoiding the construction of temporary
+   std::string objects during lookups.  std::string_view is implicitly
+   constructible from `const char *` and `std::string`, so it covers those
+   too.  */
+
+namespace detail
+{
+
+struct unordered_string_map_hash
+{
+  using is_transparent = void;
+  using is_avalanching = void;
+
+  std::uint64_t operator() (std::string_view sv) const noexcept
+  { return ankerl::unordered_dense::hash<std::string_view> () (sv); }
+};
+
+struct unordered_string_map_eq
+{
+  using is_transparent = void;
+
+  bool operator() (std::string_view lhs, std::string_view rhs) const noexcept
+  { return lhs == rhs; }
+};
+
+} /* namespace detail */
+
+template<typename T>
+using unordered_string_map
+  = gdb::unordered_map<std::string, T,
+		       detail::unordered_string_map_hash,
+		       detail::unordered_string_map_eq>;
+
 } /* namespace gdb */
 
 #endif /* GDBSUPPORT_UNORDERED_MAP_H */
-- 
2.53.0


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

* [PATCH 4/4] gdb: use gdb::unordered_string_map throughout
  2026-02-13  5:38 [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution simon.marchi
  2026-02-13  5:38 ` [PATCH 2/4] gdb/elfread: replace ifunc htab_t with gdb::unordered_map simon.marchi
  2026-02-13  5:38 ` [PATCH 3/4] gdbsupport: add gdb::unordered_string_map simon.marchi
@ 2026-02-13  5:38 ` simon.marchi
  2026-02-13  8:30 ` [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution Eli Zaretskii
  2026-02-13 18:27 ` Kevin Buettner
  4 siblings, 0 replies; 8+ messages in thread
From: simon.marchi @ 2026-02-13  5:38 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@efficios.com>

Change all uses of

  gdb::unordered_map<string, T>

to

  gdb::unordered_string_map<T>

Using unordered_string_map avoids constructing a temporary std::string
(possibly with dynamic allocation) when looking up values from
`const char *`.

I don't see any downsides to using unordered_string_map over
unordered_map, even if all the lookups are done using existing
std::string objects that would be built anyway.

I think there are places where we could refactor the code to avoid
constructing unnecessary std::string objects, but that is out of scope
for this patch.

There should be no change of behavior with this patch.

Change-Id: Ic4df78b97f2755d5821bb66942b9e4d9a79a3dc5
---
 gdb/ada-exp.y           | 2 +-
 gdb/amdgpu-tdep.c       | 2 +-
 gdb/amdgpu-tdep.h       | 2 +-
 gdb/corelow.c           | 6 +++---
 gdb/cp-namespace.c      | 2 +-
 gdb/elfread.c           | 2 +-
 gdb/gdb_bfd.c           | 2 +-
 gdb/gdbarch-selftests.c | 2 +-
 gdb/mi/mi-cmds.c        | 2 +-
 gdb/solib-rocm.c        | 4 ++--
 gdb/solib-svr4.c        | 2 +-
 gdb/source-cache.h      | 2 +-
 gdb/tui/tui-layout.h    | 2 +-
 gdb/xml-tdesc.c         | 2 +-
 14 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index 771a867c4ae6..e02f1e6d10a2 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -97,7 +97,7 @@ struct ada_parse_state
   std::vector<ada_assign_up> assignments;
 
   /* Track currently active iterated assignment names.  */
-  gdb::unordered_map<std::string, std::vector<ada_index_var_operation *>>
+  gdb::unordered_string_map<std::vector<ada_index_var_operation *>>
        iterated_associations;
 
   auto_obstack temp_space;
diff --git a/gdb/amdgpu-tdep.c b/gdb/amdgpu-tdep.c
index fc45623f92b1..5a275165fbb2 100644
--- a/gdb/amdgpu-tdep.c
+++ b/gdb/amdgpu-tdep.c
@@ -356,7 +356,7 @@ using amd_dbgapi_register_type_enum_up
 
 /* Map type lookup names to types.  */
 using amd_dbgapi_register_type_map
-  = gdb::unordered_map<std::string, amd_dbgapi_register_type_up>;
+  = gdb::unordered_string_map<amd_dbgapi_register_type_up>;
 
 /* Parse S as a ULONGEST, raise an error on overflow.  */
 
diff --git a/gdb/amdgpu-tdep.h b/gdb/amdgpu-tdep.h
index c0adf55fdf60..5404c2901b54 100644
--- a/gdb/amdgpu-tdep.h
+++ b/gdb/amdgpu-tdep.h
@@ -78,7 +78,7 @@ struct amdgpu_gdbarch_tdep : gdbarch_tdep_base
     regnum_map;
 
   /* A map of register_class_ids keyed by their name.  */
-  gdb::unordered_map<std::string, amd_dbgapi_register_class_id_t>
+  gdb::unordered_string_map<amd_dbgapi_register_class_id_t>
     register_class_map;
 };
 
diff --git a/gdb/corelow.c b/gdb/corelow.c
index 658ff6e0198c..a28a707c293a 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -124,7 +124,7 @@ struct mapped_file_info
 
   /* A type that maps a string to a build-id.  */
   using string_to_build_id_map
-    = gdb::unordered_map<std::string, const bfd_build_id *>;
+    = gdb::unordered_string_map<const bfd_build_id *>;
 
   /* A type that maps a build-id to a string.  */
   using build_id_to_string_map
@@ -402,7 +402,7 @@ core_target::core_target (gdb_bfd_ref_ptr cbfd_ref)
 void
 core_target::build_file_mappings ()
 {
-  gdb::unordered_map<std::string, struct bfd *> bfd_map;
+  gdb::unordered_string_map<struct bfd *> bfd_map;
   gdb::unordered_set<std::string> unavailable_paths;
 
   /* All files mapped into the core file.  The key is the filename.  */
@@ -2122,7 +2122,7 @@ gdb_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd)
   };
 
   /* All files mapped into the core file.  The key is the filename.  */
-  gdb::unordered_map<std::string, map_entry> mapped_files;
+  gdb::unordered_string_map<map_entry> mapped_files;
 
   /* Get the build-id of the core file.  At least on Linux, this will be
      the build-id for the main executable.  If other targets add the
diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index 2e3c539507cc..efdb2a2c850a 100644
--- a/gdb/cp-namespace.c
+++ b/gdb/cp-namespace.c
@@ -349,7 +349,7 @@ cp_lookup_symbol_in_namespace (const char *the_namespace, const char *name,
 }
 
 /* Type used for collecting symbols.  Maps names to symbols.  */
-using symbol_map = gdb::unordered_map<std::string, block_symbol>;
+using symbol_map = gdb::unordered_string_map<block_symbol>;
 
 /* This version of the function is internal, use the wrapper unless
    the list of ambiguous symbols is needed.
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 010744639118..04e9a986031c 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -660,7 +660,7 @@ elf_rel_plt_read (minimal_symbol_reader &reader,
 
 /* Per-objfile cache mapping function names to resolved ifunc addresses.  */
 
-using elf_gnu_ifunc_cache = gdb::unordered_map<std::string, CORE_ADDR>;
+using elf_gnu_ifunc_cache = gdb::unordered_string_map<CORE_ADDR>;
 
 static const registry<objfile>::key<elf_gnu_ifunc_cache>
   elf_objfile_gnu_ifunc_cache_data;
diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c
index 98ea46677493..1933166b5fbf 100644
--- a/gdb/gdb_bfd.c
+++ b/gdb/gdb_bfd.c
@@ -1241,7 +1241,7 @@ maintenance_info_bfds (const char *arg, int from_tty)
 
 struct bfd_inferior_data
 {
-  gdb::unordered_map<std::string, unsigned long> bfd_error_string_counts;
+  gdb::unordered_string_map<unsigned long> bfd_error_string_counts;
 };
 
 /* Per-inferior data key.  */
diff --git a/gdb/gdbarch-selftests.c b/gdb/gdbarch-selftests.c
index 424281134a36..c89ad5ce5fde 100644
--- a/gdb/gdbarch-selftests.c
+++ b/gdb/gdbarch-selftests.c
@@ -133,7 +133,7 @@ register_name_test (struct gdbarch *gdbarch)
   scoped_mock_context<test_target_ops> mockctx (gdbarch);
 
   /* Track the number of times each register name appears.  */
-  gdb::unordered_map<std::string, int> name_counts;
+  gdb::unordered_string_map<int> name_counts;
 
   const int num_regs = gdbarch_num_cooked_regs (gdbarch);
   for (auto regnum = 0; regnum < num_regs; regnum++)
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index 552eafbbcbc4..48d85e8785c8 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -26,7 +26,7 @@
 
 /* MI command table (built at run time). */
 
-static gdb::unordered_map<std::string, mi_command_up> mi_cmd_table;
+static gdb::unordered_string_map<mi_command_up> mi_cmd_table;
 
 /* MI command with a pure MI implementation.  */
 
diff --git a/gdb/solib-rocm.c b/gdb/solib-rocm.c
index c17d5932b553..291694176821 100644
--- a/gdb/solib-rocm.c
+++ b/gdb/solib-rocm.c
@@ -69,7 +69,7 @@ struct rocm_solib_fd_cache
   };
 
   inferior *m_inferior;
-  gdb::unordered_map<std::string, refcnt_fd> m_cache;
+  gdb::unordered_string_map<refcnt_fd> m_cache;
 };
 
 int
@@ -102,7 +102,7 @@ rocm_solib_fd_cache::open (const std::string &filename,
 int
 rocm_solib_fd_cache::close (int fd, fileio_error *target_errno)
 {
-  using cache_val = gdb::unordered_map<std::string, refcnt_fd>::value_type;
+  using cache_val = gdb::unordered_string_map<refcnt_fd>::value_type;
   auto it
     = std::find_if (m_cache.begin (), m_cache.end (),
 		    [fd](const cache_val &s) { return s.second.fd == fd; });
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index c8d78fbfc1dd..aeb6cd30f423 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -3753,7 +3753,7 @@ svr4_solib_ops::get_solibs_in_ns (int nsid) const
      faster, and to be able to remove SOs from the map, to avoid
      returning the dynamic linker multiple times.  */
   CORE_ADDR debug_base = info->namespace_id[nsid];
-  gdb::unordered_map<std::string, const lm_info_svr4 *> namespace_solibs;
+  gdb::unordered_string_map<const lm_info_svr4 *> namespace_solibs;
   for (svr4_so &so : info->solib_lists[debug_base])
     namespace_solibs[so.name] = so.lm_info.get ();
 
diff --git a/gdb/source-cache.h b/gdb/source-cache.h
index 09f65cea62f4..ab4955e553ed 100644
--- a/gdb/source-cache.h
+++ b/gdb/source-cache.h
@@ -97,7 +97,7 @@ class source_cache
 
   /* The file offset cache.  The key is the full name of the source
      file.  */
-  gdb::unordered_map<std::string, std::vector<off_t>> m_offset_cache;
+  gdb::unordered_string_map<std::vector<off_t>> m_offset_cache;
 
   /* The list of files where styling failed.  */
   gdb::unordered_set<std::string> m_no_styling_files;
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index ca9afbabae6b..536174c784d4 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -367,7 +367,7 @@ typedef std::function<tui_win_info * (const char *name)> window_factory;
 
 /* The type for a data structure that maps a window name to that window's
    factory function.  */
-typedef gdb::unordered_map<std::string, window_factory> window_types_map;
+typedef gdb::unordered_string_map<window_factory> window_types_map;
 
 /* Register a new TUI window type.  NAME is the name of the window
    type.  FACTORY is a function that can be called to instantiate the
diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c
index ac73708f005d..472c604254a8 100644
--- a/gdb/xml-tdesc.c
+++ b/gdb/xml-tdesc.c
@@ -64,7 +64,7 @@ tdesc_parse_xml (const char *document, xml_fetch_another fetcher)
    then we will create unnecessary duplicate gdbarches.  See
    gdbarch_list_lookup_by_info.  */
 
-static gdb::unordered_map<std::string, target_desc_up> xml_cache;
+static gdb::unordered_string_map<target_desc_up> xml_cache;
 
 /* Callback data for target description parsing.  */
 
-- 
2.53.0


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

* Re: [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution
  2026-02-13  5:38 [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution simon.marchi
                   ` (2 preceding siblings ...)
  2026-02-13  5:38 ` [PATCH 4/4] gdb: use gdb::unordered_string_map throughout simon.marchi
@ 2026-02-13  8:30 ` Eli Zaretskii
  2026-02-13 17:20   ` Simon Marchi
  2026-02-13 18:27 ` Kevin Buettner
  4 siblings, 1 reply; 8+ messages in thread
From: Eli Zaretskii @ 2026-02-13  8:30 UTC (permalink / raw)
  To: simon.marchi; +Cc: gdb-patches

> From: simon.marchi@polymtl.ca
> Cc: Simon Marchi <simon.marchi@polymtl.ca>
> Date: Fri, 13 Feb 2026 00:38:48 -0500
> 
> ---
>  gdb/NEWS                  |   4 ++
>  gdb/doc/gdb.texinfo       |   6 +++
>  gdb/elfread.c             | 110 +++++++++++++++++++++++++++++++++++---
>  gdbsupport/common-debug.h |   9 ++++
>  4 files changed, 123 insertions(+), 6 deletions(-)

Thanks.  The documentation parts are okay, but I would suggest to say
in the manual a few words about what are "GNU ifunc" thingies, because
otherwise the documentation is not clear enough to the reader.

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

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

* Re: [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution
  2026-02-13  8:30 ` [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution Eli Zaretskii
@ 2026-02-13 17:20   ` Simon Marchi
  0 siblings, 0 replies; 8+ messages in thread
From: Simon Marchi @ 2026-02-13 17:20 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches



On 2026-02-13 03:30, Eli Zaretskii wrote:
>> From: simon.marchi@polymtl.ca
>> Cc: Simon Marchi <simon.marchi@polymtl.ca>
>> Date: Fri, 13 Feb 2026 00:38:48 -0500
>>
>> ---
>>  gdb/NEWS                  |   4 ++
>>  gdb/doc/gdb.texinfo       |   6 +++
>>  gdb/elfread.c             | 110 +++++++++++++++++++++++++++++++++++---
>>  gdbsupport/common-debug.h |   9 ++++
>>  4 files changed, 123 insertions(+), 6 deletions(-)
> 
> Thanks.  The documentation parts are okay, but I would suggest to say
> in the manual a few words about what are "GNU ifunc" thingies, because
> otherwise the documentation is not clear enough to the reader.
> 
> Reviewed-By: Eli Zaretskii <eliz@gnu.org>

Would you put it right there where I did the change, or a new section?
If a new section, any suggestions where?

Simon

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

* Re: [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution
  2026-02-13  5:38 [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution simon.marchi
                   ` (3 preceding siblings ...)
  2026-02-13  8:30 ` [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution Eli Zaretskii
@ 2026-02-13 18:27 ` Kevin Buettner
  2026-02-13 19:10   ` Simon Marchi
  4 siblings, 1 reply; 8+ messages in thread
From: Kevin Buettner @ 2026-02-13 18:27 UTC (permalink / raw)
  To: gdb-patches

On Fri, 13 Feb 2026 00:38:48 -0500
simon.marchi@polymtl.ca wrote:

> From: Simon Marchi <simon.marchi@polymtl.ca>
> 
> Add some debug prints throughout the ifunc resolution code, to be able
> to better understand what GDB does.  Add the new "set debug gnu-ifunc"
> knob to control it.
> 
> Add the debug_prefixed_printf_cond_func macro to implement
> gnu_ifunc_debug_printf_func, that takes an explicit function name.  This
> is needed to avoid showing "operator()" as the function name in the
> debug message.
> 
> Here is a sample session with the new debug output enabled.
> 
[...]
> ---
>  gdb/NEWS                  |   4 ++
>  gdb/doc/gdb.texinfo       |   6 +++
>  gdb/elfread.c             | 110 +++++++++++++++++++++++++++++++++++---
>  gdbsupport/common-debug.h |   9 ++++
>  4 files changed, 123 insertions(+), 6 deletions(-)

This would have been helpful when I was debugging some ifunc related
problems last year.

I've looked over all four parts.  They all LGTM.

Approved-by: Kevin Buettner <kevinb@redhat.com>


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

* Re: [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution
  2026-02-13 18:27 ` Kevin Buettner
@ 2026-02-13 19:10   ` Simon Marchi
  0 siblings, 0 replies; 8+ messages in thread
From: Simon Marchi @ 2026-02-13 19:10 UTC (permalink / raw)
  To: Kevin Buettner, gdb-patches



On 2026-02-13 13:27, Kevin Buettner wrote:
> On Fri, 13 Feb 2026 00:38:48 -0500
> simon.marchi@polymtl.ca wrote:
> 
>> From: Simon Marchi <simon.marchi@polymtl.ca>
>>
>> Add some debug prints throughout the ifunc resolution code, to be able
>> to better understand what GDB does.  Add the new "set debug gnu-ifunc"
>> knob to control it.
>>
>> Add the debug_prefixed_printf_cond_func macro to implement
>> gnu_ifunc_debug_printf_func, that takes an explicit function name.  This
>> is needed to avoid showing "operator()" as the function name in the
>> debug message.
>>
>> Here is a sample session with the new debug output enabled.
>>
> [...]
>> ---
>>  gdb/NEWS                  |   4 ++
>>  gdb/doc/gdb.texinfo       |   6 +++
>>  gdb/elfread.c             | 110 +++++++++++++++++++++++++++++++++++---
>>  gdbsupport/common-debug.h |   9 ++++
>>  4 files changed, 123 insertions(+), 6 deletions(-)
> 
> This would have been helpful when I was debugging some ifunc related
> problems last year.

Glad to know that, I hope it will be useful in the future.

> I've looked over all four parts.  They all LGTM.
> 
> Approved-by: Kevin Buettner <kevinb@redhat.com>

Thanks, I pushed the series.  I can work on Eli's request to clarify
ifunc in the doc as a separate patch.

Simon

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

end of thread, other threads:[~2026-02-13 19:10 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-02-13  5:38 [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution simon.marchi
2026-02-13  5:38 ` [PATCH 2/4] gdb/elfread: replace ifunc htab_t with gdb::unordered_map simon.marchi
2026-02-13  5:38 ` [PATCH 3/4] gdbsupport: add gdb::unordered_string_map simon.marchi
2026-02-13  5:38 ` [PATCH 4/4] gdb: use gdb::unordered_string_map throughout simon.marchi
2026-02-13  8:30 ` [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution Eli Zaretskii
2026-02-13 17:20   ` Simon Marchi
2026-02-13 18:27 ` Kevin Buettner
2026-02-13 19:10   ` Simon Marchi

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