check sframe version in _bfd_elf_parse_sframe

Jens Remus jremus@linux.ibm.com
Fri Mar 13 15:33:26 GMT 2026


On 3/13/2026 12:33 AM, Alan Modra wrote:
> Prompted by ld/bootstrap test failues on Ubuntu 25.10
> ld-new: error in /lib/x86_64-linux-gnu/crt1.o (.sframe); unexpected SFrame format version 2
> ld-new: final link failed
> collect2: error: ld returned 1 exit status

Ouch!

> 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.

Not ideal.

> 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.

Nice!  Thank you for taking care of this, Alan!

> 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 --git 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;
> +    }

The following would accomplish the same, but might confuse readers that
it is a failure?  Maybe come up with better label names than fail1-4?

    goto fail4;

>  
> -  /* 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.  */

Perhaps mention what will happen?

      /* This section does not contain .sframe information.  Discard and ignore it.  */

> +      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);

A brief moment I was worried this would re-introduce a previous issue ...

> +  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;

... but you did the right thing. :-)

>    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;
>  }

> diff --git 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
> +

Nice!  Did not know about that.

>      return $text
>  }

Regards,
Jens
-- 
Jens Remus
Linux on Z Development (D3303)
jremus@de.ibm.com / jremus@linux.ibm.com

IBM Deutschland Research & Development GmbH; Vorsitzender des Aufsichtsrats: Wolfgang Wendt; Geschäftsführung: David Faller; Sitz der Gesellschaft: Ehningen; Registergericht: Amtsgericht Stuttgart, HRB 243294
IBM Data Privacy Statement: https://www.ibm.com/privacy/



More information about the Binutils mailing list