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