Coverage Report

Created: 2025-07-18 06:06

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