[PATCH] nptl: Skip tst-pthread-gdb-attach{, -static} on env mismatches

Carlos O'Donell carlos@redhat.com
Mon May 25 13:25:52 GMT 2026


On 5/21/26 12:30 PM, Adhemerval Zanella wrote:
> The test previously failed with confusing diagnostics in two situations
> that are properties of the runtime environment rather than of glibc:
> 
> 1. find_gdb only checked access(X_OK), which is true for directories
>     too.  A 'gdb' directory ahead of /usr/bin in PATH (e.g. one holding
>     gdb python helpers) was therefore returned as the gdb executable,
>     and the subsequent execl failed with errno != ENOENT, causing the
>     test to fail with `numeric comparison failure ... status 256'.
> 
> 2. The in-tree libthread_db.so.1 is built with -z mark-plt and
>     therefore carries a versioned dependency on
>     GLIBC_ABI_DT_X86_64_PLT in libc.so (see BZ #33212).  When the
>     system gdb is linked against a libc older than 2.41, that version
>     is not provided and gdb's dlopen of the in-tree libthread_db.so.1
>     fails.  Thread debugging is then disabled, the gdb script's
>     `thread 1' / `thread 2' commands fail, gdb exits non-zero, and the
>     test reports a generic status mismatch.
> 
> Two changes:
> 
> * Require S_ISREG in find_gdb so a directory named 'gdb' on PATH is
>    skipped, falling through to the next candidate.
> 
> * Before running the real gdb scenario, run a minimal probe script
>    that triggers libthread_db loading (set debug libthread-db 1; set
>    libthread-db-search-path; file /proc/self/exe; start).  If the
>    probe output contains `dlopen failed', mark the test UNSUPPORTED
>    with a clear message instead of letting the real run fail.

This makes complete sense.

Please apply.

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>


> ---
>   nptl/tst-pthread-gdb-attach.c | 62 ++++++++++++++++++++++++++++++++++-
>   1 file changed, 61 insertions(+), 1 deletion(-)
> 
> diff --git a/nptl/tst-pthread-gdb-attach.c b/nptl/tst-pthread-gdb-attach.c
> index b183dc0f30f..c737188a6c0 100644
> --- a/nptl/tst-pthread-gdb-attach.c
> +++ b/nptl/tst-pthread-gdb-attach.c
> @@ -25,6 +25,7 @@
>   #include <fcntl.h>
>   #include <signal.h>
>   #include <stdbool.h>
> +#include <stdio.h>
>   #include <stdlib.h>
>   #include <string.h>
>   #include <support/capture_subprocess.h>
> @@ -37,6 +38,7 @@
>   #include <support/xstdio.h>
>   #include <support/xthread.h>
>   #include <support/xunistd.h>
> +#include <sys/stat.h>
>   #include <unistd.h>
>   
>   /* Starts out as zero, changed to 1 or 2 by the debugger, depending on
> @@ -65,6 +67,51 @@ read_elf_header (const char *path, struct elf_prefix *elf)
>     return result;
>   }
>   
> +/* Runs gdb with a minimal probe script and returns true if gdb prints
> +   'dlopen failed' while attempting to load libthread_db.  */
> +static bool
> +libthread_db_probe_fails (const char *gdb_path)
> +{
> +  support_need_proc ("Reads /proc/self/exec to probe gdb");
> +
> +  /* The probe inferior just needs to be any pthread-linked binary; reusing
> +     /proc/self/exe avoids hard-coding a path.  */
> +  char *self = xreadlink ("/proc/self/exe");
> +
> +  char *probe_script;
> +  xclose (create_temp_file ("tst-pthread-gdb-attach-probe-", &probe_script));
> +  FILE *fp = xfopen (probe_script, "w");
> +  fprintf (fp,
> +           "set debuginfod enabled off\n"
> +           "set debug libthread-db 1\n"
> +           "set auto-load safe-path %1$s/nptl_db\n"
> +           "set libthread-db-search-path %1$s/nptl_db\n"
> +           "file %2$s\n"
> +           "start\n",
> +           support_objdir_root, self);
> +  xfclose (fp);
> +  free (self);
> +
> +  char *cmd = xasprintf ("%s -nx -batch -x %s 2>&1",
> +                         gdb_path, probe_script);
> +  FILE *gdb_out = popen (cmd, "r");
> +  free (cmd);
> +
> +  bool fails = false;
> +  if (gdb_out != NULL)
> +    {
> +      char *line = NULL;
> +      size_t linecap = 0;
> +      while (xgetline (&line, &linecap, gdb_out) > 0)
> +        if (strstr (line, "dlopen failed") != NULL)
> +          fails = true;
> +      free (line);
> +      pclose (gdb_out);
> +    }
> +  free (probe_script);
> +  return fails;
> +}
> +
>   /* Searches for "gdb" alongside the path variable.  See execvpe.  */
>   static char *
>   find_gdb (void)
> @@ -76,7 +123,10 @@ find_gdb (void)
>       {
>         const char *colon = strchrnul (path, ':');
>         char *candidate = xasprintf ("%.*s/gdb", (int) (colon - path), path);
> -      if (access (candidate, X_OK) == 0)
> +      struct stat st;
> +      if (access (candidate, X_OK) == 0
> +          && stat (candidate, &st) == 0
> +          && S_ISREG (st.st_mode))
>           return candidate;
>         free (candidate);
>         if (*colon == '\0')
> @@ -199,10 +249,20 @@ do_test (void)
>             FAIL_UNSUPPORTED ("GDB at %s has wrong data", gdb_path);
>           if (elf_gdb.e_machine != elf_threaddb.e_machine)
>             FAIL_UNSUPPORTED ("GDB at %s has wrong machine", gdb_path);
> +
>         }
>       free (threaddb_path);
>     }
>   
> +  /* Probe gdb with a minimal script that triggers libthread_db loading.  If
> +     the probe reports a dlopen failure (e.g. because the libc gdb is linked
> +     against is older than the one in-tree libthread_db.so.1 requires, see
> +     BZ #33212), skip the test as UNSUPPORTED.  */
> +  if (libthread_db_probe_fails (gdb_path))
> +    FAIL_UNSUPPORTED ("gdb cannot dlopen the in-tree libthread_db.so.1;"
> +                      " its libc is missing a required ABI version"
> +                      " (see BZ #33212)");
> +
>     /* Check if our subprocess can be debugged with ptrace.  */
>     {
>       int ptrace_scope = support_ptrace_scope ();


-- 
Cheers,
Carlos.



More information about the Libc-alpha mailing list