Determining why gl_multithreaded() returned true currently needs gdb.
This is not optimal. This patch makes this possible with less effort.


2026-05-18  Bruno Haible  <[email protected]>

        thread-optim: Add some optional rudimentary logging.
        * lib/thread-optim.c (DEBUG_ELF, dbg_printf): New macros.
        (inspect_one_GOT): Log the return value through dbg_printf.
        (gl_multithreaded): Log the override through dbg_printf.

diff --git a/lib/thread-optim.c b/lib/thread-optim.c
index 88812307ed..ba43f16d89 100644
--- a/lib/thread-optim.c
+++ b/lib/thread-optim.c
@@ -22,6 +22,9 @@
 /* Specification.  */
 #include "thread-optim.h"
 
+/* Set to 1 to get debugging output regarding the ELF GOT inspection.  */
+#define DEBUG_ELF 0
+
 static int mt_override = -1;
 
 void
@@ -122,6 +125,13 @@ gl_set_multithreaded (bool mt)
 # define ElfW_2(class,type) Elf ## class ## _ ## type
 #endif
 
+/* For debugging.  */
+#if DEBUG_ELF
+# define dbg_printf(...) fprintf (stderr, __VA_ARGS__)
+#else
+# define dbg_printf(...) (void)0
+#endif
+
 #include "thread-creators.h"
 
 /* We inspect the GOT.  This is more robust than inspecting the PLT, because
@@ -291,8 +301,13 @@ inspect_one_GOT (struct dl_phdr_info *info, size_t size, 
void *data)
               ElfW(Word) symbol_name_offset = symtab_entry->st_name;
               const char *symbol_name = strtab + symbol_name_offset;
               if (thread_creators_lookup (symbol_name, strlen (symbol_name)) 
!= NULL)
-                /* Found a jump relocation to a thread creator symbol.  */
-                return 1;
+                {
+                  /* Found a jump relocation to a thread creator symbol.  */
+                  dbg_printf ("gl_multithreaded() = true, because %s has the 
dynamic symbol %s.\n",
+                              info->dlpi_name[0] == '\0' ? "the executable" : 
info->dlpi_name,
+                              symbol_name);
+                  return 1;
+                }
             }
         }
 
@@ -370,8 +385,13 @@ inspect_one_GOT (struct dl_phdr_info *info, size_t size, 
void *data)
                     abort ();
                   const char *symbol_name = strtab + symbol_name_offset;
                   if (thread_creators_lookup (symbol_name, strlen 
(symbol_name)) != NULL)
-                    /* Found a jump relocation to a thread creator symbol.  */
-                    return 1;
+                    {
+                      /* Found a jump relocation to a thread creator symbol.  
*/
+                      dbg_printf ("gl_multithreaded() = true, because %s has 
the dynamic symbol %s.\n",
+                                  info->dlpi_name[0] == '\0' ? "the 
executable" : info->dlpi_name,
+                                  symbol_name);
+                      return 1;
+                    }
                 }
             }
         }
@@ -381,8 +401,11 @@ inspect_one_GOT (struct dl_phdr_info *info, size_t size, 
void *data)
   else
     {
       if (info->dlpi_name[0] == '\0')
-        /* The executable is statically linked.  */
-        return -1;
+        {
+          /* The executable is statically linked.  */
+          dbg_printf ("gl_multithreaded() = true, because the executable is 
statically linked.\n");
+          return -1;
+        }
     }
 
   return 0;
@@ -406,7 +429,11 @@ gl_multithreaded (void)
 {
   /* Consider the override.  */
   if (mt_override >= 0)
-    return mt_override;
+    {
+      dbg_printf ("gl_multithreaded() = %s, specified through 
gl_set_multithreaded.\n",
+                  mt_override ? "true" : "false");
+      return mt_override;
+    }
   else
     {
       /* Cache the result from is_multithreaded_uncached.  */




Reply via email to