xref: /netbsd-src/external/gpl3/gdb/dist/include/sframe.h (revision e663ba6e3a60083e70de702e9d54bf486a57b6a7)
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