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
dwfl_offline_section_address(Dwfl_Module * mod,void ** userdata,const char * modname,Dwarf_Addr base,const char * secname,Elf32_Word shndx,const GElf_Shdr * shdr,Dwarf_Addr * addr)43 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 assert (mod->e_type == ET_REL);
53 assert (shdr->sh_addr == 0);
54 assert (shdr->sh_flags & SHF_ALLOC);
55 assert (shndx != 0);
56
57 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 Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx);
66 Elf_Scn *scn = NULL;
67 uint_fast32_t skip_alloc = 0;
68 while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn)
69 {
70 assert (scn != NULL);
71 GElf_Shdr shdr_mem;
72 GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem);
73 if (unlikely (sh == NULL))
74 return -1;
75 if (sh->sh_flags & SHF_ALLOC)
76 ++skip_alloc;
77 }
78
79 scn = NULL;
80 while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
81 {
82 GElf_Shdr shdr_mem;
83 GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem);
84 if (unlikely (main_shdr == NULL))
85 return -1;
86 if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0)
87 {
88 assert (main_shdr->sh_flags == shdr->sh_flags);
89 *addr = main_shdr->sh_addr;
90 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 *
process_file(Dwfl * dwfl,const char * name,const char * file_name,int fd,Elf * elf,int (* predicate)(const char * module,const char * file))110 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 switch (elf_kind (elf))
115 {
116 default:
117 case ELF_K_NONE:
118 __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF);
119 return NULL;
120
121 case ELF_K_ELF:
122 return process_elf (dwfl, name, file_name, fd, elf);
123
124 case ELF_K_AR:
125 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 *
process_elf(Dwfl * dwfl,const char * name,const char * file_name,int fd,Elf * elf)131 process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
132 Elf *elf)
133 {
134 Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf,
135 dwfl->offline_next_address, true,
136 false);
137 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 if ((dwfl->offline_next_address >= mod->low_addr
146 || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
147 && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
148 dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
149
150 /* Don't keep the file descriptor around. */
151 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 mod->elfdir = __libdw_debugdir (mod->main.fd);
156 close (mod->main.fd);
157 mod->main.fd = -1;
158 }
159 }
160
161 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
process_archive_member(Dwfl * dwfl,const char * name,const char * file_name,int (* predicate)(const char * module,const char * file),int fd,Elf * member,Dwfl_Module ** mod)167 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 const Elf_Arhdr *h = elf_getarhdr (member);
172 if (unlikely (h == NULL))
173 {
174 __libdwfl_seterrno (DWFL_E_LIBELF);
175 fail:
176 elf_end (member);
177 *mod = NULL;
178 return ELF_C_NULL;
179 }
180
181 if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//")
182 || !strcmp (h->ar_name, "/SYM64/"))
183 {
184 skip:;
185 /* Skip this and go to the next. */
186 Elf_Cmd result = elf_next (member);
187 elf_end (member);
188 return result;
189 }
190
191 char *member_name;
192 if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0))
193 {
194 nomem:
195 __libdwfl_seterrno (DWFL_E_NOMEM);
196 elf_end (member);
197 *mod = NULL;
198 return ELF_C_NULL;
199 }
200
201 char *module_name = NULL;
202 if (name == NULL || name[0] == '\0')
203 name = h->ar_name;
204 else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0))
205 {
206 free (member_name);
207 goto nomem;
208 }
209 else
210 name = module_name;
211
212 if (predicate != NULL)
213 {
214 /* Let the predicate decide whether to use this one. */
215 int want = (*predicate) (name, member_name);
216 if (want <= 0)
217 {
218 free (member_name);
219 free (module_name);
220 if (unlikely (want < 0))
221 {
222 __libdwfl_seterrno (DWFL_E_CB);
223 goto fail;
224 }
225 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 *mod = process_file (dwfl, name, member_name, fd, member, predicate);
233 free (member_name);
234 free (module_name);
235
236 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 return elf_next (member);
241 }
242
243 /* Report each member of the archive as its own module. */
244 static Dwfl_Module *
process_archive(Dwfl * dwfl,const char * name,const char * file_name,int fd,Elf * archive,int (* predicate)(const char * module,const char * file))245 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 Dwfl_Module *mod = NULL;
251 Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
252 if (unlikely (member == NULL)) /* Empty archive. */
253 {
254 __libdwfl_seterrno (DWFL_E_BADELF);
255 return NULL;
256 }
257
258 while (process_archive_member (dwfl, name, file_name, predicate,
259 fd, member, &mod) != ELF_C_NULL)
260 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 if (mod != NULL /* If no modules, caller will clean up. */
267 && elf_end (archive) == 0)
268 close (fd);
269
270 return mod;
271 }
272
273 Dwfl_Module *
274 internal_function
__libdwfl_report_offline(Dwfl * dwfl,const char * name,const char * file_name,int fd,bool closefd,int (* predicate)(const char * module,const char * file))275 __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 Elf *elf;
281 Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true);
282 if (error != DWFL_E_NOERROR)
283 {
284 __libdwfl_seterrno (error);
285 return NULL;
286 }
287 Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate);
288 if (mod == NULL)
289 {
290 elf_end (elf);
291 if (closefd)
292 close (fd);
293 }
294 return mod;
295 }
296
297 Dwfl_Module *
dwfl_report_offline(Dwfl * dwfl,const char * name,const char * file_name,int fd)298 dwfl_report_offline (Dwfl *dwfl, const char *name,
299 const char *file_name, int fd)
300 {
301 if (dwfl == NULL)
302 return NULL;
303
304 bool closefd = false;
305 if (fd < 0)
306 {
307 closefd = true;
308 fd = open (file_name, O_RDONLY);
309 if (fd < 0)
310 {
311 __libdwfl_seterrno (DWFL_E_ERRNO);
312 return NULL;
313 }
314 }
315
316 return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
317 }
318 INTDEF (dwfl_report_offline)
319