[binutils-gdb/binutils-2_46-branch] check sframe version in _bfd_elf_parse_sframe

Alan Modra via Binutils-cvs <[email protected]>
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=e7b4e8eb10a599773c7aef3f629bf67b2f7c7323

commit e7b4e8eb10a599773c7aef3f629bf67b2f7c7323
Author: Alan Modra <[email protected]>
Date:   Fri Mar 13 08:55:04 2026 +1030

    check sframe version in _bfd_elf_parse_sframe
    
    Currently if you attempt to link an object file with sframe version 2
    contents, the linker will complain in _bfd_elf_merge_section_sframe
    and fail to produce an output.  This affects anyone who has objects
    assembled by binutils-2.45 with .sframe sections.  A work-around is to
    pass --discard-sframe to ld.
    
    Ideally the linker would rewrite version 2 sframe input to version 3,
    but in the absence of that support it would be nicer if ld just
    ignored version 2 (or 1) sframe sections without needing to pass
    --discard-sframe.  That is the aim of this patch.
    
    It does so by checking the sframe version in _bfd_elf_parse_sframe
    where various failing checks result in an error being printed and the
    section not being marked as SEC_INFO_TYPE_SFRAME, but causes no
    overall linker failure.  In addition, an sframe version failure now
    also marks the sframe section with SEC_EXCLUDE.  This is also done for
    other sframe failures.  See the changelog below for other fixes.
    
    bfd/
            * elf-sframe.c (_bfd_elf_merge_section_sframe): Don't check
            sframe version here.
            (_bfd_elf_parse_sframe): Check sframe version here instead.
            Do the "already parsed" check first.  Reorder various other
            checks.  Do not bother parsing or print errors when
            discard_sframe is set.  Free section contents on failure
            paths.  Set SEC_EXCLUDE for fails.  Check for NULL bfd_zalloc
            return, and only allocate after successfully parsing sframe.
            On errors report that the section will be ignored, not "no
            .sframe will be created".
    binutils/
            * testsuite/lib/binutils-common.exp: Ignore sframe version
            errors.
    
    (cherry picked from commit 7c80233f4d47c2508d8984bdcfc644b9a6e7bf9a)

Diff:
---
 bfd/elf-sframe.c                           | 100 ++++++++++++++---------------
 binutils/testsuite/lib/binutils-common.exp |   3 +
 2 files changed, 52 insertions(+), 51 deletions(-)

diff --git a/bfd/elf-sframe.c b/bfd/elf-sframe.c
index 7b2eed81c9f..995987eea6d 100644
--- a/bfd/elf-sframe.c
+++ b/bfd/elf-sframe.c
@@ -220,7 +220,7 @@ _bfd_elf_sframe_present (struct bfd_link_info *info)
 
 bool
 _bfd_elf_parse_sframe (bfd *abfd,
-		       struct bfd_link_info *info ATTRIBUTE_UNUSED,
+		       struct bfd_link_info *info,
 		       asection *sec, struct elf_reloc_cookie *cookie)
 {
   bfd_byte *sfbuf = NULL;
@@ -229,74 +229,85 @@ _bfd_elf_parse_sframe (bfd *abfd,
   bfd_size_type sf_size;
   int decerr = 0;
 
+  /* Check if this section was already parsed.  */
+  if (sec->sec_info_type == SEC_INFO_TYPE_SFRAME)
+    return true;
+
   if (info->discard_sframe)
-    sec->flags |= SEC_EXCLUDE;
+    {
+      sec->flags |= SEC_EXCLUDE;
+      return false;
+    }
 
-  /* Prior versions of assembler and ld were generating SFrame sections with
-     section type SHT_PROGBITS.  Issue an error for lack of support for such
-     objects now.  Even if section size is zero, a valid section type is
-     expected.  */
-  if (elf_section_type (sec) != SHT_GNU_SFRAME)
+  if ((sec->flags & SEC_EXCLUDE) != 0
+      || bfd_is_abs_section (sec->output_section))
     {
-      _bfd_error_handler
-	(_("error in %pB(%pA); unexpected SFrame section type"),
-	 abfd, sec);
+      /* This sections is being discarded from the link, ignore it.  */
       return false;
     }
 
   if (sec->size == 0
       || (sec->flags & SEC_HAS_CONTENTS) == 0)
     {
-      /* This file does not contain .sframe information.  */
-      return false;
+      /* This section does not contain .sframe information.  */
+      goto fail4;
     }
 
-  /* Check if this section was already parsed.  */
-  if (sec->sec_info_type == SEC_INFO_TYPE_SFRAME)
-    return true;
-
-  if (bfd_is_abs_section (sec->output_section))
+  /* Prior versions of assembler and ld were generating SFrame sections with
+     section type SHT_PROGBITS.  Issue an error for lack of support for such
+     objects now.  Even if section size is zero, a valid section type is
+     expected.  */
+  if (elf_section_type (sec) != SHT_GNU_SFRAME)
     {
-      /* At least one of the sections is being discarded from the
-	 link, so we should just ignore them.  */
-      return false;
+      _bfd_error_handler
+	(_("error in %pB(%pA); unexpected SFrame section type; section ignored"),
+	 abfd, sec);
+      goto fail4;
     }
 
   /* Read the SFrame stack trace information from abfd.  */
   if (!_bfd_elf_mmap_section_contents (abfd, sec, &sfbuf))
-    goto fail_no_free;
+    goto fail3;
 
   /* 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_zalloc (abfd, sizeof (*sfd_info));
   sf_size = sec->size;
+  sfd_ctx = sframe_decode ((const char *) sfbuf, sf_size, &decerr);
+  if (!sfd_ctx)
+    goto fail2;
 
-  sfd_info->sfd_ctx = sframe_decode ((const char*)sfbuf, sf_size, &decerr);
+  uint8_t dctx_version = sframe_decoder_get_version (sfd_ctx);
+  if (dctx_version != SFRAME_VERSION)
+    {
+      _bfd_error_handler
+	(_("error in %pB(%pA); unexpected SFrame format version %" PRIu8),
+	 abfd, sec, dctx_version);
+      goto fail2;
+    }
+
+  sfd_info = bfd_zalloc (abfd, sizeof (*sfd_info));
+  if (!sfd_info)
+    goto fail1;
+  sfd_info->sfd_ctx = sfd_ctx;
   sfd_info->sfd_state = SFRAME_SEC_DECODED;
-  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 (abfd, sec, sfd_info, cookie))
     {
+    fail1:
       sframe_decoder_free (&sfd_info->sfd_ctx);
-      goto fail_no_free;
+    fail2:
+      _bfd_elf_munmap_section_contents (sec, sfbuf);
+    fail3:
+      _bfd_error_handler (_("error in %pB(%pA); SFrame section ignored"),
+			  abfd, sec);
+    fail4:
+      sec->flags |= SEC_EXCLUDE;
+      return false;
     }
 
   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:
   _bfd_elf_munmap_section_contents (sec, sfbuf);
   return true;
 }
@@ -384,8 +395,6 @@ _bfd_elf_merge_section_sframe (bfd *abfd,
   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;
   uint8_t dctx_flags;
   uint8_t ectx_flags;
   int encerr = 0;
@@ -472,17 +481,6 @@ _bfd_elf_merge_section_sframe (bfd *abfd,
       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_3 || dctx_version != ectx_version)
-    {
-      _bfd_error_handler
-	(_("error in %pB (%pA); unexpected SFrame format version %" PRIu8),
-	 sec->owner, sec, dctx_version);
-      return false;
-    }
-
   /* Check that all SFrame sections being linked have the 'data encoding'
      related flags set.  The implementation does not support updating these
      data encodings on the fly; confirm by checking the ectx_flags.  */
diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp
index 72cbf4a4e05..150dbfa594b 100644
--- a/binutils/testsuite/lib/binutils-common.exp
+++ b/binutils/testsuite/lib/binutils-common.exp
@@ -792,6 +792,9 @@ proc prune_warnings_extra { text } {
     regsub -all "(^|\n)(\[^\n\]*lto-wrapper: warning: using serial compilation of \[0-9\]+ LTRANS jobs\[^\n\]*\n?)+" $text "\\1" text
     regsub -all "(^|\n)(\[^\n\]*lto-wrapper: note: \[^\n\]*\n?)+" $text "\\1" text
 
+    # Ignore warnings about linking objects with an old sframe format
+    regsub -all {(^|\n)([^\n]* unexpected SFrame format version [^\n]*\n[^\n]* SFrame section ignored\n?)+} $text {\1} text
+
     return $text
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.