|  | \input texinfo       @c                    -*- Texinfo -*- | 
|  | @setfilename sframe-spec.info | 
|  | @settitle The SFrame Format | 
|  |  | 
|  | @copying | 
|  | Copyright @copyright{} 2021-2025 Free Software Foundation, Inc. | 
|  |  | 
|  | Permission is granted to copy, distribute and/or modify this document | 
|  | under the terms of the GNU General Public License, Version 3 or any | 
|  | later version published by the Free Software Foundation.  A copy of the | 
|  | license is included in the section entitled ``GNU General Public | 
|  | License''. | 
|  |  | 
|  | @end copying | 
|  |  | 
|  | @dircategory Software development | 
|  | @direntry | 
|  | * SFrame: (sframe-spec).         The Simple Frame format. | 
|  | @end direntry | 
|  |  | 
|  | @titlepage | 
|  | @title The SFrame Format | 
|  | @subtitle Version 2 (Errata 1) | 
|  | @sp 15 | 
|  | @center @today{} | 
|  | @author Indu Bhagat | 
|  |  | 
|  | @page | 
|  | @vskip 0pt plus 1filll | 
|  | @insertcopying | 
|  | @end titlepage | 
|  | @contents | 
|  |  | 
|  | @ifnottex | 
|  | @node Top | 
|  | @top The SFrame format | 
|  |  | 
|  | This manual describes version 2 (errata 1) of the SFrame file format.  SFrame | 
|  | stands for Simple Frame.  The SFrame format keeps track of the minimal | 
|  | necessary information needed for generating stack traces: | 
|  |  | 
|  | @itemize @minus | 
|  | @item | 
|  | Canonical Frame Address (CFA). | 
|  | @item | 
|  | Frame Pointer (FP). | 
|  | @item | 
|  | Return Address (RA). | 
|  | @end itemize | 
|  |  | 
|  | The reason for existence of the SFrame format is to provide a simple, fast and | 
|  | low-overhead mechanism to generate stack traces. | 
|  |  | 
|  | @menu | 
|  | * Introduction:: | 
|  | * SFrame Section:: | 
|  | * ABI/arch-specific Definition:: | 
|  |  | 
|  | Appendices | 
|  | * Generating Stack Traces using SFrame:: | 
|  |  | 
|  | * Index:: | 
|  | @end menu | 
|  |  | 
|  | @end ifnottex | 
|  |  | 
|  | @node Introduction | 
|  | @chapter Introduction | 
|  | @cindex Introduction | 
|  |  | 
|  | @menu | 
|  | * Overview:: | 
|  | * Changes from Version 1 to Version 2:: | 
|  | @end menu | 
|  |  | 
|  | @node Overview | 
|  | @section Overview | 
|  | @cindex Overview | 
|  |  | 
|  | The SFrame stack trace information is provided in a loaded section, known as | 
|  | the @code{.sframe} section.  When available, the @code{.sframe} section appears | 
|  | in segment of type PT_GNU_SFRAME.  An ELF SFrame section will have the type | 
|  | SHT_GNU_SFRAME. | 
|  |  | 
|  | The SFrame format is currently supported only for select ABIs, namely, AMD64, | 
|  | AAPCS64, and s390x. | 
|  |  | 
|  | A portion of the SFrame format follows an unaligned on-disk representation. | 
|  | Some data structures, however, (namely the SFrame header and the SFrame | 
|  | function descriptor entry) have elements at their natural boundaries.  All data | 
|  | structures are packed, unless otherwise stated. | 
|  |  | 
|  | The contents of the SFrame section are stored in the target endianness, i.e., | 
|  | in the endianness of the system on which the section is targeted to be used. | 
|  | An SFrame section reader may use the magic number in the SFrame header to | 
|  | identify the endianness of the SFrame section. | 
|  |  | 
|  | Addresses in this specification are expressed in bytes. | 
|  |  | 
|  | The rest of this specification describes the current version of the format, | 
|  | @code{SFRAME_VERSION_2}, in detail.  Additional sections outline the major | 
|  | changes made to each previously published version of the SFrame stack trace | 
|  | format. | 
|  |  | 
|  | The associated API to decode, probe and encode the SFrame section, provided via | 
|  | @code{libsframe}, is not accompanied here at this time.  This will be added | 
|  | later. | 
|  |  | 
|  | This document is intended to be in sync with the C code in @file{sframe.h}. | 
|  | Please report discrepancies between the two, if any. | 
|  |  | 
|  | @node Changes from Version 1 to Version 2 | 
|  | @section Changes from Version 1 to Version 2 | 
|  | @cindex Changes from Version 1 to Version 2 | 
|  |  | 
|  | The following is a list of the changes made to the SFrame stack trace format | 
|  | since Version 1 was published. | 
|  |  | 
|  | @itemize @bullet | 
|  | @item | 
|  | Add an unsigned 8-bit integral field to the SFrame function descriptor entry to | 
|  | encode the size of the repetitive code blocks.  Such code blocks, e.g, pltN | 
|  | entries, use an SFrame function descriptor entry of type | 
|  | SFRAME_FDE_TYPE_PCMASK. | 
|  | @item | 
|  | Add an unsigned 16-bit integral field to the SFrame function descriptor entry | 
|  | to serve as padding.  This helps ensure natural alignment for the members of | 
|  | the data structure. | 
|  | @item | 
|  | The above two imply that each SFrame function descriptor entry has a fixed size | 
|  | of 20 bytes instead of its size of 17 bytes in SFrame format version 1. | 
|  | @item | 
|  | [Errata 1] Add a new flag SFRAME_F_FDE_FUNC_START_PCREL, as an erratum to | 
|  | SFrame Version 2, to indicate the encoding of the SFrame FDE function start | 
|  | address field: | 
|  | @itemize @minus | 
|  | @item if set, @code{sfde_func_start_address} field contains the offset in | 
|  | bytes to the start PC of the associated function from the field itself. | 
|  | @item if unset, @code{sfde_func_start_address} field contains the offset in | 
|  | bytes to the start PC of the associated function from the start of the SFrame | 
|  | section. | 
|  | @end itemize | 
|  | @item | 
|  | [Errata 1] Add a new ABI/arch identifier SFRAME_ABI_S390X_ENDIAN_BIG for the | 
|  | s390 architecture (64-bit) s390x ABI.  Other s390x-specific backward compatible | 
|  | changes including the following helper definitions have been incrementally | 
|  | added to SFrame version 2 only: | 
|  | @itemize @minus | 
|  | @item SFRAME_S390X_SP_VAL_OFFSET: SP value offset from CFA. | 
|  | @item SFRAME_V2_S390X_OFFSET_IS_REGNUM: Test whether FP/RA offset is an encoded | 
|  | DWARF register number. | 
|  | @item SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM: Encode a DWARF register number as an | 
|  | FP/RA offset. | 
|  | @item SFRAME_V2_S390X_OFFSET_DECODE_REGNUM: Decode a DWARF register number from | 
|  | an FP/RA offset. | 
|  | @item SFRAME_FRE_RA_OFFSET_INVALID: Invalid RA offset value (like | 
|  | SFRAME_CFA_FIXED_RA_INVALID).  Used on s390x as padding offset to represent | 
|  | FP without RA saved. | 
|  | @item SFRAME_S390X_CFA_OFFSET_ADJUSTMENT: CFA offset (from CFA base register) | 
|  | adjustment value.  Used to enable use of 8-bit SFrame offsets on s390x. | 
|  | @item SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR: CFA offset alignment factor. | 
|  | Used to scale down the CFA offset to improve the use of 8-bit SFrame offsets. | 
|  | @item SFRAME_V2_S390X_CFA_OFFSET_ENCODE: Encode CFA offset (i.e., apply | 
|  | CFA offset adjustment and then scale down by CFA offset alignment factor). | 
|  | @item SFRAME_V2_S390X_CFA_OFFSET_DECODE: Decode CFA offset (i.e., scale up | 
|  | by CFA offset alignment factor and then revert CFA offset adjustment). | 
|  | @end itemize | 
|  | @item | 
|  | [Errata 1] An ELF SFrame section has the type SHT_GNU_SFRAME. | 
|  | @end itemize | 
|  |  | 
|  | SFrame version 1 is now obsolete and should not be used. | 
|  |  | 
|  | @node SFrame Section | 
|  | @chapter SFrame Section | 
|  | @cindex SFrame Section | 
|  |  | 
|  | The SFrame section consists of an SFrame header, starting with a preamble, and | 
|  | two other sub-sections, namely the SFrame function descriptor entry (SFrame | 
|  | FDE) sub-section, and the SFrame frame row entry (SFrame FRE) sub-section. | 
|  |  | 
|  | @menu | 
|  | * SFrame Preamble:: | 
|  | * SFrame Header:: | 
|  | * SFrame Function Descriptor Entries:: | 
|  | * SFrame Frame Row Entries:: | 
|  | @end menu | 
|  |  | 
|  | @node SFrame Preamble | 
|  | @section SFrame Preamble | 
|  | @cindex SFrame preamble | 
|  |  | 
|  | The preamble is a 32-bit packed structure; the only part of the SFrame section | 
|  | whose format cannot vary between versions. | 
|  |  | 
|  | @example | 
|  | typedef struct sframe_preamble | 
|  | @{ | 
|  | uint16_t sfp_magic; | 
|  | uint8_t sfp_version; | 
|  | uint8_t sfp_flags; | 
|  | @} ATTRIBUTE_PACKED sframe_preamble; | 
|  | @end example | 
|  |  | 
|  | Every element of the SFrame preamble is naturally aligned. | 
|  |  | 
|  | All values are stored in the endianness of the target system for which the | 
|  | SFrame section is intended.  Further details: | 
|  |  | 
|  | @multitable {Offset} {@code{uint16_t}} {@code{sfp_version}} {The magic number for SFrame section: 0xdee2.} | 
|  | @headitem Offset @tab Type @tab Name @tab Description | 
|  | @item 0x00 | 
|  | @tab @code{uint16_t} | 
|  | @tab @code{sfp_magic} | 
|  | @tab The magic number for SFrame section: 0xdee2.  Defined as a macro @code{SFRAME_MAGIC}. | 
|  | @tindex SFRAME_MAGIC | 
|  |  | 
|  | @item 0x02 | 
|  | @tab @code{uint8_t} | 
|  | @tab @code{sfp_version} | 
|  | @tab The version number of this SFrame section.  @xref{SFrame Version}, for the | 
|  | set of valid values.  Current version is | 
|  | @code{SFRAME_VERSION_2}. | 
|  |  | 
|  | @item 0x03 | 
|  | @tab @code{uint8_t} | 
|  | @tab @code{sfp_flags} | 
|  | @tab Flags (section-wide) for this SFrame section.  @xref{SFrame Flags}, for the | 
|  | set of valid values. | 
|  | @end multitable | 
|  |  | 
|  | @menu | 
|  | * SFrame Magic Number and Endianness:: | 
|  | * SFrame Version:: | 
|  | * SFrame Flags:: | 
|  | @end menu | 
|  |  | 
|  | @node SFrame Magic Number and Endianness | 
|  | @subsection SFrame Magic Number and Endianness | 
|  |  | 
|  | @cindex endianness | 
|  | @cindex SFrame magic number | 
|  | SFrame sections are stored in the target endianness of the system that consumes | 
|  | them.  A consumer library reading or writing SFrame sections should detect | 
|  | foreign-endianness by inspecting the SFrame magic number in the | 
|  | @code{sfp_magic} field in the SFrame header.  It may then provide means to | 
|  | endian-flip the SFrame section as necessary. | 
|  |  | 
|  | @node SFrame Version | 
|  | @subsection SFrame Version | 
|  |  | 
|  | The version of the SFrame format can be determined by inspecting | 
|  | @code{sfp_version}.  The following versions are currently valid: | 
|  |  | 
|  | @tindex SFRAME_VERSION_1 | 
|  | @cindex SFrame versions | 
|  | @multitable {SFRAME_VERSION_2} {Number} {Current version, under development.} | 
|  | @headitem Version Name @tab Number @tab Description | 
|  | @item @code{SFRAME_VERSION_1} | 
|  | @tab 1 @tab First version, obsolete. | 
|  | @item @code{SFRAME_VERSION_2} | 
|  | @tab 2 @tab Current version, under development. | 
|  | @end multitable | 
|  |  | 
|  | This document describes @code{SFRAME_VERSION_2}. | 
|  |  | 
|  | @node SFrame Flags | 
|  | @subsection SFrame Flags | 
|  | @cindex SFrame Flags | 
|  |  | 
|  | The preamble contains bitflags in its @code{sfp_flags} field that | 
|  | describe various section-wide properties. | 
|  |  | 
|  | The following flags are currently defined. | 
|  |  | 
|  | @multitable {@code{SFRAME_F_FRAME_POINTER}} {Version} {Value} {Function Descriptor Entries are sorted} | 
|  | @headitem Flag @tab Version @tab Value @tab Meaning | 
|  | @tindex SFRAME_F_FDE_SORTED | 
|  | @item @code{SFRAME_F_FDE_SORTED} @tab All @tab 0x1 @tab Function Descriptor | 
|  | Entries are sorted on PC. | 
|  | @tindex SFRAME_F_FRAME_POINTER | 
|  | @item @code{SFRAME_F_FRAME_POINTER} @tab All @tab 0x2 | 
|  | @tab All functions in the object file preserve frame pointer. | 
|  | @tindex SFRAME_F_FDE_FUNC_START_PCREL | 
|  | @item @code{SFRAME_F_FDE_FUNC_START_PCREL} @tab 2 @tab 0x4 | 
|  | @tab The @code{sfde_func_start_address} field in the SFrame FDE is an offset in | 
|  | bytes to the function's start address, from the field itself.  If unset, the | 
|  | @code{sfde_func_start_address} field in the SFrame FDE is an offset in bytes to | 
|  | the function's start address, from the start of the SFrame section. | 
|  | @end multitable | 
|  |  | 
|  | The purpose of SFRAME_F_FRAME_POINTER flag is to facilitate stack tracers to | 
|  | reliably fallback on the frame pointer based stack tracing method, if SFrame | 
|  | information is not present for some function in the SFrame section. | 
|  |  | 
|  | Further flags may be added in future.  Bits corresponding to the currently | 
|  | undefined flags must be set to zero. | 
|  |  | 
|  | @node SFrame Header | 
|  | @section SFrame Header | 
|  | @cindex SFrame header | 
|  |  | 
|  | The SFrame header is the first part of an SFrame section.  It begins with the | 
|  | SFrame preamble.  All parts of it other than the preamble | 
|  | (@pxref{SFrame Preamble}) can vary between SFrame file versions.  It contains | 
|  | things that apply to the section as a whole, and offsets to the various other | 
|  | sub-sections defined in the format.  As with the rest of the SFrame section, | 
|  | all values are stored in the endianness of the target system. | 
|  |  | 
|  | The two sub-sections tile the SFrame section: each section runs from the offset | 
|  | given until the start of the next section.  An explicit length is given for the | 
|  | last sub-section, the SFrame Frame Row Entry (SFrame FRE) sub-section. | 
|  |  | 
|  | @example | 
|  | typedef struct sframe_header | 
|  | @{ | 
|  | sframe_preamble sfh_preamble; | 
|  | uint8_t sfh_abi_arch; | 
|  | int8_t sfh_cfa_fixed_fp_offset; | 
|  | int8_t sfh_cfa_fixed_ra_offset; | 
|  | uint8_t sfh_auxhdr_len; | 
|  | uint32_t sfh_num_fdes; | 
|  | uint32_t sfh_num_fres; | 
|  | uint32_t sfh_fre_len; | 
|  | uint32_t sfh_fdeoff; | 
|  | uint32_t sfh_freoff; | 
|  | @} ATTRIBUTE_PACKED sframe_header; | 
|  | @end example | 
|  |  | 
|  | Every element of the SFrame header is naturally aligned. | 
|  |  | 
|  | The sub-section offsets, namely @code{sfh_fdeoff} and @code{sfh_freoff}, in the | 
|  | SFrame header are relative to the @emph{end} of the SFrame header; they are | 
|  | each an offset in bytes into the SFrame section where the SFrame FDE | 
|  | sub-section and the SFrame FRE sub-section respectively start. | 
|  |  | 
|  | The SFrame section contains @code{sfh_num_fdes} number of fixed-length array | 
|  | elements in the SFrame FDE sub-section.  Each array element is of type SFrame | 
|  | function descriptor entry; each providing a high-level function description for | 
|  | the purpose of stack tracing.  More details in a subsequent section. | 
|  | @xref{SFrame Function Descriptor Entries}. | 
|  |  | 
|  | Next, the SFrame FRE sub-section, starting at offset @code{sfh_fre_off}, | 
|  | describes the stack trace information for each function, using a total of | 
|  | @code{sfh_num_fres} number of variable-length array elements.  Each array | 
|  | element is of type SFrame frame row entry. | 
|  | @xref{SFrame Frame Row Entries}. | 
|  |  | 
|  | SFrame header allows specifying explicitly the fixed offsets from CFA, if any, | 
|  | from which FP or RA may be recovered.  For example, in AMD64, the stack offset | 
|  | of the return address is @code{CFA - 8}.  Since these offsets are expected to | 
|  | be in close vicinity to the CFA in most ABIs, @code{sfh_cfa_fixed_fp_offset} | 
|  | and @code{sfh_cfa_fixed_ra_offset} are limited to signed 8-bit integers. | 
|  |  | 
|  | @cindex Provisions for future ABIs | 
|  | The SFrame format has made some provisions for supporting more | 
|  | ABIs/architectures in the future.  One of them is the concept of the auxiliary | 
|  | SFrame header.  Bytes in the auxiliary SFrame header may be used to convey | 
|  | further ABI-specific information.  The @code{sframe_header} structure provides | 
|  | an unsigned 8-bit integral field to denote the size (in bytes) of an auxiliary | 
|  | SFrame header.  The auxiliary SFrame header follows right after the | 
|  | @code{sframe_header} structure.  As for the calculation of the sub-section | 
|  | offsets, namely @code{sfh_fdeoff} and @code{sfh_freoff}, the @emph{end} of | 
|  | SFrame header must be the end of the auxiliary SFrame header, if the latter is | 
|  | present. | 
|  |  | 
|  | Putting it all together: | 
|  |  | 
|  | @multitable {Offset} {@code{uint32_t}} {@code{sfh_cfa_fixed_fp_offset}} {The number of SFrame FREs in the} | 
|  | @headitem Offset @tab Type @tab Name @tab Description | 
|  | @item 0x00 | 
|  | @tab @code{sframe_ @* preamble} | 
|  | @tab @code{sfh_preamble} | 
|  | @tab The SFrame preamble. @xref{SFrame Preamble}. | 
|  |  | 
|  | @item 0x04 | 
|  | @tab @code{uint8_t} | 
|  | @tab @code{sfh_abi_arch} | 
|  | @tab The ABI/arch identifier.  @xref{SFrame ABI/arch Identifier}. | 
|  |  | 
|  | @item 0x05 | 
|  | @tab @code{int8_t} | 
|  | @tab @code{sfh_cfa_fixed_fp_offset} | 
|  | @tab The CFA fixed FP offset, if any. | 
|  |  | 
|  | @item 0x06 | 
|  | @tab @code{int8_t} | 
|  | @tab @code{sfh_cfa_fixed_ra_offset} | 
|  | @tab The CFA fixed RA offset, if any. | 
|  |  | 
|  | @item 0x07 | 
|  | @tab @code{uint8_t} | 
|  | @tab @code{sfh_auxhdr_len} | 
|  | @tab Size in bytes of the auxiliary header that follows the | 
|  | @code{sframe_header} structure. | 
|  |  | 
|  | @item 0x08 | 
|  | @tab @code{uint32_t} | 
|  | @tab @code{sfh_num_fdes} | 
|  | @tab The number of SFrame FDEs in the section. | 
|  |  | 
|  | @item 0x0c | 
|  | @tab @code{uint32_t} | 
|  | @tab @code{sfh_num_fres} | 
|  | @tab The number of SFrame FREs in the section. | 
|  |  | 
|  | @item 0x10 | 
|  | @tab @code{uint32_t} | 
|  | @tab @code{sfh_fre_len} | 
|  | @tab The length in bytes of the SFrame FRE sub-section. | 
|  |  | 
|  | @item 0x14 | 
|  | @tab @code{uint32_t} | 
|  | @tab @code{sfh_fdeoff} | 
|  | @tab The offset in bytes to the SFrame FDE sub-section. | 
|  |  | 
|  | @item 0x18 | 
|  | @tab @code{uint32_t} | 
|  | @tab @code{sfh_freoff} | 
|  | @tab The offset in bytes to the SFrame FRE sub-section. | 
|  |  | 
|  | @end multitable | 
|  |  | 
|  | @menu | 
|  | * SFrame ABI/arch Identifier:: | 
|  | @end menu | 
|  |  | 
|  | @node SFrame ABI/arch Identifier | 
|  | @subsection SFrame ABI/arch Identifier | 
|  | @cindex SFrame ABI/arch Identifier | 
|  |  | 
|  | SFrame header identifies the ABI/arch of the target system for which the | 
|  | executable and hence, the stack trace information contained in the SFrame | 
|  | section, is intended.  There are currently three identifiable ABI/arch values | 
|  | in the format. | 
|  |  | 
|  | @multitable {SFRAME_ABI_AARCH64_ENDIAN_LITTLE} {Value} {@code{AARCH64 little-endian}} | 
|  | @headitem ABI/arch Identifier @tab Value @tab Description | 
|  |  | 
|  | @tindex SFRAME_ABI_AARCH64_ENDIAN_BIG | 
|  | @item @code{SFRAME_ABI_AARCH64_ENDIAN_BIG} | 
|  | @tab 1 @tab AARCH64 big-endian | 
|  |  | 
|  | @tindex SFRAME_ABI_AARCH64_ENDIAN_LITTLE | 
|  | @item @code{SFRAME_ABI_AARCH64_ENDIAN_LITTLE} | 
|  | @tab 2 @tab AARCH64 little-endian | 
|  |  | 
|  | @tindex SFRAME_ABI_AMD64_ENDIAN_LITTLE | 
|  | @item @code{SFRAME_ABI_AMD64_ENDIAN_LITTLE} | 
|  | @tab 3 @tab AMD64 little-endian | 
|  |  | 
|  | @tindex SFRAME_ABI_S390X_ENDIAN_BIG | 
|  | @item @code{SFRAME_ABI_S390X_ENDIAN_BIG} | 
|  | @tab 4 @tab s390x big-endian | 
|  |  | 
|  | @end multitable | 
|  |  | 
|  | The presence of an explicit identification of ABI/arch in SFrame may allow | 
|  | stack trace generators to make certain ABI/arch-specific decisions. | 
|  |  | 
|  | @node SFrame Function Descriptor Entries | 
|  | @section SFrame FDE | 
|  | @cindex SFrame FDE | 
|  |  | 
|  | The SFrame function descriptor entry sub-section is an array of the | 
|  | fixed-length SFrame function descriptor entries (SFrame FDEs).  Each SFrame FDE | 
|  | is a packed structure which contains information to describe a function's stack | 
|  | trace information at a high-level. | 
|  |  | 
|  | The array of SFrame FDEs is sorted on the @code{sfde_func_start_address} if | 
|  | the SFrame section header flag @code{sfp_flags} has @code{SFRAME_F_FDE_SORTED} | 
|  | set.  Typically (as is the case with GNU ld) a linked object or executable | 
|  | will have the @code{SFRAME_F_FDE_SORTED} set.  This makes the job of a stack | 
|  | tracer easier as it may then employ binary search schemes to look for the | 
|  | pertinent SFrame FDE. | 
|  |  | 
|  | @example | 
|  | typedef struct sframe_func_desc_entry | 
|  | @{ | 
|  | int32_t sfde_func_start_address; | 
|  | uint32_t sfde_func_size; | 
|  | uint32_t sfde_func_start_fre_off; | 
|  | uint32_t sfde_func_num_fres; | 
|  | uint8_t sfde_func_info; | 
|  | uint8_t sfde_func_rep_size; | 
|  | uint16_t sfde_func_padding2; | 
|  | @} ATTRIBUTE_PACKED sframe_func_desc_entry; | 
|  | @end example | 
|  |  | 
|  | Every element of the SFrame function descriptor entry is naturally aligned. | 
|  |  | 
|  | @code{sfde_func_start_fre_off} is the offset to the first SFrame FRE for the | 
|  | function.  This offset is relative to the @emph{end of the SFrame FDE} | 
|  | sub-section (unlike the sub-section offsets in the SFrame header, which are | 
|  | relative to the @emph{end} of the SFrame header). | 
|  |  | 
|  | @code{sfde_func_info} is the SFrame FDE "info word", containing information on | 
|  | the FRE type and the FDE type for the function @xref{The SFrame FDE Info Word}. | 
|  |  | 
|  | @cindex Provisions for future ABIs | 
|  | Apart from the @code{sfde_func_padding2}, the SFrame FDE has some currently | 
|  | unused bits in the SFrame FDE info word, @xref{The SFrame FDE Info Word}, that | 
|  | may be used for the purpose of extending the SFrame file format specification | 
|  | for future ABIs. | 
|  |  | 
|  | Following table describes each component of the SFrame FDE structure: | 
|  |  | 
|  | @multitable {Offset} {@code{uint32_t}} {@code{sfde_func_start_fre_off}} {Signed 32-bit integral field denoting the} | 
|  | @headitem Offset @tab Type @tab Name @tab Description | 
|  | @item 0x00 | 
|  | @tab @code{int32_t} | 
|  | @tab @code{sfde_func_start_address} | 
|  | @tab Signed 32-bit integral field denoting the virtual memory address of the | 
|  | described function, for which the SFrame FDE applies.  If the flag | 
|  | @code{SFRAME_F_FDE_FUNC_START_PCREL}, @xref{SFrame Flags}, in the SFrame | 
|  | header is set, the value encoded in the @code{sfde_func_start_address} field is | 
|  | the offset in bytes to the function's start address, from the SFrame | 
|  | @code{sfde_func_start_address} field. | 
|  |  | 
|  | @item 0x04 | 
|  | @tab @code{uint32_t} | 
|  | @tab @code{sfde_func_size} | 
|  | @tab Unsigned 32-bit integral field specifying the size of the function in | 
|  | bytes. | 
|  |  | 
|  | @item 0x08 | 
|  | @tab @code{uint32_t} | 
|  | @tab @code{sfde_func_start_fre_off} | 
|  | @tab Unsigned 32-bit integral field specifying the offset in bytes of the | 
|  | function's first SFrame FRE in the SFrame section. | 
|  |  | 
|  | @item 0x0c | 
|  | @tab @code{uint32_t} | 
|  | @tab @code{sfde_func_num_fres} | 
|  | @tab Unsigned 32-bit integral field specifying the total number of SFrame FREs | 
|  | used for the function. | 
|  |  | 
|  | @item 0x10 | 
|  | @tab @code{uint8_t} | 
|  | @tab @code{sfde_func_info} | 
|  | @tab Unsigned 8-bit integral field specifying the SFrame FDE info word. | 
|  | @xref{The SFrame FDE Info Word}. | 
|  |  | 
|  | @item 0x11 | 
|  | @tab @code{uint8_t} | 
|  | @tab @code{sfde_func_rep_size} | 
|  | @tab Unsigned 8-bit integral field specifying the size of the repetitive code | 
|  | block for which an SFrame FDE of type SFRAME_FDE_TYPE_PCMASK is used.  For | 
|  | example, in AMD64, the size of a pltN entry is 16 bytes. | 
|  |  | 
|  | @item 0x12 | 
|  | @tab @code{uint16_t} | 
|  | @tab @code{sfde_func_padding2} | 
|  | @tab Padding of 2 bytes.  Currently unused bytes. | 
|  |  | 
|  | @end multitable | 
|  |  | 
|  | @menu | 
|  | * The SFrame FDE Info Word:: | 
|  | * The SFrame FDE Types:: | 
|  | * The SFrame FRE Types:: | 
|  | @end menu | 
|  |  | 
|  | @cindex The SFrame FDE Info Word | 
|  | @node The SFrame FDE Info Word | 
|  | @subsection The SFrame FDE Info Word | 
|  |  | 
|  | The info word is a bitfield split into three parts.  From MSB to LSB: | 
|  |  | 
|  | @multitable {Bit offset} {@code{pauth_key}} {Specify which key is used for signing the return addresses} | 
|  | @headitem Bit offset @tab Name @tab Description | 
|  | @item 7--6 | 
|  | @tab @code{unused} | 
|  | @tab Unused bits. | 
|  |  | 
|  | @item 5 | 
|  | @tab @code{pauth_key} | 
|  | @tab (For AARCH64) Specify which key is used for signing the return addresses | 
|  | in the SFrame FDE.  Two possible values: @* | 
|  | SFRAME_AARCH64_PAUTH_KEY_A (0), or @* | 
|  | SFRAME_AARCH64_PAUTH_KEY_B (1). @* | 
|  | Ununsed in AMD64. | 
|  |  | 
|  | @item 4 | 
|  | @tab @code{fdetype} | 
|  | @tab Specify the SFrame FDE type.  Two possible values: @* | 
|  | SFRAME_FDE_TYPE_PCMASK (1), or @* | 
|  | SFRAME_FDE_TYPE_PCINC (0). @* | 
|  | @xref{The SFrame FDE Types}. | 
|  |  | 
|  | @item 0--3 | 
|  | @tab @code{fretype} | 
|  | @tab Choice of three SFrame FRE types. @xref{The SFrame FRE Types}. | 
|  | @end multitable | 
|  |  | 
|  | @node The SFrame FDE Types | 
|  | @subsection The SFrame FDE Types | 
|  | @tindex SFRAME_FDE_TYPE_PCMASK | 
|  | @tindex SFRAME_FDE_TYPE_PCINC | 
|  |  | 
|  | The SFrame format defines two types of FDE entries.  The choice of which SFrame | 
|  | FDE type to use is made based on the instruction patterns in the relevant | 
|  | program stub. | 
|  |  | 
|  | An SFrame FDE of type @code{SFRAME_FDE_TYPE_PCINC} is an indication that the PCs in the | 
|  | FREs should be treated as increments in bytes.  This is used fo the the bulk of | 
|  | the executable code of a program, which contains instructions with no specific | 
|  | pattern. | 
|  |  | 
|  | In contrast, an SFrame FDE of type @code{SFRAME_FDE_TYPE_PCMASK} is an | 
|  | indication that the PCs in the FREs should be treated as masks.  This type is | 
|  | useful for the cases where a small pattern of instructions in a program stub is | 
|  | used repeatedly for a specific functionality.  Typical usecases are pltN | 
|  | entries and trampolines. | 
|  |  | 
|  | @multitable {SFRAME_FDE_TYPE_PCMASK} {Value} {Unwinders perform a Unwinders perform a} | 
|  | @headitem Name of SFrame FDE type @tab Value @tab Description | 
|  |  | 
|  | @item SFRAME_FDE_TYPE_PCINC | 
|  | @tab 0 @tab Stacktracers perform a @* | 
|  | (PC >= FRE_START_ADDR) to look up a matching FRE. | 
|  |  | 
|  | @item SFRAME_FDE_TYPE_PCMASK | 
|  | @tab 1 @tab  Stacktracers perform a @* | 
|  | (PC % REP_BLOCK_SIZE @* | 
|  | >= FRE_START_ADDR) | 
|  | to look up a matching FRE.  REP_BLOCK_SIZE is the size in bytes of the | 
|  | repeating block of program instructions and is encoded via | 
|  | @code{sfde_func_rep_size} in the SFrame FDE. | 
|  |  | 
|  | @end multitable | 
|  |  | 
|  | @node The SFrame FRE Types | 
|  | @subsection The SFrame FRE Types | 
|  |  | 
|  | A real world application can have functions of size big and small.  SFrame | 
|  | format defines three types of SFrame FRE entries to effeciently encode the | 
|  | stack trace information for such a variety of function sizes.  These | 
|  | representations vary in the number of bits needed to encode the start address | 
|  | offset in the SFrame FRE. | 
|  |  | 
|  | The following constants are defined and used to identify the SFrame FRE types: | 
|  |  | 
|  | @multitable {SFRAME_FRE_TYPE_ADDR1} {@code{Value}} {The start address offset (in bytes) of the} | 
|  | @headitem Name @tab Value @tab Description | 
|  |  | 
|  | @tindex SFRAME_FRE_TYPE_ADDR1 | 
|  | @item @code{SFRAME_FRE_TYPE_ADDR1} | 
|  | @tab 0 | 
|  | @tab The start address offset (in bytes) of the SFrame FRE is an unsigned | 
|  | 8-bit value. | 
|  |  | 
|  | @tindex SFRAME_FRE_TYPE_ADDR2 | 
|  | @item @code{SFRAME_FRE_TYPE_ADDR2} | 
|  | @tab 1 | 
|  | @tab The start address offset (in bytes) of the SFrame FRE is an unsigned | 
|  | 16-bit value. | 
|  |  | 
|  | @tindex SFRAME_FRE_TYPE_ADDR4 | 
|  | @item @code{SFRAME_FRE_TYPE_ADDR4} | 
|  | @tab 2 | 
|  | @tab The start address offset (in bytes) of the SFrame FRE is an unsigned | 
|  | 32-bit value. | 
|  | @end multitable | 
|  |  | 
|  | A single function must use the same type of SFrame FRE throughout.  The | 
|  | identifier to reflect the chosen SFrame FRE type is stored in the | 
|  | @code{fretype} bits in the SFrame FDE info word, | 
|  | @xref{The SFrame FDE Info Word}. | 
|  |  | 
|  | @node SFrame Frame Row Entries | 
|  | @section SFrame FRE | 
|  | @cindex SFrame FRE | 
|  |  | 
|  | The SFrame frame row entry sub-section contains the core of the stack trace | 
|  | information.  An SFrame frame row entry (FRE) is a self-sufficient record | 
|  | containing SFrame stack trace information for a range of contiguous | 
|  | (instruction) addresses, starting at the specified offset from the start of the | 
|  | function. | 
|  |  | 
|  | Each SFrame FRE encodes the stack offsets to recover the CFA, FP and RA (where | 
|  | applicable) for the respective instruction addresses.  To encode this | 
|  | information, each SFrame FRE is followed by S*N bytes, where: | 
|  |  | 
|  | @itemize @minus | 
|  | @item | 
|  | @code{S} is the size of a stack offset for the FRE, and | 
|  | @item | 
|  | @code{N} is the number of stack offsets in the FRE | 
|  | @end itemize | 
|  |  | 
|  | The entities @code{S}, @code{N} are encoded in the SFrame FRE info word, via | 
|  | the @code{fre_offset_size} and the @code{fre_offset_count} respectively.  More | 
|  | information about the precise encoding and range of values for @code{S} and | 
|  | @code{N} is provided later in the @xref{The SFrame FRE Info Word}. | 
|  |  | 
|  | @cindex Provisions for future ABIs | 
|  | It is important to underline here that although the canonical interpretation | 
|  | of these bytes is as stack offsets (to recover CFA, FP and RA), these bytes | 
|  | @emph{may} be used by future ABIs/architectures to convey other information on | 
|  | a per SFrame FRE basis. | 
|  |  | 
|  | In summary, SFrame file format, by design, supports a variable number of stack | 
|  | offsets at the tail end of each SFrame FRE.  To keep the SFrame file | 
|  | format specification flexible yet extensible, the interpretation of the stack | 
|  | offsets is ABI/arch-specific.  The precise interpretation of the FRE stack | 
|  | offsets in the currently supported ABIs/architectures is covered in the | 
|  | ABI/arch-specific definition of the SFrame file format, | 
|  | @xref{ABI/arch-specific Definition}. | 
|  |  | 
|  | Next, the definitions of the three SFrame FRE types are as follows: | 
|  |  | 
|  | @example | 
|  | typedef struct sframe_frame_row_entry_addr1 | 
|  | @{ | 
|  | uint8_t sfre_start_address; | 
|  | sframe_fre_info sfre_info; | 
|  | @} ATTRIBUTE_PACKED sframe_frame_row_entry_addr1; | 
|  | @end example | 
|  |  | 
|  | @example | 
|  | typedef struct sframe_frame_row_entry_addr2 | 
|  | @{ | 
|  | uint16_t sfre_start_address; | 
|  | sframe_fre_info sfre_info; | 
|  | @} ATTRIBUTE_PACKED sframe_frame_row_entry_addr2; | 
|  | @end example | 
|  |  | 
|  | @example | 
|  | typedef struct sframe_frame_row_entry_addr4 | 
|  | @{ | 
|  | uint32_t sfre_start_address; | 
|  | sframe_fre_info sfre_info; | 
|  | @} ATTRIBUTE_PACKED sframe_frame_row_entry_addr4; | 
|  | @end example | 
|  |  | 
|  | For ensuring compactness, SFrame frame row entries are stored unaligned on | 
|  | disk.  Appropriate mechanisms need to be employed, as necessary, by the | 
|  | serializing and deserializing entities, if unaligned accesses need to be | 
|  | avoided. | 
|  |  | 
|  | @code{sfre_start_address} is an unsigned 8-bit/16-bit/32-bit integral field | 
|  | denoting the start address of a range of program counters, for which the | 
|  | SFrame FRE applies.  The value encoded in the @code{sfre_start_address} field | 
|  | is the offset in bytes of the range's start address, from the start address | 
|  | of the function. | 
|  |  | 
|  | Further SFrame FRE types may be added in future. | 
|  |  | 
|  | @menu | 
|  | * The SFrame FRE Info Word:: | 
|  | @end menu | 
|  |  | 
|  | @cindex The SFrame FRE Info Word | 
|  | @node The SFrame FRE Info Word | 
|  | @subsection The SFrame FRE Info Word | 
|  |  | 
|  | The SFrame FRE info word is a bitfield split into four parts.  From MSB to LSB: | 
|  |  | 
|  | @multitable {Bit offset} {@code{fre_cfa_base_reg_id}} {Size of stack offsets in bytes.  Valid values} | 
|  | @headitem Bit offset @tab Name @tab Description | 
|  | @item 7 | 
|  | @tab @code{fre_mangled_ra_p} | 
|  | @tab Indicate whether the return address is mangled with any authorization bits (signed RA). | 
|  |  | 
|  | @item 5-6 | 
|  | @tab @code{fre_offset_size} | 
|  | @tab Size of stack offsets in bytes.  Valid values are: @* | 
|  | SFRAME_FRE_OFFSET_1B, @* | 
|  | SFRAME_FRE_OFFSET_2B, and @* | 
|  | SFRAME_FRE_OFFSET_4B. | 
|  |  | 
|  | @item 1-4 | 
|  | @tab @code{fre_offset_count} | 
|  | @tab A max value of 15 is allowed.  Typically, a value of upto 3 is sufficient | 
|  | for most ABIs to track all three of CFA, FP and RA. | 
|  |  | 
|  | @item 0 | 
|  | @tab @code{fre_cfa_base_reg_id} | 
|  | @tab Distinguish between SP or FP based CFA recovery. | 
|  |  | 
|  | @end multitable | 
|  |  | 
|  | @multitable {SFRAME_FRE_OFFSET_4B} {@code{Value}} {All stack offsets following the fixed-length} | 
|  | @headitem Name @tab Value @tab Description | 
|  |  | 
|  | @tindex SFRAME_FRE_OFFSET_1B | 
|  | @item @code{SFRAME_FRE_OFFSET_1B} | 
|  | @tab 0 | 
|  | @tab All stack offsets following the fixed-length FRE structure are 1 byte | 
|  | long. | 
|  |  | 
|  | @tindex SFRAME_FRE_OFFSET_2B | 
|  | @item @code{SFRAME_FRE_OFFSET_2B} | 
|  | @tab 1 | 
|  | @tab All stack offsets following the fixed-length FRE structure are 2 bytes | 
|  | long. | 
|  |  | 
|  | @tindex SFRAME_FRE_OFFSET_4B | 
|  | @item @code{SFRAME_FRE_OFFSET_4B} | 
|  | @tab 2 | 
|  | @tab All stack offsets following the fixed-length FRE structure are 4 bytes | 
|  | long. | 
|  |  | 
|  | @end multitable | 
|  |  | 
|  | @node ABI/arch-specific Definition | 
|  | @chapter ABI/arch-specific Definition | 
|  | @cindex ABI/arch-specific Definition | 
|  |  | 
|  | This section covers the ABI/arch-specific definition of the SFrame file format. | 
|  |  | 
|  | Currently, the only part of the SFrame file format definition that is | 
|  | ABI/arch-specific is the interpretation of the variable number of bytes at the | 
|  | tail end of each SFrame FRE.  Currently, these bytes are used for representing | 
|  | stack offsets (for AMD64 and AARCH64 ABIs).  For s390x ABI, the interpretation | 
|  | of these bytes may be stack offsets or even register numbers.  It is recommended | 
|  | to peruse this section along with @xref{SFrame Frame Row Entries} for clarity of | 
|  | context. | 
|  |  | 
|  | Future ABIs must specify the algorithm for identifying the appropriate SFrame | 
|  | FRE stack offsets in this chapter.  This should inevitably include the | 
|  | blueprint for interpreting the variable number of bytes at the tail end of the | 
|  | SFrame FRE for the specific ABI/arch. Any further provisions, e.g., using the | 
|  | auxiliary SFrame header, etc., if used, must also be outlined here. | 
|  |  | 
|  | @menu | 
|  | * AMD64:: | 
|  | * AArch64:: | 
|  | * s390x:: | 
|  | @end menu | 
|  |  | 
|  | @node AMD64 | 
|  | @section AMD64 | 
|  |  | 
|  | Irrespective of the ABI, the first stack offset is always used to locate the | 
|  | CFA, by interpreting it as: CFA = @code{BASE_REG} + offset1.  The | 
|  | identification of the @code{BASE_REG} is done by using the | 
|  | @code{fre_cfa_base_reg_id} field in the SFrame FRE info word. | 
|  |  | 
|  | In AMD64, the return address (RA) is always saved on stack when a function | 
|  | call is executed.  Further, AMD64 ABI mandates that the RA be saved at a | 
|  | @code{fixed offset} from the CFA when entering a new function.  This means | 
|  | that the RA does not need to be tracked per SFrame FRE.  The fixed offset is | 
|  | encoded in the SFrame file format in the field @code{sfh_cfa_fixed_ra_offset} | 
|  | in the SFrame header.  @xref{SFrame Header}. | 
|  |  | 
|  | Hence, the second stack offset (in the SFrame FRE), when present, will be used | 
|  | to locate the FP, by interpreting it as: FP = CFA + offset2. | 
|  |  | 
|  | Hence, in summary: | 
|  |  | 
|  | @multitable {Offset ID} {Interpretation in AMD64 in AMD64} | 
|  | @headitem Offset ID @tab Interpretation in AMD64 | 
|  | @item 1 @tab CFA = @code{BASE_REG} + offset1 | 
|  | @item 2 @tab FP = CFA + offset2 | 
|  | @end multitable | 
|  |  | 
|  | @node AArch64 | 
|  | @section AArch64 | 
|  |  | 
|  | Irrespective of the ABI, the first stack offset is always used to locate the | 
|  | CFA, by interpreting it as: CFA = @code{BASE_REG} + offset1.  The | 
|  | identification of the @code{BASE_REG} is done by using the | 
|  | @code{fre_cfa_base_reg_id} field in the SFrame FRE info word. | 
|  |  | 
|  | In AARCH64, the AAPCS64 standard specifies that the Frame Record saves both FP | 
|  | and LR (a.k.a the RA).  However, the standard does not mandate the precise | 
|  | location in the function where the frame record is created, if at all.  Hence | 
|  | the need to track RA in the SFrame stack trace format.  As RA is being tracked | 
|  | in this ABI, the second stack offset is always used to locate the RA, by | 
|  | interpreting it as: RA = CFA + offset2. The third stack offset will be used to | 
|  | locate the FP, by interpreting it as: FP = CFA + offset3. | 
|  |  | 
|  | Given the nature of things, the number of stack offsets seen on AARCH64 per | 
|  | SFrame FRE is either 1 or 3. | 
|  |  | 
|  | Hence, in summary: | 
|  |  | 
|  | @multitable {Offset ID} {Interpretation in AArch64 in X} | 
|  | @headitem Offset ID @tab Interpretation in AArch64 | 
|  | @item 1 @tab CFA = @code{BASE_REG} + offset1 | 
|  | @item 2 @tab RA = CFA + offset2 | 
|  | @item 3 @tab FP = CFA + offset3 | 
|  | @end multitable | 
|  |  | 
|  | @node s390x | 
|  | @section s390x | 
|  |  | 
|  | A stack tracer implementation must initialize the SP to the designated SP | 
|  | register value, the FP to the preferred FP register value, and the RA to the | 
|  | designated RA register value in the topmost stack frame of the callchain.  This | 
|  | is required, as either the SP or FP is used as CFA base register and as the FP | 
|  | and/or RA are not necessarily saved on the stack.  For RA this may only be the | 
|  | case in the topmost stack frame of the callchain.  For FP this may be the case | 
|  | in any stack frame. | 
|  |  | 
|  | Irrespective of the ABI, the first stack offset is always used to locate the | 
|  | CFA.  On s390x the value of the offset is stored adjusted by the s390x-specific | 
|  | @code{SFRAME_S390X_CFA_OFFSET_ADJUSTMENT} and scaled down by the s390x-specific | 
|  | @code{SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR}, to enable and improve the use | 
|  | of signed 8-bit offsets on s390x. | 
|  | s390x-specific helpers @code{SFRAME_V2_S390X_CFA_OFFSET_ENCODE} and | 
|  | @code{SFRAME_V2_S390X_CFA_OFFSET_DECODE} are provided to perform or undo | 
|  | the adjustment and scaling.  The CFA offset can therefore be interpreted as: | 
|  | CFA = @code{BASE_REG} + offset1 - @code{SFRAME_S390X_CFA_OFFSET_ADJUSTMENT} | 
|  | or | 
|  | CFA = @code{BASE_REG} | 
|  | + (offset1 * @code{SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR}) | 
|  | - @code{SFRAME_S390X_CFA_OFFSET_ADJUSTMENT}. | 
|  | The identification of the @code{BASE_REG} is done by using the | 
|  | @code{fre_cfa_base_reg_id} field in the SFrame FRE info word. | 
|  |  | 
|  | The (64-bit) s390x ELF ABI does not mandate the precise location in a function | 
|  | where the return address (RA) and frame pointer (FP) are saved, if at all. | 
|  | Hence the need to track RA in the SFrame stack trace format.  As RA is being | 
|  | tracked in this ABI, the second stack offset is always used to locate the RA | 
|  | stack slot, by interpreting it as: RA = CFA + offset2, unless the offset has a | 
|  | value of @code{SFRAME_FRE_RA_OFFSET_INVALID}.  RA remains unchanged, if the | 
|  | offset is not available or has a value of @code{SFRAME_FRE_RA_OFFSET_INVALID}. | 
|  | Stack tracers are recommended to validate that the "unchanged RA" pattern, when | 
|  | present, is seen only for the topmost stack frame.  The third stack offset is | 
|  | used to locate the FP stack slot, by interpreting it as: FP = CFA + offset3. | 
|  | FP remains unchanged, if the offset is not available. | 
|  |  | 
|  | In leaf functions the RA and FP may be saved in other registers, such as | 
|  | floating-point registers (FPRs), instead of on the stack.  To represent this | 
|  | in the SFrame stack trace format the DWARF register number is encoded as | 
|  | RA/FP offset using the least-significant bit (LSB) as indication: | 
|  | offset = (regnum << 1) | 1.  A LSB of zero indicates a stack slot offset. | 
|  | A LSB of one indicates a DWARF register number, which is interpreted as: | 
|  | regnum = offset >> 1.  Given the nature of leaf functions, this can only occur | 
|  | in the topmost frame during stack tracing.  It is recommended that a stack | 
|  | tracer implementation performs the required checks to ensure that restoring | 
|  | FP and RA from the said register locations is done only for topmost stack | 
|  | frame in the callchain. | 
|  |  | 
|  | Given the nature of things, the number of stack offsets and/or register numbers | 
|  | seen on s390x per SFrame FRE is either 1, 2, or 3. | 
|  |  | 
|  | Hence, in summary: | 
|  |  | 
|  | @multitable @columnfractions .15 .85 | 
|  | @headitem Offset ID @tab Interpretation in s390x | 
|  | @item 1 @tab CFA = @code{BASE_REG} + offset1 | 
|  | @item 2 @tab RA stack slot = CFA + offset2, if (offset2 & 1 == 0) | 
|  | @*RA register number = offset2 >> 1, if (offset2 & 1 == 1) | 
|  | @*RA not saved if (offset2 == @code{SFRAME_FRE_RA_OFFSET_INVALID}) | 
|  | @item 3 @tab FP stack slot = CFA + offset3, if (offset3 & 1 == 0) | 
|  | @*FP register number = offset3 >> 1, if (offset3 & 1 == 1) | 
|  | @end multitable | 
|  |  | 
|  | The s390x ELF ABI defines the CFA as stack pointer (SP) at call site +160.  The | 
|  | SP can therefore be obtained using the SP value offset from CFA | 
|  | @code{SFRAME_S390X_SP_VAL_OFFSET} of -160 as follows: | 
|  | SP = CFA + @code{SFRAME_S390X_SP_VAL_OFFSET} | 
|  |  | 
|  | @node Generating Stack Traces using SFrame | 
|  | @appendix Generating Stack Traces using SFrame | 
|  |  | 
|  | Using some C-like pseudocode, this section highlights how SFrame provides a | 
|  | simple, fast and low-overhead mechanism to generate stack traces.  Needless to | 
|  | say that for generating accurate and useful stack traces, several other aspects | 
|  | will need attention: finding and decoding bits of SFrame section(s) in the | 
|  | program binary, symbolization of addresses, to name a few. | 
|  |  | 
|  | In the current context, a @code{frame} is the abstract construct that | 
|  | encapsulates the following information: | 
|  | @itemize @minus | 
|  | @item | 
|  | program counter (PC), | 
|  | @item | 
|  | stack pointer (SP), and | 
|  | @item | 
|  | frame pointer (FP) | 
|  | @end itemize | 
|  |  | 
|  | With that said, establishing the first @code{frame} should be trivial: | 
|  |  | 
|  | @example | 
|  | // frame 0 | 
|  | frame->pc = current_IP; | 
|  | frame->sp = get_reg_value (REG_SP); | 
|  | frame->fp = get_reg_value (REG_FP); | 
|  | @end example | 
|  |  | 
|  | where @code{REG_SP} and @code{REG_FP} are are ABI-designated stack pointer and | 
|  | frame pointer registers respectively. | 
|  |  | 
|  | Next, given frame N, generating stack trace needs us to get frame N+1.  This | 
|  | can be done as follows: | 
|  |  | 
|  | @example | 
|  | // Get the PC, SP, and FP for frame N. | 
|  | pc = frame->pc; | 
|  | sp = frame->sp; | 
|  | fp = frame->fp; | 
|  | // Populate frame N+1. | 
|  | int err = get_next_frame (&next_frame, pc, sp, fp); | 
|  | @end example | 
|  |  | 
|  | where given the values of the program counter, stack pointer and frame pointer | 
|  | from frame N, @code{get_next_frame} populates the provided @code{next_frame} | 
|  | object and returns the error code, if any. In the following pseudocode for | 
|  | @code{get_next_frame}, the @code{sframe_*} functions fetch information from the | 
|  | SFrame section. | 
|  |  | 
|  | @example | 
|  | fre = sframe_find_fre (pc); | 
|  | if (fre) | 
|  | // Whether the base register for CFA tracking is REG_FP. | 
|  | base_reg_val = sframe_fre_base_reg_fp_p (fre) ? fp : sp; | 
|  | // Get the CFA stack offset from the FRE. | 
|  | cfa_offset = sframe_fre_get_cfa_offset (fre); | 
|  | // Get the fixed RA offset or FRE stack offset as applicable. | 
|  | ra_offset = sframe_fre_get_ra_offset (fre); | 
|  | // Get the fixed FP offset or FRE stack offset as applicable. | 
|  | fp_offset = sframe_fre_get_fp_offset (fre); | 
|  |  | 
|  | cfa = base_reg_val + cfa_offset; | 
|  | next_frame->sp = cfa [+ SFRAME_S390X_SP_VAL_OFFSET on s390x]; | 
|  |  | 
|  | ra_stack_loc = cfa + ra_offset; | 
|  | // Get the address stored in the stack location. | 
|  | next_frame->pc = read_value (ra_stack_loc); | 
|  |  | 
|  | if (fp_offset is VALID) | 
|  | fp_stack_loc = cfa + fp_offset; | 
|  | // Get the value stored in the stack location. | 
|  | next_frame->fp = read_value (fp_stack_loc); | 
|  | else | 
|  | // Continue to use the value of fp as it has not | 
|  | // been clobbered by the current frame yet. | 
|  | next_frame->fp = fp; | 
|  | else | 
|  | ret = ERR_NO_SFRAME_FRE; | 
|  | @end example | 
|  |  | 
|  | @node Index | 
|  | @unnumbered Index | 
|  |  | 
|  | @syncodeindex tp cp | 
|  | @printindex cp | 
|  |  | 
|  | @bye |