[PATCH v5 4/4] gas: sframe: Represent .cfi_undefined RA as FRE without offsets

Indu indu.bhagat@oracle.com
Wed Jul 30 08:30:50 GMT 2025


On 2025-07-29 8:16 a.m., Jens Remus wrote:
> In DWARF CFI an "undefined" register rule for the return address (RA)
> register indicates that there is no return address and the stack trace
> is complete.
> 
> Represent DW_CFA_undefined as SFrame FRE without any offsets, so that a
> stack tracer implementation can use this as indication that an outermost
> frame has been reached and the stack trace is complete.
> 
> This representation is backward compatible, as existing stack tracers
> should already deal with the case, that an SFrame FRE a so far invalid
> offset count of zero and stop the trace.
> 
> include/
> 	* sframe.h (SFRAME_V2_FRE_RA_UNDEFINED_P): New macro to test
> 	FRE info word for RA undefined (FRE without any offsets).
> 
> binutils/
> 	* NEWS: Mention SFrame can represent an undefined RA as FRE
> 	without	any offsets.
> 
> gas/
> 	* gen-sframe.h (struct sframe_row_entry): Add ra_undefined_p
> 	flag.
> 	* gen-sframe.c (sframe_row_entry_new): Initialize ra_undefined_p
> 	flag to not set.
> 	(sframe_row_entry_initialize): Treat ra_undefined_p flag as
> 	sticky.
> 	(sframe_fre_set_ra_track): Reset ra_undefined_p flag.
> 	(sframe_xlate_do_restore): Reset ra_undefined_p flag to saved
> 	state.
> 	(sframe_xlate_do_same_value): Reset ra_undefined_p flag.
> 	(sframe_xlate_do_cfi_undefined): For RA set ra_undefined_p flag.
> 	(output_sframe_row_entry): Represent RA undefined as SFrame FRE
> 	without any offsets and FRE info word fields zeroed.
> 	* NEWS: Mention assembler represents .cfi_undefined RA in SFrame
> 	as FRE without any offsets.
> 
> libsframe/
> 	* doc/sframe-spec.texi (Changes from Version 1 to Version 2):
> 	Mention that a SFrame FRE without any offsets flag indicates an
> 	outermost frame with an undefined RA.
> 	(fre_offset_count): Document that a FRE offset count of zero
> 	indicates an outermost frame with an undefined RA.
> 	* sframe.c (sframe_get_fre_ra_undefined_p): Use macro
> 	SFRAME_V2_FRE_RA_UNDEFINED_P.
> 	(sframe_fre_get_ra_offset): Do not return fixed RA offset if
> 	RA undefined.
> 	* sframe-dump.c (dump_sframe_func_with_fres): Show FRE without
> 	any offsets as "RA undefined".
> 
> gas/testsuite/
> 	* gas/cfi-sframe/cfi-sframe.exp: Run tests for .cfi_undefined RA
> 	on AArch64, s390x, and x86-64.
> 	* gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.d: Add test
> 	for .cfi_undefined RA on AArch64.
> 	* gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.s: Likewise.
> 	* as/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.d: Add test
> 	for .cfi_undefined RA on s390x.
> 	* gas/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.s: Likewise.
> 	* gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.d: Add test
> 	for .cfi_undefined RA on x86-64.
> 	* gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.s: Likewise.
> 
> Signed-off-by: Jens Remus <jremus@linux.ibm.com>



> ---
> 
> Notes (jremus):
>      Changes in V5:
>      - Rename ra_undefined to ra_undefined_p. (Indu)
>      - Explicitly set FRE info word fields to zero if RA undefined,
>        instead of having get_fre_base_reg_id, get_fre_num_offsets, and
>        frame_get_fre_offset_size return 0 if RA undefined.
>      - Have API to get RA offset return an error if RA undefined,
>        regardless of whether an architecture tracks RA. (Indu)
>        Note that no new error code is introduced.
>      - Add entry to gas/NEWS and binutils/NEWS. (Jose)
>      
>      Changes in V4:
>      - Represent RA undefined as SFrame FRE without any offsets. (Indu)
>        This aligns to DWARF and saves from adding a SFrame FDE flag.
>      
>      Changes in V3:
>      - Introduce a FDE info word flag ra_undefined.  Represent RA undefined
>        as FDE without any FREs and the ra_undefined flag set. (Indu)
>      - Set sfde_func_start_fre_off to zero, if FDE without any FREs.
>      - In x86-64 tests use spaces to separate mnemonic from operands. (Indu)
>      - Reword commit subject, commit message, and GNU ChangeLog.
>      
>      An alternative to introducing a FDE info word flag ra_undefined would
>      be to repurpose the FRE offset in the FDE to carry indications, if
>      the FRE count is zero.  While that would be easy in the assembler to
>      generate and easy for a stack tracer to process it would require
>      a few modifications in libsframe to preserve those special FRE offset
>      values.
>      
>      Wouldn't it make sense to remove the half baked versioned operations
>      (see struct sframe_version_ops) with a preparatory cleanup patch?  I
>      don't see how the current implementation would work in the future.
>      The operations would otherwise probably need to be split up into
>      smaller ones: fde_info_init(fde_type, fre_type), fde_info_set_pauth_key,
>      fde_info_set_ra_undefined, ... .
>      
>      Changes in V2:
>      - Use sframe_xlate_ctx_init to re-initialize translation context.
>      - Reword comment on sframe_xlate_do_cfi_escape.
>      - Reword comment in sframe_do_fde for SFRAME_XLATE_RA_UNDEFINED.
>      - Reword comment in create_sframe_all for SFRAME_XLATE_RA_UNDEFINED.
> 
>   binutils/NEWS                                 |  8 +++
>   gas/NEWS                                      |  3 +
>   gas/gen-sframe.c                              | 61 ++++++++++++++++---
>   gas/gen-sframe.h                              |  3 +
>   .../cfi-sframe-aarch64-ra-undefined-1.d       | 20 ++++++
>   .../cfi-sframe-aarch64-ra-undefined-1.s       | 13 ++++
>   .../cfi-sframe-s390x-ra-undefined-1.d         | 21 +++++++
>   .../cfi-sframe-s390x-ra-undefined-1.s         | 11 ++++
>   .../cfi-sframe-x86_64-ra-undefined-1.d        | 22 +++++++
>   .../cfi-sframe-x86_64-ra-undefined-1.s        | 11 ++++
>   gas/testsuite/gas/cfi-sframe/cfi-sframe.exp   |  3 +
>   include/sframe.h                              |  1 +
>   libsframe/doc/sframe-spec.texi                | 10 ++-
>   libsframe/sframe-dump.c                       | 15 ++++-
>   libsframe/sframe.c                            |  5 +-
>   15 files changed, 192 insertions(+), 15 deletions(-)
>   create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.d
>   create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.s
>   create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.d
>   create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.s
>   create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.d
>   create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.s
> 
> diff --git a/binutils/NEWS b/binutils/NEWS
> index 5038851b4553..79ab32b0874a 100644
> --- a/binutils/NEWS
> +++ b/binutils/NEWS
> @@ -1,5 +1,13 @@
>   -*- text -*-
>   
> +* The SFrame stack trace format got extended to represent an undefined return
> +  address as SFrame FRE without any offsets.  The assembler uses this to
> +  translate .cfi_undefined RA into SFrame.  libsframe provides a new API to
> +  test for RA undefined, which is used when dumping SFrame information
> +  (e.g. using objdump and readelf) to show such FREs as "RA undefined".
> +

How about in binutils/NEWS:

* SFrame stack trace format now represents an undefined return address 
as an SFrame FRE without any offsets.  libsframe provides ... as "RA 
undefined".

And in gas/NEWS:

* gas now emits an SFrame FRE with zero offsets to convey an undefined 
return address in the SFrame stack trace format.

> +* libsframe provides dumps of RA undefined (SFrame FRE without any offsets).
> +

This sentence can be skipped IMO from binutils/NEWS.

>   * NaCl target support is removed.
>   
>   Changes in 2.45:
> diff --git a/gas/NEWS b/gas/NEWS
> index a9858939f06e..e2693d05c45e 100644
> --- a/gas/NEWS
> +++ b/gas/NEWS
> @@ -1,5 +1,8 @@
>   -*- text -*-
>   
> +* Represent .cfi_undefined RA in SFrame stack trace information as SFrame FRE
> +  without any offsets.
> +
>   * NaCl target support is removed.
>   
>   Changes in 2.45:
> diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
> index 5897087fe501..4602b2d2eeb2 100644
> --- a/gas/gen-sframe.c
> +++ b/gas/gen-sframe.c
> @@ -164,6 +164,7 @@ sframe_fre_set_ra_track (struct sframe_row_entry *fre, offsetT ra_offset)
>   {
>     fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK;
>     fre->ra_offset = ra_offset;
> +  fre->ra_undefined_p = false;
>     fre->merge_candidate = false;
>   }
>   
> @@ -514,6 +515,8 @@ sframe_row_entry_new (void)
>        initialize it in sframe_row_entry_initialize () with the sticky
>        bit if set.  */
>     fre->mangled_ra_p = false;
> +  /* Reset the RA undefined status by to zero by default.  */
> +  fre->ra_undefined_p = false;
>   
>     return fre;
>   }
> @@ -555,6 +558,7 @@ output_sframe_row_entry (symbolS *fde_start_addr,
>     unsigned int fre_num_offsets;
>     unsigned int fre_offset_size;
>     unsigned int fre_base_reg;
> +  bool fre_mangled_ra_p;
>     expressionS exp;
>     unsigned int fre_addr_size;
>   
> @@ -580,14 +584,30 @@ output_sframe_row_entry (symbolS *fde_start_addr,
>   #endif
>   
>     /* Create the fre_info using the CFA base register, number of offsets and max
> -     size of offset in this frame row entry.  */
> -  fre_base_reg = get_fre_base_reg_id (sframe_fre);
> -  fre_num_offsets = get_fre_num_offsets (sframe_fre);
> -  fre_offset_size = sframe_get_fre_offset_size (sframe_fre);
> +     size of offset in this frame row entry.  Represent RA undefined as FRE
> +     without any offsets and all FRE info word fields zeroed.  */
> +  if (sframe_fre->ra_undefined_p)
> +    {
> +      fre_base_reg = 0;
> +      fre_num_offsets = 0;
> +      fre_offset_size = 0;
> +      fre_mangled_ra_p = 0;
> +    }
> +  else
> +    {
> +      fre_base_reg = get_fre_base_reg_id (sframe_fre);
> +      fre_num_offsets = get_fre_num_offsets (sframe_fre);
> +      fre_offset_size = sframe_get_fre_offset_size (sframe_fre);
> +      fre_mangled_ra_p = sframe_fre->mangled_ra_p;
> +    }
>     fre_info = sframe_set_fre_info (fre_base_reg, fre_num_offsets,
> -				  fre_offset_size, sframe_fre->mangled_ra_p);
> +				  fre_offset_size, fre_mangled_ra_p);

Perhaps this can be avoided by reseting as necessary in 
sframe_xlate_do_cfi_undefined?

>     out_one (fre_info);
>   
> +  /* Represent RA undefined as FRE without any offsets.  */
> +  if (sframe_fre->ra_undefined_p)
> +    return;
> +
>     idx = sframe_fre_offset_func_map_index (fre_offset_size);
>     gas_assert (idx < SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX);
>   
> @@ -942,6 +962,10 @@ sframe_row_entry_initialize (struct sframe_row_entry *cur_fre,
>     /* Treat RA mangling as a sticky bit.  It retains its value until another
>        .cfi_negate_ra_state is seen.  */
>     cur_fre->mangled_ra_p = prev_fre->mangled_ra_p;
> +  /* Treat RA undefined as a sticky bit.  It retains its value until a
> +     .cfi_offset RA, .cfi_register RA, .cfi_restore RA, or .cfi_same_value RA
> +     is seen.  */
> +  cur_fre->ra_undefined_p = prev_fre->ra_undefined_p;
>   }
>   
>   /* Return SFrame register name for SP, FP, and RA, or NULL if other.  */
> @@ -1317,6 +1341,7 @@ sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
>         gas_assert (cur_fre);
>         cur_fre->ra_loc = cie_fre->ra_loc;
>         cur_fre->ra_offset = cie_fre->ra_offset;
> +      cur_fre->ra_undefined_p = cie_fre->ra_undefined_p;
>         cur_fre->merge_candidate = false;
>       }
>     return SFRAME_XLATE_OK;
> @@ -1603,9 +1628,15 @@ sframe_xlate_do_cfi_escape (const struct sframe_xlate_ctx *xlate_ctx,
>   /* Translate DW_CFA_undefined into SFrame context.
>   
>      DW_CFA_undefined op indicates that from now on, the previous value of
> -   register can’t be restored anymore.  In SFrame stack trace, we cannot
> -   represent such a semantic.  So, we skip generating an SFrame FDE for this,
> -   when a register of interest is used with DW_CFA_undefined.
> +   register can’t be restored anymore.  In DWARF, for the return address (RA)
> +   register, this indicates to an unwinder that there is no return address
> +   and the unwind is complete.
> +
> +   In SFrame, represent the use of the RA register with DW_CFA_undefined as
> +   SFrame FRE without any offsets.  Stack tracers can use this as indication
> +   that an outermost frame has been reached and the stack trace is complete.
> +   The use of other registers of interest with  DW_CFA_undefined cannot be
> +   represented in SFrame.  Therefore skip generating an SFrame FDE.
>   
>      Return SFRAME_XLATE_OK if success.  */
>   
> @@ -1614,15 +1645,24 @@ sframe_xlate_do_cfi_undefined (const struct sframe_xlate_ctx *xlate_ctx ATTRIBUT
>   			       const struct cfi_insn_data *cfi_insn)
>   {
>     if (cfi_insn->u.r == SFRAME_CFA_FP_REG
> -      || cfi_insn->u.r == SFRAME_CFA_RA_REG
>         || cfi_insn->u.r == SFRAME_CFA_SP_REG)
>       {
>         as_warn (_("no SFrame FDE emitted; %s reg %u in .cfi_undefined"),
>   	       sframe_register_name (cfi_insn->u.r), cfi_insn->u.r);
>         return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented.  */
>       }
> +  else if (cfi_insn->u.r == SFRAME_CFA_RA_REG)
> +    {
> +      /* Represent RA undefined (i.e. outermost frame) as FRE without any
> +	 offsets.  */
> +      struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
> +
> +      gas_assert (cur_fre);
> +      /* Set RA undefined status bit.  */
> +      cur_fre->ra_undefined_p = true;
> +      cur_fre->merge_candidate = false;
> +    }
>   
> -  /* Safe to skip.  */
>     return SFRAME_XLATE_OK;
>   }
>   
> @@ -1670,6 +1710,7 @@ sframe_xlate_do_same_value (const struct sframe_xlate_ctx *xlate_ctx,
>       {
>         cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_REG;
>         cur_fre->ra_offset = 0;
> +      cur_fre->ra_undefined_p = false;
>         cur_fre->merge_candidate = false;
>       }
>     else if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
> diff --git a/gas/gen-sframe.h b/gas/gen-sframe.h
> index e4a4c6ea0ceb..32faddbe98fd 100644
> --- a/gas/gen-sframe.h
> +++ b/gas/gen-sframe.h
> @@ -55,6 +55,9 @@ struct sframe_row_entry
>     /* Whether the return address is mangled with pauth code.  */
>     bool mangled_ra_p;
>   
> +  /* Whether RA is undefined.  */
> +  bool ra_undefined_p;
> +
>     /* Track CFA base (architectural) register ID.  */
>     unsigned int cfa_base_reg;
>     /* Offset from the CFA base register for recovering CFA.  */
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.d
> new file mode 100644
> index 000000000000..f6bd6d71008b
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.d
> @@ -0,0 +1,20 @@
> +#as: --gsframe
> +#objdump: --sframe=.sframe
> +#name: SFrame generation on aarch64 - .cfi_undefined RA
> +#...
> +Contents of the SFrame section .sframe:
> +  Header :
> +
> +    Version: SFRAME_VERSION_2
> +    Flags: SFRAME_F_FDE_FUNC_START_PCREL
> +    Num FDEs: 1
> +    Num FREs: 4
> +
> +  Function Index :
> +
> +    func idx \[0\]: pc = 0x0, size = 16 bytes
> +    STARTPC +CFA +FP +RA +
> +    0+0000 +sp\+0 +u +u +
> +    0+0004 +sp\+16 +c\-16 +c\-8 +
> +    0+0008 +RA undefined
> +    0+000c +RA undefined
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.s
> new file mode 100644
> index 000000000000..7b28ab8f6528
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.s
> @@ -0,0 +1,13 @@
> +	.cfi_startproc
> +	stp	fp, lr, [sp, #-16]!
> +	.cfi_def_cfa_offset 16
> +	.cfi_offset 29, -16
> +	.cfi_offset 30, -8
> +	nop
> +	.cfi_undefined 30
> +	ldp	fp, lr, [sp], #16
> +	.cfi_restore 20
> +	.cfi_restore 19
> +	.cfi_def_cfa_offset 0
> +	ret	lr
> +	.cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.d
> new file mode 100644
> index 000000000000..dfd47e30bbe9
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.d
> @@ -0,0 +1,21 @@
> +#name: SFrame generation on s390x - .cfi_undefined RA
> +#as: --gsframe
> +#objdump: --sframe=.sframe
> +#...
> +Contents of the SFrame section .sframe:
> +
> +  Header :
> +
> +    Version: SFRAME_VERSION_2
> +    Flags: SFRAME_F_FDE_FUNC_START_PCREL
> +    Num FDEs: 1
> +    Num FREs: 4
> +
> +  Function Index :
> +
> +    func idx \[0\]: pc = 0x0, size = 18 bytes
> +    STARTPC +CFA +FP +RA +
> +    0+0000 +sp\+160 +u +u +
> +    0+0006 +sp\+160 +u +c\-48 +
> +    0+000a +RA undefined
> +    0+0010 +sp\+160 +u +u +
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.s
> new file mode 100644
> index 000000000000..dda7abcdf4d7
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.s
> @@ -0,0 +1,11 @@
> +	.cfi_startproc
> +	stmg	%r11,%r15,48(%r15)
> +	.cfi_offset 14, -48
> +	.cfi_offset 15, -40
> +	nop
> +	.cfi_undefined 14
> +	lmg	%r14,%r15,160+48(%r11)
> +	.cfi_restore 15
> +	.cfi_restore 14
> +	br	%r14
> +	.cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.d
> new file mode 100644
> index 000000000000..a635c3cd9cbf
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.d
> @@ -0,0 +1,22 @@
> +#as: --gsframe -O0
> +#objdump: --sframe=.sframe
> +#name: SFrame generation on x86_64 - .cfi_undefined RA
> +#...
> +Contents of the SFrame section .sframe:
> +
> +  Header :
> +
> +    Version: SFRAME_VERSION_2
> +    Flags: SFRAME_F_FDE_FUNC_START_PCREL
> +    CFA fixed RA offset: \-8
> +    Num FDEs: 1
> +    Num FREs: 4
> +
> +  Function Index :
> +
> +    func idx \[0\]: pc = 0x0, size = 6 bytes
> +    STARTPC +CFA +FP +RA +
> +    0+0000 +sp\+8 +u +f +
> +    0+0001 +sp\+16 +c\-16 +f +
> +    0+0004 +fp\+16 +c\-16 +f +
> +    0+0005 +RA undefined
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.s
> new file mode 100644
> index 000000000000..0f5b9c71715f
> --- /dev/null
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.s
> @@ -0,0 +1,11 @@
> +	.cfi_startproc
> +	pushq   %rbp
> +	.cfi_def_cfa_offset 16
> +	.cfi_offset 6, -16
> +	movq    %rsp, %rbp
> +	.cfi_def_cfa_register 6
> +	nop
> +	.cfi_undefined 16
> +	.cfi_def_cfa 7, 8
> +	ret
> +	.cfi_endproc
> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> index 9380c98fc3db..41b927fd7196 100644
> --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
> @@ -64,6 +64,7 @@ if { [istarget "x86_64-*-*"] && [gas_sframe_check] } then {
>   	run_dump_test "cfi-sframe-x86_64-empty-2"
>   	run_dump_test "cfi-sframe-x86_64-empty-3"
>   	run_dump_test "cfi-sframe-x86_64-empty-4"
> +	run_dump_test "cfi-sframe-x86_64-ra-undefined-1"
>   	set ASFLAGS "$old_ASFLAGS"
>       }
>   }
> @@ -75,6 +76,7 @@ if { [istarget "aarch64*-*-*"] && [gas_sframe_check] } then {
>       run_dump_test "cfi-sframe-aarch64-3"
>       run_dump_test "cfi-sframe-aarch64-4"
>       run_dump_test "cfi-sframe-aarch64-pac-ab-key-1"
> +    run_dump_test "cfi-sframe-aarch64-ra-undefined-1"
>   }
>   
>   # s390x specific tests
> @@ -89,4 +91,5 @@ if { [istarget "s390x*-*-*"] && [gas_sframe_check] } then {
>       run_dump_test "cfi-sframe-s390x-fpra-offset-2"
>       run_dump_test "cfi-sframe-s390x-fpra-register-1"
>       run_dump_test "cfi-sframe-s390x-fpra-register-2"
> +    run_dump_test "cfi-sframe-s390x-ra-undefined-1"
>   }
> diff --git a/include/sframe.h b/include/sframe.h
> index 7523adbef3a8..127bf3750577 100644
> --- a/include/sframe.h
> +++ b/include/sframe.h
> @@ -287,6 +287,7 @@ typedef struct sframe_fre_info
>   #define SFRAME_V1_FRE_OFFSET_COUNT(data)	  (((data) >> 1) & 0xf)
>   #define SFRAME_V1_FRE_OFFSET_SIZE(data)		  (((data) >> 5) & 0x3)
>   #define SFRAME_V1_FRE_MANGLED_RA_P(data)	  (((data) >> 7) & 0x1)
> +#define SFRAME_V2_FRE_RA_UNDEFINED_P(data)	  (SFRAME_V1_FRE_OFFSET_COUNT (data) == 0)
>   
>   /* SFrame Frame Row Entry definitions.
>   
> diff --git a/libsframe/doc/sframe-spec.texi b/libsframe/doc/sframe-spec.texi
> index f25791e364bf..f0005d549d56 100644
> --- a/libsframe/doc/sframe-spec.texi
> +++ b/libsframe/doc/sframe-spec.texi
> @@ -167,6 +167,11 @@ by CFA offset alignment factor and then revert CFA offset adjustment).
>    @end itemize
>   @item
>   [Errata 1] An ELF SFrame section has the type SHT_GNU_SFRAME.
> +@item
> +[Errata 2] An SFrame FRE info word offset count of zero indicates that the
> +return address (RA) is undefined for the range of PCs covered by the SFrame FRE.
> +A stack tracer may use this as indication that an outermost frame has been
> +reached and the stack trace is complete.
>   @end itemize
>   
>   SFrame version 1 is now obsolete and should not be used.
> @@ -773,7 +778,10 @@ SFRAME_FRE_OFFSET_4B.
>   @item 1-4
>   @tab @code{fre_offset_count}
>   @tab A max value of 15 is allowed.  Typically, a value of upto 3 is sufficient
> -for most ABIs to track all three of CFA, FP and RA.
> +for most ABIs to track all three of CFA, FP and RA.  A value of zero indicates
> +that the return address (RA) is undefined.  A stack tracer may use this as
> +indication that an outermost frame has been reached and the stack trace is
> +complete.
>   
>   @item 0
>   @tab @code{fre_cfa_base_reg_id}
> diff --git a/libsframe/sframe-dump.c b/libsframe/sframe-dump.c
> index d55d3847194e..1290966439f2 100644
> --- a/libsframe/sframe-dump.c
> +++ b/libsframe/sframe-dump.c
> @@ -130,6 +130,7 @@ dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx,
>     uint64_t func_start_pc_vma = 0;
>     uint64_t fre_start_pc_vma = 0;
>     const char *base_reg_str[] = {"fp", "sp"};
> +  bool ra_undefined_p = false;
>     int32_t cfa_offset = 0;
>     int32_t fp_offset = 0;
>     int32_t ra_offset = 0;
> @@ -180,15 +181,25 @@ dump_sframe_func_with_fres (sframe_decoder_ctx *sfd_ctx,
>   			  : func_start_pc_vma + fre.fre_start_addr);
>   
>         /* FIXME - fixup the err caching in array.
> -	 assert no error for base reg id.  */
> +	 assert no error for base reg id and RA undefined.  */
>         base_reg_id = sframe_fre_get_base_reg_id (&fre, &err[0]);
> +      ra_undefined_p = sframe_fre_get_ra_undefined_p (sfd_ctx, &fre, &err[0]);
>         cfa_offset = sframe_fre_get_cfa_offset (sfd_ctx, &fre, &err[0]);
>         fp_offset = sframe_fre_get_fp_offset (sfd_ctx, &fre, &err[1]);
>         ra_offset = sframe_fre_get_ra_offset (sfd_ctx, &fre, &err[2]);
>   
> -      /* Dump CFA info.  */
> +      /* Dump VMA.  */
>         printf ("\n");
>         printf ("    %016"PRIx64, fre_start_pc_vma);
> +
> +      /* Dump RA undefined (FRE without any offsets).  */
> +      if (ra_undefined_p)
> +	{
> +	  printf ("  RA undefined");
> +	  continue;
> +	}
> +
> +      /* Dump CFA info.  */
>         sprintf (temp, "%s+%d", base_reg_str[base_reg_id], cfa_offset);
>         printf ("  %-10s", temp);
>   
> diff --git a/libsframe/sframe.c b/libsframe/sframe.c
> index e4ef22720924..26948022f69d 100644
> --- a/libsframe/sframe.c
> +++ b/libsframe/sframe.c
> @@ -134,7 +134,7 @@ sframe_get_fre_ra_mangled_p (uint8_t fre_info)
>   static bool
>   sframe_get_fre_ra_undefined_p (uint8_t fre_info)
>   {
> -  return SFRAME_V1_FRE_OFFSET_COUNT (fre_info) == 0;
> +  return SFRAME_V2_FRE_RA_UNDEFINED_P (fre_info);
>   }
>   
>   /* Access functions for info from function descriptor entry.  */
> @@ -760,7 +760,8 @@ sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
>     int8_t ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
>     /* If the RA offset was not being tracked, return the fixed RA offset
>        from the SFrame header.  */
> -  if (ra_offset != SFRAME_CFA_FIXED_RA_INVALID)
> +  if (ra_offset != SFRAME_CFA_FIXED_RA_INVALID
> +      && !sframe_get_fre_ra_undefined_p (fre->fre_info))
>       {
>         if (errp)
>   	*errp = 0;

Same for sframe_fre_get_fp_offset as well.

Thanks


More information about the Binutils mailing list