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