[V3 15/36] [SFrame-V3] include: sframe: reserve 5 bits for new FDE types

Indu Bhagat indu.bhagat@oracle.com
Tue Jan 13 11:12:19 GMT 2026


In SFrame V2, the FDE representation caters to the most common cases of
stack trace metadata:
  - CFA is SP/FP based,
  - FP/RA offsets, if present are CFA based (except some cases in s390x
    where reg can be encoded).

Introduce an additional FDE type SFRAME_FDE_TYPE_FLEX, which can encode
a more flexible set of CFA, FP and RA recovery rules.  Some of the
patterns supported include:
  - CFA may be non-SP/FP based.
  - CFA, FP may encode dereferencing of register after offset adjustment
  - RA may be in a non-default register.

The important bit here is that since SFrame does not track all
callee-saved registers, the above-mentioned recovery rules must only be
done for topmost frames (by the stack tracer).

Adding a new FDE type does have implications for a stack tracer in that
it needs to:
  - Check the FDE type before interpreting the Stack offsets data.
  - If the FDE type is SFRAME_FDE_TYPE_FLEX, and the
    recovery rules employ the use of any non-SP/FP based register, the
    stack tracer must proceed only if it is the topmost frame on stack.

For CFA, RA, and FP, up to two offsets are always used.  The two offsets
represent the information as follows:
  - (minimum 8-bit) offset1 to encode register like:
    (regnum << 3) | unused << 2 | deref << 1 | reg_p (=1)
  - offset2 to encode offset: offset

reg_p = 1 indicates a register, reg_p = 0 indicates CFA.

The offsets are in the usual order:  CFA, RA, FP if present.

For example, for FP/RA tracking,

a) If the reg is REG1 for FP/RA tracking,
   - Encoding:
     + offset1 to encode register: (REG1 << 3) | unused << 2 | deref << 1 | reg_p (=1)
     + offset2 to encode offset: offset
   - Action:
     + if deref, FP/RA = \*(REG1 + offset) (e.g., seen for FP recovery
       with certain DRAP patterns on x86_64)
     + if no deref, FP/RA = REG1 + offset

b) If the reg is CFA for FP/RA tracking,
   - Encoding:
     + [=Effectively Padding] offset1 to encode register:
        (( 0 << 3 ) | unused << 2 | 0 << 1 | reg_p (=0))
     + offset2 to encode offset: offset
   - Action:
     + if deref, FP/RA = *(CFA + offset)
     + if no deref, FP/RA = CFA + offset (pattern shouldnt be seen for
       RA)

Next for CFA tracking,
   - Action:
     + if deref, CFA = *(reg + offset) (e.g., seen for CFA recovery in
       some stack realignment patterns on AMD64)
     + if no deref, CFA = reg + offset (e.g., for .cfi_def_cfa 2, 8, or
       .cfi_def_cfa 10, 0)

Expected usage of this FDE type is quite low (DRAP on x86_64).

NB: In SFrame V2, we did use the the term 'FDE Type' for the two
designated 'PC Type' for the SFrame FDEs (SFRAME_FDE_TYPE_PCINC,
SFRAME_FDE_TYPE_PCMASK).  In hindsight, 'FDE Type' was inappropriate
term.  In a subsequent commit, we will fix this terminology for SFrame
V3.

include/
	* sframe.h (SFRAME_FDE_TYPE_FLEX): New SFrame FDE type.
	(SFRAME_V3_FDE_TYPE_MASK): New constant definition.
	(SFRAME_V3_FDE_TYPE): New macro definition.
	(SFRAME_V3_SET_FDE_TYPE): Likewise.
	(SFRAME_V3_FLEX_FDE_REG_ENCODE): Macro to encode register in the
	SFrame offset data.
	(SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM): New definition.
	(SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P): Likewise.
	(SFRAME_V3_FLEX_FDE_OFFSET_REG_P): Likewise.

---
[Changes in V1]
  - Increase the number of bits for FDE type from 4 to 5 [Indu].
  - Adjust the macro names to V3_FDE_TYPE etc [Jens].
  - Removed the TBD From commit log regarding the terminology concern of
    using 'FDE Type' (up until now) for referring to (what is really)
    the PC Types for the functions (SFRAME_FDE_TYPE_PCINC,
    SFRAME_FDE_TYPE_PCMASK).  This is fixed in a subsequent commit in
    the series [Indu].
[End of changes in V1]

[No changes in V2]

[Changes in V3]
  - Adjusted the text in commit log from "two offsets" to "up to two
    offsets" [Indu]
[End of changes in V3]
---
 include/sframe.h | 38 +++++++++++++++++++++++++++++++++++---
 1 file changed, 35 insertions(+), 3 deletions(-)

diff --git a/include/sframe.h b/include/sframe.h
index 0d8c1123d6b..222b6a5fcc6 100644
--- a/include/sframe.h
+++ b/include/sframe.h
@@ -140,6 +140,19 @@ extern "C"
    matching FRE.  */
 #define SFRAME_FDE_TYPE_PCMASK  1
 
+/* SFrame FDE types.  */
+
+/* Default FDE type.  */
+#define SFRAME_FDE_TYPE_DEFAULT	  0
+/* Flexible Frame FDE type.
+   The recovery rule for CFA, RA and FP allow more flexibility.  Examples of
+   patterns supported include:
+     - CFA may be non-SP/FP based.
+     - CFA, FP may encode dereferencing of register after offset adjustment
+     - RA may be in a non-default register.
+   Currently used for SFRAME_ABI_AMD64_ENDIAN_LITTLE.  */
+#define SFRAME_FDE_TYPE_FLEX	  1
+
 typedef struct sframe_preamble
 {
   uint16_t sfp_magic;	/* Magic number (SFRAME_MAGIC).  */
@@ -270,11 +283,13 @@ typedef struct sframe_func_desc_entry_v3
      8        7             6                             5         4              0     */
   uint8_t sfde_func_info;
   /* Additional information for stack tracing from the function:
-     - 8-bits: Unused.
+     - 5-bits: FDE type.
+     - 3-bits: Unused.
      ------------------------------------------------------------
-     |                         Unused                           |
+     |                     Unused                 |  FDE Type   |
+     |                                            |             |
      ------------------------------------------------------------
-     8        7         6                         5             0     */
+     8                7             6             5             0     */
   uint8_t sfde_func_info2;
   /* Size of the block of repeating insns.  Used for SFrame FDEs of type
      SFRAME_FDE_TYPE_PCMASK.  */
@@ -284,17 +299,34 @@ typedef struct sframe_func_desc_entry_v3
 #define SFRAME_V3_FDE_FUNC_INFO(fde_pc_type, fre_type) \
   (SFRAME_V2_FUNC_INFO (fde_pc_type, fre_type))
 
+/* Mask for the ABI/arch specific FDE type (lower 5 bits).  */
+#define SFRAME_V3_FDE_TYPE_MASK		      0x01f
+/* Get the FDE type from the info2 byte.  */
+#define SFRAME_V3_FDE_TYPE(info2) \
+  ((info2) & SFRAME_V3_FDE_TYPE_MASK)
 #define SFRAME_V3_FDE_FRE_TYPE(info)          (SFRAME_V2_FUNC_FRE_TYPE (info))
 #define SFRAME_V3_FDE_PC_TYPE(info)           (SFRAME_V2_FUNC_PC_TYPE (info))
 #define SFRAME_V3_AARCH64_FDE_PAUTH_KEY(info) (SFRAME_V2_FUNC_PAUTH_KEY (info))
 #define SFRAME_V3_FDE_SIGNAL_P(info)           (((info) >> 7) & 0x1)
 
+/* Set the FDE type in the info2 byte, preserving upper bits.  */
+#define SFRAME_V3_SET_FDE_TYPE(info2, fde_type) \
+  (((info2) & ~SFRAME_V3_FDE_TYPE_MASK) \
+   | ((fde_type) & SFRAME_V3_FDE_TYPE_MASK))
+
 #define SFRAME_V3_FDE_UPDATE_PAUTH_KEY(pauth_key, info) \
   SFRAME_V2_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, info)
 
 #define SFRAME_V3_FDE_UPDATE_SIGNAL_P(signal_p, info)  \
   ((((signal_p) & 0x1) << 7) | ((info) & 0x7f))
 
+#define SFRAME_V3_FLEX_FDE_REG_ENCODE(reg, deref_p, reg_p)  \
+  ((((reg) << 0x3) | (0 << 0x2) | (((deref_p) & 0x1) << 0x1) | ((reg_p) & 0x1)))
+
+#define SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM(data)       ((data) >> 3)
+#define SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P(data)   (((data) >> 1) & 0x1)
+#define SFRAME_V3_FLEX_FDE_OFFSET_REG_P(data)         ((data) & 0x1)
+
 /* 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.43.0



More information about the Binutils mailing list