Branch data Line data Source code
1 : : /* Recover relocatibility for addresses computed from debug information.
2 : : Copyright (C) 2005-2009, 2012 Red Hat, Inc.
3 : : Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
4 : : Copyright (C) 2022 Google LLC
5 : : This file is part of elfutils.
6 : :
7 : : This file is free software; you can redistribute it and/or modify
8 : : it under the terms of either
9 : :
10 : : * the GNU Lesser General Public License as published by the Free
11 : : Software Foundation; either version 3 of the License, or (at
12 : : your option) any later version
13 : :
14 : : or
15 : :
16 : : * the GNU General Public License as published by the Free
17 : : Software Foundation; either version 2 of the License, or (at
18 : : your option) any later version
19 : :
20 : : or both in parallel, as here.
21 : :
22 : : elfutils is distributed in the hope that it will be useful, but
23 : : WITHOUT ANY WARRANTY; without even the implied warranty of
24 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 : : General Public License for more details.
26 : :
27 : : You should have received copies of the GNU General Public License and
28 : : the GNU Lesser General Public License along with this program. If
29 : : not, see <http://www.gnu.org/licenses/>. */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : # include <config.h>
33 : : #endif
34 : :
35 : : #include "libdwflP.h"
36 : : #include <fcntl.h>
37 : :
38 : : /* Since dwfl_report_elf lays out the sections already, this will only be
39 : : called when the section headers of the debuginfo file are being
40 : : consulted instead, or for the section placed at 0. With binutils
41 : : strip-to-debug, the symbol table is in the debuginfo file and relocation
42 : : looks there. */
43 : : int
44 : 50380 : dwfl_offline_section_address (Dwfl_Module *mod,
45 : : void **userdata __attribute__ ((unused)),
46 : : const char *modname __attribute__ ((unused)),
47 : : Dwarf_Addr base __attribute__ ((unused)),
48 : : const char *secname __attribute__ ((unused)),
49 : : Elf32_Word shndx,
50 : : const GElf_Shdr *shdr __attribute__ ((unused)),
51 : : Dwarf_Addr *addr)
52 : : {
53 [ + - ]: 50380 : if (mod->e_type != ET_REL
54 [ + - ]: 50380 : || shdr->sh_addr != 0
55 [ + - ]: 50380 : || !(shdr->sh_flags & SHF_ALLOC)
56 [ - + ]: 50380 : || shndx == 0)
57 : : return -1;
58 : :
59 [ + + ]: 50380 : if (mod->debug.elf == NULL)
60 : : /* We are only here because sh_addr is zero even though layout is complete.
61 : : The first section in the first file under -e is placed at 0. */
62 : : return 0;
63 : :
64 : : /* The section numbers might not match between the two files.
65 : : The best we can rely on is the order of SHF_ALLOC sections. */
66 : :
67 : 116 : Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx);
68 : 116 : Elf_Scn *scn = NULL;
69 : 116 : uint_fast32_t skip_alloc = 0;
70 [ + + ]: 206 : while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn)
71 : : {
72 [ - + ]: 90 : assert (scn != NULL);
73 : 90 : GElf_Shdr shdr_mem;
74 : 90 : GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem);
75 [ - + ]: 90 : if (unlikely (sh == NULL))
76 : 0 : return -1;
77 [ + + ]: 90 : if (sh->sh_flags & SHF_ALLOC)
78 : 56 : ++skip_alloc;
79 : : }
80 : :
81 : : scn = NULL;
82 [ - + ]: 176 : while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
83 : : {
84 : 176 : GElf_Shdr shdr_mem;
85 : 176 : GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem);
86 [ + - ]: 176 : if (unlikely (main_shdr == NULL))
87 : 116 : return -1;
88 [ + + + + ]: 176 : if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0)
89 : : {
90 [ - + ]: 116 : assert (main_shdr->sh_flags == shdr->sh_flags);
91 : 116 : *addr = main_shdr->sh_addr;
92 : 116 : return 0;
93 : : }
94 : : }
95 : :
96 : : /* This should never happen. */
97 : : return -1;
98 : : }
99 : : INTDEF (dwfl_offline_section_address)
100 : :
101 : : /* Forward declarations. */
102 : : static Dwfl_Module *process_elf (Dwfl *dwfl, const char *name,
103 : : const char *file_name, int fd, Elf *elf);
104 : : static Dwfl_Module *process_archive (Dwfl *dwfl, const char *name,
105 : : const char *file_name, int fd, Elf *elf,
106 : : int (*predicate) (const char *module,
107 : : const char *file));
108 : :
109 : : /* Report one module for an ELF file, or many for an archive.
110 : : Always consumes ELF and FD. */
111 : : static Dwfl_Module *
112 : 1428 : process_file (Dwfl *dwfl, const char *name, const char *file_name, int fd,
113 : : Elf *elf, int (*predicate) (const char *module,
114 : : const char *file))
115 : : {
116 [ - + + ]: 1428 : switch (elf_kind (elf))
117 : : {
118 : 0 : default:
119 : : case ELF_K_NONE:
120 [ # # ]: 0 : __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF);
121 : 0 : return NULL;
122 : :
123 : 1426 : case ELF_K_ELF:
124 : 1426 : return process_elf (dwfl, name, file_name, fd, elf);
125 : :
126 : 2 : case ELF_K_AR:
127 : 2 : return process_archive (dwfl, name, file_name, fd, elf, predicate);
128 : : }
129 : : }
130 : :
131 : : /* Report the open ELF file as a module. Always consumes ELF and FD. */
132 : : static Dwfl_Module *
133 : 1426 : process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
134 : : Elf *elf)
135 : : {
136 : 1426 : Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf,
137 : : dwfl->offline_next_address, true,
138 : : false);
139 [ + - ]: 1426 : if (mod != NULL)
140 : : {
141 : : /* If this is an ET_EXEC file with fixed addresses, the address range
142 : : it consumed may or may not intersect with the arbitrary range we
143 : : will use for relocatable modules. Make sure we always use a free
144 : : range for the offline allocations. If this module did use
145 : : offline_next_address, it may have rounded it up for the module's
146 : : alignment requirements. */
147 [ + + ]: 1426 : if ((dwfl->offline_next_address >= mod->low_addr
148 [ + + ]: 788 : || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
149 [ + - ]: 660 : && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
150 : 660 : dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
151 : :
152 : : /* Don't keep the file descriptor around. */
153 [ + + + - ]: 1426 : if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
154 : : {
155 : : /* Grab the path in case we want to report this file as
156 : : Dwarf later. */
157 : 1404 : mod->elfpath = __libdw_elfpath (mod->main.fd);
158 : 1404 : close (mod->main.fd);
159 : 1404 : mod->main.fd = -1;
160 : : }
161 : : }
162 : :
163 : 1426 : return mod;
164 : : }
165 : :
166 : : /* Always consumes MEMBER. Returns elf_next result on success.
167 : : For errors returns ELF_C_NULL with *MOD set to null. */
168 : : static Elf_Cmd
169 : 8 : process_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
170 : : int (*predicate) (const char *module, const char *file),
171 : : int fd, Elf *member, Dwfl_Module **mod)
172 : : {
173 : 8 : const Elf_Arhdr *h = elf_getarhdr (member);
174 [ - + ]: 8 : if (unlikely (h == NULL))
175 : : {
176 : 0 : __libdwfl_seterrno (DWFL_E_LIBELF);
177 : 0 : fail:
178 : 0 : elf_end (member);
179 : 0 : *mod = NULL;
180 : 0 : return ELF_C_NULL;
181 : : }
182 : :
183 [ - + - + ]: 8 : if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//")
184 [ + + ]: 8 : || !strcmp (h->ar_name, "/SYM64/"))
185 : : {
186 : 2 : skip:;
187 : : /* Skip this and go to the next. */
188 : 2 : Elf_Cmd result = elf_next (member);
189 : 2 : elf_end (member);
190 : 2 : return result;
191 : : }
192 : :
193 : 6 : char *member_name;
194 [ - + ]: 6 : if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0))
195 : : {
196 : 0 : nomem:
197 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
198 : 0 : elf_end (member);
199 : 0 : *mod = NULL;
200 : 0 : return ELF_C_NULL;
201 : : }
202 : :
203 : 6 : char *module_name = NULL;
204 [ + - - + ]: 6 : if (name == NULL || name[0] == '\0')
205 : 0 : name = h->ar_name;
206 [ - + ]: 6 : else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0))
207 : : {
208 : 0 : free (member_name);
209 : 0 : goto nomem;
210 : : }
211 : : else
212 : 6 : name = module_name;
213 : :
214 [ - + ]: 6 : if (predicate != NULL)
215 : : {
216 : : /* Let the predicate decide whether to use this one. */
217 : 0 : int want = (*predicate) (name, member_name);
218 [ # # ]: 0 : if (want <= 0)
219 : : {
220 : 0 : free (member_name);
221 : 0 : free (module_name);
222 [ # # ]: 0 : if (unlikely (want < 0))
223 : : {
224 : 0 : __libdwfl_seterrno (DWFL_E_CB);
225 : 0 : goto fail;
226 : : }
227 : 0 : goto skip;
228 : : }
229 : : }
230 : :
231 : : /* We let __libdwfl_report_elf cache the fd in mod->main.fd,
232 : : though it's the same fd for all the members.
233 : : On module teardown we will close it only on the last Elf reference. */
234 : 6 : *mod = process_file (dwfl, name, member_name, fd, member, predicate);
235 : 6 : free (member_name);
236 : 6 : free (module_name);
237 : :
238 [ - + ]: 6 : if (*mod == NULL)
239 : : {
240 : 0 : elf_end (member);
241 : 0 : return ELF_C_NULL;
242 : : }
243 : :
244 : : /* Advance the archive-reading offset for the next iteration. */
245 : 6 : return elf_next (member);
246 : : }
247 : :
248 : : /* Report each member of the archive as its own module. */
249 : : static Dwfl_Module *
250 : 2 : process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd,
251 : : Elf *archive,
252 : : int (*predicate) (const char *module, const char *file))
253 : :
254 : : {
255 : 2 : Dwfl_Module *mod = NULL;
256 : : /* elf_begin supports opening archives even with fd == -1 passed. */
257 : 2 : Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
258 [ - + ]: 2 : if (unlikely (member == NULL)) /* Empty archive. */
259 : : {
260 : 0 : __libdwfl_seterrno (DWFL_E_BADELF);
261 : 0 : return NULL;
262 : : }
263 : :
264 : 8 : while (process_archive_member (dwfl, name, file_name, predicate,
265 [ + + ]: 8 : fd, member, &mod) != ELF_C_NULL)
266 : 6 : member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
267 : :
268 : : /* We can drop the archive Elf handle even if we're still using members
269 : : in live modules. When the last module's elf_end on a member returns
270 : : zero, that module will close FD. If no modules survived the predicate,
271 : : we are all done with the file right here. */
272 [ + - ]: 2 : if (mod != NULL /* If no modules, caller will clean up. */
273 [ - + ]: 2 : && elf_end (archive) == 0)
274 : 2 : close (fd);
275 : :
276 : : return mod;
277 : : }
278 : :
279 : : Dwfl_Module *
280 : : internal_function
281 : 1418 : __libdwfl_report_offline (Dwfl *dwfl, const char *name,
282 : : const char *file_name, int fd, bool closefd,
283 : : int (*predicate) (const char *module,
284 : : const char *file))
285 : : {
286 : 1418 : Elf *elf;
287 : 1418 : Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true);
288 [ - + ]: 1418 : if (error != DWFL_E_NOERROR)
289 : : {
290 : 0 : __libdwfl_seterrno (error);
291 : 0 : return NULL;
292 : : }
293 : 1418 : Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate);
294 [ - + ]: 1418 : if (mod == NULL)
295 : : {
296 : 0 : elf_end (elf);
297 [ # # ]: 0 : if (closefd)
298 : 0 : close (fd);
299 : : }
300 : : return mod;
301 : : }
302 : :
303 : : Dwfl_Module *
304 : 1418 : dwfl_report_offline (Dwfl *dwfl, const char *name,
305 : : const char *file_name, int fd)
306 : : {
307 [ - + ]: 1418 : if (dwfl == NULL)
308 : : return NULL;
309 : :
310 : 1418 : bool closefd = false;
311 [ + + ]: 1418 : if (fd < 0)
312 : : {
313 : 394 : closefd = true;
314 : 394 : fd = open (file_name, O_RDONLY);
315 [ - + ]: 394 : if (fd < 0)
316 : : {
317 : 0 : __libdwfl_seterrno (DWFL_E_ERRNO);
318 : 0 : return NULL;
319 : : }
320 : : }
321 : :
322 : 1418 : return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
323 : : }
324 : : INTDEF (dwfl_report_offline)
325 : :
326 : : Dwfl_Module *
327 : 8 : dwfl_report_offline_memory (Dwfl *dwfl, const char *name,
328 : : const char *file_name, char *data, size_t size)
329 : : {
330 [ - + ]: 8 : if (dwfl == NULL)
331 : : return NULL;
332 : :
333 : 8 : Elf *elf;
334 : 8 : Dwfl_Error error = __libdw_open_elf_memory (data, size, &elf, true);
335 [ + + ]: 8 : if (error != DWFL_E_NOERROR)
336 : : {
337 : 4 : __libdwfl_seterrno (error);
338 : 4 : return NULL;
339 : : }
340 : : /* It is ok to pass fd == -1 here, because libelf uses it as a value for
341 : : "no file opened" and supports working with files without fd, thanks to
342 : : the existence of the elf_memory function. */
343 : 4 : Dwfl_Module *mod = process_file (dwfl, name, file_name, -1, elf, NULL);
344 [ - + ]: 4 : if (mod == NULL)
345 : 0 : elf_end (elf);
346 : : return mod;
347 : : }
348 : : INTDEF (dwfl_report_offline_memory)
|