]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[SFrame-V3] include: sframe: reserve 4 bits for new FDE types
authorIndu Bhagat <indu.bhagat@oracle.com>
Tue, 25 Nov 2025 00:27:30 +0000 (16:27 -0800)
committerIndu Bhagat <indu.bhagat@oracle.com>
Tue, 9 Dec 2025 08:26:14 +0000 (00:26 -0800)
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_TOPMOST_FRAME,
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 top-most 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_TOPMOST_FRAME, 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 each of CFA and RA 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).

TBD:
  - Terminology concern. Up until now, we called the following as FDE
    types:
       - SFRAME_FDE_TYPE_PCINC
       - SFRAME_FDE_TYPE_PCMASK
     In hindsight, these should have been referred to as "PC type" for
     FDE.  Fixup comments and macro etc.
  - Cleanup the FDE type terminology from code base.

include/
        * sframe.h (SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME): New SFrame FDE
type.
(SFRAME_V3_FUNC_FDE_TYPE_MASK): New constant definition.
(SFRAME_V3_FUNC_INFO2_GET_FDE_TYPE): New macro definition.
(SFRAME_V3_FUNC_INFO2_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.

include/sframe.h

index dec3c017a5bd795190f2433fdfa2285c96c0f0ee..88c4f97a46ed10862ecf403d892ef9ca077cdcc7 100644 (file)
@@ -135,6 +135,17 @@ extern "C"
    matching FRE.  */
 #define SFRAME_FDE_TYPE_PCMASK  1
 
+/* Extended FDE types.  */
+
+/* Flexible Topmost Frame encoding FDE type.
+   The recovery rule for CFA, RA and FP allow more flexibility.  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.
+   Currently used for SFRAME_ABI_AMD64_ENDIAN_LITTLE.  */
+#define SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME  1
+
 typedef struct sframe_preamble
 {
   uint16_t sfp_magic;  /* Magic number (SFRAME_MAGIC).  */
@@ -265,11 +276,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.
+     - 4-bits: ABI/arch specific FDE types.
+     - 4-bits: Unused.
      -------------------------------------------------------------------------
-     |                            Unused                                     |
+     |                     Unused                             |  ABI/arch    |
+     |                                                        |  FDE Type    |
      -------------------------------------------------------------------------
-     8        7         6                  5           4              0     */
+     8        7         6                         5           4              0     */
   uint8_t sfde_func_info2;
   /* Size of the block of repeating insns.  Used for SFrame FDEs of type
      SFRAME_FDE_TYPE_PCMASK.  */
@@ -281,6 +294,18 @@ typedef struct sframe_func_desc_entry_v3
 #define SFRAME_V3_FUNC_INFO(fde_type, fre_enc_type) \
   (SFRAME_V2_FUNC_INFO (fde_type, fre_enc_type))
 
+/* Mask for the ABI/arch specific FDE type (lower 4 bits). */
+#define SFRAME_V3_FUNC_FDE_TYPE_MASK 0x0f
+
+/* Get the FDE type from the info2 byte. */
+#define SFRAME_V3_FUNC_INFO2_GET_FDE_TYPE(info2) \
+  ((info2) & SFRAME_V3_FUNC_FDE_TYPE_MASK)
+
+/* Set the FDE type in the info2 byte, preserving upper bits. */
+#define SFRAME_V3_FUNC_INFO2_SET_FDE_TYPE(info2, fde_type) \
+  (((info2) & ~SFRAME_V3_FUNC_FDE_TYPE_MASK) \
+   | ((fde_type) & SFRAME_V3_FUNC_FDE_TYPE_MASK))
+
 #define SFRAME_V3_FUNC_FRE_TYPE(data)    (SFRAME_V2_FUNC_FRE_TYPE (data))
 #define SFRAME_V3_FUNC_FDE_TYPE(data)    (SFRAME_V2_FUNC_FDE_TYPE (data))
 #define SFRAME_V3_FUNC_PAUTH_KEY(data)   (SFRAME_V2_FUNC_PAUTH_KEY (data))
@@ -292,6 +317,14 @@ typedef struct sframe_func_desc_entry_v3
 #define SFRAME_V3_FUNC_INFO_UPDATE_SIGNAL_P(signal_p, fde_info)  \
   ((((signal_p) & 0x1) << 7) | ((fde_info) & 0x7f))
 
+#define SFRAME_V3_FLEX_FDE_REG_ENCODE(reg, deref, reg_p)  \
+  (((((reg) & 0x1f) << 0x3) | (0 << 0x2) | (((deref) & 0x1) << 0x1) \
+    | ((reg_p) & 0x1)))
+
+#define SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM(data)       (((data) >> 3) & 0x1f)
+#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.  */