Coverage Report

Created: 2025-06-24 06:45

/src/binutils-gdb/bfd/elf-sframe.c
Line
Count
Source (jump to first uncovered line)
1
/* .sframe section processing.
2
   Copyright (C) 2022-2025 Free Software Foundation, Inc.
3
4
   This file is part of BFD, the Binary File Descriptor library.
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program; if not, write to the Free Software
18
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19
   MA 02110-1301, USA.  */
20
21
#include "sysdep.h"
22
#include "bfd.h"
23
#include "libbfd.h"
24
#include "elf-bfd.h"
25
#include "sframe-api.h"
26
27
/* Return TRUE if the function has been marked for deletion during the linking
28
   process.  */
29
30
static bool
31
sframe_decoder_func_deleted_p (struct sframe_dec_info *sfd_info,
32
             unsigned int func_idx)
33
0
{
34
0
  if (func_idx < sfd_info->sfd_fde_count)
35
0
    return sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p;
36
37
0
  return false;
38
0
}
39
40
/* Mark the function in the decoder info for deletion.  */
41
42
static void
43
sframe_decoder_mark_func_deleted (struct sframe_dec_info *sfd_info,
44
          unsigned int func_idx)
45
0
{
46
0
  if (func_idx < sfd_info->sfd_fde_count)
47
0
    sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p = true;
48
0
}
49
50
/* Get the relocation offset from the decoder info for the given function.  */
51
52
static unsigned int
53
sframe_decoder_get_func_r_offset (struct sframe_dec_info *sfd_info,
54
          unsigned int func_idx)
55
0
{
56
0
  BFD_ASSERT (func_idx < sfd_info->sfd_fde_count);
57
0
  unsigned int func_r_offset
58
0
    = sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset;
59
  /* There must have been a reloc.  */
60
0
  BFD_ASSERT (func_r_offset);
61
0
  return func_r_offset;
62
0
}
63
64
/* Bookkeep the function relocation offset in the decoder info.  */
65
66
static void
67
sframe_decoder_set_func_r_offset (struct sframe_dec_info *sfd_info,
68
          unsigned int func_idx,
69
          unsigned int r_offset)
70
0
{
71
0
  if (func_idx < sfd_info->sfd_fde_count)
72
0
    sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset = r_offset;
73
0
}
74
75
/* Get the relocation index in the elf_reloc_cookie for the function.  */
76
77
static unsigned int
78
sframe_decoder_get_func_reloc_index (struct sframe_dec_info *sfd_info,
79
             unsigned int func_idx)
80
0
{
81
0
  BFD_ASSERT (func_idx < sfd_info->sfd_fde_count);
82
0
  return sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index;
83
0
}
84
85
/* Bookkeep the relocation index in the elf_reloc_cookie for the function.  */
86
87
static void
88
sframe_decoder_set_func_reloc_index (struct sframe_dec_info *sfd_info,
89
             unsigned int func_idx,
90
             unsigned int reloc_index)
91
0
{
92
0
  if (func_idx < sfd_info->sfd_fde_count)
93
0
    sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index = reloc_index;
94
0
}
95
96
/* Initialize the set of additional information in CFD_INFO,
97
   needed for linking SEC.  Returns TRUE if setup is done successfully.  */
98
99
static bool
100
sframe_decoder_init_func_bfdinfo (bfd *abfd,
101
          const asection *sec,
102
          struct sframe_dec_info *sfd_info,
103
          const struct elf_reloc_cookie *cookie)
104
0
{
105
0
  unsigned int fde_count;
106
0
  unsigned int func_bfdinfo_size, i;
107
0
  const Elf_Internal_Rela *rel;
108
109
0
  fde_count = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx);
110
0
  sfd_info->sfd_fde_count = fde_count;
111
112
  /* Allocate and clear the memory.  */
113
0
  func_bfdinfo_size = (sizeof (struct sframe_func_bfdinfo)) * fde_count;
114
0
  sfd_info->sfd_func_bfdinfo = bfd_zalloc (abfd, func_bfdinfo_size);
115
0
  if (sfd_info->sfd_func_bfdinfo == NULL)
116
0
    return false;
117
118
  /* For linker generated .sframe sections, we have no relocs.  Skip.  */
119
0
  if ((sec->flags & SEC_LINKER_CREATED) && cookie->rels == NULL)
120
0
    return true;
121
122
0
  BFD_ASSERT (cookie->rels + fde_count == cookie->relend);
123
0
  rel = cookie->rels;
124
0
  for (i = 0; i < fde_count; i++)
125
0
    {
126
      /* Bookkeep the relocation offset and relocation index of each function
127
   for later use.  */
128
0
      sframe_decoder_set_func_r_offset (sfd_info, i, rel->r_offset);
129
0
      sframe_decoder_set_func_reloc_index (sfd_info, i, i);
130
131
0
      rel++;
132
0
    }
133
134
0
  return true;
135
0
}
136
137
/* Read the value from CONTENTS at the specified OFFSET for the given ABFD.  */
138
139
static bfd_vma
140
sframe_read_value (bfd *abfd, bfd_byte *contents, unsigned int offset,
141
       unsigned int width)
142
0
{
143
0
  BFD_ASSERT (contents && offset);
144
  /* Supporting the usecase of reading only the 4-byte relocated
145
     value (signed offset for func start addr) for now.  */
146
0
  BFD_ASSERT (width == 4);
147
  /* FIXME endianness ?? */
148
0
  unsigned char *buf = contents + offset;
149
0
  bfd_vma value = bfd_get_signed_32 (abfd, buf);
150
0
  return value;
151
0
}
152
153
/* Return true if there is at least one non-empty .sframe section in
154
   input files.  Can only be called after ld has mapped input to
155
   output sections, and before sections are stripped.  */
156
157
bool
158
_bfd_elf_sframe_present (struct bfd_link_info *info)
159
0
{
160
0
  asection *sframe = bfd_get_section_by_name (info->output_bfd, ".sframe");
161
162
0
  if (sframe == NULL)
163
0
    return false;
164
165
  /* Count only sections which have at least a single FDE.  */
166
0
  for (sframe = sframe->map_head.s; sframe != NULL; sframe = sframe->map_head.s)
167
    /* Note that this may become an approximate check in the future when
168
       some ABI/arch begin to use the sfh_auxhdr_len.  When sfh_auxhdr_len has
169
       non-zero value, it will need to be accounted for in the calculation of
170
       the SFrame header size.  */
171
0
    if (sframe->size > sizeof (sframe_header))
172
0
      return true;
173
0
  return false;
174
0
}
175
176
/* Try to parse .sframe section SEC, which belongs to ABFD.  Store the
177
   information in the section's sec_info field on success.  COOKIE
178
   describes the relocations in SEC.
179
180
   Returns TRUE if success, FALSE if any error or failure.  */
181
182
bool
183
_bfd_elf_parse_sframe (bfd *abfd,
184
           struct bfd_link_info *info ATTRIBUTE_UNUSED,
185
           asection *sec, struct elf_reloc_cookie *cookie)
186
0
{
187
0
  bfd_byte *sfbuf = NULL;
188
0
  struct sframe_dec_info *sfd_info;
189
0
  sframe_decoder_ctx *sfd_ctx;
190
0
  bfd_size_type sf_size;
191
0
  int decerr = 0;
192
193
0
  if (sec->size == 0
194
0
      || (sec->flags & SEC_HAS_CONTENTS) == 0
195
0
      || sec->sec_info_type != SEC_INFO_TYPE_NONE)
196
0
    {
197
      /* This file does not contain .sframe information.  */
198
0
      return false;
199
0
    }
200
201
0
  if (bfd_is_abs_section (sec->output_section))
202
0
    {
203
      /* At least one of the sections is being discarded from the
204
   link, so we should just ignore them.  */
205
0
      return false;
206
0
    }
207
208
  /* Read the SFrame stack trace information from abfd.  */
209
0
  if (!_bfd_elf_mmap_section_contents (abfd, sec, &sfbuf))
210
0
    goto fail_no_free;
211
212
  /* Decode the buffer and keep decoded contents for later use.
213
     Relocations are performed later, but are such that the section's
214
     size is unaffected.  */
215
0
  sfd_info = bfd_alloc (abfd, sizeof (*sfd_info));
216
0
  sf_size = sec->size;
217
218
0
  sfd_info->sfd_ctx = sframe_decode ((const char*)sfbuf, sf_size, &decerr);
219
0
  sfd_ctx = sfd_info->sfd_ctx;
220
0
  if (!sfd_ctx)
221
    /* Free'ing up any memory held by decoder context is done by
222
       sframe_decode in case of error.  */
223
0
    goto fail_no_free;
224
225
0
  if (!sframe_decoder_init_func_bfdinfo (abfd, sec, sfd_info, cookie))
226
0
    {
227
0
      sframe_decoder_free (&sfd_ctx);
228
0
      goto fail_no_free;
229
0
    }
230
231
0
  elf_section_data (sec)->sec_info = sfd_info;
232
0
  sec->sec_info_type = SEC_INFO_TYPE_SFRAME;
233
234
0
  goto success;
235
236
0
fail_no_free:
237
0
  _bfd_error_handler
238
0
   (_("error in %pB(%pA); no .sframe will be created"),
239
0
    abfd, sec);
240
0
  return false;
241
0
success:
242
0
  _bfd_elf_munmap_section_contents (sec, sfbuf);
243
0
  return true;
244
0
}
245
246
/* This function is called for each input file before the .sframe section
247
   is relocated.  It marks the SFrame FDE for the discarded functions for
248
   deletion.
249
250
   The function returns TRUE iff any entries have been deleted.  */
251
252
bool
253
_bfd_elf_discard_section_sframe
254
   (asection *sec,
255
    bool (*reloc_symbol_deleted_p) (bfd_vma, void *),
256
    struct elf_reloc_cookie *cookie)
257
0
{
258
0
  bool changed;
259
0
  bool keep;
260
0
  unsigned int i;
261
0
  unsigned int func_desc_offset;
262
0
  unsigned int num_fidx;
263
0
  struct sframe_dec_info *sfd_info;
264
265
0
  changed = false;
266
  /* FIXME - if relocatable link and changed = true, how does the final
267
     .rela.sframe get updated ?.  */
268
0
  keep = false;
269
270
0
  sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info;
271
272
  /* Skip checking for the linker created .sframe sections
273
     (for PLT sections).  */
274
0
  if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL)
275
0
    {
276
0
      num_fidx = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx);
277
0
      for (i = 0; i < num_fidx; i++)
278
0
  {
279
0
    func_desc_offset = sframe_decoder_get_func_r_offset (sfd_info, i);
280
281
0
    cookie->rel = cookie->rels
282
0
      + sframe_decoder_get_func_reloc_index (sfd_info, i);
283
0
    keep = !(*reloc_symbol_deleted_p) (func_desc_offset, cookie);
284
285
0
    if (!keep)
286
0
      {
287
0
        sframe_decoder_mark_func_deleted (sfd_info, i);
288
0
        changed = true;
289
0
      }
290
0
  }
291
0
    }
292
0
  return changed;
293
0
}
294
295
/* Update the reference to the output .sframe section in the output ELF
296
   BFD ABFD.  Returns true if no error.  */
297
298
bool
299
_bfd_elf_set_section_sframe (bfd *abfd,
300
        struct bfd_link_info *info)
301
0
{
302
0
  asection *cfsec;
303
304
0
  cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe");
305
0
  if (!cfsec)
306
0
    return false;
307
308
0
  elf_sframe (abfd) = cfsec;
309
310
0
  return true;
311
0
}
312
313
/* Merge .sframe section SEC.  This is called with the relocated
314
   CONTENTS.  */
315
316
bool
317
_bfd_elf_merge_section_sframe (bfd *abfd,
318
             struct bfd_link_info *info,
319
             asection *sec,
320
             bfd_byte *contents)
321
0
{
322
0
  struct sframe_dec_info *sfd_info;
323
0
  struct sframe_enc_info *sfe_info;
324
0
  sframe_decoder_ctx *sfd_ctx;
325
0
  sframe_encoder_ctx *sfe_ctx;
326
0
  uint8_t sfd_ctx_abi_arch;
327
0
  int8_t sfd_ctx_fixed_fp_offset;
328
0
  int8_t sfd_ctx_fixed_ra_offset;
329
0
  uint8_t dctx_version;
330
0
  uint8_t ectx_version;
331
0
  int encerr = 0;
332
333
0
  struct elf_link_hash_table *htab;
334
0
  asection *cfsec;
335
336
  /* Sanity check - handle SFrame sections only.  */
337
0
  if (sec->sec_info_type != SEC_INFO_TYPE_SFRAME)
338
0
    return false;
339
340
0
  sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info;
341
0
  sfd_ctx = sfd_info->sfd_ctx;
342
343
0
  htab = elf_hash_table (info);
344
0
  sfe_info = &(htab->sfe_info);
345
0
  sfe_ctx = sfe_info->sfe_ctx;
346
347
  /* All input bfds are expected to have a valid SFrame section.  Even if
348
     the SFrame section is empty with only a header, there must be a valid
349
     SFrame decoder context by now.  The SFrame encoder context, however,
350
     will get set later here, if this is the first call to the function.  */
351
0
  if (sfd_ctx == NULL || sfe_info == NULL)
352
0
    return false;
353
354
0
  if (htab->sfe_info.sfe_ctx == NULL)
355
0
    {
356
0
      sfd_ctx_abi_arch = sframe_decoder_get_abi_arch (sfd_ctx);
357
0
      sfd_ctx_fixed_fp_offset = sframe_decoder_get_fixed_fp_offset (sfd_ctx);
358
0
      sfd_ctx_fixed_ra_offset = sframe_decoder_get_fixed_ra_offset (sfd_ctx);
359
360
      /* Valid values are non-zero.  */
361
0
      if (!sfd_ctx_abi_arch)
362
0
  return false;
363
364
0
      htab->sfe_info.sfe_ctx = sframe_encode (SFRAME_VERSION_2,
365
0
                0, /* SFrame flags.  */
366
0
                sfd_ctx_abi_arch,
367
0
                sfd_ctx_fixed_fp_offset,
368
0
                sfd_ctx_fixed_ra_offset,
369
0
                &encerr);
370
      /* Handle errors from sframe_encode.  */
371
0
      if (htab->sfe_info.sfe_ctx == NULL)
372
0
  return false;
373
0
    }
374
0
  sfe_ctx = sfe_info->sfe_ctx;
375
376
0
  if (sfe_info->sframe_section == NULL)
377
0
    {
378
      /* Make sure things are set for an eventual write.
379
   Size of the output section is not known until
380
   _bfd_elf_write_section_sframe is ready with the buffer
381
   to write out.  */
382
0
      cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe");
383
0
      if (cfsec)
384
0
  {
385
0
    sfe_info->sframe_section = cfsec;
386
    // elf_sframe (abfd) = cfsec;
387
0
  }
388
0
      else
389
0
  return false;
390
0
    }
391
392
  /* Check that all .sframe sections being linked have the same
393
     ABI/arch.  */
394
0
  if (sframe_decoder_get_abi_arch (sfd_ctx)
395
0
      != sframe_encoder_get_abi_arch (sfe_ctx))
396
0
    {
397
0
      _bfd_error_handler
398
0
  (_("input SFrame sections with different abi prevent .sframe"
399
0
    " generation"));
400
0
      return false;
401
0
    }
402
403
  /* Check that all .sframe sections being linked have the same version.  */
404
0
  dctx_version = sframe_decoder_get_version (sfd_ctx);
405
0
  ectx_version = sframe_encoder_get_version (sfe_ctx);
406
0
  if (dctx_version != SFRAME_VERSION_2 || dctx_version != ectx_version)
407
0
    {
408
0
      _bfd_error_handler
409
0
  (_("input SFrame sections with different format versions prevent"
410
0
    " .sframe generation"));
411
0
      return false;
412
0
    }
413
414
415
  /* Iterate over the function descriptor entries and the FREs of the
416
     function from the decoder context.  Add each of them to the encoder
417
     context, if suitable.  */
418
0
  uint32_t i = 0, j = 0, cur_fidx = 0;
419
420
0
  uint32_t num_fidx = sframe_decoder_get_num_fidx (sfd_ctx);
421
0
  uint32_t num_enc_fidx = sframe_encoder_get_num_fidx (sfe_ctx);
422
423
0
  for (i = 0; i < num_fidx; i++)
424
0
    {
425
0
      unsigned int num_fres = 0;
426
0
      int32_t func_start_addr;
427
0
      bfd_vma address;
428
0
      uint32_t func_size = 0;
429
0
      unsigned char func_info = 0;
430
0
      unsigned int r_offset = 0;
431
0
      bool pltn_reloc_by_hand = false;
432
0
      unsigned int pltn_r_offset = 0;
433
0
      uint8_t rep_block_size = 0;
434
435
0
      if (!sframe_decoder_get_funcdesc_v2 (sfd_ctx, i, &num_fres, &func_size,
436
0
             &func_start_addr, &func_info,
437
0
             &rep_block_size))
438
0
  {
439
    /* If function belongs to a deleted section, skip editing the
440
       function descriptor entry.  */
441
0
    if (sframe_decoder_func_deleted_p(sfd_info, i))
442
0
      continue;
443
444
    /* Don't edit function descriptor entries for relocatable link.  */
445
0
    if (!bfd_link_relocatable (info))
446
0
      {
447
0
        if (!(sec->flags & SEC_LINKER_CREATED))
448
0
    {
449
      /* Get relocated contents by reading the value of the
450
         relocated function start address at the beginning of the
451
         function descriptor entry.  */
452
0
      r_offset = sframe_decoder_get_func_r_offset (sfd_info, i);
453
0
    }
454
0
        else
455
0
    {
456
      /* Expected to land here when SFrame stack trace info is
457
         created dynamically for the .plt* sections.  These
458
         sections are expected to have upto two SFrame FDE entries.
459
         Although the code should work for > 2,  leaving this
460
         assert here for safety.  */
461
0
      BFD_ASSERT (num_fidx <= 2);
462
      /* For the first entry, we know the offset of the SFrame FDE's
463
         sfde_func_start_address.  Side note: see how the value
464
         of PLT_SFRAME_FDE_START_OFFSET is also set to the
465
         same.  */
466
0
      r_offset = sframe_decoder_get_hdr_size (sfd_ctx);
467
      /* For any further SFrame FDEs, the generator has already put
468
         in an offset in place of sfde_func_start_address of the
469
         corresponding FDE.  We will use it by hand to relocate.  */
470
0
      if (i > 0)
471
0
        {
472
0
          pltn_r_offset
473
0
      = r_offset + (i * sizeof (sframe_func_desc_entry));
474
0
          pltn_reloc_by_hand = true;
475
0
        }
476
0
    }
477
478
        /* Get the SFrame FDE function start address after relocation.  */
479
0
        address = sframe_read_value (abfd, contents, r_offset, 4);
480
0
        if (pltn_reloc_by_hand)
481
0
    address += sframe_read_value (abfd, contents,
482
0
                pltn_r_offset, 4);
483
0
        address += (sec->output_offset + r_offset);
484
485
        /* FIXME For testing only. Cleanup later.  */
486
        // address += (sec->output_section->vma);
487
488
0
        func_start_addr = address;
489
0
      }
490
491
    /* Update the encoder context with updated content.  */
492
0
    int err = sframe_encoder_add_funcdesc_v2 (sfe_ctx, func_start_addr,
493
0
                func_size, func_info,
494
0
                rep_block_size, num_fres);
495
0
    cur_fidx++;
496
0
    BFD_ASSERT (!err);
497
0
  }
498
499
0
      for (j = 0; j < num_fres; j++)
500
0
  {
501
0
    sframe_frame_row_entry fre;
502
0
    if (!sframe_decoder_get_fre (sfd_ctx, i, j, &fre))
503
0
      {
504
0
        int err = sframe_encoder_add_fre (sfe_ctx,
505
0
            cur_fidx-1+num_enc_fidx,
506
0
            &fre);
507
0
        BFD_ASSERT (!err);
508
0
      }
509
0
  }
510
0
    }
511
  /* Free the SFrame decoder context.  */
512
0
  sframe_decoder_free (&sfd_ctx);
513
514
0
  return true;
515
0
}
516
517
/* Write out the .sframe section.  This must be called after
518
   _bfd_elf_merge_section_sframe has been called on all input
519
   .sframe sections.  */
520
521
bool
522
_bfd_elf_write_section_sframe (bfd *abfd, struct bfd_link_info *info)
523
0
{
524
0
  bool retval = true;
525
526
0
  struct elf_link_hash_table *htab;
527
0
  struct sframe_enc_info *sfe_info;
528
0
  sframe_encoder_ctx *sfe_ctx;
529
0
  asection *sec;
530
0
  void *contents;
531
0
  size_t sec_size;
532
0
  int err = 0;
533
534
0
  htab = elf_hash_table (info);
535
0
  sfe_info = &htab->sfe_info;
536
0
  sec = sfe_info->sframe_section;
537
0
  sfe_ctx = sfe_info->sfe_ctx;
538
539
0
  if (sec == NULL)
540
0
    return true;
541
542
0
  contents = sframe_encoder_write (sfe_ctx, &sec_size, &err);
543
0
  sec->size = (bfd_size_type) sec_size;
544
545
0
  if (!bfd_set_section_contents (abfd, sec->output_section, contents,
546
0
         (file_ptr) sec->output_offset,
547
0
         sec->size))
548
0
    retval = false;
549
0
  else if (!bfd_link_relocatable (info))
550
0
    {
551
0
      Elf_Internal_Shdr *hdr = &elf_section_data (sec)->this_hdr;
552
0
      hdr->sh_size = sec->size;
553
0
    }
554
  /* For relocatable links, do not update the section size as the section
555
     contents have not been relocated.  */
556
557
0
  sframe_encoder_free (&sfe_ctx);
558
559
0
  return retval;
560
0
}