Coverage Report

Created: 2026-08-13 06:52

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