1*cb63e24eSchristos /* SFrame format description. 2*cb63e24eSchristos Copyright (C) 2022-2024 Free Software Foundation, Inc. 3*cb63e24eSchristos 4*cb63e24eSchristos This file is part of libsframe. 5*cb63e24eSchristos 6*cb63e24eSchristos libsframe is free software; you can redistribute it and/or modify it 7*cb63e24eSchristos under the terms of the GNU General Public License as published by the Free 8*cb63e24eSchristos Software Foundation; either version 3, or (at your option) any later 9*cb63e24eSchristos version. 10*cb63e24eSchristos 11*cb63e24eSchristos This program is distributed in the hope that it will be useful, but 12*cb63e24eSchristos WITHOUT ANY WARRANTY; without even the implied warranty of 13*cb63e24eSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14*cb63e24eSchristos See the GNU General Public License for more details. 15*cb63e24eSchristos 16*cb63e24eSchristos You should have received a copy of the GNU General Public License 17*cb63e24eSchristos along with this program; see the file COPYING. If not see 18*cb63e24eSchristos <http://www.gnu.org/licenses/>. */ 19*cb63e24eSchristos 20*cb63e24eSchristos #ifndef _SFRAME_H 21*cb63e24eSchristos #define _SFRAME_H 22*cb63e24eSchristos 23*cb63e24eSchristos #include <sys/types.h> 24*cb63e24eSchristos #include <limits.h> 25*cb63e24eSchristos #include <stdint.h> 26*cb63e24eSchristos 27*cb63e24eSchristos #include "ansidecl.h" 28*cb63e24eSchristos 29*cb63e24eSchristos #ifdef __cplusplus 30*cb63e24eSchristos extern "C" 31*cb63e24eSchristos { 32*cb63e24eSchristos #endif 33*cb63e24eSchristos 34*cb63e24eSchristos /* SFrame format. 35*cb63e24eSchristos 36*cb63e24eSchristos SFrame format is a simple format to represent the information needed 37*cb63e24eSchristos for generating vanilla backtraces. SFrame format keeps track of the 38*cb63e24eSchristos minimal necessary information needed for stack tracing: 39*cb63e24eSchristos - Canonical Frame Address (CFA) 40*cb63e24eSchristos - Frame Pointer (FP) 41*cb63e24eSchristos - Return Address (RA) 42*cb63e24eSchristos 43*cb63e24eSchristos The SFrame section itself has the following structure: 44*cb63e24eSchristos 45*cb63e24eSchristos +--------+------------+---------+ 46*cb63e24eSchristos | file | function | frame | 47*cb63e24eSchristos | header | descriptor | row | 48*cb63e24eSchristos | | entries | entries | 49*cb63e24eSchristos +--------+------------+---------+ 50*cb63e24eSchristos 51*cb63e24eSchristos The file header stores a magic number and version information, flags, and 52*cb63e24eSchristos the byte offset of each of the sections relative to the end of the header 53*cb63e24eSchristos itself. The file header also specifies the total number of Function 54*cb63e24eSchristos Descriptor Entries, Frame Row Entries and length of the FRE sub-section. 55*cb63e24eSchristos 56*cb63e24eSchristos Following the header is a list of Function Descriptor Entries (FDEs). 57*cb63e24eSchristos This list may be sorted if the flags in the file header indicate it to be 58*cb63e24eSchristos so. The sort order, if applicable, is the order of functions in the 59*cb63e24eSchristos .text.* sections in the resulting binary artifact. Each Function 60*cb63e24eSchristos Descriptor Entry specifies the start PC of a function, the size in bytes 61*cb63e24eSchristos of the function and an offset to its first Frame Row Entry (FRE). Each FDE 62*cb63e24eSchristos additionally also specifies the type of FRE it uses to encode the stack 63*cb63e24eSchristos trace information. 64*cb63e24eSchristos 65*cb63e24eSchristos Next, the SFrame Frame Row Entry sub-section is a list of variable size 66*cb63e24eSchristos records. Each entry represents stack trace information for a set of PCs 67*cb63e24eSchristos of the function. A singular Frame Row Entry is a self-sufficient record 68*cb63e24eSchristos which contains information on how to generate stack trace from the 69*cb63e24eSchristos applicable set of PCs. 70*cb63e24eSchristos 71*cb63e24eSchristos */ 72*cb63e24eSchristos 73*cb63e24eSchristos 74*cb63e24eSchristos /* SFrame format versions. */ 75*cb63e24eSchristos #define SFRAME_VERSION_1 1 76*cb63e24eSchristos #define SFRAME_VERSION_2 2 77*cb63e24eSchristos /* SFrame magic number. */ 78*cb63e24eSchristos #define SFRAME_MAGIC 0xdee2 79*cb63e24eSchristos /* Current version of SFrame format. */ 80*cb63e24eSchristos #define SFRAME_VERSION SFRAME_VERSION_2 81*cb63e24eSchristos 82*cb63e24eSchristos /* Various flags for SFrame. */ 83*cb63e24eSchristos 84*cb63e24eSchristos /* Function Descriptor Entries are sorted on PC. */ 85*cb63e24eSchristos #define SFRAME_F_FDE_SORTED 0x1 86*cb63e24eSchristos /* Functions preserve frame pointer. */ 87*cb63e24eSchristos #define SFRAME_F_FRAME_POINTER 0x2 88*cb63e24eSchristos 89*cb63e24eSchristos #define SFRAME_CFA_FIXED_FP_INVALID 0 90*cb63e24eSchristos #define SFRAME_CFA_FIXED_RA_INVALID 0 91*cb63e24eSchristos 92*cb63e24eSchristos /* Supported ABIs/Arch. */ 93*cb63e24eSchristos #define SFRAME_ABI_AARCH64_ENDIAN_BIG 1 /* AARCH64 big endian. */ 94*cb63e24eSchristos #define SFRAME_ABI_AARCH64_ENDIAN_LITTLE 2 /* AARCH64 little endian. */ 95*cb63e24eSchristos #define SFRAME_ABI_AMD64_ENDIAN_LITTLE 3 /* AMD64 little endian. */ 96*cb63e24eSchristos 97*cb63e24eSchristos /* SFrame FRE types. */ 98*cb63e24eSchristos #define SFRAME_FRE_TYPE_ADDR1 0 99*cb63e24eSchristos #define SFRAME_FRE_TYPE_ADDR2 1 100*cb63e24eSchristos #define SFRAME_FRE_TYPE_ADDR4 2 101*cb63e24eSchristos 102*cb63e24eSchristos /* SFrame Function Descriptor Entry types. 103*cb63e24eSchristos 104*cb63e24eSchristos The SFrame format has two possible representations for functions. The 105*cb63e24eSchristos choice of which type to use is made according to the instruction patterns 106*cb63e24eSchristos in the relevant program stub. 107*cb63e24eSchristos 108*cb63e24eSchristos An SFrame FDE of type SFRAME_FDE_TYPE_PCINC is an indication 109*cb63e24eSchristos that the PCs in the FREs should be treated as increments in bytes. This is 110*cb63e24eSchristos used for a bulk of the executable code of a program, which contains 111*cb63e24eSchristos instructions with no specific pattern. 112*cb63e24eSchristos 113*cb63e24eSchristos An SFrame FDE of type SFRAME_FDE_TYPE_PCMASK is an indication 114*cb63e24eSchristos that the PCs in the FREs should be treated as masks. This type is useful 115*cb63e24eSchristos for the cases when a small pattern of instructions in a program stub is 116*cb63e24eSchristos repeatedly to cover a specific functionality. Typical usescases are pltN 117*cb63e24eSchristos entries, trampolines etc. */ 118*cb63e24eSchristos 119*cb63e24eSchristos /* Unwinders perform a (PC >= FRE_START_ADDR) to look up a matching FRE. */ 120*cb63e24eSchristos #define SFRAME_FDE_TYPE_PCINC 0 121*cb63e24eSchristos /* Unwinders perform a (PC % REP_BLOCK_SIZE >= FRE_START_ADDR) to look up a 122*cb63e24eSchristos matching FRE. */ 123*cb63e24eSchristos #define SFRAME_FDE_TYPE_PCMASK 1 124*cb63e24eSchristos 125*cb63e24eSchristos typedef struct sframe_preamble 126*cb63e24eSchristos { 127*cb63e24eSchristos uint16_t sfp_magic; /* Magic number (SFRAME_MAGIC). */ 128*cb63e24eSchristos uint8_t sfp_version; /* Data format version number (SFRAME_VERSION). */ 129*cb63e24eSchristos uint8_t sfp_flags; /* Flags. */ 130*cb63e24eSchristos } ATTRIBUTE_PACKED sframe_preamble; 131*cb63e24eSchristos 132*cb63e24eSchristos typedef struct sframe_header 133*cb63e24eSchristos { 134*cb63e24eSchristos sframe_preamble sfh_preamble; 135*cb63e24eSchristos /* Information about the arch (endianness) and ABI. */ 136*cb63e24eSchristos uint8_t sfh_abi_arch; 137*cb63e24eSchristos /* Offset for the Frame Pointer (FP) from CFA may be fixed for some 138*cb63e24eSchristos ABIs (e.g, in AMD64 when -fno-omit-frame-pointer is used). When fixed, 139*cb63e24eSchristos this field specifies the fixed stack frame offset and the individual 140*cb63e24eSchristos FREs do not need to track it. When not fixed, it is set to 141*cb63e24eSchristos SFRAME_CFA_FIXED_FP_INVALID, and the individual FREs may provide 142*cb63e24eSchristos the applicable stack frame offset, if any. */ 143*cb63e24eSchristos int8_t sfh_cfa_fixed_fp_offset; 144*cb63e24eSchristos /* Offset for the Return Address from CFA is fixed for some ABIs 145*cb63e24eSchristos (e.g., AMD64 has it as CFA-8). When fixed, the header specifies the 146*cb63e24eSchristos fixed stack frame offset and the individual FREs do not track it. When 147*cb63e24eSchristos not fixed, it is set to SFRAME_CFA_FIXED_RA_INVALID, and individual 148*cb63e24eSchristos FREs provide the applicable stack frame offset, if any. */ 149*cb63e24eSchristos int8_t sfh_cfa_fixed_ra_offset; 150*cb63e24eSchristos /* Number of bytes making up the auxiliary header, if any. 151*cb63e24eSchristos Some ABI/arch, in the future, may use this space for extending the 152*cb63e24eSchristos information in SFrame header. Auxiliary header is contained in 153*cb63e24eSchristos bytes sequentially following the sframe_header. */ 154*cb63e24eSchristos uint8_t sfh_auxhdr_len; 155*cb63e24eSchristos /* Number of SFrame FDEs in this SFrame section. */ 156*cb63e24eSchristos uint32_t sfh_num_fdes; 157*cb63e24eSchristos /* Number of SFrame Frame Row Entries. */ 158*cb63e24eSchristos uint32_t sfh_num_fres; 159*cb63e24eSchristos /* Number of bytes in the SFrame Frame Row Entry section. */ 160*cb63e24eSchristos uint32_t sfh_fre_len; 161*cb63e24eSchristos /* Offset of SFrame Function Descriptor Entry section. */ 162*cb63e24eSchristos uint32_t sfh_fdeoff; 163*cb63e24eSchristos /* Offset of SFrame Frame Row Entry section. */ 164*cb63e24eSchristos uint32_t sfh_freoff; 165*cb63e24eSchristos } ATTRIBUTE_PACKED sframe_header; 166*cb63e24eSchristos 167*cb63e24eSchristos #define SFRAME_V1_HDR_SIZE(sframe_hdr) \ 168*cb63e24eSchristos ((sizeof (sframe_header) + (sframe_hdr).sfh_auxhdr_len)) 169*cb63e24eSchristos 170*cb63e24eSchristos /* Two possible keys for executable (instruction) pointers signing. */ 171*cb63e24eSchristos #define SFRAME_AARCH64_PAUTH_KEY_A 0 /* Key A. */ 172*cb63e24eSchristos #define SFRAME_AARCH64_PAUTH_KEY_B 1 /* Key B. */ 173*cb63e24eSchristos 174*cb63e24eSchristos typedef struct sframe_func_desc_entry 175*cb63e24eSchristos { 176*cb63e24eSchristos /* Function start address. Encoded as a signed offset, relative to the 177*cb63e24eSchristos beginning of the current FDE. */ 178*cb63e24eSchristos int32_t sfde_func_start_address; 179*cb63e24eSchristos /* Size of the function in bytes. */ 180*cb63e24eSchristos uint32_t sfde_func_size; 181*cb63e24eSchristos /* Offset of the first SFrame Frame Row Entry of the function, relative to the 182*cb63e24eSchristos beginning of the SFrame Frame Row Entry sub-section. */ 183*cb63e24eSchristos uint32_t sfde_func_start_fre_off; 184*cb63e24eSchristos /* Number of frame row entries for the function. */ 185*cb63e24eSchristos uint32_t sfde_func_num_fres; 186*cb63e24eSchristos /* Additional information for stack tracing from the function: 187*cb63e24eSchristos - 4-bits: Identify the FRE type used for the function. 188*cb63e24eSchristos - 1-bit: Identify the FDE type of the function - mask or inc. 189*cb63e24eSchristos - 1-bit: PAC authorization A/B key (aarch64). 190*cb63e24eSchristos - 2-bits: Unused. 191*cb63e24eSchristos ------------------------------------------------------------------------ 192*cb63e24eSchristos | Unused | PAC auth A/B key (aarch64) | FDE type | FRE type | 193*cb63e24eSchristos | | Unused (amd64) | | | 194*cb63e24eSchristos ------------------------------------------------------------------------ 195*cb63e24eSchristos 8 6 5 4 0 */ 196*cb63e24eSchristos uint8_t sfde_func_info; 197*cb63e24eSchristos /* Size of the block of repeating insns. Used for SFrame FDEs of type 198*cb63e24eSchristos SFRAME_FDE_TYPE_PCMASK. */ 199*cb63e24eSchristos uint8_t sfde_func_rep_size; 200*cb63e24eSchristos uint16_t sfde_func_padding2; 201*cb63e24eSchristos } ATTRIBUTE_PACKED sframe_func_desc_entry; 202*cb63e24eSchristos 203*cb63e24eSchristos /* Macros to compose and decompose function info in FDE. */ 204*cb63e24eSchristos 205*cb63e24eSchristos /* Note: Set PAC auth key to SFRAME_AARCH64_PAUTH_KEY_A by default. */ 206*cb63e24eSchristos #define SFRAME_V1_FUNC_INFO(fde_type, fre_enc_type) \ 207*cb63e24eSchristos (((SFRAME_AARCH64_PAUTH_KEY_A & 0x1) << 5) | \ 208*cb63e24eSchristos (((fde_type) & 0x1) << 4) | ((fre_enc_type) & 0xf)) 209*cb63e24eSchristos 210*cb63e24eSchristos #define SFRAME_V1_FUNC_FRE_TYPE(data) ((data) & 0xf) 211*cb63e24eSchristos #define SFRAME_V1_FUNC_FDE_TYPE(data) (((data) >> 4) & 0x1) 212*cb63e24eSchristos #define SFRAME_V1_FUNC_PAUTH_KEY(data) (((data) >> 5) & 0x1) 213*cb63e24eSchristos 214*cb63e24eSchristos /* Set the pauth key as indicated. */ 215*cb63e24eSchristos #define SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY(pauth_key, fde_info) \ 216*cb63e24eSchristos ((((pauth_key) & 0x1) << 5) | ((fde_info) & 0xdf)) 217*cb63e24eSchristos 218*cb63e24eSchristos /* Size of stack frame offsets in an SFrame Frame Row Entry. A single 219*cb63e24eSchristos SFrame FRE has all offsets of the same size. Offset size may vary 220*cb63e24eSchristos across frame row entries. */ 221*cb63e24eSchristos #define SFRAME_FRE_OFFSET_1B 0 222*cb63e24eSchristos #define SFRAME_FRE_OFFSET_2B 1 223*cb63e24eSchristos #define SFRAME_FRE_OFFSET_4B 2 224*cb63e24eSchristos 225*cb63e24eSchristos /* An SFrame Frame Row Entry can be SP or FP based. */ 226*cb63e24eSchristos #define SFRAME_BASE_REG_FP 0 227*cb63e24eSchristos #define SFRAME_BASE_REG_SP 1 228*cb63e24eSchristos 229*cb63e24eSchristos /* The index at which a specific offset is presented in the variable length 230*cb63e24eSchristos bytes of an FRE. */ 231*cb63e24eSchristos #define SFRAME_FRE_CFA_OFFSET_IDX 0 232*cb63e24eSchristos /* The RA stack offset, if present, will always be at index 1 in the variable 233*cb63e24eSchristos length bytes of the FRE. */ 234*cb63e24eSchristos #define SFRAME_FRE_RA_OFFSET_IDX 1 235*cb63e24eSchristos /* The FP stack offset may appear at offset 1 or 2, depending on the ABI as RA 236*cb63e24eSchristos may or may not be tracked. */ 237*cb63e24eSchristos #define SFRAME_FRE_FP_OFFSET_IDX 2 238*cb63e24eSchristos 239*cb63e24eSchristos typedef struct sframe_fre_info 240*cb63e24eSchristos { 241*cb63e24eSchristos /* Information about 242*cb63e24eSchristos - 1 bit: base reg for CFA 243*cb63e24eSchristos - 4 bits: Number of offsets (N). A value of upto 3 is allowed to track 244*cb63e24eSchristos all three of CFA, FP and RA (fixed implicit order). 245*cb63e24eSchristos - 2 bits: information about size of the offsets (S) in bytes. 246*cb63e24eSchristos Valid values are SFRAME_FRE_OFFSET_1B, SFRAME_FRE_OFFSET_2B, 247*cb63e24eSchristos SFRAME_FRE_OFFSET_4B 248*cb63e24eSchristos - 1 bit: Mangled RA state bit (aarch64 only). 249*cb63e24eSchristos ---------------------------------------------------------------------------------- 250*cb63e24eSchristos | Mangled-RA (aarch64) | Size of offsets | Number of offsets | base_reg | 251*cb63e24eSchristos | Unused (amd64) | | | | 252*cb63e24eSchristos ---------------------------------------------------------------------------------- 253*cb63e24eSchristos 8 7 5 1 0 254*cb63e24eSchristos 255*cb63e24eSchristos */ 256*cb63e24eSchristos uint8_t fre_info; 257*cb63e24eSchristos } sframe_fre_info; 258*cb63e24eSchristos 259*cb63e24eSchristos /* Macros to compose and decompose FRE info. */ 260*cb63e24eSchristos 261*cb63e24eSchristos /* Note: Set mangled_ra_p to zero by default. */ 262*cb63e24eSchristos #define SFRAME_V1_FRE_INFO(base_reg_id, offset_num, offset_size) \ 263*cb63e24eSchristos (((0 & 0x1) << 7) | (((offset_size) & 0x3) << 5) | \ 264*cb63e24eSchristos (((offset_num) & 0xf) << 1) | ((base_reg_id) & 0x1)) 265*cb63e24eSchristos 266*cb63e24eSchristos /* Set the mangled_ra_p bit as indicated. */ 267*cb63e24eSchristos #define SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P(mangled_ra_p, fre_info) \ 268*cb63e24eSchristos ((((mangled_ra_p) & 0x1) << 7) | ((fre_info) & 0x7f)) 269*cb63e24eSchristos 270*cb63e24eSchristos #define SFRAME_V1_FRE_CFA_BASE_REG_ID(data) ((data) & 0x1) 271*cb63e24eSchristos #define SFRAME_V1_FRE_OFFSET_COUNT(data) (((data) >> 1) & 0xf) 272*cb63e24eSchristos #define SFRAME_V1_FRE_OFFSET_SIZE(data) (((data) >> 5) & 0x3) 273*cb63e24eSchristos #define SFRAME_V1_FRE_MANGLED_RA_P(data) (((data) >> 7) & 0x1) 274*cb63e24eSchristos 275*cb63e24eSchristos /* SFrame Frame Row Entry definitions. 276*cb63e24eSchristos 277*cb63e24eSchristos Used for both AMD64 and AARCH64. 278*cb63e24eSchristos 279*cb63e24eSchristos An SFrame Frame Row Entry is a self-sufficient record which contains 280*cb63e24eSchristos information on how to generate the stack trace for the specified range of 281*cb63e24eSchristos PCs. Each SFrame Frame Row Entry is followed by S*N bytes, where: 282*cb63e24eSchristos S is the size of the stack frame offset for the FRE, and 283*cb63e24eSchristos N is the number of stack frame offsets in the FRE 284*cb63e24eSchristos 285*cb63e24eSchristos The offsets are interpreted in order as follows: 286*cb63e24eSchristos 287*cb63e24eSchristos offset1 (interpreted as CFA = BASE_REG + offset1) 288*cb63e24eSchristos 289*cb63e24eSchristos if RA is being tracked 290*cb63e24eSchristos offset2 (interpreted as RA = CFA + offset2) 291*cb63e24eSchristos if FP is being tracked 292*cb63e24eSchristos offset3 (intrepreted as FP = CFA + offset2) 293*cb63e24eSchristos fi 294*cb63e24eSchristos else 295*cb63e24eSchristos if FP is being tracked 296*cb63e24eSchristos offset2 (intrepreted as FP = CFA + offset2) 297*cb63e24eSchristos fi 298*cb63e24eSchristos fi 299*cb63e24eSchristos */ 300*cb63e24eSchristos 301*cb63e24eSchristos /* Used when SFRAME_FRE_TYPE_ADDR1 is specified as FRE type. */ 302*cb63e24eSchristos typedef struct sframe_frame_row_entry_addr1 303*cb63e24eSchristos { 304*cb63e24eSchristos /* Start address of the frame row entry. Encoded as an 1-byte unsigned 305*cb63e24eSchristos offset, relative to the start address of the function. */ 306*cb63e24eSchristos uint8_t sfre_start_address; 307*cb63e24eSchristos sframe_fre_info sfre_info; 308*cb63e24eSchristos } ATTRIBUTE_PACKED sframe_frame_row_entry_addr1; 309*cb63e24eSchristos 310*cb63e24eSchristos /* Upper limit of start address in sframe_frame_row_entry_addr1 311*cb63e24eSchristos is 0x100 (not inclusive). */ 312*cb63e24eSchristos #define SFRAME_FRE_TYPE_ADDR1_LIMIT \ 313*cb63e24eSchristos (1ULL << ((SFRAME_FRE_TYPE_ADDR1 + 1) * 8)) 314*cb63e24eSchristos 315*cb63e24eSchristos /* Used when SFRAME_FRE_TYPE_ADDR2 is specified as FRE type. */ 316*cb63e24eSchristos typedef struct sframe_frame_row_entry_addr2 317*cb63e24eSchristos { 318*cb63e24eSchristos /* Start address of the frame row entry. Encoded as an 2-byte unsigned 319*cb63e24eSchristos offset, relative to the start address of the function. */ 320*cb63e24eSchristos uint16_t sfre_start_address; 321*cb63e24eSchristos sframe_fre_info sfre_info; 322*cb63e24eSchristos } ATTRIBUTE_PACKED sframe_frame_row_entry_addr2; 323*cb63e24eSchristos 324*cb63e24eSchristos /* Upper limit of start address in sframe_frame_row_entry_addr2 325*cb63e24eSchristos is 0x10000 (not inclusive). */ 326*cb63e24eSchristos #define SFRAME_FRE_TYPE_ADDR2_LIMIT \ 327*cb63e24eSchristos (1ULL << ((SFRAME_FRE_TYPE_ADDR2 * 2) * 8)) 328*cb63e24eSchristos 329*cb63e24eSchristos /* Used when SFRAME_FRE_TYPE_ADDR4 is specified as FRE type. */ 330*cb63e24eSchristos typedef struct sframe_frame_row_entry_addr4 331*cb63e24eSchristos { 332*cb63e24eSchristos /* Start address of the frame row entry. Encoded as a 4-byte unsigned 333*cb63e24eSchristos offset, relative to the start address of the function. */ 334*cb63e24eSchristos uint32_t sfre_start_address; 335*cb63e24eSchristos sframe_fre_info sfre_info; 336*cb63e24eSchristos } ATTRIBUTE_PACKED sframe_frame_row_entry_addr4; 337*cb63e24eSchristos 338*cb63e24eSchristos /* Upper limit of start address in sframe_frame_row_entry_addr2 339*cb63e24eSchristos is 0x100000000 (not inclusive). */ 340*cb63e24eSchristos #define SFRAME_FRE_TYPE_ADDR4_LIMIT \ 341*cb63e24eSchristos (1ULL << ((SFRAME_FRE_TYPE_ADDR4 * 2) * 8)) 342*cb63e24eSchristos 343*cb63e24eSchristos #ifdef __cplusplus 344*cb63e24eSchristos } 345*cb63e24eSchristos #endif 346*cb63e24eSchristos 347*cb63e24eSchristos #endif /* _SFRAME_H */ 348