14b169a6bSchristos /* SFrame format description. 2*e663ba6eSchristos Copyright (C) 2022-2024 Free Software Foundation, Inc. 34b169a6bSchristos 44b169a6bSchristos This file is part of libsframe. 54b169a6bSchristos 64b169a6bSchristos libsframe is free software; you can redistribute it and/or modify it 74b169a6bSchristos under the terms of the GNU General Public License as published by the Free 84b169a6bSchristos Software Foundation; either version 3, or (at your option) any later 94b169a6bSchristos version. 104b169a6bSchristos 114b169a6bSchristos This program is distributed in the hope that it will be useful, but 124b169a6bSchristos WITHOUT ANY WARRANTY; without even the implied warranty of 134b169a6bSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 144b169a6bSchristos See the GNU General Public License for more details. 154b169a6bSchristos 164b169a6bSchristos You should have received a copy of the GNU General Public License 174b169a6bSchristos along with this program; see the file COPYING. If not see 184b169a6bSchristos <http://www.gnu.org/licenses/>. */ 194b169a6bSchristos 204b169a6bSchristos #ifndef _SFRAME_H 214b169a6bSchristos #define _SFRAME_H 224b169a6bSchristos 234b169a6bSchristos #include <sys/types.h> 244b169a6bSchristos #include <limits.h> 254b169a6bSchristos #include <stdint.h> 264b169a6bSchristos 274b169a6bSchristos #include "ansidecl.h" 284b169a6bSchristos 294b169a6bSchristos #ifdef __cplusplus 304b169a6bSchristos extern "C" 314b169a6bSchristos { 324b169a6bSchristos #endif 334b169a6bSchristos 344b169a6bSchristos /* SFrame format. 354b169a6bSchristos 364b169a6bSchristos SFrame format is a simple format to represent the information needed 37*e663ba6eSchristos for generating vanilla backtraces. SFrame format keeps track of the 38*e663ba6eSchristos minimal necessary information needed for stack tracing: 394b169a6bSchristos - Canonical Frame Address (CFA) 404b169a6bSchristos - Frame Pointer (FP) 414b169a6bSchristos - Return Address (RA) 424b169a6bSchristos 434b169a6bSchristos The SFrame section itself has the following structure: 444b169a6bSchristos 454b169a6bSchristos +--------+------------+---------+ 464b169a6bSchristos | file | function | frame | 474b169a6bSchristos | header | descriptor | row | 484b169a6bSchristos | | entries | entries | 494b169a6bSchristos +--------+------------+---------+ 504b169a6bSchristos 514b169a6bSchristos The file header stores a magic number and version information, flags, and 524b169a6bSchristos the byte offset of each of the sections relative to the end of the header 534b169a6bSchristos itself. The file header also specifies the total number of Function 544b169a6bSchristos Descriptor Entries, Frame Row Entries and length of the FRE sub-section. 554b169a6bSchristos 564b169a6bSchristos Following the header is a list of Function Descriptor Entries (FDEs). 574b169a6bSchristos This list may be sorted if the flags in the file header indicate it to be 584b169a6bSchristos so. The sort order, if applicable, is the order of functions in the 594b169a6bSchristos .text.* sections in the resulting binary artifact. Each Function 604b169a6bSchristos Descriptor Entry specifies the start PC of a function, the size in bytes 614b169a6bSchristos of the function and an offset to its first Frame Row Entry (FRE). Each FDE 62*e663ba6eSchristos additionally also specifies the type of FRE it uses to encode the stack 63*e663ba6eSchristos trace information. 644b169a6bSchristos 65*e663ba6eSchristos Next, the SFrame Frame Row Entry sub-section is a list of variable size 66*e663ba6eSchristos records. Each entry represents stack trace information for a set of PCs 67*e663ba6eSchristos of the function. A singular Frame Row Entry is a self-sufficient record 68*e663ba6eSchristos which contains information on how to generate stack trace from the 69*e663ba6eSchristos applicable set of PCs. 704b169a6bSchristos 714b169a6bSchristos */ 724b169a6bSchristos 734b169a6bSchristos 744b169a6bSchristos /* SFrame format versions. */ 754b169a6bSchristos #define SFRAME_VERSION_1 1 76*e663ba6eSchristos #define SFRAME_VERSION_2 2 774b169a6bSchristos /* SFrame magic number. */ 784b169a6bSchristos #define SFRAME_MAGIC 0xdee2 794b169a6bSchristos /* Current version of SFrame format. */ 80*e663ba6eSchristos #define SFRAME_VERSION SFRAME_VERSION_2 814b169a6bSchristos 824b169a6bSchristos /* Various flags for SFrame. */ 834b169a6bSchristos 844b169a6bSchristos /* Function Descriptor Entries are sorted on PC. */ 854b169a6bSchristos #define SFRAME_F_FDE_SORTED 0x1 86*e663ba6eSchristos /* Functions preserve frame pointer. */ 874b169a6bSchristos #define SFRAME_F_FRAME_POINTER 0x2 884b169a6bSchristos 894b169a6bSchristos #define SFRAME_CFA_FIXED_FP_INVALID 0 904b169a6bSchristos #define SFRAME_CFA_FIXED_RA_INVALID 0 914b169a6bSchristos 924b169a6bSchristos /* Supported ABIs/Arch. */ 934b169a6bSchristos #define SFRAME_ABI_AARCH64_ENDIAN_BIG 1 /* AARCH64 big endian. */ 944b169a6bSchristos #define SFRAME_ABI_AARCH64_ENDIAN_LITTLE 2 /* AARCH64 little endian. */ 954b169a6bSchristos #define SFRAME_ABI_AMD64_ENDIAN_LITTLE 3 /* AMD64 little endian. */ 964b169a6bSchristos 974b169a6bSchristos /* SFrame FRE types. */ 984b169a6bSchristos #define SFRAME_FRE_TYPE_ADDR1 0 994b169a6bSchristos #define SFRAME_FRE_TYPE_ADDR2 1 1004b169a6bSchristos #define SFRAME_FRE_TYPE_ADDR4 2 1014b169a6bSchristos 1024b169a6bSchristos /* SFrame Function Descriptor Entry types. 1034b169a6bSchristos 1044b169a6bSchristos The SFrame format has two possible representations for functions. The 1054b169a6bSchristos choice of which type to use is made according to the instruction patterns 1064b169a6bSchristos in the relevant program stub. 1074b169a6bSchristos 1084b169a6bSchristos An SFrame FDE of type SFRAME_FDE_TYPE_PCINC is an indication 1094b169a6bSchristos that the PCs in the FREs should be treated as increments in bytes. This is 1104b169a6bSchristos used for a bulk of the executable code of a program, which contains 1114b169a6bSchristos instructions with no specific pattern. 1124b169a6bSchristos 1134b169a6bSchristos An SFrame FDE of type SFRAME_FDE_TYPE_PCMASK is an indication 1144b169a6bSchristos that the PCs in the FREs should be treated as masks. This type is useful 1154b169a6bSchristos for the cases when a small pattern of instructions in a program stub is 1164b169a6bSchristos repeatedly to cover a specific functionality. Typical usescases are pltN 1174b169a6bSchristos entries, trampolines etc. */ 1184b169a6bSchristos 1194b169a6bSchristos /* Unwinders perform a (PC >= FRE_START_ADDR) to look up a matching FRE. */ 1204b169a6bSchristos #define SFRAME_FDE_TYPE_PCINC 0 121*e663ba6eSchristos /* Unwinders perform a (PC % REP_BLOCK_SIZE >= FRE_START_ADDR) to look up a 122*e663ba6eSchristos matching FRE. */ 1234b169a6bSchristos #define SFRAME_FDE_TYPE_PCMASK 1 1244b169a6bSchristos 1254b169a6bSchristos typedef struct sframe_preamble 1264b169a6bSchristos { 1274b169a6bSchristos uint16_t sfp_magic; /* Magic number (SFRAME_MAGIC). */ 1284b169a6bSchristos uint8_t sfp_version; /* Data format version number (SFRAME_VERSION). */ 1294b169a6bSchristos uint8_t sfp_flags; /* Flags. */ 1304b169a6bSchristos } ATTRIBUTE_PACKED sframe_preamble; 1314b169a6bSchristos 1324b169a6bSchristos typedef struct sframe_header 1334b169a6bSchristos { 1344b169a6bSchristos sframe_preamble sfh_preamble; 1354b169a6bSchristos /* Information about the arch (endianness) and ABI. */ 1364b169a6bSchristos uint8_t sfh_abi_arch; 1374b169a6bSchristos /* Offset for the Frame Pointer (FP) from CFA may be fixed for some 1384b169a6bSchristos ABIs (e.g, in AMD64 when -fno-omit-frame-pointer is used). When fixed, 1394b169a6bSchristos this field specifies the fixed stack frame offset and the individual 1404b169a6bSchristos FREs do not need to track it. When not fixed, it is set to 1414b169a6bSchristos SFRAME_CFA_FIXED_FP_INVALID, and the individual FREs may provide 1424b169a6bSchristos the applicable stack frame offset, if any. */ 1434b169a6bSchristos int8_t sfh_cfa_fixed_fp_offset; 1444b169a6bSchristos /* Offset for the Return Address from CFA is fixed for some ABIs 1454b169a6bSchristos (e.g., AMD64 has it as CFA-8). When fixed, the header specifies the 1464b169a6bSchristos fixed stack frame offset and the individual FREs do not track it. When 1474b169a6bSchristos not fixed, it is set to SFRAME_CFA_FIXED_RA_INVALID, and individual 1484b169a6bSchristos FREs provide the applicable stack frame offset, if any. */ 1494b169a6bSchristos int8_t sfh_cfa_fixed_ra_offset; 150*e663ba6eSchristos /* Number of bytes making up the auxiliary header, if any. 1514b169a6bSchristos Some ABI/arch, in the future, may use this space for extending the 152*e663ba6eSchristos information in SFrame header. Auxiliary header is contained in 1534b169a6bSchristos bytes sequentially following the sframe_header. */ 1544b169a6bSchristos uint8_t sfh_auxhdr_len; 1554b169a6bSchristos /* Number of SFrame FDEs in this SFrame section. */ 1564b169a6bSchristos uint32_t sfh_num_fdes; 1574b169a6bSchristos /* Number of SFrame Frame Row Entries. */ 1584b169a6bSchristos uint32_t sfh_num_fres; 1594b169a6bSchristos /* Number of bytes in the SFrame Frame Row Entry section. */ 1604b169a6bSchristos uint32_t sfh_fre_len; 1614b169a6bSchristos /* Offset of SFrame Function Descriptor Entry section. */ 1624b169a6bSchristos uint32_t sfh_fdeoff; 1634b169a6bSchristos /* Offset of SFrame Frame Row Entry section. */ 1644b169a6bSchristos uint32_t sfh_freoff; 1654b169a6bSchristos } ATTRIBUTE_PACKED sframe_header; 1664b169a6bSchristos 1674b169a6bSchristos #define SFRAME_V1_HDR_SIZE(sframe_hdr) \ 1684b169a6bSchristos ((sizeof (sframe_header) + (sframe_hdr).sfh_auxhdr_len)) 1694b169a6bSchristos 170*e663ba6eSchristos /* Two possible keys for executable (instruction) pointers signing. */ 171*e663ba6eSchristos #define SFRAME_AARCH64_PAUTH_KEY_A 0 /* Key A. */ 172*e663ba6eSchristos #define SFRAME_AARCH64_PAUTH_KEY_B 1 /* Key B. */ 173*e663ba6eSchristos 1744b169a6bSchristos typedef struct sframe_func_desc_entry 1754b169a6bSchristos { 1764b169a6bSchristos /* Function start address. Encoded as a signed offset, relative to the 1774b169a6bSchristos beginning of the current FDE. */ 1784b169a6bSchristos int32_t sfde_func_start_address; 1794b169a6bSchristos /* Size of the function in bytes. */ 1804b169a6bSchristos uint32_t sfde_func_size; 1814b169a6bSchristos /* Offset of the first SFrame Frame Row Entry of the function, relative to the 1824b169a6bSchristos beginning of the SFrame Frame Row Entry sub-section. */ 1834b169a6bSchristos uint32_t sfde_func_start_fre_off; 1844b169a6bSchristos /* Number of frame row entries for the function. */ 1854b169a6bSchristos uint32_t sfde_func_num_fres; 186*e663ba6eSchristos /* Additional information for stack tracing from the function: 1874b169a6bSchristos - 4-bits: Identify the FRE type used for the function. 1884b169a6bSchristos - 1-bit: Identify the FDE type of the function - mask or inc. 189*e663ba6eSchristos - 1-bit: PAC authorization A/B key (aarch64). 190*e663ba6eSchristos - 2-bits: Unused. 191*e663ba6eSchristos ------------------------------------------------------------------------ 192*e663ba6eSchristos | Unused | PAC auth A/B key (aarch64) | FDE type | FRE type | 193*e663ba6eSchristos | | Unused (amd64) | | | 194*e663ba6eSchristos ------------------------------------------------------------------------ 195*e663ba6eSchristos 8 6 5 4 0 */ 1964b169a6bSchristos uint8_t sfde_func_info; 197*e663ba6eSchristos /* Size of the block of repeating insns. Used for SFrame FDEs of type 198*e663ba6eSchristos SFRAME_FDE_TYPE_PCMASK. */ 199*e663ba6eSchristos uint8_t sfde_func_rep_size; 200*e663ba6eSchristos uint16_t sfde_func_padding2; 2014b169a6bSchristos } ATTRIBUTE_PACKED sframe_func_desc_entry; 2024b169a6bSchristos 2034b169a6bSchristos /* Macros to compose and decompose function info in FDE. */ 2044b169a6bSchristos 205*e663ba6eSchristos /* Note: Set PAC auth key to SFRAME_AARCH64_PAUTH_KEY_A by default. */ 2064b169a6bSchristos #define SFRAME_V1_FUNC_INFO(fde_type, fre_enc_type) \ 207*e663ba6eSchristos (((SFRAME_AARCH64_PAUTH_KEY_A & 0x1) << 5) | \ 208*e663ba6eSchristos (((fde_type) & 0x1) << 4) | ((fre_enc_type) & 0xf)) 2094b169a6bSchristos 2104b169a6bSchristos #define SFRAME_V1_FUNC_FRE_TYPE(data) ((data) & 0xf) 2114b169a6bSchristos #define SFRAME_V1_FUNC_FDE_TYPE(data) (((data) >> 4) & 0x1) 212*e663ba6eSchristos #define SFRAME_V1_FUNC_PAUTH_KEY(data) (((data) >> 5) & 0x1) 213*e663ba6eSchristos 214*e663ba6eSchristos /* Set the pauth key as indicated. */ 215*e663ba6eSchristos #define SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY(pauth_key, fde_info) \ 216*e663ba6eSchristos ((((pauth_key) & 0x1) << 5) | ((fde_info) & 0xdf)) 2174b169a6bSchristos 2184b169a6bSchristos /* Size of stack frame offsets in an SFrame Frame Row Entry. A single 2194b169a6bSchristos SFrame FRE has all offsets of the same size. Offset size may vary 2204b169a6bSchristos across frame row entries. */ 2214b169a6bSchristos #define SFRAME_FRE_OFFSET_1B 0 2224b169a6bSchristos #define SFRAME_FRE_OFFSET_2B 1 2234b169a6bSchristos #define SFRAME_FRE_OFFSET_4B 2 2244b169a6bSchristos 2254b169a6bSchristos /* An SFrame Frame Row Entry can be SP or FP based. */ 2264b169a6bSchristos #define SFRAME_BASE_REG_FP 0 2274b169a6bSchristos #define SFRAME_BASE_REG_SP 1 2284b169a6bSchristos 2294b169a6bSchristos /* The index at which a specific offset is presented in the variable length 2304b169a6bSchristos bytes of an FRE. */ 2314b169a6bSchristos #define SFRAME_FRE_CFA_OFFSET_IDX 0 2324b169a6bSchristos /* The RA stack offset, if present, will always be at index 1 in the variable 2334b169a6bSchristos length bytes of the FRE. */ 2344b169a6bSchristos #define SFRAME_FRE_RA_OFFSET_IDX 1 2354b169a6bSchristos /* The FP stack offset may appear at offset 1 or 2, depending on the ABI as RA 2364b169a6bSchristos may or may not be tracked. */ 2374b169a6bSchristos #define SFRAME_FRE_FP_OFFSET_IDX 2 2384b169a6bSchristos 2394b169a6bSchristos typedef struct sframe_fre_info 2404b169a6bSchristos { 2414b169a6bSchristos /* Information about 2424b169a6bSchristos - 1 bit: base reg for CFA 2434b169a6bSchristos - 4 bits: Number of offsets (N). A value of upto 3 is allowed to track 2444b169a6bSchristos all three of CFA, FP and RA (fixed implicit order). 2454b169a6bSchristos - 2 bits: information about size of the offsets (S) in bytes. 2464b169a6bSchristos Valid values are SFRAME_FRE_OFFSET_1B, SFRAME_FRE_OFFSET_2B, 2474b169a6bSchristos SFRAME_FRE_OFFSET_4B 2484b169a6bSchristos - 1 bit: Mangled RA state bit (aarch64 only). 2494b169a6bSchristos ---------------------------------------------------------------------------------- 2504b169a6bSchristos | Mangled-RA (aarch64) | Size of offsets | Number of offsets | base_reg | 2514b169a6bSchristos | Unused (amd64) | | | | 2524b169a6bSchristos ---------------------------------------------------------------------------------- 2534b169a6bSchristos 8 7 5 1 0 2544b169a6bSchristos 2554b169a6bSchristos */ 2564b169a6bSchristos uint8_t fre_info; 2574b169a6bSchristos } sframe_fre_info; 2584b169a6bSchristos 2594b169a6bSchristos /* Macros to compose and decompose FRE info. */ 2604b169a6bSchristos 2614b169a6bSchristos /* Note: Set mangled_ra_p to zero by default. */ 2624b169a6bSchristos #define SFRAME_V1_FRE_INFO(base_reg_id, offset_num, offset_size) \ 2634b169a6bSchristos (((0 & 0x1) << 7) | (((offset_size) & 0x3) << 5) | \ 2644b169a6bSchristos (((offset_num) & 0xf) << 1) | ((base_reg_id) & 0x1)) 2654b169a6bSchristos 2664b169a6bSchristos /* Set the mangled_ra_p bit as indicated. */ 2674b169a6bSchristos #define SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P(mangled_ra_p, fre_info) \ 2684b169a6bSchristos ((((mangled_ra_p) & 0x1) << 7) | ((fre_info) & 0x7f)) 2694b169a6bSchristos 2704b169a6bSchristos #define SFRAME_V1_FRE_CFA_BASE_REG_ID(data) ((data) & 0x1) 2714b169a6bSchristos #define SFRAME_V1_FRE_OFFSET_COUNT(data) (((data) >> 1) & 0xf) 2724b169a6bSchristos #define SFRAME_V1_FRE_OFFSET_SIZE(data) (((data) >> 5) & 0x3) 2734b169a6bSchristos #define SFRAME_V1_FRE_MANGLED_RA_P(data) (((data) >> 7) & 0x1) 2744b169a6bSchristos 2754b169a6bSchristos /* SFrame Frame Row Entry definitions. 2764b169a6bSchristos 2774b169a6bSchristos Used for both AMD64 and AARCH64. 2784b169a6bSchristos 279*e663ba6eSchristos An SFrame Frame Row Entry is a self-sufficient record which contains 280*e663ba6eSchristos information on how to generate the stack trace for the specified range of 281*e663ba6eSchristos PCs. Each SFrame Frame Row Entry is followed by S*N bytes, where: 2824b169a6bSchristos S is the size of the stack frame offset for the FRE, and 2834b169a6bSchristos N is the number of stack frame offsets in the FRE 2844b169a6bSchristos 2854b169a6bSchristos The offsets are interpreted in order as follows: 2864b169a6bSchristos 2874b169a6bSchristos offset1 (interpreted as CFA = BASE_REG + offset1) 2884b169a6bSchristos 2894b169a6bSchristos if RA is being tracked 2904b169a6bSchristos offset2 (interpreted as RA = CFA + offset2) 2914b169a6bSchristos if FP is being tracked 2924b169a6bSchristos offset3 (intrepreted as FP = CFA + offset2) 2934b169a6bSchristos fi 2944b169a6bSchristos else 2954b169a6bSchristos if FP is being tracked 2964b169a6bSchristos offset2 (intrepreted as FP = CFA + offset2) 2974b169a6bSchristos fi 2984b169a6bSchristos fi 2994b169a6bSchristos */ 3004b169a6bSchristos 3014b169a6bSchristos /* Used when SFRAME_FRE_TYPE_ADDR1 is specified as FRE type. */ 3024b169a6bSchristos typedef struct sframe_frame_row_entry_addr1 3034b169a6bSchristos { 3044b169a6bSchristos /* Start address of the frame row entry. Encoded as an 1-byte unsigned 3054b169a6bSchristos offset, relative to the start address of the function. */ 3064b169a6bSchristos uint8_t sfre_start_address; 3074b169a6bSchristos sframe_fre_info sfre_info; 3084b169a6bSchristos } ATTRIBUTE_PACKED sframe_frame_row_entry_addr1; 3094b169a6bSchristos 3104b169a6bSchristos /* Upper limit of start address in sframe_frame_row_entry_addr1 3114b169a6bSchristos is 0x100 (not inclusive). */ 312*e663ba6eSchristos #define SFRAME_FRE_TYPE_ADDR1_LIMIT \ 313*e663ba6eSchristos (1ULL << ((SFRAME_FRE_TYPE_ADDR1 + 1) * 8)) 3144b169a6bSchristos 3154b169a6bSchristos /* Used when SFRAME_FRE_TYPE_ADDR2 is specified as FRE type. */ 3164b169a6bSchristos typedef struct sframe_frame_row_entry_addr2 3174b169a6bSchristos { 3184b169a6bSchristos /* Start address of the frame row entry. Encoded as an 2-byte unsigned 3194b169a6bSchristos offset, relative to the start address of the function. */ 3204b169a6bSchristos uint16_t sfre_start_address; 3214b169a6bSchristos sframe_fre_info sfre_info; 3224b169a6bSchristos } ATTRIBUTE_PACKED sframe_frame_row_entry_addr2; 3234b169a6bSchristos 3244b169a6bSchristos /* Upper limit of start address in sframe_frame_row_entry_addr2 3254b169a6bSchristos is 0x10000 (not inclusive). */ 326*e663ba6eSchristos #define SFRAME_FRE_TYPE_ADDR2_LIMIT \ 327*e663ba6eSchristos (1ULL << ((SFRAME_FRE_TYPE_ADDR2 * 2) * 8)) 3284b169a6bSchristos 3294b169a6bSchristos /* Used when SFRAME_FRE_TYPE_ADDR4 is specified as FRE type. */ 3304b169a6bSchristos typedef struct sframe_frame_row_entry_addr4 3314b169a6bSchristos { 3324b169a6bSchristos /* Start address of the frame row entry. Encoded as a 4-byte unsigned 3334b169a6bSchristos offset, relative to the start address of the function. */ 3344b169a6bSchristos uint32_t sfre_start_address; 3354b169a6bSchristos sframe_fre_info sfre_info; 3364b169a6bSchristos } ATTRIBUTE_PACKED sframe_frame_row_entry_addr4; 3374b169a6bSchristos 3384b169a6bSchristos /* Upper limit of start address in sframe_frame_row_entry_addr2 3394b169a6bSchristos is 0x100000000 (not inclusive). */ 340*e663ba6eSchristos #define SFRAME_FRE_TYPE_ADDR4_LIMIT \ 341*e663ba6eSchristos (1ULL << ((SFRAME_FRE_TYPE_ADDR4 * 2) * 8)) 3424b169a6bSchristos 3434b169a6bSchristos #ifdef __cplusplus 3444b169a6bSchristos } 3454b169a6bSchristos #endif 3464b169a6bSchristos 3474b169a6bSchristos #endif /* _SFRAME_H */ 348