[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