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