From: Indu Bhagat Date: Fri, 16 Jan 2026 00:42:21 +0000 (-0800) Subject: [SFrame-V3] include: sframe: reserve 5 bits for new FDE types X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=df9859418359cd83241ceea1f512f89f5cf0afd3;p=thirdparty%2Fbinutils-gdb.git [SFrame-V3] include: sframe: reserve 5 bits for new FDE types 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 variable length bytes trailing the SFrame FRE header as stack offsets. - 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" may be 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. --- diff --git a/include/sframe.h b/include/sframe.h index 3b656663ce2..cc439e52154 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. */ @@ -359,7 +391,7 @@ typedef struct sframe_fre_info /* SFrame Frame Row Entry definitions. - Used for AMD64, AARCH64, and s390x. + Used for Default FDEs in AMD64, AARCH64, and s390x. An SFrame Frame Row Entry is a self-sufficient record which contains information on how to generate the stack trace for the specified range of @@ -367,7 +399,7 @@ typedef struct sframe_fre_info S is the size of the stack frame offset for the FRE, and N is the number of stack frame offsets in the FRE - The interpretation of FRE stack offsets is ABI-specific: + The interpretation of FRE stack offsets for default FDEs is ABI-specific: AMD64: offset1 (interpreted as CFA = BASE_REG + offset1)