|
|
860497a |
commit 36783141cf090412e3e6f042f25f7f6c63d6a14a
|
|
|
860497a |
Author: Florian Weimer <fweimer@redhat.com>
|
|
|
860497a |
Date: Thu Apr 22 11:07:43 2021 +0200
|
|
|
860497a |
|
|
|
860497a |
nptl: Check for compatible GDB in nptl/tst-pthread-gdb-attach
|
|
|
860497a |
|
|
|
860497a |
Also do not clear the subprocess environment, in case running
|
|
|
860497a |
GDB needs certain environment variables.
|
|
|
860497a |
|
|
|
860497a |
(cherry picked from commit f553dc066071a4465321fbc122bed8a75afd996b)
|
|
|
860497a |
|
|
|
860497a |
diff --git a/nptl/tst-pthread-gdb-attach.c b/nptl/tst-pthread-gdb-attach.c
|
|
|
860497a |
index 0603ad844defb8de..901a12003426d342 100644
|
|
|
860497a |
--- a/nptl/tst-pthread-gdb-attach.c
|
|
|
860497a |
+++ b/nptl/tst-pthread-gdb-attach.c
|
|
|
860497a |
@@ -20,8 +20,12 @@
|
|
|
860497a |
whether libthread_db can be loaded, and that access to thread-local
|
|
|
860497a |
variables works. */
|
|
|
860497a |
|
|
|
860497a |
+#include <elf.h>
|
|
|
860497a |
#include <errno.h>
|
|
|
860497a |
+#include <fcntl.h>
|
|
|
860497a |
+#include <stdbool.h>
|
|
|
860497a |
#include <stdlib.h>
|
|
|
860497a |
+#include <string.h>
|
|
|
860497a |
#include <support/check.h>
|
|
|
860497a |
#include <support/support.h>
|
|
|
860497a |
#include <support/temp_file.h>
|
|
|
860497a |
@@ -35,6 +39,49 @@
|
|
|
860497a |
the thread. */
|
|
|
860497a |
__thread volatile int altered_by_debugger;
|
|
|
860497a |
|
|
|
860497a |
+/* Common prefix between 32-bit and 64-bit ELF. */
|
|
|
860497a |
+struct elf_prefix
|
|
|
860497a |
+{
|
|
|
860497a |
+ unsigned char e_ident[EI_NIDENT];
|
|
|
860497a |
+ uint16_t e_type;
|
|
|
860497a |
+ uint16_t e_machine;
|
|
|
860497a |
+ uint32_t e_version;
|
|
|
860497a |
+};
|
|
|
860497a |
+_Static_assert (sizeof (struct elf_prefix) == EI_NIDENT + 8,
|
|
|
860497a |
+ "padding in struct elf_prefix");
|
|
|
860497a |
+
|
|
|
860497a |
+/* Reads the ELF header from PATH. Returns true if the header can be
|
|
|
860497a |
+ read, false if the file is too short. */
|
|
|
860497a |
+static bool
|
|
|
860497a |
+read_elf_header (const char *path, struct elf_prefix *elf)
|
|
|
860497a |
+{
|
|
|
860497a |
+ int fd = xopen (path, O_RDONLY, 0);
|
|
|
860497a |
+ bool result = read (fd, elf, sizeof (*elf)) == sizeof (*elf);
|
|
|
860497a |
+ xclose (fd);
|
|
|
860497a |
+ return result;
|
|
|
860497a |
+}
|
|
|
860497a |
+
|
|
|
860497a |
+/* Searches for "gdb" alongside the path variable. See execvpe. */
|
|
|
860497a |
+static char *
|
|
|
860497a |
+find_gdb (void)
|
|
|
860497a |
+{
|
|
|
860497a |
+ const char *path = getenv ("PATH");
|
|
|
860497a |
+ if (path == NULL)
|
|
|
860497a |
+ return NULL;
|
|
|
860497a |
+ while (true)
|
|
|
860497a |
+ {
|
|
|
860497a |
+ const char *colon = strchrnul (path, ':');
|
|
|
860497a |
+ char *candidate = xasprintf ("%.*s/gdb", (int) (colon - path), path);
|
|
|
860497a |
+ if (access (candidate, X_OK) == 0)
|
|
|
860497a |
+ return candidate;
|
|
|
860497a |
+ free (candidate);
|
|
|
860497a |
+ if (*colon == '\0')
|
|
|
860497a |
+ break;
|
|
|
860497a |
+ path = colon + 1;
|
|
|
860497a |
+ }
|
|
|
860497a |
+ return NULL;
|
|
|
860497a |
+}
|
|
|
860497a |
+
|
|
|
860497a |
/* Writes the GDB script to run the test to PATH. */
|
|
|
860497a |
static void
|
|
|
860497a |
write_gdbscript (const char *path, int tested_pid)
|
|
|
860497a |
@@ -105,6 +152,33 @@ in_subprocess (void)
|
|
|
860497a |
static int
|
|
|
860497a |
do_test (void)
|
|
|
860497a |
{
|
|
|
860497a |
+ char *gdb_path = find_gdb ();
|
|
|
860497a |
+ if (gdb_path == NULL)
|
|
|
860497a |
+ FAIL_UNSUPPORTED ("gdb command not found in PATH: %s", getenv ("PATH"));
|
|
|
860497a |
+
|
|
|
860497a |
+ /* Check that libthread_db is compatible with the gdb architecture
|
|
|
860497a |
+ because gdb loads it via dlopen. */
|
|
|
860497a |
+ {
|
|
|
860497a |
+ char *threaddb_path = xasprintf ("%s/nptl_db/libthread_db.so",
|
|
|
860497a |
+ support_objdir_root);
|
|
|
860497a |
+ struct elf_prefix elf_threaddb;
|
|
|
860497a |
+ TEST_VERIFY_EXIT (read_elf_header (threaddb_path, &elf_threaddb));
|
|
|
860497a |
+ struct elf_prefix elf_gdb;
|
|
|
860497a |
+ /* If the ELF header cannot be read or "gdb" is not an ELF file,
|
|
|
860497a |
+ assume this is a wrapper script that can run. */
|
|
|
860497a |
+ if (read_elf_header (gdb_path, &elf_gdb)
|
|
|
860497a |
+ && memcmp (&elf_gdb, ELFMAG, SELFMAG) == 0)
|
|
|
860497a |
+ {
|
|
|
860497a |
+ if (elf_gdb.e_ident[EI_CLASS] != elf_threaddb.e_ident[EI_CLASS])
|
|
|
860497a |
+ FAIL_UNSUPPORTED ("GDB at %s has wrong class", gdb_path);
|
|
|
860497a |
+ if (elf_gdb.e_ident[EI_DATA] != elf_threaddb.e_ident[EI_DATA])
|
|
|
860497a |
+ FAIL_UNSUPPORTED ("GDB at %s has wrong data", gdb_path);
|
|
|
860497a |
+ if (elf_gdb.e_machine != elf_threaddb.e_machine)
|
|
|
860497a |
+ FAIL_UNSUPPORTED ("GDB at %s has wrong machine", gdb_path);
|
|
|
860497a |
+ }
|
|
|
860497a |
+ free (threaddb_path);
|
|
|
860497a |
+ }
|
|
|
860497a |
+
|
|
|
860497a |
pid_t tested_pid = xfork ();
|
|
|
860497a |
if (tested_pid == 0)
|
|
|
860497a |
in_subprocess ();
|
|
|
860497a |
@@ -117,9 +191,8 @@ do_test (void)
|
|
|
860497a |
pid_t gdb_pid = xfork ();
|
|
|
860497a |
if (gdb_pid == 0)
|
|
|
860497a |
{
|
|
|
860497a |
- clearenv ();
|
|
|
860497a |
xdup2 (STDOUT_FILENO, STDERR_FILENO);
|
|
|
860497a |
- execlp ("gdb", "gdb", "-nx", "-batch", "-x", gdbscript, NULL);
|
|
|
860497a |
+ execl (gdb_path, "gdb", "-nx", "-batch", "-x", gdbscript, NULL);
|
|
|
860497a |
if (errno == ENOENT)
|
|
|
860497a |
_exit (EXIT_UNSUPPORTED);
|
|
|
860497a |
else
|
|
|
860497a |
@@ -137,6 +210,7 @@ do_test (void)
|
|
|
860497a |
|
|
|
860497a |
free (tested_pid_string);
|
|
|
860497a |
free (gdbscript);
|
|
|
860497a |
+ free (gdb_path);
|
|
|
860497a |
return 0;
|
|
|
860497a |
}
|
|
|
860497a |
|