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