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