[RFC PATCH v3 1/3] sframe: Support for RA undefined as indication for outermost frame

Jens Remus jremus@linux.ibm.com
Wed Jul 23 14:23:45 GMT 2025


SFrame V2 has been enhanced to represent return address (RA) undefined
as a SFrame FDE without any FREs and the FDE info word flag
"RA undefined" set.  This is backward compatible, as the flag was
previously unused and therefore unset.

In sense of DWARF an undefined rule for the RA indicates that there is
no return address and the stack trace is complete because an explicitly
as such marked outermost frame has been reached.

Use a SFrame FDE without any FREs and "RA undefined" flag set as
indication that an outermost frame has been reached and the stack trace
is complete.

sysdeps/generic/
	* sframe.h (FDE info word): New flag "RA undefined".
	(SFRAME_V2_FUNC_RA_UNDEF, SFRAME_V2_FUNC_INFO_UPDATE_RA_UNDEF):
	New macros to test and set the "RA undefined" flag.
	* sframe-read.h (__sframe_find_fre): Return _URC_NORMAL_STOP
	if outermost frame reached.
	* sframe-read.c (__sframe_find_fre): Likewise, if FDE without
	any FREs and RA undefined set.
	* sframe.c (__stacktrace_sframe): Stop stack trace if outermost
	frame reached.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---

Notes:
    Changes in v3:
    - New patch.

 sysdeps/generic/sframe-read.c | 11 +++++++++--
 sysdeps/generic/sframe-read.h |  3 ++-
 sysdeps/generic/sframe.c      |  9 ++++++++-
 sysdeps/generic/sframe.h      | 17 ++++++++++++-----
 4 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/sysdeps/generic/sframe-read.c b/sysdeps/generic/sframe-read.c
index a6ebc42d6689..5a8573214d0c 100644
--- a/sysdeps/generic/sframe-read.c
+++ b/sysdeps/generic/sframe-read.c
@@ -570,8 +570,9 @@ __sframe_decode (sframe_decoder_ctx *dctx, const char *sf_buf)
   return _URC_NO_REASON;
 }
 
-/* Find the SFrame Row Entry which contains the PC.  Returns
-   _URC_END_OF_STACK if failure.  */
+/* Find the SFrame Frame Row Entry which contains the PC.  Returns
+   _URC_END_OF_STACK if failure, _URC_NORMAL_STOP if outermost
+   frame reached, or _URC_NO_REASON otherwise.  */
 
 _Unwind_Reason_Code
 __sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
@@ -595,6 +596,12 @@ __sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
   if (fdep == NULL || ctx->sfd_fres == NULL)
     return _URC_END_OF_STACK;
 
+  /* A FDE without any FREs and RA undefined flag set indicates an
+     outermost frame.  */
+  if (fdep->sfde_func_num_fres == 0
+      && SFRAME_V2_FUNC_RA_UNDEF (fdep->sfde_func_info))
+    return _URC_NORMAL_STOP;
+
   fre_type = sframe_get_fre_type (fdep);
 
   fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
diff --git a/sysdeps/generic/sframe-read.h b/sysdeps/generic/sframe-read.h
index 146142143c6b..79a2b0f83bd2 100644
--- a/sysdeps/generic/sframe-read.h
+++ b/sysdeps/generic/sframe-read.h
@@ -64,7 +64,8 @@ extern _Unwind_Reason_Code
 __sframe_decode (sframe_decoder_ctx *dctx, const char *cf_buf);
 
 /* Find the SFrame Frame Row Entry which contains the PC.  Returns
-   _URC_END_OF_STACK if failure.  */
+   _URC_END_OF_STACK if failure, _URC_NORMAL_STOP if outermost
+   frame reached, or _URC_NO_REASON otherwise.  */
 
 extern _Unwind_Reason_Code
 __sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
diff --git a/sysdeps/generic/sframe.c b/sysdeps/generic/sframe.c
index ba0830da3d30..0dff78a9cacc 100644
--- a/sysdeps/generic/sframe.c
+++ b/sysdeps/generic/sframe.c
@@ -56,6 +56,7 @@ __stacktrace_sframe (void **ra_lst, int count, frame *frame)
     frame_ptr;
   int cfa_offset, fp_offset, ra_offset, i;
   sframe_frame_row_entry fred, *frep = &fred;
+  _Unwind_Reason_Code rc;
 
   if (!ra_lst || !count)
     return 0;
@@ -98,7 +99,8 @@ __stacktrace_sframe (void **ra_lst, int count, frame *frame)
 
       pc = frame->pc - sframe_vma;
       /* Find the SFrame Row Entry which contains the PC.  */
-      if (__sframe_find_fre (dctx, pc, frep) == _URC_END_OF_STACK)
+      rc = __sframe_find_fre (dctx, pc, frep);
+      if (rc == _URC_END_OF_STACK)
 	{
 #ifdef MD_DECODE_SIGNAL_FRAME
 	  /* If there are no valid FREs, check if it is a signal
@@ -116,6 +118,11 @@ __stacktrace_sframe (void **ra_lst, int count, frame *frame)
 	  /* Force fallback to DWARF stacktracer.  */
 	  return 0;
 	}
+      else if (rc == _URC_NORMAL_STOP)
+	{
+	  /* Outermost frame reached.  Stack trace is complete.  */
+	  return i;
+	}
 
       /* Get the CFA offset from the FRE.  If offset is unavailable,
 	 sets err.  */
diff --git a/sysdeps/generic/sframe.h b/sysdeps/generic/sframe.h
index e38adcfe1769..6225eda5d6dc 100644
--- a/sysdeps/generic/sframe.h
+++ b/sysdeps/generic/sframe.h
@@ -196,12 +196,13 @@ typedef struct sframe_func_desc_entry
      - 4-bits: Identify the FRE type used for the function.
      - 1-bit: Identify the FDE type of the function - mask or inc.
      - 1-bit: PAC authorization A/B key (aarch64).
-     - 2-bits: Unused.
+     - 1-bit: Identify whether the RA is undefined (i.e. outermost frame).
+     - 1-bit: Unused.
      ------------------------------------------------------------------------
-     |     Unused    |  PAC auth A/B key (aarch64) |  FDE type |   FRE type   |
-     |               |        Unused (amd64)       |           |              |
+     | Unused|  RA   |  PAC auth A/B key (aarch64) |  FDE type |   FRE type   |
+     |       | undef.|        Unused (amd64)       |           |              |
      ------------------------------------------------------------------------
-     8               6                             5           4              0     */
+     8       7       6                             5           4              0     */
   uint8_t sfde_func_info;
   /* Size of the block of repeating insns.  Used for SFrame FDEs of type
      SFRAME_FDE_TYPE_PCMASK.  */
@@ -211,7 +212,8 @@ typedef struct sframe_func_desc_entry
 
 /* Macros to compose and decompose function info in FDE.  */
 
-/* Note: Set PAC auth key to SFRAME_AARCH64_PAUTH_KEY_A by default.  */
+/* Note: Set PAC auth key to SFRAME_AARCH64_PAUTH_KEY_A and RA undefined to
+	 0 by default.  */
 #define SFRAME_V1_FUNC_INFO(fde_type, fre_enc_type) \
   (((SFRAME_AARCH64_PAUTH_KEY_A & 0x1) << 5) | \
    (((fde_type) & 0x1) << 4) | ((fre_enc_type) & 0xf))
@@ -219,11 +221,16 @@ typedef struct sframe_func_desc_entry
 #define SFRAME_V1_FUNC_FRE_TYPE(data)	  ((data) & 0xf)
 #define SFRAME_V1_FUNC_FDE_TYPE(data)	  (((data) >> 4) & 0x1)
 #define SFRAME_V1_FUNC_PAUTH_KEY(data)	  (((data) >> 5) & 0x1)
+#define SFRAME_V2_FUNC_RA_UNDEF(data)     (((data) >> 6) & 0x1)
 
 /* Set the pauth key as indicated.  */
 #define SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY(pauth_key, fde_info) \
   ((((pauth_key) & 0x1) << 5) | ((fde_info) & 0xdf))
 
+/* Set the RA undefined flag as indicated.  */
+#define SFRAME_V2_FUNC_INFO_UPDATE_RA_UNDEF(ra_undef, fde_info) \
+  ((((ra_undef) & 0x1) << 6) | ((fde_info) & 0xbf))
+
 /* Size of stack frame offsets in an SFrame Frame Row Entry.  A single
    SFrame FRE has all offsets of the same size.  Offset size may vary
    across frame row entries.  */
-- 
2.48.1



More information about the Libc-alpha mailing list