[binutils-gdb] check sframe version in _bfd_elf_parse_sframe

Alan Modra amodra@sourceware.org
Thu Mar 12 23:34:39 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=7c80233f4d47c2508d8984bdcfc644b9a6e7bf9a

commit 7c80233f4d47c2508d8984bdcfc644b9a6e7bf9a
Author: Alan Modra <amodra@gmail.com>
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.

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 24215502069..2dafd14e3ee 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
 }


More information about the Binutils-cvs mailing list