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