summarylogtreecommitdiffstats
path: root/0002-nptl-Check-for-compatible-GDB-in-nptl-tst-pthread-gd.patch
blob: d3846d654ca7de6f17acbb8a1e77b6dc7472ba18 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
From f553dc066071a4465321fbc122bed8a75afd996b Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Thu, 22 Apr 2021 11:07:43 +0200
Subject: [PATCH 405/576] nptl: Check for compatible GDB in
 nptl/tst-pthread-gdb-attach

Also do not clear the subprocess environment, in case running
GDB needs certain environment variables.
---
 nptl/tst-pthread-gdb-attach.c | 78 ++++++++++++++++++++++++++++++++++-
 1 file changed, 76 insertions(+), 2 deletions(-)

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