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