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