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