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