• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Recover relocatibility for addresses computed from debug information.
2    Copyright (C) 2005-2009, 2012 Red Hat, Inc.
3    Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
4    Copyright (C) 2022 Google LLC
5    This file is part of elfutils.
6 
7    This file is free software; you can redistribute it and/or modify
8    it under the terms of either
9 
10      * the GNU Lesser General Public License as published by the Free
11        Software Foundation; either version 3 of the License, or (at
12        your option) any later version
13 
14    or
15 
16      * the GNU General Public License as published by the Free
17        Software Foundation; either version 2 of the License, or (at
18        your option) any later version
19 
20    or both in parallel, as here.
21 
22    elfutils is distributed in the hope that it will be useful, but
23    WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25    General Public License for more details.
26 
27    You should have received copies of the GNU General Public License and
28    the GNU Lesser General Public License along with this program.  If
29    not, see <http://www.gnu.org/licenses/>.  */
30 
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #include "libdwflP.h"
36 #include <fcntl.h>
37 
38 /* Since dwfl_report_elf lays out the sections already, this will only be
39    called when the section headers of the debuginfo file are being
40    consulted instead, or for the section placed at 0.  With binutils
41    strip-to-debug, the symbol table is in the debuginfo file and relocation
42    looks there.  */
43 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)44 dwfl_offline_section_address (Dwfl_Module *mod,
45 			      void **userdata __attribute__ ((unused)),
46 			      const char *modname __attribute__ ((unused)),
47 			      Dwarf_Addr base __attribute__ ((unused)),
48 			      const char *secname __attribute__ ((unused)),
49 			      Elf32_Word shndx,
50 			      const GElf_Shdr *shdr __attribute__ ((unused)),
51 			      Dwarf_Addr *addr)
52 {
53   assert (mod->e_type == ET_REL);
54   assert (shdr->sh_addr == 0);
55   assert (shdr->sh_flags & SHF_ALLOC);
56   assert (shndx != 0);
57 
58   if (mod->debug.elf == NULL)
59     /* We are only here because sh_addr is zero even though layout is complete.
60        The first section in the first file under -e is placed at 0.  */
61     return 0;
62 
63   /* The section numbers might not match between the two files.
64      The best we can rely on is the order of SHF_ALLOC sections.  */
65 
66   Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx);
67   Elf_Scn *scn = NULL;
68   uint_fast32_t skip_alloc = 0;
69   while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn)
70     {
71       assert (scn != NULL);
72       GElf_Shdr shdr_mem;
73       GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem);
74       if (unlikely (sh == NULL))
75 	return -1;
76       if (sh->sh_flags & SHF_ALLOC)
77 	++skip_alloc;
78     }
79 
80   scn = NULL;
81   while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
82     {
83       GElf_Shdr shdr_mem;
84       GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem);
85       if (unlikely (main_shdr == NULL))
86 	return -1;
87       if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0)
88 	{
89 	  assert (main_shdr->sh_flags == shdr->sh_flags);
90 	  *addr = main_shdr->sh_addr;
91 	  return 0;
92 	}
93     }
94 
95   /* This should never happen.  */
96   return -1;
97 }
98 INTDEF (dwfl_offline_section_address)
99 
100 /* Forward declarations.  */
101 static Dwfl_Module *process_elf (Dwfl *dwfl, const char *name,
102 				 const char *file_name, int fd, Elf *elf);
103 static Dwfl_Module *process_archive (Dwfl *dwfl, const char *name,
104 				     const char *file_name, int fd, Elf *elf,
105 				     int (*predicate) (const char *module,
106 						       const char *file));
107 
108 /* Report one module for an ELF file, or many for an archive.
109    Always consumes ELF and FD.  */
110 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))111 process_file (Dwfl *dwfl, const char *name, const char *file_name, int fd,
112 	      Elf *elf, int (*predicate) (const char *module,
113 					  const char *file))
114 {
115   switch (elf_kind (elf))
116     {
117     default:
118     case ELF_K_NONE:
119       __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF);
120       return NULL;
121 
122     case ELF_K_ELF:
123       return process_elf (dwfl, name, file_name, fd, elf);
124 
125     case ELF_K_AR:
126       return process_archive (dwfl, name, file_name, fd, elf, predicate);
127     }
128 }
129 
130 /* Report the open ELF file as a module.  Always consumes ELF and FD.  */
131 static Dwfl_Module *
process_elf(Dwfl * dwfl,const char * name,const char * file_name,int fd,Elf * elf)132 process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
133 	     Elf *elf)
134 {
135   Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf,
136 					   dwfl->offline_next_address, true,
137 					   false);
138   if (mod != NULL)
139     {
140       /* If this is an ET_EXEC file with fixed addresses, the address range
141 	 it consumed may or may not intersect with the arbitrary range we
142 	 will use for relocatable modules.  Make sure we always use a free
143 	 range for the offline allocations.  If this module did use
144 	 offline_next_address, it may have rounded it up for the module's
145 	 alignment requirements.  */
146       if ((dwfl->offline_next_address >= mod->low_addr
147 	   || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE)
148 	  && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE)
149 	dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE;
150 
151       /* Don't keep the file descriptor around.  */
152       if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
153 	{
154 	  /* Grab the dir path in case we want to report this file as
155 	     Dwarf later.  */
156 	  mod->elfdir = __libdw_debugdir (mod->main.fd);
157 	  close (mod->main.fd);
158 	  mod->main.fd = -1;
159 	}
160     }
161 
162   return mod;
163 }
164 
165 /* Always consumes MEMBER.  Returns elf_next result on success.
166    For errors returns ELF_C_NULL with *MOD set to null.  */
167 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)168 process_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
169 			int (*predicate) (const char *module, const char *file),
170 			int fd, Elf *member, Dwfl_Module **mod)
171 {
172   const Elf_Arhdr *h = elf_getarhdr (member);
173   if (unlikely (h == NULL))
174     {
175       __libdwfl_seterrno (DWFL_E_LIBELF);
176     fail:
177       elf_end (member);
178       *mod = NULL;
179       return ELF_C_NULL;
180     }
181 
182   if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//")
183       || !strcmp (h->ar_name, "/SYM64/"))
184     {
185     skip:;
186       /* Skip this and go to the next.  */
187       Elf_Cmd result = elf_next (member);
188       elf_end (member);
189       return result;
190     }
191 
192   char *member_name;
193   if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0))
194     {
195     nomem:
196       __libdwfl_seterrno (DWFL_E_NOMEM);
197       elf_end (member);
198       *mod = NULL;
199       return ELF_C_NULL;
200     }
201 
202   char *module_name = NULL;
203   if (name == NULL || name[0] == '\0')
204     name = h->ar_name;
205   else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0))
206     {
207       free (member_name);
208       goto nomem;
209     }
210   else
211     name = module_name;
212 
213   if (predicate != NULL)
214     {
215       /* Let the predicate decide whether to use this one.  */
216       int want = (*predicate) (name, member_name);
217       if (want <= 0)
218 	{
219 	  free (member_name);
220 	  free (module_name);
221 	  if (unlikely (want < 0))
222 	    {
223 	      __libdwfl_seterrno (DWFL_E_CB);
224 	      goto fail;
225 	    }
226 	  goto skip;
227 	}
228     }
229 
230   /* We let __libdwfl_report_elf cache the fd in mod->main.fd,
231      though it's the same fd for all the members.
232      On module teardown we will close it only on the last Elf reference.  */
233   *mod = process_file (dwfl, name, member_name, fd, member, predicate);
234   free (member_name);
235   free (module_name);
236 
237   if (*mod == NULL)
238     {
239       elf_end (member);
240       return ELF_C_NULL;
241     }
242 
243   /* Advance the archive-reading offset for the next iteration.  */
244   return elf_next (member);
245 }
246 
247 /* Report each member of the archive as its own module.  */
248 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))249 process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd,
250 		 Elf *archive,
251 		 int (*predicate) (const char *module, const char *file))
252 
253 {
254   Dwfl_Module *mod = NULL;
255   /* elf_begin supports opening archives even with fd == -1 passed.  */
256   Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
257   if (unlikely (member == NULL)) /* Empty archive.  */
258     {
259       __libdwfl_seterrno (DWFL_E_BADELF);
260       return NULL;
261     }
262 
263   while (process_archive_member (dwfl, name, file_name, predicate,
264 				 fd, member, &mod) != ELF_C_NULL)
265     member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive);
266 
267   /* We can drop the archive Elf handle even if we're still using members
268      in live modules.  When the last module's elf_end on a member returns
269      zero, that module will close FD.  If no modules survived the predicate,
270      we are all done with the file right here.  */
271   if (mod != NULL		/* If no modules, caller will clean up.  */
272       && elf_end (archive) == 0)
273     close (fd);
274 
275   return mod;
276 }
277 
278 Dwfl_Module *
279 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))280 __libdwfl_report_offline (Dwfl *dwfl, const char *name,
281 			  const char *file_name, int fd, bool closefd,
282 			  int (*predicate) (const char *module,
283 					    const char *file))
284 {
285   Elf *elf;
286   Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true);
287   if (error != DWFL_E_NOERROR)
288     {
289       __libdwfl_seterrno (error);
290       return NULL;
291     }
292   Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate);
293   if (mod == NULL)
294     {
295       elf_end (elf);
296       if (closefd)
297 	close (fd);
298     }
299   return mod;
300 }
301 
302 Dwfl_Module *
dwfl_report_offline(Dwfl * dwfl,const char * name,const char * file_name,int fd)303 dwfl_report_offline (Dwfl *dwfl, const char *name,
304 		     const char *file_name, int fd)
305 {
306   if (dwfl == NULL)
307     return NULL;
308 
309   bool closefd = false;
310   if (fd < 0)
311     {
312       closefd = true;
313       fd = open (file_name, O_RDONLY);
314       if (fd < 0)
315 	{
316 	  __libdwfl_seterrno (DWFL_E_ERRNO);
317 	  return NULL;
318 	}
319     }
320 
321   return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
322 }
INTDEF(dwfl_report_offline)323 INTDEF (dwfl_report_offline)
324 
325 Dwfl_Module *
326 dwfl_report_offline_memory (Dwfl *dwfl, const char *name,
327 			    const char *file_name, char *data, size_t size)
328 {
329   if (dwfl == NULL)
330     return NULL;
331 
332   Elf *elf;
333   Dwfl_Error error = __libdw_open_elf_memory (data, size, &elf, true);
334   if (error != DWFL_E_NOERROR)
335     {
336       __libdwfl_seterrno (error);
337       return NULL;
338     }
339   /* It is ok to pass fd == -1 here, because libelf uses it as a value for
340      "no file opened" and supports working with files without fd, thanks to
341      the existence of the elf_memory function.  */
342   Dwfl_Module *mod = process_file (dwfl, name, file_name, -1, elf, NULL);
343   if (mod == NULL)
344     elf_end (elf);
345   return mod;
346 }
347 INTDEF (dwfl_report_offline_memory)
348