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