Finish elflint .gnu.attributes checking
[platform/upstream/elfutils.git] / libdwfl / relocate.c
1 /* Relocate debug information.
2    Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
3    This file is part of Red Hat elfutils.
4
5    Red Hat elfutils is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by the
7    Free Software Foundation; version 2 of the License.
8
9    Red Hat elfutils is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with Red Hat elfutils; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
17
18    In addition, as a special exception, Red Hat, Inc. gives You the
19    additional right to link the code of Red Hat elfutils with code licensed
20    under any Open Source Initiative certified open source license
21    (http://www.opensource.org/licenses/index.php) which requires the
22    distribution of source code with any binary distribution and to
23    distribute linked combinations of the two.  Non-GPL Code permitted under
24    this exception must only link to the code of Red Hat elfutils through
25    those well defined interfaces identified in the file named EXCEPTION
26    found in the source code files (the "Approved Interfaces").  The files
27    of Non-GPL Code may instantiate templates or use macros or inline
28    functions from the Approved Interfaces without causing the resulting
29    work to be covered by the GNU General Public License.  Only Red Hat,
30    Inc. may make changes or additions to the list of Approved Interfaces.
31    Red Hat's grant of this exception is conditioned upon your not adding
32    any new exceptions.  If you wish to add a new Approved Interface or
33    exception, please contact Red Hat.  You must obey the GNU General Public
34    License in all respects for all of the Red Hat elfutils code and other
35    code used in conjunction with Red Hat elfutils except the Non-GPL Code
36    covered by this exception.  If you modify this file, you may extend this
37    exception to your version of the file, but you are not obligated to do
38    so.  If you do not wish to provide this exception without modification,
39    you must delete this exception statement from your version and license
40    this file solely under the GPL without exception.
41
42    Red Hat elfutils is an included package of the Open Invention Network.
43    An included package of the Open Invention Network is a package for which
44    Open Invention Network licensees cross-license their patents.  No patent
45    license is granted, either expressly or impliedly, by designation as an
46    included package.  Should you wish to participate in the Open Invention
47    Network licensing program, please visit www.openinventionnetwork.com
48    <http://www.openinventionnetwork.com>.  */
49
50 #include "libdwflP.h"
51
52 typedef uint8_t GElf_Byte;
53
54 /* Adjust *VALUE to add the load address of the SHNDX section.
55    We update the section header in place to cache the result.  */
56
57 Dwfl_Error
58 internal_function
59 __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
60                           Elf32_Word shndx, GElf_Addr *value)
61 {
62   Elf_Scn *refscn = elf_getscn (elf, shndx);
63   GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
64   if (refshdr == NULL)
65     return DWFL_E_LIBELF;
66
67   if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
68     {
69       /* This is a loaded section.  Find its actual
70          address and update the section header.  */
71
72       if (*shstrndx == SHN_UNDEF
73           && unlikely (elf_getshstrndx (elf, shstrndx) < 0))
74         return DWFL_E_LIBELF;
75
76       const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
77       if (unlikely (name == NULL))
78         return DWFL_E_LIBELF;
79
80       if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
81                                                     name, shndx, refshdr,
82                                                     &refshdr->sh_addr))
83         return CBFAIL;
84
85       if (refshdr->sh_addr == (Dwarf_Addr) -1l)
86         /* The callback indicated this section wasn't really loaded but we
87            don't really care.  */
88         refshdr->sh_addr = 0;   /* Make no adjustment below.  */
89
90       /* Update the in-core file's section header to show the final
91          load address (or unloadedness).  This serves as a cache,
92          so we won't get here again for the same section.  */
93       if (likely (refshdr->sh_addr != 0)
94           && unlikely (! gelf_update_shdr (refscn, refshdr)))
95         return DWFL_E_LIBELF;
96     }
97
98   /* Apply the adjustment.  */
99   *value += refshdr->sh_addr;
100   return DWFL_E_NOERROR;
101 }
102
103
104 /* Cache used by relocate_getsym.  */
105 struct reloc_symtab_cache
106 {
107   Elf *symelf;
108   Elf_Data *symdata;
109   Elf_Data *symxndxdata;
110   Elf_Data *symstrdata;
111   size_t symshstrndx;
112   size_t strtabndx;
113 };
114 #define RELOC_SYMTAB_CACHE(cache)       \
115   struct reloc_symtab_cache cache =     \
116     { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
117
118 /* This is just doing dwfl_module_getsym, except that we must always use
119    the symbol table in RELOCATED itself when it has one, not MOD->symfile.  */
120 static Dwfl_Error
121 relocate_getsym (Dwfl_Module *mod,
122                  Elf *relocated, struct reloc_symtab_cache *cache,
123                  int symndx, GElf_Sym *sym, GElf_Word *shndx)
124 {
125   if (cache->symdata == NULL)
126     {
127       if (mod->symfile == NULL || mod->symfile->elf != relocated)
128         {
129           /* We have to look up the symbol table in the file we are
130              relocating, if it has its own.  These reloc sections refer to
131              the symbol table in this file, and a symbol table in the main
132              file might not match.  However, some tools did produce ET_REL
133              .debug files with relocs but no symtab of their own.  */
134           Elf_Scn *scn = NULL;
135           while ((scn = elf_nextscn (relocated, scn)) != NULL)
136             {
137               GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
138               if (shdr != NULL)
139                 switch (shdr->sh_type)
140                   {
141                   default:
142                     continue;
143                   case SHT_SYMTAB:
144                     cache->symelf = relocated;
145                     cache->symdata = elf_getdata (scn, NULL);
146                     cache->strtabndx = shdr->sh_link;
147                     if (unlikely (cache->symdata == NULL))
148                       return DWFL_E_LIBELF;
149                     break;
150                   case SHT_SYMTAB_SHNDX:
151                     cache->symxndxdata = elf_getdata (scn, NULL);
152                     if (unlikely (cache->symxndxdata == NULL))
153                       return DWFL_E_LIBELF;
154                     break;
155                   }
156               if (cache->symdata != NULL && cache->symxndxdata != NULL)
157                 break;
158             }
159         }
160       if (cache->symdata == NULL)
161         {
162           /* We might not have looked for a symbol table file yet,
163              when coming from __libdwfl_relocate_section.  */
164           if (unlikely (mod->symfile == NULL)
165               && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
166             return dwfl_errno ();
167
168           /* The symbol table we have already cached is the one from
169              the file being relocated, so it's what we need.  Or else
170              this is an ET_REL .debug file with no .symtab of its own;
171              the symbols refer to the section indices in the main file.  */
172           cache->symelf = mod->symfile->elf;
173           cache->symdata = mod->symdata;
174           cache->symxndxdata = mod->symxndxdata;
175           cache->symstrdata = mod->symstrdata;
176         }
177     }
178
179   if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
180                                   symndx, sym, shndx) == NULL))
181     return DWFL_E_LIBELF;
182
183   if (sym->st_shndx != SHN_XINDEX)
184     *shndx = sym->st_shndx;
185
186   switch (*shndx)
187     {
188     case SHN_ABS:
189     case SHN_UNDEF:
190     case SHN_COMMON:
191       return DWFL_E_NOERROR;
192     }
193
194   return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
195                                    *shndx, &sym->st_value);
196 }
197
198 /* Handle an undefined symbol.  We really only support ET_REL for Linux
199    kernel modules, and offline archives.  The behavior of the Linux module
200    loader is very simple and easy to mimic.  It only matches magically
201    exported symbols, and we match any defined symbols.  But we get the same
202    answer except when the module's symbols are undefined and would prevent
203    it from being loaded.  */
204 static Dwfl_Error
205 resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
206                 GElf_Sym *sym, GElf_Word shndx)
207 {
208   /* First we need its name.  */
209   if (sym->st_name != 0)
210     {
211       if (symtab->symstrdata == NULL)
212         {
213           /* Cache the strtab for this symtab.  */
214           assert (referer->symfile == NULL
215                   || referer->symfile->elf != symtab->symelf);
216           symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
217                                                         symtab->strtabndx),
218                                             NULL);
219           if (unlikely (symtab->symstrdata == NULL))
220             return DWFL_E_LIBELF;
221         }
222       if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
223         return DWFL_E_BADSTROFF;
224
225       const char *name = symtab->symstrdata->d_buf;
226       name += sym->st_name;
227
228       for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
229         if (m != referer)
230           {
231             /* Get this module's symtab.
232                If we got a fresh error reading the table, report it.
233                If we just have no symbols in this module, no harm done.  */
234             if (m->symdata == NULL
235                 && m->symerr == DWFL_E_NOERROR
236                 && INTUSE(dwfl_module_getsymtab) (m) < 0
237                 && m->symerr != DWFL_E_NO_SYMTAB)
238               return m->symerr;
239
240             for (size_t ndx = 1; ndx < m->syments; ++ndx)
241               {
242                 sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
243                                         ndx, sym, &shndx);
244                 if (unlikely (sym == NULL))
245                   return DWFL_E_LIBELF;
246                 if (sym->st_shndx != SHN_XINDEX)
247                   shndx = sym->st_shndx;
248
249                 /* We are looking for a defined global symbol with a name.  */
250                 if (shndx == SHN_UNDEF || shndx == SHN_COMMON
251                     || GELF_ST_BIND (sym->st_info) == STB_LOCAL
252                     || sym->st_name == 0)
253                   continue;
254
255                 /* Get this candidate symbol's name.  */
256                 if (unlikely (sym->st_name >= m->symstrdata->d_size))
257                   return DWFL_E_BADSTROFF;
258                 const char *n = m->symstrdata->d_buf;
259                 n += sym->st_name;
260
261                 /* Does the name match?  */
262                 if (strcmp (name, n))
263                   continue;
264
265                 /* We found it!  */
266                 if (shndx == SHN_ABS)
267                   return DWFL_E_NOERROR;
268
269                 /* In an ET_REL file, the symbol table values are relative
270                    to the section, not to the module's load base.  */
271                 size_t symshstrndx = SHN_UNDEF;
272                 return __libdwfl_relocate_value (m, m->symfile->elf,
273                                                  &symshstrndx,
274                                                  shndx, &sym->st_value);
275               }
276           }
277     }
278
279   return DWFL_E_RELUNDEF;
280 }
281
282 static Dwfl_Error
283 relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
284                   size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
285                   Elf_Scn *scn, GElf_Shdr *shdr,
286                   Elf_Scn *tscn, bool debugscn, bool partial)
287 {
288   /* First, fetch the name of the section these relocations apply to.  */
289   GElf_Shdr tshdr_mem;
290   GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
291   const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
292   if (tname == NULL)
293     return DWFL_E_LIBELF;
294
295   if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
296     /* This relocation section is not for a debugging section.
297        Nothing to do here.  */
298     return DWFL_E_NOERROR;
299
300   /* Fetch the section data that needs the relocations applied.  */
301   Elf_Data *tdata = elf_rawdata (tscn, NULL);
302   if (tdata == NULL)
303     return DWFL_E_LIBELF;
304
305   /* Apply one relocation.  Returns true for any invalid data.  */
306   Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
307                        int rtype, int symndx)
308   {
309     /* First see if this is a reloc we can handle.
310        If we are skipping it, don't bother resolving the symbol.  */
311     Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
312     if (unlikely (type == ELF_T_NUM))
313       return DWFL_E_BADRELTYPE;
314
315     /* First, resolve the symbol to an absolute value.  */
316     GElf_Addr value;
317
318     if (symndx == STN_UNDEF)
319       /* When strip removes a section symbol referring to a
320          section moved into the debuginfo file, it replaces
321          that symbol index in relocs with STN_UNDEF.  We
322          don't actually need the symbol, because those relocs
323          are always references relative to the nonallocated
324          debugging sections, which start at zero.  */
325       value = 0;
326     else
327       {
328         GElf_Sym sym;
329         GElf_Word shndx;
330         Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
331                                             symndx, &sym, &shndx);
332         if (unlikely (error != DWFL_E_NOERROR))
333           return error;
334
335         if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
336           {
337             /* Maybe we can figure it out anyway.  */
338             error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
339             if (error != DWFL_E_NOERROR)
340               return error;
341           }
342
343         value = sym.st_value;
344       }
345
346     /* These are the types we can relocate.  */
347 #define TYPES           DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);     \
348     DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);                       \
349     DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
350     size_t size;
351     switch (type)
352       {
353 #define DO_TYPE(NAME, Name)                     \
354         case ELF_T_##NAME:                      \
355           size = sizeof (GElf_##Name);          \
356         break
357         TYPES;
358 #undef DO_TYPE
359       default:
360         return DWFL_E_BADRELTYPE;
361       }
362
363     if (offset + size > tdata->d_size)
364       return DWFL_E_BADRELOFF;
365
366 #define DO_TYPE(NAME, Name) GElf_##Name Name;
367     union { TYPES; } tmpbuf;
368 #undef DO_TYPE
369     Elf_Data tmpdata =
370       {
371         .d_type = type,
372         .d_buf = &tmpbuf,
373         .d_size = size,
374         .d_version = EV_CURRENT,
375       };
376     Elf_Data rdata =
377       {
378         .d_type = type,
379         .d_buf = tdata->d_buf + offset,
380         .d_size = size,
381         .d_version = EV_CURRENT,
382       };
383
384     /* XXX check for overflow? */
385     if (addend)
386       {
387         /* For the addend form, we have the value already.  */
388         value += *addend;
389         switch (type)
390           {
391 #define DO_TYPE(NAME, Name)                     \
392             case ELF_T_##NAME:                  \
393               tmpbuf.Name = value;              \
394             break
395             TYPES;
396 #undef DO_TYPE
397           default:
398             abort ();
399           }
400       }
401     else
402       {
403         /* Extract the original value and apply the reloc.  */
404         Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
405                                      ehdr->e_ident[EI_DATA]);
406         if (d == NULL)
407           return DWFL_E_LIBELF;
408         assert (d == &tmpdata);
409         switch (type)
410           {
411 #define DO_TYPE(NAME, Name)                             \
412             case ELF_T_##NAME:                          \
413               tmpbuf.Name += (GElf_##Name) value;       \
414             break
415             TYPES;
416 #undef DO_TYPE
417           default:
418             abort ();
419           }
420       }
421
422     /* Now convert the relocated datum back to the target
423        format.  This will write into rdata.d_buf, which
424        points into the raw section data being relocated.  */
425     Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
426                                  ehdr->e_ident[EI_DATA]);
427     if (s == NULL)
428       return DWFL_E_LIBELF;
429     assert (s == &rdata);
430
431     /* We have applied this relocation!  */
432     return DWFL_E_NOERROR;
433   }
434
435   /* Fetch the relocation section and apply each reloc in it.  */
436   Elf_Data *reldata = elf_getdata (scn, NULL);
437   if (reldata == NULL)
438     return DWFL_E_LIBELF;
439
440   Dwfl_Error result = DWFL_E_NOERROR;
441   bool first_badreltype = true;
442   inline void check_badreltype (void)
443   {
444     if (first_badreltype)
445       {
446         first_badreltype = false;
447         if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
448           /* This might be because ebl_openbackend failed to find
449              any libebl_CPU.so library.  Diagnose that clearly.  */
450           result = DWFL_E_UNKNOWN_MACHINE;
451       }
452   }
453
454   size_t nrels = shdr->sh_size / shdr->sh_entsize;
455   size_t complete = 0;
456   if (shdr->sh_type == SHT_REL)
457     for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
458       {
459         GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
460         if (r == NULL)
461           return DWFL_E_LIBELF;
462         result = relocate (r->r_offset, NULL,
463                            GELF_R_TYPE (r->r_info),
464                            GELF_R_SYM (r->r_info));
465         check_badreltype ();
466         if (partial)
467           switch (result)
468             {
469             case DWFL_E_NOERROR:
470               /* We applied the relocation.  Elide it.  */
471               memset (&rel_mem, 0, sizeof rel_mem);
472               gelf_update_rel (reldata, relidx, &rel_mem);
473               ++complete;
474               break;
475             case DWFL_E_BADRELTYPE:
476             case DWFL_E_RELUNDEF:
477               /* We couldn't handle this relocation.  Skip it.  */
478               result = DWFL_E_NOERROR;
479               break;
480             default:
481               break;
482             }
483       }
484   else
485     for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
486       {
487         GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
488                                                &rela_mem);
489         if (r == NULL)
490           return DWFL_E_LIBELF;
491         result = relocate (r->r_offset, &r->r_addend,
492                            GELF_R_TYPE (r->r_info),
493                            GELF_R_SYM (r->r_info));
494         check_badreltype ();
495         if (partial)
496           switch (result)
497             {
498             case DWFL_E_NOERROR:
499               /* We applied the relocation.  Elide it.  */
500               memset (&rela_mem, 0, sizeof rela_mem);
501               gelf_update_rela (reldata, relidx, &rela_mem);
502               ++complete;
503               break;
504             case DWFL_E_BADRELTYPE:
505             case DWFL_E_RELUNDEF:
506               /* We couldn't handle this relocation.  Skip it.  */
507               result = DWFL_E_NOERROR;
508               break;
509             default:
510               break;
511             }
512       }
513
514   if (likely (result == DWFL_E_NOERROR))
515     {
516       if (!partial || complete == nrels)
517         /* Mark this relocation section as being empty now that we have
518            done its work.  This affects unstrip -R, so e.g. it emits an
519            empty .rela.debug_info along with a .debug_info that has
520            already been fully relocated.  */
521         nrels = 0;
522       else if (complete != 0)
523         {
524           /* We handled some of the relocations but not all.
525              We've zeroed out the ones we processed.
526              Now remove them from the section.  */
527
528           size_t next = 0;
529           if (shdr->sh_type == SHT_REL)
530             for (size_t relidx = 0; relidx < nrels; ++relidx)
531               {
532                 GElf_Rel rel_mem;
533                 GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
534                 if (r->r_info != 0 || r->r_offset != 0)
535                   {
536                     if (next != relidx)
537                       gelf_update_rel (reldata, next, r);
538                     ++next;
539                   }
540               }
541           else
542             for (size_t relidx = 0; relidx < nrels; ++relidx)
543               {
544                 GElf_Rela rela_mem;
545                 GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
546                 if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
547                   {
548                     if (next != relidx)
549                       gelf_update_rela (reldata, next, r);
550                     ++next;
551                   }
552               }
553           nrels = next;
554         }
555
556       shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
557       gelf_update_shdr (scn, shdr);
558     }
559
560   return result;
561 }
562
563 Dwfl_Error
564 internal_function
565 __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
566 {
567   assert (mod->e_type == ET_REL);
568
569   GElf_Ehdr ehdr_mem;
570   const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem);
571   if (ehdr == NULL)
572     return DWFL_E_LIBELF;
573
574   size_t d_shstrndx;
575   if (elf_getshstrndx (debugfile, &d_shstrndx) < 0)
576     return DWFL_E_LIBELF;
577
578   RELOC_SYMTAB_CACHE (reloc_symtab);
579
580   /* Look at each section in the debuginfo file, and process the
581      relocation sections for debugging sections.  */
582   Dwfl_Error result = DWFL_E_NOERROR;
583   Elf_Scn *scn = NULL;
584   while (result == DWFL_E_NOERROR
585          && (scn = elf_nextscn (debugfile, scn)) != NULL)
586     {
587       GElf_Shdr shdr_mem;
588       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
589
590       if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
591           && shdr->sh_size != 0)
592         {
593           /* It's a relocation section.  */
594
595           Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
596           if (unlikely (tscn == NULL))
597             result = DWFL_E_LIBELF;
598           else
599             result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
600                                        &reloc_symtab, scn, shdr, tscn,
601                                        debug, !debug);
602         }
603     }
604
605   return result;
606 }
607
608 Dwfl_Error
609 internal_function
610 __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
611                             Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
612 {
613   GElf_Ehdr ehdr_mem;
614   GElf_Shdr shdr_mem;
615
616   RELOC_SYMTAB_CACHE (reloc_symtab);
617
618   size_t shstrndx;
619   if (elf_getshstrndx (relocated, &shstrndx) < 0)
620     return DWFL_E_LIBELF;
621
622   return (__libdwfl_module_getebl (mod)
623           ?: relocate_section (mod, relocated,
624                                gelf_getehdr (relocated, &ehdr_mem), shstrndx,
625                                &reloc_symtab,
626                                relocscn, gelf_getshdr (relocscn, &shdr_mem),
627                                tscn, false, partial));
628 }