| /* .sframe section processing. | 
 |    Copyright (C) 2022-2023 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of BFD, the Binary File Descriptor library. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program; if not, write to the Free Software | 
 |    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
 |    MA 02110-1301, USA.  */ | 
 |  | 
 | #include "sysdep.h" | 
 | #include "bfd.h" | 
 | #include "libbfd.h" | 
 | #include "elf-bfd.h" | 
 | #include "sframe-api.h" | 
 |  | 
 | /* Return TRUE if the function has been marked for deletion during the linking | 
 |    process.  */ | 
 |  | 
 | static bool | 
 | sframe_decoder_func_deleted_p (struct sframe_dec_info *sfd_info, | 
 | 			       unsigned int func_idx) | 
 | { | 
 |   if (func_idx < sfd_info->sfd_fde_count) | 
 |     return sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p; | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | /* Mark the function in the decoder info for deletion.  */ | 
 |  | 
 | static void | 
 | sframe_decoder_mark_func_deleted (struct sframe_dec_info *sfd_info, | 
 | 				  unsigned int func_idx) | 
 | { | 
 |   if (func_idx < sfd_info->sfd_fde_count) | 
 |     sfd_info->sfd_func_bfdinfo[func_idx].func_deleted_p = true; | 
 | } | 
 |  | 
 | /* Get the relocation offset from the decoder info for the given function.  */ | 
 |  | 
 | static unsigned int | 
 | sframe_decoder_get_func_r_offset (struct sframe_dec_info *sfd_info, | 
 | 				  unsigned int func_idx) | 
 | { | 
 |   BFD_ASSERT (func_idx < sfd_info->sfd_fde_count); | 
 |   unsigned int func_r_offset | 
 |     = sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset; | 
 |   /* There must have been a reloc.  */ | 
 |   BFD_ASSERT (func_r_offset); | 
 |   return func_r_offset; | 
 | } | 
 |  | 
 | /* Bookkeep the function relocation offset in the decoder info.  */ | 
 |  | 
 | static void | 
 | sframe_decoder_set_func_r_offset (struct sframe_dec_info *sfd_info, | 
 | 				  unsigned int func_idx, | 
 | 				  unsigned int r_offset) | 
 | { | 
 |   if (func_idx < sfd_info->sfd_fde_count) | 
 |     sfd_info->sfd_func_bfdinfo[func_idx].func_r_offset = r_offset; | 
 | } | 
 |  | 
 | /* Get the relocation index in the elf_reloc_cookie for the function.  */ | 
 |  | 
 | static unsigned int | 
 | sframe_decoder_get_func_reloc_index (struct sframe_dec_info *sfd_info, | 
 | 				     unsigned int func_idx) | 
 | { | 
 |   BFD_ASSERT (func_idx < sfd_info->sfd_fde_count); | 
 |   return sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index; | 
 | } | 
 |  | 
 | /* Bookkeep the relocation index in the elf_reloc_cookie for the function.  */ | 
 |  | 
 | static void | 
 | sframe_decoder_set_func_reloc_index (struct sframe_dec_info *sfd_info, | 
 | 				     unsigned int func_idx, | 
 | 				     unsigned int reloc_index) | 
 | { | 
 |   if (func_idx < sfd_info->sfd_fde_count) | 
 |     sfd_info->sfd_func_bfdinfo[func_idx].func_reloc_index = reloc_index; | 
 | } | 
 |  | 
 | /* Initialize the set of additional information in CFD_INFO, | 
 |    needed for linking SEC.  Returns TRUE if setup is done successfully.  */ | 
 |  | 
 | static bool | 
 | sframe_decoder_init_func_bfdinfo (asection *sec, | 
 | 				  struct sframe_dec_info *sfd_info, | 
 | 				  struct elf_reloc_cookie *cookie) | 
 | { | 
 |   unsigned int fde_count; | 
 |   unsigned int func_bfdinfo_size, i; | 
 |  | 
 |   fde_count = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx); | 
 |   sfd_info->sfd_fde_count = fde_count; | 
 |  | 
 |   /* Allocate and clear the memory.  */ | 
 |   func_bfdinfo_size = (sizeof (struct sframe_func_bfdinfo)) * fde_count; | 
 |   sfd_info->sfd_func_bfdinfo | 
 |     = (struct sframe_func_bfdinfo*) bfd_malloc (func_bfdinfo_size); | 
 |   if (sfd_info->sfd_func_bfdinfo == NULL) | 
 |     return false; | 
 |   memset (sfd_info->sfd_func_bfdinfo, 0, func_bfdinfo_size); | 
 |  | 
 |   /* For linker generated .sframe sections, we have no relocs.  Skip.  */ | 
 |   if ((sec->flags & SEC_LINKER_CREATED) && cookie->rels == NULL) | 
 |     return true; | 
 |  | 
 |   for (i = 0; i < fde_count; i++) | 
 |     { | 
 |       cookie->rel = cookie->rels + i; | 
 |       BFD_ASSERT (cookie->rel < cookie->relend); | 
 |       /* Bookkeep the relocation offset and relocation index of each function | 
 | 	 for later use.  */ | 
 |       sframe_decoder_set_func_r_offset (sfd_info, i, cookie->rel->r_offset); | 
 |       sframe_decoder_set_func_reloc_index (sfd_info, i, | 
 | 					   (cookie->rel - cookie->rels)); | 
 |  | 
 |       cookie->rel++; | 
 |     } | 
 |   BFD_ASSERT (cookie->rel == cookie->relend); | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /* Read the value from CONTENTS at the specified OFFSET for the given ABFD.  */ | 
 |  | 
 | static bfd_vma | 
 | sframe_read_value (bfd *abfd, bfd_byte *contents, unsigned int offset, | 
 | 		   unsigned int width) | 
 | { | 
 |   BFD_ASSERT (contents && offset); | 
 |   /* Supporting the usecase of reading only the 4-byte relocated | 
 |      value (signed offset for func start addr) for now.  */ | 
 |   BFD_ASSERT (width == 4); | 
 |   /* FIXME endianness ?? */ | 
 |   unsigned char *buf = contents + offset; | 
 |   bfd_vma value = bfd_get_signed_32 (abfd, buf); | 
 |   return value; | 
 | } | 
 |  | 
 | /* Return true if there is at least one non-empty .sframe section in | 
 |    input files.  Can only be called after ld has mapped input to | 
 |    output sections, and before sections are stripped.  */ | 
 |  | 
 | bool | 
 | _bfd_elf_sframe_present (struct bfd_link_info *info) | 
 | { | 
 |   asection *sframe = bfd_get_section_by_name (info->output_bfd, ".sframe"); | 
 |  | 
 |   if (sframe == NULL) | 
 |     return false; | 
 |  | 
 |   /* Count only sections which have at least a single FDE.  */ | 
 |   for (sframe = sframe->map_head.s; sframe != NULL; sframe = sframe->map_head.s) | 
 |     /* Note that this may become an approximate check in the future when | 
 |        some ABI/arch begin to use the sfh_auxhdr_len.  When sfh_auxhdr_len has | 
 |        non-zero value, it will need to be accounted for in the calculation of | 
 |        the SFrame header size.  */ | 
 |     if (sframe->size > sizeof (sframe_header)) | 
 |       return true; | 
 |   return false; | 
 | } | 
 |  | 
 | /* Try to parse .sframe section SEC, which belongs to ABFD.  Store the | 
 |    information in the section's sec_info field on success.  COOKIE | 
 |    describes the relocations in SEC. | 
 |  | 
 |    Returns TRUE if success, FALSE if any error or failure.  */ | 
 |  | 
 | bool | 
 | _bfd_elf_parse_sframe (bfd *abfd, | 
 | 		       struct bfd_link_info *info ATTRIBUTE_UNUSED, | 
 | 		       asection *sec, struct elf_reloc_cookie *cookie) | 
 | { | 
 |   bfd_byte *sfbuf = NULL; | 
 |   struct sframe_dec_info *sfd_info; | 
 |   sframe_decoder_ctx *sfd_ctx; | 
 |   bfd_size_type sf_size; | 
 |   int decerr = 0; | 
 |  | 
 |   if (sec->size == 0 | 
 |       || (sec->flags & SEC_HAS_CONTENTS) == 0 | 
 |       || sec->sec_info_type != SEC_INFO_TYPE_NONE) | 
 |     { | 
 |       /* This file does not contain .sframe information.  */ | 
 |       return false; | 
 |     } | 
 |  | 
 |   if (bfd_is_abs_section (sec->output_section)) | 
 |     { | 
 |       /* At least one of the sections is being discarded from the | 
 | 	 link, so we should just ignore them.  */ | 
 |       return false; | 
 |     } | 
 |  | 
 |   /* Read the SFrame stack trace information from abfd.  */ | 
 |   if (!bfd_malloc_and_get_section (abfd, sec, &sfbuf)) | 
 |     goto fail_no_free; | 
 |  | 
 |   /* Decode the buffer and keep decoded contents for later use. | 
 |      Relocations are performed later, but are such that the section's | 
 |      size is unaffected.  */ | 
 |   sfd_info = bfd_malloc (sizeof (struct sframe_dec_info)); | 
 |   sf_size = sec->size; | 
 |  | 
 |   sfd_info->sfd_ctx = sframe_decode ((const char*)sfbuf, sf_size, &decerr); | 
 |   sfd_ctx = sfd_info->sfd_ctx; | 
 |   if (!sfd_ctx) | 
 |     /* Free'ing up any memory held by decoder context is done by | 
 |        sframe_decode in case of error.  */ | 
 |     goto fail_no_free; | 
 |  | 
 |   if (!sframe_decoder_init_func_bfdinfo (sec, sfd_info, cookie)) | 
 |     { | 
 |       sframe_decoder_free (&sfd_ctx); | 
 |       goto fail_no_free; | 
 |     } | 
 |  | 
 |   elf_section_data (sec)->sec_info = sfd_info; | 
 |   sec->sec_info_type = SEC_INFO_TYPE_SFRAME; | 
 |  | 
 |   goto success; | 
 |  | 
 | fail_no_free: | 
 |   _bfd_error_handler | 
 |    (_("error in %pB(%pA); no .sframe will be created"), | 
 |     abfd, sec); | 
 |   return false; | 
 | success: | 
 |   free (sfbuf); | 
 |   return true; | 
 | } | 
 |  | 
 | /* This function is called for each input file before the .sframe section | 
 |    is relocated.  It marks the SFrame FDE for the discarded functions for | 
 |    deletion. | 
 |  | 
 |    The function returns TRUE iff any entries have been deleted.  */ | 
 |  | 
 | bool | 
 | _bfd_elf_discard_section_sframe | 
 |    (asection *sec, | 
 |     bool (*reloc_symbol_deleted_p) (bfd_vma, void *), | 
 |     struct elf_reloc_cookie *cookie) | 
 | { | 
 |   bool changed; | 
 |   bool keep; | 
 |   unsigned int i; | 
 |   unsigned int func_desc_offset; | 
 |   unsigned int num_fidx; | 
 |   struct sframe_dec_info *sfd_info; | 
 |  | 
 |   changed = false; | 
 |   /* FIXME - if relocatable link and changed = true, how does the final | 
 |      .rela.sframe get updated ?.  */ | 
 |   keep = false; | 
 |  | 
 |   sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info; | 
 |  | 
 |   /* Skip checking for the linker created .sframe sections | 
 |      (for PLT sections).  */ | 
 |   if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL) | 
 |     { | 
 |       num_fidx = sframe_decoder_get_num_fidx (sfd_info->sfd_ctx); | 
 |       for (i = 0; i < num_fidx; i++) | 
 | 	{ | 
 | 	  func_desc_offset = sframe_decoder_get_func_r_offset (sfd_info, i); | 
 |  | 
 | 	  cookie->rel = cookie->rels | 
 | 	    + sframe_decoder_get_func_reloc_index (sfd_info, i); | 
 | 	  keep = !(*reloc_symbol_deleted_p) (func_desc_offset, cookie); | 
 |  | 
 | 	  if (!keep) | 
 | 	    { | 
 | 	      sframe_decoder_mark_func_deleted (sfd_info, i); | 
 | 	      changed = true; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |   return changed; | 
 | } | 
 |  | 
 | /* Update the reference to the output .sframe section in the output ELF | 
 |    BFD ABFD.  Returns true if no error.  */ | 
 |  | 
 | bool | 
 | _bfd_elf_set_section_sframe (bfd *abfd, | 
 | 				struct bfd_link_info *info) | 
 | { | 
 |   asection *cfsec; | 
 |  | 
 |   cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe"); | 
 |   if (!cfsec) | 
 |     return false; | 
 |  | 
 |   elf_sframe (abfd) = cfsec; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /* Merge .sframe section SEC.  This is called with the relocated | 
 |    CONTENTS.  */ | 
 |  | 
 | bool | 
 | _bfd_elf_merge_section_sframe (bfd *abfd, | 
 | 			       struct bfd_link_info *info, | 
 | 			       asection *sec, | 
 | 			       bfd_byte *contents) | 
 | { | 
 |   struct sframe_dec_info *sfd_info; | 
 |   struct sframe_enc_info *sfe_info; | 
 |   sframe_decoder_ctx *sfd_ctx; | 
 |   sframe_encoder_ctx *sfe_ctx; | 
 |   uint8_t sfd_ctx_abi_arch; | 
 |   int8_t sfd_ctx_fixed_fp_offset; | 
 |   int8_t sfd_ctx_fixed_ra_offset; | 
 |   uint8_t dctx_version; | 
 |   uint8_t ectx_version; | 
 |   int encerr = 0; | 
 |  | 
 |   struct elf_link_hash_table *htab; | 
 |   asection *cfsec; | 
 |  | 
 |   /* Sanity check - handle SFrame sections only.  */ | 
 |   if (sec->sec_info_type != SEC_INFO_TYPE_SFRAME) | 
 |     return false; | 
 |  | 
 |   sfd_info = (struct sframe_dec_info *) elf_section_data (sec)->sec_info; | 
 |   sfd_ctx = sfd_info->sfd_ctx; | 
 |  | 
 |   htab = elf_hash_table (info); | 
 |   sfe_info = &(htab->sfe_info); | 
 |   sfe_ctx = sfe_info->sfe_ctx; | 
 |  | 
 |   /* All input bfds are expected to have a valid SFrame section.  Even if | 
 |      the SFrame section is empty with only a header, there must be a valid | 
 |      SFrame decoder context by now.  The SFrame encoder context, however, | 
 |      will get set later here, if this is the first call to the function.  */ | 
 |   if (sfd_ctx == NULL || sfe_info == NULL) | 
 |     return false; | 
 |  | 
 |   if (htab->sfe_info.sfe_ctx == NULL) | 
 |     { | 
 |       sfd_ctx_abi_arch = sframe_decoder_get_abi_arch (sfd_ctx); | 
 |       sfd_ctx_fixed_fp_offset = sframe_decoder_get_fixed_fp_offset (sfd_ctx); | 
 |       sfd_ctx_fixed_ra_offset = sframe_decoder_get_fixed_ra_offset (sfd_ctx); | 
 |  | 
 |       /* Valid values are non-zero.  */ | 
 |       if (!sfd_ctx_abi_arch) | 
 | 	return false; | 
 |  | 
 |       htab->sfe_info.sfe_ctx = sframe_encode (SFRAME_VERSION_2, | 
 | 					      0, /* SFrame flags.  */ | 
 | 					      sfd_ctx_abi_arch, | 
 | 					      sfd_ctx_fixed_fp_offset, | 
 | 					      sfd_ctx_fixed_ra_offset, | 
 | 					      &encerr); | 
 |       /* Handle errors from sframe_encode.  */ | 
 |       if (htab->sfe_info.sfe_ctx == NULL) | 
 | 	return false; | 
 |     } | 
 |   sfe_ctx = sfe_info->sfe_ctx; | 
 |  | 
 |   if (sfe_info->sframe_section == NULL) | 
 |     { | 
 |       /* Make sure things are set for an eventual write. | 
 | 	 Size of the output section is not known until | 
 | 	 _bfd_elf_write_section_sframe is ready with the buffer | 
 | 	 to write out.  */ | 
 |       cfsec = bfd_get_section_by_name (info->output_bfd, ".sframe"); | 
 |       if (cfsec) | 
 | 	{ | 
 | 	  sfe_info->sframe_section = cfsec; | 
 | 	  // elf_sframe (abfd) = cfsec; | 
 | 	} | 
 |       else | 
 | 	return false; | 
 |     } | 
 |  | 
 |   /* Check that all .sframe sections being linked have the same | 
 |      ABI/arch.  */ | 
 |   if (sframe_decoder_get_abi_arch (sfd_ctx) | 
 |       != sframe_encoder_get_abi_arch (sfe_ctx)) | 
 |     { | 
 |       _bfd_error_handler | 
 | 	(_("input SFrame sections with different abi prevent .sframe" | 
 | 	  " generation")); | 
 |       return false; | 
 |     } | 
 |  | 
 |   /* Check that all .sframe sections being linked have the same version.  */ | 
 |   dctx_version = sframe_decoder_get_version (sfd_ctx); | 
 |   ectx_version = sframe_encoder_get_version (sfe_ctx); | 
 |   if (dctx_version != SFRAME_VERSION_2 || dctx_version != ectx_version) | 
 |     { | 
 |       _bfd_error_handler | 
 | 	(_("input SFrame sections with different format versions prevent" | 
 | 	  " .sframe generation")); | 
 |       return false; | 
 |     } | 
 |  | 
 |  | 
 |   /* Iterate over the function descriptor entries and the FREs of the | 
 |      function from the decoder context.  Add each of them to the encoder | 
 |      context, if suitable.  */ | 
 |   uint32_t i = 0, j = 0, cur_fidx = 0; | 
 |  | 
 |   uint32_t num_fidx = sframe_decoder_get_num_fidx (sfd_ctx); | 
 |   uint32_t num_enc_fidx = sframe_encoder_get_num_fidx (sfe_ctx); | 
 |  | 
 |   for (i = 0; i < num_fidx; i++) | 
 |     { | 
 |       unsigned int num_fres = 0; | 
 |       int32_t func_start_addr; | 
 |       bfd_vma address; | 
 |       uint32_t func_size = 0; | 
 |       unsigned char func_info = 0; | 
 |       unsigned int r_offset = 0; | 
 |       bool pltn_reloc_by_hand = false; | 
 |       unsigned int pltn_r_offset = 0; | 
 |       uint8_t rep_block_size = 0; | 
 |  | 
 |       if (!sframe_decoder_get_funcdesc_v2 (sfd_ctx, i, &num_fres, &func_size, | 
 | 					   &func_start_addr, &func_info, | 
 | 					   &rep_block_size)) | 
 | 	{ | 
 | 	  /* If function belongs to a deleted section, skip editing the | 
 | 	     function descriptor entry.  */ | 
 | 	  if (sframe_decoder_func_deleted_p(sfd_info, i)) | 
 | 	    continue; | 
 |  | 
 | 	  /* Don't edit function descriptor entries for relocatable link.  */ | 
 | 	  if (!bfd_link_relocatable (info)) | 
 | 	    { | 
 | 	      if (!(sec->flags & SEC_LINKER_CREATED)) | 
 | 		{ | 
 | 		  /* Get relocated contents by reading the value of the | 
 | 		     relocated function start address at the beginning of the | 
 | 		     function descriptor entry.  */ | 
 | 		  r_offset = sframe_decoder_get_func_r_offset (sfd_info, i); | 
 | 		} | 
 | 	      else | 
 | 		{ | 
 | 		  /* Expected to land here when SFrame stack trace info is | 
 | 		     created dynamically for the .plt* sections.  These | 
 | 		     sections are expected to have upto two SFrame FDE entries. | 
 | 		     Although the code should work for > 2,  leaving this | 
 | 		     assert here for safety.  */ | 
 | 		  BFD_ASSERT (num_fidx <= 2); | 
 | 		  /* For the first entry, we know the offset of the SFrame FDE's | 
 | 		     sfde_func_start_address.  Side note: see how the value | 
 | 		     of PLT_SFRAME_FDE_START_OFFSET is also set to the | 
 | 		     same.  */ | 
 | 		  r_offset = sframe_decoder_get_hdr_size (sfd_ctx); | 
 | 		  /* For any further SFrame FDEs, the generator has already put | 
 | 		     in an offset in place of sfde_func_start_address of the | 
 | 		     corresponding FDE.  We will use it by hand to relocate.  */ | 
 | 		  if (i > 0) | 
 | 		    { | 
 | 		      pltn_r_offset | 
 | 			= r_offset + (i * sizeof (sframe_func_desc_entry)); | 
 | 		      pltn_reloc_by_hand = true; | 
 | 		    } | 
 | 		} | 
 |  | 
 | 	      /* Get the SFrame FDE function start address after relocation.  */ | 
 | 	      address = sframe_read_value (abfd, contents, r_offset, 4); | 
 | 	      if (pltn_reloc_by_hand) | 
 | 		address += sframe_read_value (abfd, contents, | 
 | 					      pltn_r_offset, 4); | 
 | 	      address += (sec->output_offset + r_offset); | 
 |  | 
 | 	      /* FIXME For testing only. Cleanup later.  */ | 
 | 	      // address += (sec->output_section->vma); | 
 |  | 
 | 	      func_start_addr = address; | 
 | 	    } | 
 |  | 
 | 	  /* Update the encoder context with updated content.  */ | 
 | 	  int err = sframe_encoder_add_funcdesc_v2 (sfe_ctx, func_start_addr, | 
 | 						    func_size, func_info, | 
 | 						    rep_block_size, num_fres); | 
 | 	  cur_fidx++; | 
 | 	  BFD_ASSERT (!err); | 
 | 	} | 
 |  | 
 |       for (j = 0; j < num_fres; j++) | 
 | 	{ | 
 | 	  sframe_frame_row_entry fre; | 
 | 	  if (!sframe_decoder_get_fre (sfd_ctx, i, j, &fre)) | 
 | 	    { | 
 | 	      int err = sframe_encoder_add_fre (sfe_ctx, | 
 | 						cur_fidx-1+num_enc_fidx, | 
 | 						&fre); | 
 | 	      BFD_ASSERT (!err); | 
 | 	    } | 
 | 	} | 
 |     } | 
 |   /* Free the SFrame decoder context.  */ | 
 |   sframe_decoder_free (&sfd_ctx); | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /* Write out the .sframe section.  This must be called after | 
 |    _bfd_elf_merge_section_sframe has been called on all input | 
 |    .sframe sections.  */ | 
 |  | 
 | bool | 
 | _bfd_elf_write_section_sframe (bfd *abfd, struct bfd_link_info *info) | 
 | { | 
 |   bool retval = true; | 
 |  | 
 |   struct elf_link_hash_table *htab; | 
 |   struct sframe_enc_info *sfe_info; | 
 |   sframe_encoder_ctx *sfe_ctx; | 
 |   asection *sec; | 
 |   void *contents; | 
 |   size_t sec_size; | 
 |   int err = 0; | 
 |  | 
 |   htab = elf_hash_table (info); | 
 |   sfe_info = &htab->sfe_info; | 
 |   sec = sfe_info->sframe_section; | 
 |   sfe_ctx = sfe_info->sfe_ctx; | 
 |  | 
 |   if (sec == NULL) | 
 |     return true; | 
 |  | 
 |   contents = sframe_encoder_write (sfe_ctx, &sec_size, &err); | 
 |   sec->size = (bfd_size_type) sec_size; | 
 |  | 
 |   if (!bfd_set_section_contents (abfd, sec->output_section, contents, | 
 | 				 (file_ptr) sec->output_offset, | 
 | 				 sec->size)) | 
 |     retval = false; | 
 |   else if (!bfd_link_relocatable (info)) | 
 |     { | 
 |       Elf_Internal_Shdr *hdr = &elf_section_data (sec)->this_hdr; | 
 |       hdr->sh_size = sec->size; | 
 |     } | 
 |   /* For relocatable links, do not update the section size as the section | 
 |      contents have not been relocated.  */ | 
 |  | 
 |   sframe_encoder_free (&sfe_ctx); | 
 |  | 
 |   return retval; | 
 | } |