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