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