Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libdwfl / offline.c
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 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   assert (mod->e_type == ET_REL);
49   assert (shdr->sh_addr == 0);
50   assert (shdr->sh_flags & SHF_ALLOC);
51
52   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   Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx);
61   Elf_Scn *scn = NULL;
62   uint_fast32_t skip_alloc = 0;
63   while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn)
64     {
65       assert (scn != NULL);
66       GElf_Shdr shdr_mem;
67       GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem);
68       if (unlikely (sh == NULL))
69         return -1;
70       if (sh->sh_flags & SHF_ALLOC)
71         ++skip_alloc;
72     }
73
74   scn = NULL;
75   while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
76     {
77       GElf_Shdr shdr_mem;
78       GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem);
79       if (unlikely (main_shdr == NULL))
80         return -1;
81       if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0)
82         {
83           assert (main_shdr->sh_flags == shdr->sh_flags);
84           *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 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   switch (elf_kind (elf))
110     {
111     default:
112     case ELF_K_NONE:
113       __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF);
114       return NULL;
115
116     case ELF_K_ELF:
117       return process_elf (dwfl, name, file_name, fd, elf);
118
119     case ELF_K_AR:
120       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 process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
127              Elf *elf)
128 {
129   Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf,
130                                            dwfl->offline_next_address, false);
131   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       if ((dwfl->offline_next_address >= mod->low_addr
140            || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
141           && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
142         dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
143
144       /* Don't keep the file descriptor around.  */
145       if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
146         {
147           close (mod->main.fd);
148           mod->main.fd = -1;
149         }
150     }
151
152   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 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   const Elf_Arhdr *h = elf_getarhdr (member);
163   if (unlikely (h == NULL))
164     {
165       __libdwfl_seterrno (DWFL_E_LIBELF);
166     fail:
167       elf_end (member);
168       *mod = NULL;
169       return ELF_C_NULL;
170     }
171
172   if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//")
173       || !strcmp (h->ar_name, "/SYM64/"))
174     {
175     skip:;
176       /* Skip this and go to the next.  */
177       Elf_Cmd result = elf_next (member);
178       elf_end (member);
179       return result;
180     }
181
182   char *member_name;
183   if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0))
184     {
185     nomem:
186       __libdwfl_seterrno (DWFL_E_NOMEM);
187       elf_end (member);
188       *mod = NULL;
189       return ELF_C_NULL;
190     }
191
192   char *module_name = NULL;
193   if (name == NULL || name[0] == '\0')
194     name = h->ar_name;
195   else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0))
196     {
197       free (member_name);
198       goto nomem;
199     }
200   else
201     name = module_name;
202
203   if (predicate != NULL)
204     {
205       /* Let the predicate decide whether to use this one.  */
206       int want = (*predicate) (name, member_name);
207       if (want <= 0)
208         {
209           free (member_name);
210           free (module_name);
211           if (unlikely (want < 0))
212             {
213               __libdwfl_seterrno (DWFL_E_CB);
214               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   *mod = process_file (dwfl, name, member_name, fd, member, predicate);
224   free (member_name);
225   free (module_name);
226
227   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   return elf_next (member);
232 }
233
234 /* Report each member of the archive as its own module.  */
235 static Dwfl_Module *
236 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   Dwfl_Module *mod = NULL;
242   Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
243   if (unlikely (member == NULL)) /* Empty archive.  */
244     {
245       __libdwfl_seterrno (DWFL_E_BADELF);
246       return NULL;
247     }
248
249   while (process_archive_member (dwfl, name, file_name, predicate,
250                                  fd, member, &mod) != ELF_C_NULL)
251     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   if (mod != NULL               /* If no modules, caller will clean up.  */
258       && elf_end (archive) == 0)
259     close (fd);
260
261   return mod;
262 }
263
264 Dwfl_Module *
265 internal_function
266 __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   Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true);
273   if (error != DWFL_E_NOERROR)
274     {
275       __libdwfl_seterrno (error);
276       return NULL;
277     }
278   Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate);
279   if (mod == NULL)
280     {
281       elf_end (elf);
282       if (closefd)
283         close (fd);
284     }
285   return mod;
286 }
287
288 Dwfl_Module *
289 dwfl_report_offline (Dwfl *dwfl, const char *name,
290                      const char *file_name, int fd)
291 {
292   if (dwfl == NULL)
293     return NULL;
294
295   bool closefd = false;
296   if (fd < 0)
297     {
298       closefd = true;
299       fd = open64 (file_name, O_RDONLY);
300       if (fd < 0)
301         {
302           __libdwfl_seterrno (DWFL_E_ERRNO);
303           return NULL;
304         }
305     }
306
307   return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
308 }
309 INTDEF (dwfl_report_offline)