Imported Upstream version 0.160
[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, true,
131                                            false);
132   if (mod != NULL)
133     {
134       /* If this is an ET_EXEC file with fixed addresses, the address range
135          it consumed may or may not intersect with the arbitrary range we
136          will use for relocatable modules.  Make sure we always use a free
137          range for the offline allocations.  If this module did use
138          offline_next_address, it may have rounded it up for the module's
139          alignment requirements.  */
140       if ((dwfl->offline_next_address >= mod->low_addr
141            || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
142           && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
143         dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
144
145       /* Don't keep the file descriptor around.  */
146       if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
147         {
148           close (mod->main.fd);
149           mod->main.fd = -1;
150         }
151     }
152
153   return mod;
154 }
155
156 /* Always consumes MEMBER.  Returns elf_next result on success.
157    For errors returns ELF_C_NULL with *MOD set to null.  */
158 static Elf_Cmd
159 process_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
160                         int (*predicate) (const char *module, const char *file),
161                         int fd, Elf *member, Dwfl_Module **mod)
162 {
163   const Elf_Arhdr *h = elf_getarhdr (member);
164   if (unlikely (h == NULL))
165     {
166       __libdwfl_seterrno (DWFL_E_LIBELF);
167     fail:
168       elf_end (member);
169       *mod = NULL;
170       return ELF_C_NULL;
171     }
172
173   if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//")
174       || !strcmp (h->ar_name, "/SYM64/"))
175     {
176     skip:;
177       /* Skip this and go to the next.  */
178       Elf_Cmd result = elf_next (member);
179       elf_end (member);
180       return result;
181     }
182
183   char *member_name;
184   if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0))
185     {
186     nomem:
187       __libdwfl_seterrno (DWFL_E_NOMEM);
188       elf_end (member);
189       *mod = NULL;
190       return ELF_C_NULL;
191     }
192
193   char *module_name = NULL;
194   if (name == NULL || name[0] == '\0')
195     name = h->ar_name;
196   else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0))
197     {
198       free (member_name);
199       goto nomem;
200     }
201   else
202     name = module_name;
203
204   if (predicate != NULL)
205     {
206       /* Let the predicate decide whether to use this one.  */
207       int want = (*predicate) (name, member_name);
208       if (want <= 0)
209         {
210           free (member_name);
211           free (module_name);
212           if (unlikely (want < 0))
213             {
214               __libdwfl_seterrno (DWFL_E_CB);
215               goto fail;
216             }
217           goto skip;
218         }
219     }
220
221   /* We let __libdwfl_report_elf cache the fd in mod->main.fd,
222      though it's the same fd for all the members.
223      On module teardown we will close it only on the last Elf reference.  */
224   *mod = process_file (dwfl, name, member_name, fd, member, predicate);
225   free (member_name);
226   free (module_name);
227
228   if (*mod == NULL)             /* process_file called elf_end.  */
229     return ELF_C_NULL;
230
231   /* Advance the archive-reading offset for the next iteration.  */
232   return elf_next (member);
233 }
234
235 /* Report each member of the archive as its own module.  */
236 static Dwfl_Module *
237 process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd,
238                  Elf *archive,
239                  int (*predicate) (const char *module, const char *file))
240
241 {
242   Dwfl_Module *mod = NULL;
243   Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
244   if (unlikely (member == NULL)) /* Empty archive.  */
245     {
246       __libdwfl_seterrno (DWFL_E_BADELF);
247       return NULL;
248     }
249
250   while (process_archive_member (dwfl, name, file_name, predicate,
251                                  fd, member, &mod) != ELF_C_NULL)
252     member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
253
254   /* We can drop the archive Elf handle even if we're still using members
255      in live modules.  When the last module's elf_end on a member returns
256      zero, that module will close FD.  If no modules survived the predicate,
257      we are all done with the file right here.  */
258   if (mod != NULL               /* If no modules, caller will clean up.  */
259       && elf_end (archive) == 0)
260     close (fd);
261
262   return mod;
263 }
264
265 Dwfl_Module *
266 internal_function
267 __libdwfl_report_offline (Dwfl *dwfl, const char *name,
268                           const char *file_name, int fd, bool closefd,
269                           int (*predicate) (const char *module,
270                                             const char *file))
271 {
272   Elf *elf;
273   Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true);
274   if (error != DWFL_E_NOERROR)
275     {
276       __libdwfl_seterrno (error);
277       return NULL;
278     }
279   Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate);
280   if (mod == NULL)
281     {
282       elf_end (elf);
283       if (closefd)
284         close (fd);
285     }
286   return mod;
287 }
288
289 Dwfl_Module *
290 dwfl_report_offline (Dwfl *dwfl, const char *name,
291                      const char *file_name, int fd)
292 {
293   if (dwfl == NULL)
294     return NULL;
295
296   bool closefd = false;
297   if (fd < 0)
298     {
299       closefd = true;
300       fd = open64 (file_name, O_RDONLY);
301       if (fd < 0)
302         {
303           __libdwfl_seterrno (DWFL_E_ERRNO);
304           return NULL;
305         }
306     }
307
308   return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
309 }
310 INTDEF (dwfl_report_offline)