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