From: Indu Bhagat Date: Tue, 25 Nov 2025 00:27:30 +0000 (-0800) Subject: [SFrame-V3] include: sframe: reserve 4 bits for new FDE types X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=56c6fe4b9141b1129b5ebbb60ad240708cea5cbc;p=thirdparty%2Fbinutils-gdb.git [SFrame-V3] include: sframe: reserve 4 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_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. --- diff --git a/include/sframe.h b/include/sframe.h index dec3c017a5b..88c4f97a46e 100644 --- a/include/sframe.h +++ b/include/sframe.h @@ -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. */