]> git.ipfire.org Git - thirdparty/glibc.git/blob - elf/pldd-xx.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / elf / pldd-xx.c
1 /* Copyright (C) 2011-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
17
18 #define E(name) E_(name, CLASS)
19 #define E_(name, cl) E__(name, cl)
20 #define E__(name, cl) name##cl
21 #define EW(type) EW_(Elf, CLASS, type)
22 #define EW_(e, w, t) EW__(e, w, _##t)
23 #define EW__(e, w, t) e##w##t
24
25 struct E(link_map)
26 {
27 EW(Addr) l_addr;
28 EW(Addr) l_name;
29 EW(Addr) l_ld;
30 EW(Addr) l_next;
31 EW(Addr) l_prev;
32 EW(Addr) l_real;
33 Lmid_t l_ns;
34 EW(Addr) l_libname;
35 };
36 #if CLASS == __ELF_NATIVE_CLASS
37 _Static_assert (offsetof (struct link_map, l_addr)
38 == offsetof (struct E(link_map), l_addr), "l_addr");
39 _Static_assert (offsetof (struct link_map, l_name)
40 == offsetof (struct E(link_map), l_name), "l_name");
41 _Static_assert (offsetof (struct link_map, l_next)
42 == offsetof (struct E(link_map), l_next), "l_next");
43 #endif
44
45
46 struct E(libname_list)
47 {
48 EW(Addr) name;
49 EW(Addr) next;
50 };
51 #if CLASS == __ELF_NATIVE_CLASS
52 _Static_assert (offsetof (struct libname_list, name)
53 == offsetof (struct E(libname_list), name), "name");
54 _Static_assert (offsetof (struct libname_list, next)
55 == offsetof (struct E(libname_list), next), "next");
56 #endif
57
58 struct E(r_debug)
59 {
60 int r_version;
61 #if CLASS == 64
62 int pad;
63 #endif
64 EW(Addr) r_map;
65 };
66 #if CLASS == __ELF_NATIVE_CLASS
67 _Static_assert (offsetof (struct r_debug, r_version)
68 == offsetof (struct E(r_debug), r_version), "r_version");
69 _Static_assert (offsetof (struct r_debug, r_map)
70 == offsetof (struct E(r_debug), r_map), "r_map");
71 #endif
72
73
74 static int
75
76 E(find_maps) (const char *exe, int memfd, pid_t pid, void *auxv,
77 size_t auxv_size)
78 {
79 EW(Addr) phdr = 0;
80 unsigned int phnum = 0;
81 unsigned int phent = 0;
82
83 EW(auxv_t) *auxvXX = (EW(auxv_t) *) auxv;
84 for (int i = 0; i < auxv_size / sizeof (EW(auxv_t)); ++i)
85 switch (auxvXX[i].a_type)
86 {
87 case AT_PHDR:
88 phdr = auxvXX[i].a_un.a_val;
89 break;
90 case AT_PHNUM:
91 phnum = auxvXX[i].a_un.a_val;
92 break;
93 case AT_PHENT:
94 phent = auxvXX[i].a_un.a_val;
95 break;
96 default:
97 break;
98 }
99
100 if (phdr == 0 || phnum == 0 || phent == 0)
101 error (EXIT_FAILURE, 0, gettext ("cannot find program header of process"));
102
103 EW(Phdr) *p = xmalloc (phnum * phent);
104 if (pread (memfd, p, phnum * phent, phdr) != phnum * phent)
105 error (EXIT_FAILURE, 0, gettext ("cannot read program header"));
106
107 /* Determine the load offset. We need this for interpreting the
108 other program header entries so we do this in a separate loop.
109 Fortunately it is the first time unless someone does something
110 stupid when linking the application. */
111 EW(Addr) offset = 0;
112 for (unsigned int i = 0; i < phnum; ++i)
113 if (p[i].p_type == PT_PHDR)
114 {
115 offset = phdr - p[i].p_vaddr;
116 break;
117 }
118
119 EW(Addr) list = 0;
120 char *interp = NULL;
121 for (unsigned int i = 0; i < phnum; ++i)
122 if (p[i].p_type == PT_DYNAMIC)
123 {
124 EW(Dyn) *dyn = xmalloc (p[i].p_filesz);
125 if (pread (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr)
126 != p[i].p_filesz)
127 error (EXIT_FAILURE, 0, gettext ("cannot read dynamic section"));
128
129 /* Search for the DT_DEBUG entry. */
130 for (unsigned int j = 0; j < p[i].p_filesz / sizeof (EW(Dyn)); ++j)
131 if (dyn[j].d_tag == DT_DEBUG && dyn[j].d_un.d_ptr != 0)
132 {
133 struct E(r_debug) r;
134 if (pread (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr)
135 != sizeof (r))
136 error (EXIT_FAILURE, 0, gettext ("cannot read r_debug"));
137
138 if (r.r_map != 0)
139 {
140 list = r.r_map;
141 break;
142 }
143 }
144
145 free (dyn);
146 break;
147 }
148 else if (p[i].p_type == PT_INTERP)
149 {
150 interp = xmalloc (p[i].p_filesz);
151 if (pread (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr)
152 != p[i].p_filesz)
153 error (EXIT_FAILURE, 0, gettext ("cannot read program interpreter"));
154 }
155
156 if (list == 0)
157 {
158 if (interp == NULL)
159 {
160 // XXX check whether the executable itself is the loader
161 exit (EXIT_FAILURE);
162 }
163
164 // XXX perhaps try finding ld.so and _r_debug in it
165 exit (EXIT_FAILURE);
166 }
167
168 free (p);
169 free (interp);
170
171 /* Print the PID and program name first. */
172 printf ("%lu:\t%s\n", (unsigned long int) pid, exe);
173
174 /* Iterate over the list of objects and print the information. */
175 struct scratch_buffer tmpbuf;
176 scratch_buffer_init (&tmpbuf);
177 int status = 0;
178 do
179 {
180 struct E(link_map) m;
181 if (pread (memfd, &m, sizeof (m), list) != sizeof (m))
182 error (EXIT_FAILURE, 0, gettext ("cannot read link map"));
183
184 EW(Addr) name_offset = m.l_name;
185 while (1)
186 {
187 ssize_t n = pread (memfd, tmpbuf.data, tmpbuf.length, name_offset);
188 if (n == -1)
189 error (EXIT_FAILURE, 0, gettext ("cannot read object name"));
190
191 if (memchr (tmpbuf.data, '\0', n) != NULL)
192 break;
193
194 if (!scratch_buffer_grow (&tmpbuf))
195 error (EXIT_FAILURE, 0,
196 gettext ("cannot allocate buffer for object name"));
197 }
198
199 /* The m.l_name and m.l_libname.name for loader linkmap points to same
200 values (since BZ#387 fix). Trying to use l_libname name as the
201 shared object name might lead to an infinite loop (BZ#18035). */
202
203 /* Skip over the executable. */
204 if (((char *)tmpbuf.data)[0] != '\0')
205 printf ("%s\n", (char *)tmpbuf.data);
206
207 list = m.l_next;
208 }
209 while (list != 0);
210
211 scratch_buffer_free (&tmpbuf);
212 return status;
213 }
214
215
216 #undef CLASS