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