gen-sframe.c revision 1.1.1.1 1 1.1 christos /* gen-sframe.c - Support for generating SFrame section.
2 1.1 christos Copyright (C) 2022-2024 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos This file is part of GAS, the GNU Assembler.
5 1.1 christos
6 1.1 christos GAS is free software; you can redistribute it and/or modify
7 1.1 christos it under the terms of the GNU General Public License as published by
8 1.1 christos the Free Software Foundation; either version 3, or (at your option)
9 1.1 christos any later version.
10 1.1 christos
11 1.1 christos GAS is distributed in the hope that it will be useful,
12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 1.1 christos GNU General Public License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with GAS; see the file COPYING. If not, write to the Free
18 1.1 christos Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19 1.1 christos 02110-1301, USA. */
20 1.1 christos
21 1.1 christos #include "as.h"
22 1.1 christos #include "subsegs.h"
23 1.1 christos #include "sframe.h"
24 1.1 christos #include "gen-sframe.h"
25 1.1 christos #include "dw2gencfi.h"
26 1.1 christos
27 1.1 christos #ifdef support_sframe_p
28 1.1 christos
29 1.1 christos /* By default, use 32-bit relocations from .sframe into .text. */
30 1.1 christos #ifndef SFRAME_RELOC_SIZE
31 1.1 christos # define SFRAME_RELOC_SIZE 4
32 1.1 christos #endif
33 1.1 christos
34 1.1 christos /* Whether frame row entries track RA.
35 1.1 christos
36 1.1 christos A target may not need return address tracking for stack tracing. If it
37 1.1 christos does need the same, SFRAME_CFA_RA_REG must be defined with the return
38 1.1 christos address register number. */
39 1.1 christos
40 1.1 christos #if defined (sframe_ra_tracking_p) && defined (SFRAME_CFA_RA_REG)
41 1.1 christos # ifndef SFRAME_FRE_RA_TRACKING
42 1.1 christos # define SFRAME_FRE_RA_TRACKING 1
43 1.1 christos # endif
44 1.1 christos #endif
45 1.1 christos
46 1.1 christos /* SFrame FRE type selection optimization is an optimization for size.
47 1.1 christos
48 1.1 christos There are three flavors of SFrame FRE representation in the binary format:
49 1.1 christos - sframe_frame_row_entry_addr1 where the FRE start address is 1 byte.
50 1.1 christos - sframe_frame_row_entry_addr2 where the FRE start address is 2 bytes.
51 1.1 christos - sframe_frame_row_entry_addr4 where the FRE start address is 4 bytes.
52 1.1 christos
53 1.1 christos Note that in the SFrame format, all SFrame FREs of a function use one
54 1.1 christos single representation. The SFrame FRE type itself is identified via the
55 1.1 christos information in the SFrame FDE function info.
56 1.1 christos
57 1.1 christos Now, to select the minimum required one from the list above, one needs to
58 1.1 christos make a decision based on the size (in bytes) of the function.
59 1.1 christos
60 1.1 christos As a result, for this optimization, some fragments (generated with a new
61 1.1 christos type rs_sframe) for the SFrame section are fixed up later.
62 1.1 christos
63 1.1 christos This optimization (for size) is enabled by default. */
64 1.1 christos
65 1.1 christos #ifndef SFRAME_FRE_TYPE_SELECTION_OPT
66 1.1 christos # define SFRAME_FRE_TYPE_SELECTION_OPT 1
67 1.1 christos #endif
68 1.1 christos
69 1.1 christos /* Emit a single byte into the current segment. */
70 1.1 christos
71 1.1 christos static inline void
72 1.1 christos out_one (int byte)
73 1.1 christos {
74 1.1 christos FRAG_APPEND_1_CHAR (byte);
75 1.1 christos }
76 1.1 christos
77 1.1 christos /* Emit a two-byte word into the current segment. */
78 1.1 christos
79 1.1 christos static inline void
80 1.1 christos out_two (int data)
81 1.1 christos {
82 1.1 christos md_number_to_chars (frag_more (2), data, 2);
83 1.1 christos }
84 1.1 christos
85 1.1 christos /* Emit a four byte word into the current segment. */
86 1.1 christos
87 1.1 christos static inline void
88 1.1 christos out_four (int data)
89 1.1 christos {
90 1.1 christos md_number_to_chars (frag_more (4), data, 4);
91 1.1 christos }
92 1.1 christos
93 1.1 christos /* Get the start address symbol from the DWARF FDE. */
94 1.1 christos
95 1.1 christos static symbolS*
96 1.1 christos get_dw_fde_start_addrS (const struct fde_entry *dw_fde)
97 1.1 christos {
98 1.1 christos return dw_fde->start_address;
99 1.1 christos }
100 1.1 christos
101 1.1 christos /* Get the start address symbol from the DWARF FDE. */
102 1.1 christos
103 1.1 christos static symbolS*
104 1.1 christos get_dw_fde_end_addrS (const struct fde_entry *dw_fde)
105 1.1 christos {
106 1.1 christos return dw_fde->end_address;
107 1.1 christos }
108 1.1 christos
109 1.1 christos /* Get whether PAUTH B key is used. */
110 1.1 christos static bool
111 1.1 christos get_dw_fde_pauth_b_key_p (const struct fde_entry *dw_fde ATTRIBUTE_UNUSED)
112 1.1 christos {
113 1.1 christos #ifdef tc_fde_entry_extras
114 1.1 christos return (dw_fde->pauth_key == AARCH64_PAUTH_KEY_B);
115 1.1 christos #else
116 1.1 christos return false;
117 1.1 christos #endif
118 1.1 christos }
119 1.1 christos
120 1.1 christos /* SFrame Frame Row Entry (FRE) related functions. */
121 1.1 christos
122 1.1 christos static void
123 1.1 christos sframe_fre_set_begin_addr (struct sframe_row_entry *fre, symbolS *beginS)
124 1.1 christos {
125 1.1 christos fre->pc_begin = beginS;
126 1.1 christos }
127 1.1 christos
128 1.1 christos static void
129 1.1 christos sframe_fre_set_end_addr (struct sframe_row_entry *fre, symbolS *endS)
130 1.1 christos {
131 1.1 christos fre->pc_end = endS;
132 1.1 christos }
133 1.1 christos
134 1.1 christos static void
135 1.1 christos sframe_fre_set_cfa_base_reg (struct sframe_row_entry *fre,
136 1.1 christos unsigned int cfa_base_reg)
137 1.1 christos {
138 1.1 christos fre->cfa_base_reg = cfa_base_reg;
139 1.1 christos fre->merge_candidate = false;
140 1.1 christos }
141 1.1 christos
142 1.1 christos static void
143 1.1 christos sframe_fre_set_cfa_offset (struct sframe_row_entry *fre,
144 1.1 christos offsetT cfa_offset)
145 1.1 christos {
146 1.1 christos fre->cfa_offset = cfa_offset;
147 1.1 christos fre->merge_candidate = false;
148 1.1 christos }
149 1.1 christos
150 1.1 christos #ifdef SFRAME_FRE_RA_TRACKING
151 1.1 christos static void
152 1.1 christos sframe_fre_set_ra_track (struct sframe_row_entry *fre, offsetT ra_offset)
153 1.1 christos {
154 1.1 christos fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK;
155 1.1 christos fre->ra_offset = ra_offset;
156 1.1 christos fre->merge_candidate = false;
157 1.1 christos }
158 1.1 christos #endif
159 1.1 christos
160 1.1 christos static void
161 1.1 christos sframe_fre_set_bp_track (struct sframe_row_entry *fre, offsetT bp_offset)
162 1.1 christos {
163 1.1 christos fre->bp_loc = SFRAME_FRE_ELEM_LOC_STACK;
164 1.1 christos fre->bp_offset = bp_offset;
165 1.1 christos fre->merge_candidate = false;
166 1.1 christos }
167 1.1 christos
168 1.1 christos /* All stack offset values within an FRE are uniformly encoded in the same
169 1.1 christos number of bytes. The size of the stack offset values will, however, vary
170 1.1 christos across FREs. */
171 1.1 christos
172 1.1 christos #define VALUE_8BIT 0x7f
173 1.1 christos #define VALUE_16BIT 0x7fff
174 1.1 christos #define VALUE_32BIT 0x7fffffff
175 1.1 christos #define VALUE_64BIT 0x7fffffffffffffff
176 1.1 christos
177 1.1 christos /* Given a signed offset, return the size in bytes needed to represent it. */
178 1.1 christos
179 1.1 christos static unsigned int
180 1.1 christos get_offset_size_in_bytes (offsetT value)
181 1.1 christos {
182 1.1 christos unsigned int size = 0;
183 1.1 christos
184 1.1 christos if (value <= VALUE_8BIT && value >= (offsetT) -VALUE_8BIT)
185 1.1 christos size = 1;
186 1.1 christos else if (value <= VALUE_16BIT && value >= (offsetT) -VALUE_16BIT)
187 1.1 christos size = 2;
188 1.1 christos else if (value <= VALUE_32BIT && value >= (offsetT) -VALUE_32BIT)
189 1.1 christos size = 4;
190 1.1 christos else if ((sizeof (offsetT) > 4) && (value <= (offsetT) VALUE_64BIT
191 1.1 christos && value >= (offsetT) -VALUE_64BIT))
192 1.1 christos size = 8;
193 1.1 christos
194 1.1 christos return size;
195 1.1 christos }
196 1.1 christos
197 1.1 christos #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B 0 /* SFRAME_FRE_OFFSET_1B. */
198 1.1 christos #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B 1 /* SFRAME_FRE_OFFSET_2B. */
199 1.1 christos #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B 2 /* SFRAME_FRE_OFFSET_4B. */
200 1.1 christos #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B 3 /* Not supported in SFrame. */
201 1.1 christos #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B
202 1.1 christos
203 1.1 christos /* Helper struct for mapping offset size to output functions. */
204 1.1 christos
205 1.1 christos struct sframe_fre_offset_func_map
206 1.1 christos {
207 1.1 christos unsigned int offset_size;
208 1.1 christos void (*out_func)(int);
209 1.1 christos };
210 1.1 christos
211 1.1 christos /* Given an OFFSET_SIZE, return the size in bytes needed to represent it. */
212 1.1 christos
213 1.1 christos static unsigned int
214 1.1 christos sframe_fre_offset_func_map_index (unsigned int offset_size)
215 1.1 christos {
216 1.1 christos unsigned int idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX;
217 1.1 christos
218 1.1 christos switch (offset_size)
219 1.1 christos {
220 1.1 christos case SFRAME_FRE_OFFSET_1B:
221 1.1 christos idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B;
222 1.1 christos break;
223 1.1 christos case SFRAME_FRE_OFFSET_2B:
224 1.1 christos idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B;
225 1.1 christos break;
226 1.1 christos case SFRAME_FRE_OFFSET_4B:
227 1.1 christos idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B;
228 1.1 christos break;
229 1.1 christos default:
230 1.1 christos /* Not supported in SFrame. */
231 1.1 christos break;
232 1.1 christos }
233 1.1 christos
234 1.1 christos return idx;
235 1.1 christos }
236 1.1 christos
237 1.1 christos /* Mapping from offset size to the output function to emit the value. */
238 1.1 christos
239 1.1 christos static const
240 1.1 christos struct sframe_fre_offset_func_map
241 1.1 christos fre_offset_func_map[SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX+1] =
242 1.1 christos {
243 1.1 christos { SFRAME_FRE_OFFSET_1B, out_one },
244 1.1 christos { SFRAME_FRE_OFFSET_2B, out_two },
245 1.1 christos { SFRAME_FRE_OFFSET_4B, out_four },
246 1.1 christos { -1, NULL } /* Not Supported in SFrame. */
247 1.1 christos };
248 1.1 christos
249 1.1 christos /* SFrame version specific operations access. */
250 1.1 christos
251 1.1 christos static struct sframe_version_ops sframe_ver_ops;
252 1.1 christos
253 1.1 christos /* SFrame (SFRAME_VERSION_1) set FRE info. */
254 1.1 christos
255 1.1 christos static unsigned char
256 1.1 christos sframe_v1_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
257 1.1 christos unsigned int offset_size, bool mangled_ra_p)
258 1.1 christos {
259 1.1 christos unsigned char fre_info;
260 1.1 christos fre_info = SFRAME_V1_FRE_INFO (base_reg, num_offsets, offset_size);
261 1.1 christos fre_info = SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P (mangled_ra_p, fre_info);
262 1.1 christos return fre_info;
263 1.1 christos }
264 1.1 christos
265 1.1 christos /* SFrame (SFRAME_VERSION_1) set function info. */
266 1.1 christos static unsigned char
267 1.1 christos sframe_v1_set_func_info (unsigned int fde_type, unsigned int fre_type,
268 1.1 christos unsigned int pauth_key)
269 1.1 christos {
270 1.1 christos unsigned char func_info;
271 1.1 christos func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
272 1.1 christos func_info = SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, func_info);
273 1.1 christos return func_info;
274 1.1 christos }
275 1.1 christos
276 1.1 christos /* SFrame version specific operations setup. */
277 1.1 christos
278 1.1 christos static void
279 1.1 christos sframe_set_version (uint32_t sframe_version ATTRIBUTE_UNUSED)
280 1.1 christos {
281 1.1 christos sframe_ver_ops.format_version = SFRAME_VERSION_2;
282 1.1 christos
283 1.1 christos /* These operations remain the same for SFRAME_VERSION_2 as fre_info and
284 1.1 christos func_info have not changed from SFRAME_VERSION_1. */
285 1.1 christos
286 1.1 christos sframe_ver_ops.set_fre_info = sframe_v1_set_fre_info;
287 1.1 christos
288 1.1 christos sframe_ver_ops.set_func_info = sframe_v1_set_func_info;
289 1.1 christos }
290 1.1 christos
291 1.1 christos /* SFrame set FRE info. */
292 1.1 christos
293 1.1 christos static unsigned char
294 1.1 christos sframe_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
295 1.1 christos unsigned int offset_size, bool mangled_ra_p)
296 1.1 christos {
297 1.1 christos return sframe_ver_ops.set_fre_info (base_reg, num_offsets,
298 1.1 christos offset_size, mangled_ra_p);
299 1.1 christos }
300 1.1 christos
301 1.1 christos /* SFrame set func info. */
302 1.1 christos
303 1.1 christos static unsigned char
304 1.1 christos sframe_set_func_info (unsigned int fde_type, unsigned int fre_type,
305 1.1 christos unsigned int pauth_key)
306 1.1 christos {
307 1.1 christos return sframe_ver_ops.set_func_info (fde_type, fre_type, pauth_key);
308 1.1 christos }
309 1.1 christos
310 1.1 christos /* Get the number of SFrame FDEs for the current file. */
311 1.1 christos
312 1.1 christos static unsigned int
313 1.1 christos get_num_sframe_fdes (void);
314 1.1 christos
315 1.1 christos /* Get the number of SFrame frame row entries for the current file. */
316 1.1 christos
317 1.1 christos static unsigned int
318 1.1 christos get_num_sframe_fres (void);
319 1.1 christos
320 1.1 christos /* Get CFA base register ID as represented in SFrame Frame Row Entry. */
321 1.1 christos
322 1.1 christos static unsigned int
323 1.1 christos get_fre_base_reg_id (struct sframe_row_entry *sframe_fre)
324 1.1 christos {
325 1.1 christos unsigned int cfi_insn_cfa_base_reg = sframe_fre->cfa_base_reg;
326 1.1 christos unsigned fre_base_reg = SFRAME_BASE_REG_SP;
327 1.1 christos
328 1.1 christos if (cfi_insn_cfa_base_reg == SFRAME_CFA_FP_REG)
329 1.1 christos fre_base_reg = SFRAME_BASE_REG_FP;
330 1.1 christos
331 1.1 christos /* Only one bit is reserved in SFRAME_VERSION_1. */
332 1.1 christos gas_assert (fre_base_reg == SFRAME_BASE_REG_SP
333 1.1 christos || fre_base_reg == SFRAME_BASE_REG_FP);
334 1.1 christos
335 1.1 christos return fre_base_reg;
336 1.1 christos }
337 1.1 christos
338 1.1 christos /* Get number of offsets necessary for the SFrame Frame Row Entry. */
339 1.1 christos
340 1.1 christos static unsigned int
341 1.1 christos get_fre_num_offsets (struct sframe_row_entry *sframe_fre)
342 1.1 christos {
343 1.1 christos /* Atleast 1 must always be present (to recover CFA). */
344 1.1 christos unsigned int fre_num_offsets = 1;
345 1.1 christos
346 1.1 christos if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
347 1.1 christos fre_num_offsets++;
348 1.1 christos #ifdef SFRAME_FRE_RA_TRACKING
349 1.1 christos if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
350 1.1 christos fre_num_offsets++;
351 1.1 christos #endif
352 1.1 christos return fre_num_offsets;
353 1.1 christos }
354 1.1 christos
355 1.1 christos /* Get the minimum necessary offset size (in bytes) for this
356 1.1 christos SFrame frame row entry. */
357 1.1 christos
358 1.1 christos static unsigned int
359 1.1 christos sframe_get_fre_offset_size (struct sframe_row_entry *sframe_fre)
360 1.1 christos {
361 1.1 christos unsigned int max_offset_size = 0;
362 1.1 christos unsigned int cfa_offset_size = 0;
363 1.1 christos unsigned int bp_offset_size = 0;
364 1.1 christos unsigned int ra_offset_size = 0;
365 1.1 christos
366 1.1 christos unsigned int fre_offset_size = 0;
367 1.1 christos
368 1.1 christos /* What size of offsets appear in this frame row entry. */
369 1.1 christos cfa_offset_size = get_offset_size_in_bytes (sframe_fre->cfa_offset);
370 1.1 christos if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
371 1.1 christos bp_offset_size = get_offset_size_in_bytes (sframe_fre->bp_offset);
372 1.1 christos #ifdef SFRAME_FRE_RA_TRACKING
373 1.1 christos if (sframe_ra_tracking_p ()
374 1.1 christos && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
375 1.1 christos ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
376 1.1 christos #endif
377 1.1 christos
378 1.1 christos /* Get the maximum size needed to represent the offsets. */
379 1.1 christos max_offset_size = cfa_offset_size;
380 1.1 christos if (bp_offset_size > max_offset_size)
381 1.1 christos max_offset_size = bp_offset_size;
382 1.1 christos if (ra_offset_size > max_offset_size)
383 1.1 christos max_offset_size = ra_offset_size;
384 1.1 christos
385 1.1 christos gas_assert (max_offset_size);
386 1.1 christos
387 1.1 christos switch (max_offset_size)
388 1.1 christos {
389 1.1 christos case 1:
390 1.1 christos fre_offset_size = SFRAME_FRE_OFFSET_1B;
391 1.1 christos break;
392 1.1 christos case 2:
393 1.1 christos fre_offset_size = SFRAME_FRE_OFFSET_2B;
394 1.1 christos break;
395 1.1 christos case 4:
396 1.1 christos fre_offset_size = SFRAME_FRE_OFFSET_4B;
397 1.1 christos break;
398 1.1 christos default:
399 1.1 christos /* Offset of size 8 bytes is not supported in SFrame format
400 1.1 christos version 1. */
401 1.1 christos as_fatal (_("SFrame unsupported offset value\n"));
402 1.1 christos break;
403 1.1 christos }
404 1.1 christos
405 1.1 christos return fre_offset_size;
406 1.1 christos }
407 1.1 christos
408 1.1 christos #if SFRAME_FRE_TYPE_SELECTION_OPT
409 1.1 christos
410 1.1 christos /* Create a composite expression CEXP (for SFrame FRE start address) such that:
411 1.1 christos
412 1.1 christos exp = <val> OP_absent <width>, where,
413 1.1 christos
414 1.1 christos - <val> and <width> are themselves expressionS.
415 1.1 christos - <val> stores the expression which when evaluated gives the value of the
416 1.1 christos start address offset of the FRE.
417 1.1 christos - <width> stores the expression when evaluated gives the number of bytes
418 1.1 christos needed to encode the start address offset of the FRE.
419 1.1 christos
420 1.1 christos The use of OP_absent as the X_op_symbol helps identify this expression
421 1.1 christos later when fragments are fixed up. */
422 1.1 christos
423 1.1 christos static void
424 1.1 christos create_fre_start_addr_exp (expressionS *cexp, symbolS *fre_pc_begin,
425 1.1 christos symbolS *fde_start_address,
426 1.1 christos symbolS *fde_end_address)
427 1.1 christos {
428 1.1 christos expressionS val;
429 1.1 christos expressionS width;
430 1.1 christos
431 1.1 christos /* val expression stores the FDE start address offset from the start PC
432 1.1 christos of function. */
433 1.1 christos val.X_op = O_subtract;
434 1.1 christos val.X_add_symbol = fre_pc_begin;
435 1.1 christos val.X_op_symbol = fde_start_address;
436 1.1 christos val.X_add_number = 0;
437 1.1 christos
438 1.1 christos /* width expressions stores the size of the function. This is used later
439 1.1 christos to determine the number of bytes to be used to encode the FRE start
440 1.1 christos address of each FRE of the function. */
441 1.1 christos width.X_op = O_subtract;
442 1.1 christos width.X_add_symbol = fde_end_address;
443 1.1 christos width.X_op_symbol = fde_start_address;
444 1.1 christos width.X_add_number = 0;
445 1.1 christos
446 1.1 christos cexp->X_op = O_absent;
447 1.1 christos cexp->X_add_symbol = make_expr_symbol (&val);
448 1.1 christos cexp->X_op_symbol = make_expr_symbol (&width);
449 1.1 christos cexp->X_add_number = 0;
450 1.1 christos }
451 1.1 christos
452 1.1 christos /* Create a composite expression CEXP (for SFrame FDE function info) such that:
453 1.1 christos
454 1.1 christos exp = <rest_of_func_info> OP_modulus <width>, where,
455 1.1 christos
456 1.1 christos - <rest_of_func_info> and <width> are themselves expressionS.
457 1.1 christos - <rest_of_func_info> stores a constant expression where X_add_number is
458 1.1 christos used to stash away the func_info. The upper 4-bits of the func_info are copied
459 1.1 christos back to the resulting byte by the fragment fixup logic.
460 1.1 christos - <width> stores the expression when evaluated gives the size of the
461 1.1 christos function in number of bytes.
462 1.1 christos
463 1.1 christos The use of OP_modulus as the X_op_symbol helps identify this expression
464 1.1 christos later when fragments are fixed up. */
465 1.1 christos
466 1.1 christos static void
467 1.1 christos create_func_info_exp (expressionS *cexp, symbolS *dw_fde_end_addrS,
468 1.1 christos symbolS *dw_fde_start_addrS, uint8_t func_info)
469 1.1 christos {
470 1.1 christos expressionS width;
471 1.1 christos expressionS rest_of_func_info;
472 1.1 christos
473 1.1 christos width.X_op = O_subtract;
474 1.1 christos width.X_add_symbol = dw_fde_end_addrS;
475 1.1 christos width.X_op_symbol = dw_fde_start_addrS;
476 1.1 christos width.X_add_number = 0;
477 1.1 christos
478 1.1 christos rest_of_func_info.X_op = O_constant;
479 1.1 christos rest_of_func_info.X_add_number = func_info;
480 1.1 christos
481 1.1 christos cexp->X_op = O_modulus;
482 1.1 christos cexp->X_add_symbol = make_expr_symbol (&rest_of_func_info);
483 1.1 christos cexp->X_op_symbol = make_expr_symbol (&width);
484 1.1 christos cexp->X_add_number = 0;
485 1.1 christos }
486 1.1 christos
487 1.1 christos #endif
488 1.1 christos
489 1.1 christos static void
490 1.1 christos output_sframe_row_entry (symbolS *fde_start_addr,
491 1.1 christos symbolS *fde_end_addr,
492 1.1 christos struct sframe_row_entry *sframe_fre)
493 1.1 christos {
494 1.1 christos unsigned char fre_info;
495 1.1 christos unsigned int fre_num_offsets;
496 1.1 christos unsigned int fre_offset_size;
497 1.1 christos unsigned int fre_base_reg;
498 1.1 christos expressionS exp;
499 1.1 christos unsigned int fre_addr_size;
500 1.1 christos
501 1.1 christos unsigned int idx = 0;
502 1.1 christos unsigned int fre_write_offsets = 0;
503 1.1 christos
504 1.1 christos fre_addr_size = 4; /* 4 bytes by default. FIXME tie it to fre_type? */
505 1.1 christos
506 1.1 christos /* SFrame FRE Start Address. */
507 1.1 christos #if SFRAME_FRE_TYPE_SELECTION_OPT
508 1.1 christos create_fre_start_addr_exp (&exp, sframe_fre->pc_begin, fde_start_addr,
509 1.1 christos fde_end_addr);
510 1.1 christos frag_grow (fre_addr_size);
511 1.1 christos frag_var (rs_sframe, fre_addr_size, 0, (relax_substateT) 0,
512 1.1 christos make_expr_symbol (&exp), 0, (char *) frag_now);
513 1.1 christos #else
514 1.1 christos gas_assert (fde_end_addr);
515 1.1 christos exp.X_op = O_subtract;
516 1.1 christos exp.X_add_symbol = sframe_fre->pc_begin; /* to. */
517 1.1 christos exp.X_op_symbol = fde_start_addr; /* from. */
518 1.1 christos exp.X_add_number = 0;
519 1.1 christos emit_expr (&exp, fre_addr_size);
520 1.1 christos #endif
521 1.1 christos
522 1.1 christos /* Create the fre_info using the CFA base register, number of offsets and max
523 1.1 christos size of offset in this frame row entry. */
524 1.1 christos fre_base_reg = get_fre_base_reg_id (sframe_fre);
525 1.1 christos fre_num_offsets = get_fre_num_offsets (sframe_fre);
526 1.1 christos fre_offset_size = sframe_get_fre_offset_size (sframe_fre);
527 1.1 christos fre_info = sframe_set_fre_info (fre_base_reg, fre_num_offsets,
528 1.1 christos fre_offset_size, sframe_fre->mangled_ra_p);
529 1.1 christos out_one (fre_info);
530 1.1 christos
531 1.1 christos idx = sframe_fre_offset_func_map_index (fre_offset_size);
532 1.1 christos gas_assert (idx < SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX);
533 1.1 christos
534 1.1 christos /* Write out the offsets in order - cfa, bp, ra. */
535 1.1 christos fre_offset_func_map[idx].out_func (sframe_fre->cfa_offset);
536 1.1 christos fre_write_offsets++;
537 1.1 christos
538 1.1 christos #ifdef SFRAME_FRE_RA_TRACKING
539 1.1 christos if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
540 1.1 christos {
541 1.1 christos fre_offset_func_map[idx].out_func (sframe_fre->ra_offset);
542 1.1 christos fre_write_offsets++;
543 1.1 christos }
544 1.1 christos #endif
545 1.1 christos if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
546 1.1 christos {
547 1.1 christos fre_offset_func_map[idx].out_func (sframe_fre->bp_offset);
548 1.1 christos fre_write_offsets++;
549 1.1 christos }
550 1.1 christos
551 1.1 christos /* Check if the expected number offsets have been written out
552 1.1 christos in this FRE. */
553 1.1 christos gas_assert (fre_write_offsets == fre_num_offsets);
554 1.1 christos }
555 1.1 christos
556 1.1 christos static void
557 1.1 christos output_sframe_funcdesc (symbolS *start_of_fre_section,
558 1.1 christos symbolS *fre_symbol,
559 1.1 christos struct sframe_func_entry *sframe_fde)
560 1.1 christos {
561 1.1 christos expressionS exp;
562 1.1 christos unsigned int addr_size;
563 1.1 christos symbolS *dw_fde_start_addrS, *dw_fde_end_addrS;
564 1.1 christos unsigned int pauth_key;
565 1.1 christos
566 1.1 christos addr_size = SFRAME_RELOC_SIZE;
567 1.1 christos dw_fde_start_addrS = get_dw_fde_start_addrS (sframe_fde->dw_fde);
568 1.1 christos dw_fde_end_addrS = get_dw_fde_end_addrS (sframe_fde->dw_fde);
569 1.1 christos
570 1.1 christos /* Start address of the function. */
571 1.1 christos exp.X_op = O_subtract;
572 1.1 christos exp.X_add_symbol = dw_fde_start_addrS; /* to location. */
573 1.1 christos exp.X_op_symbol = symbol_temp_new_now (); /* from location. */
574 1.1 christos exp.X_add_number = 0;
575 1.1 christos emit_expr (&exp, addr_size);
576 1.1 christos
577 1.1 christos /* Size of the function in bytes. */
578 1.1 christos exp.X_op = O_subtract;
579 1.1 christos exp.X_add_symbol = dw_fde_end_addrS;
580 1.1 christos exp.X_op_symbol = dw_fde_start_addrS;
581 1.1 christos exp.X_add_number = 0;
582 1.1 christos emit_expr (&exp, addr_size);
583 1.1 christos
584 1.1 christos /* Offset to the first frame row entry. */
585 1.1 christos exp.X_op = O_subtract;
586 1.1 christos exp.X_add_symbol = fre_symbol; /* Minuend. */
587 1.1 christos exp.X_op_symbol = start_of_fre_section; /* Subtrahend. */
588 1.1 christos exp.X_add_number = 0;
589 1.1 christos emit_expr (&exp, addr_size);
590 1.1 christos
591 1.1 christos /* Number of FREs. */
592 1.1 christos out_four (sframe_fde->num_fres);
593 1.1 christos
594 1.1 christos /* SFrame FDE function info. */
595 1.1 christos unsigned char func_info;
596 1.1 christos pauth_key = (get_dw_fde_pauth_b_key_p (sframe_fde->dw_fde)
597 1.1 christos ? SFRAME_AARCH64_PAUTH_KEY_B : SFRAME_AARCH64_PAUTH_KEY_A);
598 1.1 christos func_info = sframe_set_func_info (SFRAME_FDE_TYPE_PCINC,
599 1.1 christos SFRAME_FRE_TYPE_ADDR4,
600 1.1 christos pauth_key);
601 1.1 christos #if SFRAME_FRE_TYPE_SELECTION_OPT
602 1.1 christos expressionS cexp;
603 1.1 christos create_func_info_exp (&cexp, dw_fde_end_addrS, dw_fde_start_addrS,
604 1.1 christos func_info);
605 1.1 christos frag_grow (1); /* Size of func info is unsigned char. */
606 1.1 christos frag_var (rs_sframe, 1, 0, (relax_substateT) 0,
607 1.1 christos make_expr_symbol (&cexp), 0, (char *) frag_now);
608 1.1 christos #else
609 1.1 christos out_one (func_info);
610 1.1 christos #endif
611 1.1 christos out_one (0);
612 1.1 christos out_two (0);
613 1.1 christos }
614 1.1 christos
615 1.1 christos static void
616 1.1 christos output_sframe_internal (void)
617 1.1 christos {
618 1.1 christos expressionS exp;
619 1.1 christos unsigned int i = 0;
620 1.1 christos
621 1.1 christos symbolS *end_of_frame_hdr;
622 1.1 christos symbolS *end_of_frame_section;
623 1.1 christos symbolS *start_of_func_desc_section;
624 1.1 christos symbolS *start_of_fre_section;
625 1.1 christos struct sframe_func_entry *sframe_fde;
626 1.1 christos struct sframe_row_entry *sframe_fre;
627 1.1 christos unsigned char abi_arch = 0;
628 1.1 christos int fixed_bp_offset = SFRAME_CFA_FIXED_FP_INVALID;
629 1.1 christos int fixed_ra_offset = SFRAME_CFA_FIXED_RA_INVALID;
630 1.1 christos unsigned int addr_size;
631 1.1 christos
632 1.1 christos addr_size = SFRAME_RELOC_SIZE;
633 1.1 christos
634 1.1 christos /* The function descriptor entries as dumped by the assembler are not
635 1.1 christos sorted on PCs. */
636 1.1 christos unsigned char sframe_flags = 0;
637 1.1 christos sframe_flags |= !SFRAME_F_FDE_SORTED;
638 1.1 christos
639 1.1 christos unsigned int num_fdes = get_num_sframe_fdes ();
640 1.1 christos unsigned int num_fres = get_num_sframe_fres ();
641 1.1 christos symbolS **fre_symbols = XNEWVEC (symbolS *, num_fres);
642 1.1 christos for (i = 0; i < num_fres; i++)
643 1.1 christos fre_symbols[i] = symbol_temp_make ();
644 1.1 christos
645 1.1 christos end_of_frame_hdr = symbol_temp_make ();
646 1.1 christos start_of_fre_section = symbol_temp_make ();
647 1.1 christos start_of_func_desc_section = symbol_temp_make ();
648 1.1 christos end_of_frame_section = symbol_temp_make ();
649 1.1 christos
650 1.1 christos /* Output the preamble of SFrame section. */
651 1.1 christos out_two (SFRAME_MAGIC);
652 1.1 christos out_one (SFRAME_VERSION);
653 1.1 christos out_one (sframe_flags);
654 1.1 christos /* abi/arch. */
655 1.1 christos #ifdef sframe_get_abi_arch
656 1.1 christos abi_arch = sframe_get_abi_arch ();
657 1.1 christos #endif
658 1.1 christos gas_assert (abi_arch);
659 1.1 christos out_one (abi_arch);
660 1.1 christos
661 1.1 christos /* Offset for the BP register from CFA. Neither of the AMD64 or AAPCS64
662 1.1 christos ABIs have a fixed offset for the BP register from the CFA. This may be
663 1.1 christos useful in future (but not without additional support in the toolchain)
664 1.1 christos for specialized handling/encoding for cases where, for example,
665 1.1 christos -fno-omit-frame-pointer is used. */
666 1.1 christos out_one (fixed_bp_offset);
667 1.1 christos
668 1.1 christos /* Offset for the return address from CFA is fixed for some ABIs
669 1.1 christos (e.g., AMD64), output a SFRAME_CFA_FIXED_RA_INVALID otherwise. */
670 1.1 christos #ifdef sframe_ra_tracking_p
671 1.1 christos if (!sframe_ra_tracking_p ())
672 1.1 christos fixed_ra_offset = sframe_cfa_ra_offset ();
673 1.1 christos #endif
674 1.1 christos out_one (fixed_ra_offset);
675 1.1 christos
676 1.1 christos /* None of the AMD64, or AARCH64 ABIs need the auxiliary header.
677 1.1 christos When the need does arise to use this field, the appropriate backend
678 1.1 christos must provide this information. */
679 1.1 christos out_one (0); /* Auxiliary SFrame header length. */
680 1.1 christos
681 1.1 christos out_four (num_fdes); /* Number of FDEs. */
682 1.1 christos out_four (num_fres); /* Number of FREs. */
683 1.1 christos
684 1.1 christos /* FRE sub-section len. */
685 1.1 christos exp.X_op = O_subtract;
686 1.1 christos exp.X_add_symbol = end_of_frame_section;
687 1.1 christos exp.X_op_symbol = start_of_fre_section;
688 1.1 christos exp.X_add_number = 0;
689 1.1 christos emit_expr (&exp, addr_size);
690 1.1 christos
691 1.1 christos /* Offset of Function Index sub-section. */
692 1.1 christos exp.X_op = O_subtract;
693 1.1 christos exp.X_add_symbol = end_of_frame_hdr;
694 1.1 christos exp.X_op_symbol = start_of_func_desc_section;
695 1.1 christos exp.X_add_number = 0;
696 1.1 christos emit_expr (&exp, addr_size);
697 1.1 christos
698 1.1 christos /* Offset of FRE sub-section. */
699 1.1 christos exp.X_op = O_subtract;
700 1.1 christos exp.X_add_symbol = start_of_fre_section;
701 1.1 christos exp.X_op_symbol = end_of_frame_hdr;
702 1.1 christos exp.X_add_number = 0;
703 1.1 christos emit_expr (&exp, addr_size);
704 1.1 christos
705 1.1 christos symbol_set_value_now (end_of_frame_hdr);
706 1.1 christos symbol_set_value_now (start_of_func_desc_section);
707 1.1 christos
708 1.1 christos /* Output the SFrame function descriptor entries. */
709 1.1 christos i = 0;
710 1.1 christos for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
711 1.1 christos {
712 1.1 christos output_sframe_funcdesc (start_of_fre_section,
713 1.1 christos fre_symbols[i], sframe_fde);
714 1.1 christos i += sframe_fde->num_fres;
715 1.1 christos }
716 1.1 christos
717 1.1 christos symbol_set_value_now (start_of_fre_section);
718 1.1 christos
719 1.1 christos /* Output the SFrame FREs. */
720 1.1 christos i = 0;
721 1.1 christos sframe_fde = all_sframe_fdes;
722 1.1 christos
723 1.1 christos for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
724 1.1 christos {
725 1.1 christos for (sframe_fre = sframe_fde->sframe_fres;
726 1.1 christos sframe_fre;
727 1.1 christos sframe_fre = sframe_fre->next)
728 1.1 christos {
729 1.1 christos symbol_set_value_now (fre_symbols[i]);
730 1.1 christos output_sframe_row_entry (get_dw_fde_start_addrS (sframe_fde->dw_fde),
731 1.1 christos get_dw_fde_end_addrS (sframe_fde->dw_fde),
732 1.1 christos sframe_fre);
733 1.1 christos i++;
734 1.1 christos }
735 1.1 christos }
736 1.1 christos
737 1.1 christos symbol_set_value_now (end_of_frame_section);
738 1.1 christos
739 1.1 christos gas_assert (i == num_fres);
740 1.1 christos
741 1.1 christos free (fre_symbols);
742 1.1 christos fre_symbols = NULL;
743 1.1 christos }
744 1.1 christos
745 1.1 christos /* List of SFrame FDE entries. */
746 1.1 christos
747 1.1 christos struct sframe_func_entry *all_sframe_fdes;
748 1.1 christos
749 1.1 christos /* Tail of the list to add to. */
750 1.1 christos
751 1.1 christos static struct sframe_func_entry **last_sframe_fde = &all_sframe_fdes;
752 1.1 christos
753 1.1 christos static unsigned int
754 1.1 christos get_num_sframe_fdes (void)
755 1.1 christos {
756 1.1 christos struct sframe_func_entry *sframe_fde;
757 1.1 christos unsigned int total_fdes = 0;
758 1.1 christos
759 1.1 christos for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
760 1.1 christos total_fdes++;
761 1.1 christos
762 1.1 christos return total_fdes;
763 1.1 christos }
764 1.1 christos
765 1.1 christos /* Get the total number of SFrame row entries across the FDEs. */
766 1.1 christos
767 1.1 christos static unsigned int
768 1.1 christos get_num_sframe_fres (void)
769 1.1 christos {
770 1.1 christos struct sframe_func_entry *sframe_fde;
771 1.1 christos unsigned int total_fres = 0;
772 1.1 christos
773 1.1 christos for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
774 1.1 christos total_fres += sframe_fde->num_fres;
775 1.1 christos
776 1.1 christos return total_fres;
777 1.1 christos }
778 1.1 christos
779 1.1 christos /* Allocate an SFrame FDE. */
780 1.1 christos
781 1.1 christos static struct sframe_func_entry*
782 1.1 christos sframe_fde_alloc (void)
783 1.1 christos {
784 1.1 christos struct sframe_func_entry *sframe_fde = XCNEW (struct sframe_func_entry);
785 1.1 christos return sframe_fde;
786 1.1 christos }
787 1.1 christos
788 1.1 christos /* Link the SFrame FDE in. */
789 1.1 christos
790 1.1 christos static int
791 1.1 christos sframe_fde_link (struct sframe_func_entry *sframe_fde)
792 1.1 christos {
793 1.1 christos *last_sframe_fde = sframe_fde;
794 1.1 christos last_sframe_fde = &sframe_fde->next;
795 1.1 christos
796 1.1 christos return 0;
797 1.1 christos }
798 1.1 christos
799 1.1 christos /* Free up the SFrame FDE. */
800 1.1 christos
801 1.1 christos static void
802 1.1 christos sframe_fde_free (struct sframe_func_entry *sframe_fde)
803 1.1 christos {
804 1.1 christos XDELETE (sframe_fde);
805 1.1 christos sframe_fde = NULL;
806 1.1 christos }
807 1.1 christos
808 1.1 christos /* SFrame translation context functions. */
809 1.1 christos
810 1.1 christos /* Allocate a new SFrame translation context. */
811 1.1 christos
812 1.1 christos static struct sframe_xlate_ctx*
813 1.1 christos sframe_xlate_ctx_alloc (void)
814 1.1 christos {
815 1.1 christos struct sframe_xlate_ctx* xlate_ctx = XCNEW (struct sframe_xlate_ctx);
816 1.1 christos return xlate_ctx;
817 1.1 christos }
818 1.1 christos
819 1.1 christos /* Initialize the given SFrame translation context. */
820 1.1 christos
821 1.1 christos static void
822 1.1 christos sframe_xlate_ctx_init (struct sframe_xlate_ctx *xlate_ctx)
823 1.1 christos {
824 1.1 christos xlate_ctx->dw_fde = NULL;
825 1.1 christos xlate_ctx->first_fre = NULL;
826 1.1 christos xlate_ctx->last_fre = NULL;
827 1.1 christos xlate_ctx->cur_fre = NULL;
828 1.1 christos xlate_ctx->remember_fre = NULL;
829 1.1 christos xlate_ctx->num_xlate_fres = 0;
830 1.1 christos }
831 1.1 christos
832 1.1 christos /* Cleanup the given SFrame translation context. */
833 1.1 christos
834 1.1 christos static void
835 1.1 christos sframe_xlate_ctx_cleanup (struct sframe_xlate_ctx *xlate_ctx)
836 1.1 christos {
837 1.1 christos struct sframe_row_entry *fre, *fre_next;
838 1.1 christos
839 1.1 christos if (xlate_ctx->num_xlate_fres)
840 1.1 christos {
841 1.1 christos fre = xlate_ctx->first_fre;
842 1.1 christos while (fre)
843 1.1 christos {
844 1.1 christos fre_next = fre->next;
845 1.1 christos XDELETE (fre);
846 1.1 christos fre = fre_next;
847 1.1 christos }
848 1.1 christos }
849 1.1 christos
850 1.1 christos sframe_xlate_ctx_init (xlate_ctx);
851 1.1 christos }
852 1.1 christos
853 1.1 christos /* Transfer the state from the SFrame translation context to the SFrame FDE. */
854 1.1 christos
855 1.1 christos static void
856 1.1 christos sframe_xlate_ctx_finalize (struct sframe_xlate_ctx *xlate_ctx,
857 1.1 christos struct sframe_func_entry *sframe_fde)
858 1.1 christos {
859 1.1 christos sframe_fde->dw_fde = xlate_ctx->dw_fde;
860 1.1 christos sframe_fde->sframe_fres = xlate_ctx->first_fre;
861 1.1 christos sframe_fde->num_fres = xlate_ctx->num_xlate_fres;
862 1.1 christos }
863 1.1 christos
864 1.1 christos static struct sframe_row_entry*
865 1.1 christos sframe_row_entry_new (void)
866 1.1 christos {
867 1.1 christos struct sframe_row_entry *fre = XCNEW (struct sframe_row_entry);
868 1.1 christos /* Reset cfa_base_reg to -1. A value of 0 will imply some valid register
869 1.1 christos for the supported arches. */
870 1.1 christos fre->cfa_base_reg = -1;
871 1.1 christos fre->merge_candidate = true;
872 1.1 christos /* Reset the mangled RA status bit to zero by default. We will initialize it in
873 1.1 christos sframe_row_entry_initialize () with the sticky bit if set. */
874 1.1 christos fre->mangled_ra_p = false;
875 1.1 christos
876 1.1 christos return fre;
877 1.1 christos }
878 1.1 christos
879 1.1 christos /* Add the given FRE in the list of frame row entries in the given FDE
880 1.1 christos translation context. */
881 1.1 christos
882 1.1 christos static void
883 1.1 christos sframe_xlate_ctx_add_fre (struct sframe_xlate_ctx *xlate_ctx,
884 1.1 christos struct sframe_row_entry *fre)
885 1.1 christos {
886 1.1 christos gas_assert (xlate_ctx && fre);
887 1.1 christos
888 1.1 christos /* Add the frame row entry. */
889 1.1 christos if (!xlate_ctx->first_fre)
890 1.1 christos xlate_ctx->first_fre = fre;
891 1.1 christos else if (xlate_ctx->last_fre)
892 1.1 christos xlate_ctx->last_fre->next = fre;
893 1.1 christos
894 1.1 christos xlate_ctx->last_fre = fre;
895 1.1 christos
896 1.1 christos /* Keep track of the total number of SFrame frame row entries. */
897 1.1 christos xlate_ctx->num_xlate_fres++;
898 1.1 christos }
899 1.1 christos
900 1.1 christos /* A SFrame Frame Row Entry is self-sufficient in terms of stack tracing info
901 1.1 christos for a given PC. It contains information assimilated from multiple CFI
902 1.1 christos instructions, and hence, a new SFrame FRE is initialized with the data from
903 1.1 christos the previous known FRE, if any.
904 1.1 christos
905 1.1 christos Understandably, not all information (especially the instruction begin
906 1.1 christos and end boundaries) needs to be relayed. Hence, the caller of this API
907 1.1 christos must set the pc_begin and pc_end as applicable. */
908 1.1 christos
909 1.1 christos static void
910 1.1 christos sframe_row_entry_initialize (struct sframe_row_entry *cur_fre,
911 1.1 christos struct sframe_row_entry *prev_fre)
912 1.1 christos {
913 1.1 christos gas_assert (prev_fre);
914 1.1 christos cur_fre->cfa_base_reg = prev_fre->cfa_base_reg;
915 1.1 christos cur_fre->cfa_offset = prev_fre->cfa_offset;
916 1.1 christos cur_fre->bp_loc = prev_fre->bp_loc;
917 1.1 christos cur_fre->bp_offset = prev_fre->bp_offset;
918 1.1 christos cur_fre->ra_loc = prev_fre->ra_loc;
919 1.1 christos cur_fre->ra_offset = prev_fre->ra_offset;
920 1.1 christos /* Treat RA mangling as a sticky bit. It retains its value until another
921 1.1 christos .cfi_negate_ra_state is seen. */
922 1.1 christos cur_fre->mangled_ra_p = prev_fre->mangled_ra_p;
923 1.1 christos }
924 1.1 christos
925 1.1 christos /* Translate DW_CFA_advance_loc into SFrame context.
926 1.1 christos Return SFRAME_XLATE_OK if success. */
927 1.1 christos
928 1.1 christos static int
929 1.1 christos sframe_xlate_do_advance_loc (struct sframe_xlate_ctx *xlate_ctx,
930 1.1 christos struct cfi_insn_data *cfi_insn)
931 1.1 christos {
932 1.1 christos struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
933 1.1 christos /* Get the scratchpad FRE currently being updated as the cfi_insn's
934 1.1 christos get interpreted. This FRE eventually gets linked in into the
935 1.1 christos list of FREs for the specific function. */
936 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
937 1.1 christos
938 1.1 christos if (cur_fre)
939 1.1 christos {
940 1.1 christos if (!cur_fre->merge_candidate)
941 1.1 christos {
942 1.1 christos sframe_fre_set_end_addr (cur_fre, cfi_insn->u.ll.lab2);
943 1.1 christos
944 1.1 christos sframe_xlate_ctx_add_fre (xlate_ctx, cur_fre);
945 1.1 christos last_fre = xlate_ctx->last_fre;
946 1.1 christos
947 1.1 christos xlate_ctx->cur_fre = sframe_row_entry_new ();
948 1.1 christos cur_fre = xlate_ctx->cur_fre;
949 1.1 christos
950 1.1 christos if (last_fre)
951 1.1 christos sframe_row_entry_initialize (cur_fre, last_fre);
952 1.1 christos }
953 1.1 christos else
954 1.1 christos {
955 1.1 christos sframe_fre_set_end_addr (last_fre, cfi_insn->u.ll.lab2);
956 1.1 christos gas_assert (last_fre->merge_candidate == false);
957 1.1 christos }
958 1.1 christos }
959 1.1 christos else
960 1.1 christos {
961 1.1 christos xlate_ctx->cur_fre = sframe_row_entry_new ();
962 1.1 christos cur_fre = xlate_ctx->cur_fre;
963 1.1 christos }
964 1.1 christos
965 1.1 christos gas_assert (cur_fre);
966 1.1 christos sframe_fre_set_begin_addr (cur_fre, cfi_insn->u.ll.lab2);
967 1.1 christos
968 1.1 christos return SFRAME_XLATE_OK;
969 1.1 christos }
970 1.1 christos
971 1.1 christos /* Translate DW_CFA_def_cfa into SFrame context.
972 1.1 christos Return SFRAME_XLATE_OK if success. */
973 1.1 christos
974 1.1 christos static int
975 1.1 christos sframe_xlate_do_def_cfa (struct sframe_xlate_ctx *xlate_ctx,
976 1.1 christos struct cfi_insn_data *cfi_insn)
977 1.1 christos
978 1.1 christos {
979 1.1 christos /* Get the scratchpad FRE. This FRE will eventually get linked in. */
980 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
981 1.1 christos if (!cur_fre)
982 1.1 christos {
983 1.1 christos xlate_ctx->cur_fre = sframe_row_entry_new ();
984 1.1 christos cur_fre = xlate_ctx->cur_fre;
985 1.1 christos sframe_fre_set_begin_addr (cur_fre,
986 1.1 christos get_dw_fde_start_addrS (xlate_ctx->dw_fde));
987 1.1 christos }
988 1.1 christos /* Define the current CFA rule to use the provided register and
989 1.1 christos offset. */
990 1.1 christos sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
991 1.1 christos sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.ri.offset);
992 1.1 christos cur_fre->merge_candidate = false;
993 1.1 christos
994 1.1 christos return SFRAME_XLATE_OK;
995 1.1 christos }
996 1.1 christos
997 1.1 christos /* Translate DW_CFA_def_cfa_register into SFrame context.
998 1.1 christos Return SFRAME_XLATE_OK if success. */
999 1.1 christos
1000 1.1 christos static int
1001 1.1 christos sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
1002 1.1 christos struct cfi_insn_data *cfi_insn)
1003 1.1 christos {
1004 1.1 christos struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1005 1.1 christos /* Get the scratchpad FRE. This FRE will eventually get linked in. */
1006 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1007 1.1 christos gas_assert (cur_fre);
1008 1.1 christos /* Define the current CFA rule to use the provided register (but to
1009 1.1 christos keep the old offset). */
1010 1.1 christos sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
1011 1.1 christos sframe_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
1012 1.1 christos cur_fre->merge_candidate = false;
1013 1.1 christos
1014 1.1 christos return SFRAME_XLATE_OK;
1015 1.1 christos }
1016 1.1 christos
1017 1.1 christos /* Translate DW_CFA_def_cfa_offset into SFrame context.
1018 1.1 christos Return SFRAME_XLATE_OK if success. */
1019 1.1 christos
1020 1.1 christos static int
1021 1.1 christos sframe_xlate_do_def_cfa_offset (struct sframe_xlate_ctx *xlate_ctx,
1022 1.1 christos struct cfi_insn_data *cfi_insn)
1023 1.1 christos {
1024 1.1 christos /* The scratchpad FRE currently being updated with each cfi_insn
1025 1.1 christos being interpreted. This FRE eventually gets linked in into the
1026 1.1 christos list of FREs for the specific function. */
1027 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1028 1.1 christos
1029 1.1 christos gas_assert (cur_fre);
1030 1.1 christos /* Define the current CFA rule to use the provided offset (but to keep
1031 1.1 christos the old register). However, if the old register is not FP/SP,
1032 1.1 christos skip creating SFrame stack trace info for the function. */
1033 1.1 christos if ((cur_fre->cfa_base_reg == SFRAME_CFA_FP_REG)
1034 1.1 christos || (cur_fre->cfa_base_reg == SFRAME_CFA_SP_REG))
1035 1.1 christos {
1036 1.1 christos sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.i);
1037 1.1 christos cur_fre->merge_candidate = false;
1038 1.1 christos }
1039 1.1 christos else
1040 1.1 christos return SFRAME_XLATE_ERR_NOTREPRESENTED;
1041 1.1 christos
1042 1.1 christos return SFRAME_XLATE_OK;
1043 1.1 christos }
1044 1.1 christos
1045 1.1 christos /* Translate DW_CFA_offset into SFrame context.
1046 1.1 christos Return SFRAME_XLATE_OK if success. */
1047 1.1 christos
1048 1.1 christos static int
1049 1.1 christos sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
1050 1.1 christos struct cfi_insn_data *cfi_insn)
1051 1.1 christos {
1052 1.1 christos /* The scratchpad FRE currently being updated with each cfi_insn
1053 1.1 christos being interpreted. This FRE eventually gets linked in into the
1054 1.1 christos list of FREs for the specific function. */
1055 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1056 1.1 christos
1057 1.1 christos gas_assert (cur_fre);
1058 1.1 christos /* Change the rule for the register indicated by the register number to
1059 1.1 christos be the specified offset. */
1060 1.1 christos if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1061 1.1 christos {
1062 1.1 christos gas_assert (!cur_fre->base_reg);
1063 1.1 christos sframe_fre_set_bp_track (cur_fre, cfi_insn->u.ri.offset);
1064 1.1 christos cur_fre->merge_candidate = false;
1065 1.1 christos }
1066 1.1 christos #ifdef SFRAME_FRE_RA_TRACKING
1067 1.1 christos else if (sframe_ra_tracking_p ()
1068 1.1 christos && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1069 1.1 christos {
1070 1.1 christos sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
1071 1.1 christos cur_fre->merge_candidate = false;
1072 1.1 christos }
1073 1.1 christos #endif
1074 1.1 christos /* This is used to track changes to non-rsp registers, skip all others
1075 1.1 christos except FP / RA for now. */
1076 1.1 christos return SFRAME_XLATE_OK;
1077 1.1 christos }
1078 1.1 christos
1079 1.1 christos /* Translate DW_CFA_val_offset into SFrame context.
1080 1.1 christos Return SFRAME_XLATE_OK if success. */
1081 1.1 christos
1082 1.1 christos static int
1083 1.1 christos sframe_xlate_do_val_offset (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1084 1.1 christos struct cfi_insn_data *cfi_insn)
1085 1.1 christos {
1086 1.1 christos /* Previous value of register is CFA + offset. However, if the specified
1087 1.1 christos register is not interesting (FP or RA reg), the current DW_CFA_val_offset
1088 1.1 christos instruction can be safely skipped without sacrificing the asynchronicity of
1089 1.1 christos stack trace information. */
1090 1.1 christos if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1091 1.1 christos return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
1092 1.1 christos #ifdef SFRAME_FRE_RA_TRACKING
1093 1.1 christos else if (sframe_ra_tracking_p ()
1094 1.1 christos && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1095 1.1 christos return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
1096 1.1 christos #endif
1097 1.1 christos
1098 1.1 christos /* Safe to skip. */
1099 1.1 christos return SFRAME_XLATE_OK;
1100 1.1 christos }
1101 1.1 christos
1102 1.1 christos /* Translate DW_CFA_remember_state into SFrame context.
1103 1.1 christos Return SFRAME_XLATE_OK if success. */
1104 1.1 christos
1105 1.1 christos static int
1106 1.1 christos sframe_xlate_do_remember_state (struct sframe_xlate_ctx *xlate_ctx)
1107 1.1 christos {
1108 1.1 christos struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1109 1.1 christos
1110 1.1 christos /* If there is no FRE state to remember, nothing to do here. Return
1111 1.1 christos early with non-zero error code, this will cause no SFrame stack trace
1112 1.1 christos info for the function involved. */
1113 1.1 christos if (!last_fre)
1114 1.1 christos return SFRAME_XLATE_ERR_INVAL;
1115 1.1 christos
1116 1.1 christos if (!xlate_ctx->remember_fre)
1117 1.1 christos xlate_ctx->remember_fre = sframe_row_entry_new ();
1118 1.1 christos sframe_row_entry_initialize (xlate_ctx->remember_fre, last_fre);
1119 1.1 christos
1120 1.1 christos return SFRAME_XLATE_OK;
1121 1.1 christos }
1122 1.1 christos
1123 1.1 christos /* Translate DW_CFA_restore_state into SFrame context.
1124 1.1 christos Return SFRAME_XLATE_OK if success. */
1125 1.1 christos
1126 1.1 christos static int
1127 1.1 christos sframe_xlate_do_restore_state (struct sframe_xlate_ctx *xlate_ctx)
1128 1.1 christos {
1129 1.1 christos /* The scratchpad FRE currently being updated with each cfi_insn
1130 1.1 christos being interpreted. This FRE eventually gets linked in into the
1131 1.1 christos list of FREs for the specific function. */
1132 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1133 1.1 christos
1134 1.1 christos gas_assert (xlate_ctx->remember_fre);
1135 1.1 christos gas_assert (cur_fre && cur_fre->merge_candidate);
1136 1.1 christos
1137 1.1 christos /* Get the CFA state from the DW_CFA_remember_state insn. */
1138 1.1 christos sframe_row_entry_initialize (cur_fre, xlate_ctx->remember_fre);
1139 1.1 christos /* The PC boundaries of the current SFrame FRE are updated
1140 1.1 christos via other machinery. */
1141 1.1 christos cur_fre->merge_candidate = false;
1142 1.1 christos return SFRAME_XLATE_OK;
1143 1.1 christos }
1144 1.1 christos
1145 1.1 christos /* Translate DW_CFA_restore into SFrame context.
1146 1.1 christos Return SFRAME_XLATE_OK if success. */
1147 1.1 christos
1148 1.1 christos static int
1149 1.1 christos sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
1150 1.1 christos struct cfi_insn_data *cfi_insn)
1151 1.1 christos {
1152 1.1 christos struct sframe_row_entry *cie_fre = xlate_ctx->first_fre;
1153 1.1 christos /* The scratchpad FRE currently being updated with each cfi_insn
1154 1.1 christos being interpreted. This FRE eventually gets linked in into the
1155 1.1 christos list of FREs for the specific function. */
1156 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1157 1.1 christos
1158 1.1 christos /* Change the rule for the indicated register to the rule assigned to
1159 1.1 christos it by the initial_instructions in the CIE. */
1160 1.1 christos gas_assert (cie_fre);
1161 1.1 christos /* SFrame FREs track only CFA and FP / RA for backtracing purposes;
1162 1.1 christos skip the other .cfi_restore directives. */
1163 1.1 christos if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1164 1.1 christos {
1165 1.1 christos gas_assert (cur_fre);
1166 1.1 christos cur_fre->bp_loc = cie_fre->bp_loc;
1167 1.1 christos cur_fre->bp_offset = cie_fre->bp_offset;
1168 1.1 christos cur_fre->merge_candidate = false;
1169 1.1 christos }
1170 1.1 christos #ifdef SFRAME_FRE_RA_TRACKING
1171 1.1 christos else if (sframe_ra_tracking_p ()
1172 1.1 christos && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1173 1.1 christos {
1174 1.1 christos gas_assert (cur_fre);
1175 1.1 christos cur_fre->ra_loc = cie_fre->ra_loc;
1176 1.1 christos cur_fre->ra_offset = cie_fre->ra_offset;
1177 1.1 christos cur_fre->merge_candidate = false;
1178 1.1 christos }
1179 1.1 christos #endif
1180 1.1 christos return SFRAME_XLATE_OK;
1181 1.1 christos }
1182 1.1 christos
1183 1.1 christos /* Translate DW_CFA_GNU_window_save into SFrame context.
1184 1.1 christos Return SFRAME_XLATE_OK if success. */
1185 1.1 christos
1186 1.1 christos static int
1187 1.1 christos sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
1188 1.1 christos struct cfi_insn_data *cfi_insn ATTRIBUTE_UNUSED)
1189 1.1 christos {
1190 1.1 christos struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1191 1.1 christos
1192 1.1 christos gas_assert (cur_fre);
1193 1.1 christos /* Toggle the mangled RA status bit. */
1194 1.1 christos cur_fre->mangled_ra_p = !cur_fre->mangled_ra_p;
1195 1.1 christos cur_fre->merge_candidate = false;
1196 1.1 christos
1197 1.1 christos return SFRAME_XLATE_OK;
1198 1.1 christos }
1199 1.1 christos
1200 1.1 christos /* Process CFI_INSN and update the translation context with the FRE
1201 1.1 christos information.
1202 1.1 christos
1203 1.1 christos Returns an error code (sframe_xlate_err) if CFI_INSN is not successfully
1204 1.1 christos processed. */
1205 1.1 christos
1206 1.1 christos static int
1207 1.1 christos sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
1208 1.1 christos struct cfi_insn_data *cfi_insn)
1209 1.1 christos {
1210 1.1 christos int err = 0;
1211 1.1 christos
1212 1.1 christos /* Atleast one cfi_insn per FDE is expected. */
1213 1.1 christos gas_assert (cfi_insn);
1214 1.1 christos int op = cfi_insn->insn;
1215 1.1 christos
1216 1.1 christos switch (op)
1217 1.1 christos {
1218 1.1 christos case DW_CFA_advance_loc:
1219 1.1 christos err = sframe_xlate_do_advance_loc (xlate_ctx, cfi_insn);
1220 1.1 christos break;
1221 1.1 christos case DW_CFA_def_cfa:
1222 1.1 christos err = sframe_xlate_do_def_cfa (xlate_ctx, cfi_insn);
1223 1.1 christos break;
1224 1.1 christos case DW_CFA_def_cfa_register:
1225 1.1 christos err = sframe_xlate_do_def_cfa_register (xlate_ctx, cfi_insn);
1226 1.1 christos break;
1227 1.1 christos case DW_CFA_def_cfa_offset:
1228 1.1 christos err = sframe_xlate_do_def_cfa_offset (xlate_ctx, cfi_insn);
1229 1.1 christos break;
1230 1.1 christos case DW_CFA_offset:
1231 1.1 christos err = sframe_xlate_do_offset (xlate_ctx, cfi_insn);
1232 1.1 christos break;
1233 1.1 christos case DW_CFA_val_offset:
1234 1.1 christos err = sframe_xlate_do_val_offset (xlate_ctx, cfi_insn);
1235 1.1 christos break;
1236 1.1 christos case DW_CFA_remember_state:
1237 1.1 christos err = sframe_xlate_do_remember_state (xlate_ctx);
1238 1.1 christos break;
1239 1.1 christos case DW_CFA_restore_state:
1240 1.1 christos err = sframe_xlate_do_restore_state (xlate_ctx);
1241 1.1 christos break;
1242 1.1 christos case DW_CFA_restore:
1243 1.1 christos err = sframe_xlate_do_restore (xlate_ctx, cfi_insn);
1244 1.1 christos break;
1245 1.1 christos /* DW_CFA_AARCH64_negate_ra_state is multiplexed with
1246 1.1 christos DW_CFA_GNU_window_save. */
1247 1.1 christos case DW_CFA_GNU_window_save:
1248 1.1 christos err = sframe_xlate_do_gnu_window_save (xlate_ctx, cfi_insn);
1249 1.1 christos break;
1250 1.1 christos /* Other CFI opcodes are not processed at this time.
1251 1.1 christos These do not impact the coverage of the basic stack tracing
1252 1.1 christos information as conveyed in the SFrame format.
1253 1.1 christos - DW_CFA_register,
1254 1.1 christos - etc. */
1255 1.1 christos case DW_CFA_register:
1256 1.1 christos if (cfi_insn->u.rr.reg1 == SFRAME_CFA_SP_REG
1257 1.1 christos #ifdef SFRAME_FRE_RA_TRACKING
1258 1.1 christos || cfi_insn->u.rr.reg1 == SFRAME_CFA_RA_REG
1259 1.1 christos #endif
1260 1.1 christos || cfi_insn->u.rr.reg1 == SFRAME_CFA_FP_REG)
1261 1.1 christos err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1262 1.1 christos break;
1263 1.1 christos case DW_CFA_undefined:
1264 1.1 christos case DW_CFA_same_value:
1265 1.1 christos break;
1266 1.1 christos default:
1267 1.1 christos /* Following skipped operations do, however, impact the asynchronicity:
1268 1.1 christos - CFI_escape. */
1269 1.1 christos err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1270 1.1 christos }
1271 1.1 christos
1272 1.1 christos /* An error here will cause no SFrame FDE later. Warn the user because this
1273 1.1 christos will affect the overall coverage and hence, asynchronicity. */
1274 1.1 christos if (err)
1275 1.1 christos as_warn (_("skipping SFrame FDE due to DWARF CFI op %#x"), op);
1276 1.1 christos
1277 1.1 christos return err;
1278 1.1 christos }
1279 1.1 christos
1280 1.1 christos
1281 1.1 christos static int
1282 1.1 christos sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
1283 1.1 christos const struct fde_entry *dw_fde)
1284 1.1 christos {
1285 1.1 christos struct cfi_insn_data *cfi_insn;
1286 1.1 christos int err = SFRAME_XLATE_OK;
1287 1.1 christos
1288 1.1 christos xlate_ctx->dw_fde = dw_fde;
1289 1.1 christos
1290 1.1 christos /* If the return column is not RIP, SFrame format cannot represent it. */
1291 1.1 christos if (xlate_ctx->dw_fde->return_column != DWARF2_DEFAULT_RETURN_COLUMN)
1292 1.1 christos return SFRAME_XLATE_ERR_NOTREPRESENTED;
1293 1.1 christos
1294 1.1 christos /* Iterate over the CFIs and create SFrame FREs. */
1295 1.1 christos for (cfi_insn = dw_fde->data; cfi_insn; cfi_insn = cfi_insn->next)
1296 1.1 christos {
1297 1.1 christos /* Translate each CFI, and buffer the state in translation context. */
1298 1.1 christos err = sframe_do_cfi_insn (xlate_ctx, cfi_insn);
1299 1.1 christos if (err != SFRAME_XLATE_OK)
1300 1.1 christos {
1301 1.1 christos /* Skip generating SFrame stack trace info for the function if any
1302 1.1 christos offending CFI is encountered by sframe_do_cfi_insn (). */
1303 1.1 christos return err; /* Return the error code. */
1304 1.1 christos }
1305 1.1 christos }
1306 1.1 christos
1307 1.1 christos /* No errors encountered. */
1308 1.1 christos
1309 1.1 christos /* Link in the scratchpad FRE that the last few CFI insns helped create. */
1310 1.1 christos if (xlate_ctx->cur_fre)
1311 1.1 christos {
1312 1.1 christos sframe_xlate_ctx_add_fre (xlate_ctx, xlate_ctx->cur_fre);
1313 1.1 christos xlate_ctx->cur_fre = NULL;
1314 1.1 christos }
1315 1.1 christos /* Designate the end of the last SFrame FRE. */
1316 1.1 christos if (xlate_ctx->last_fre)
1317 1.1 christos {
1318 1.1 christos xlate_ctx->last_fre->pc_end
1319 1.1 christos = get_dw_fde_end_addrS (xlate_ctx->dw_fde);
1320 1.1 christos }
1321 1.1 christos
1322 1.1 christos return SFRAME_XLATE_OK;
1323 1.1 christos }
1324 1.1 christos
1325 1.1 christos /* Create SFrame stack trace info for all functions.
1326 1.1 christos
1327 1.1 christos This function consumes the already generated DWARF FDEs (by dw2gencfi) and
1328 1.1 christos generates data which is later emitted as stack trace information encoded in
1329 1.1 christos the SFrame format. */
1330 1.1 christos
1331 1.1 christos static void
1332 1.1 christos create_sframe_all (void)
1333 1.1 christos {
1334 1.1 christos struct fde_entry *dw_fde = NULL;
1335 1.1 christos struct sframe_func_entry *sframe_fde = NULL;
1336 1.1 christos
1337 1.1 christos struct sframe_xlate_ctx *xlate_ctx = sframe_xlate_ctx_alloc ();
1338 1.1 christos
1339 1.1 christos for (dw_fde = all_fde_data; dw_fde ; dw_fde = dw_fde->next)
1340 1.1 christos {
1341 1.1 christos sframe_fde = sframe_fde_alloc ();
1342 1.1 christos /* Initialize the translation context with information anew. */
1343 1.1 christos sframe_xlate_ctx_init (xlate_ctx);
1344 1.1 christos
1345 1.1 christos /* Process and link SFrame FDEs if no error. Also skip adding an SFrame
1346 1.1 christos FDE if it does not contain any SFrame FREs. There is little use of an
1347 1.1 christos SFrame FDE if there is no stack tracing information for the
1348 1.1 christos function. */
1349 1.1 christos int err = sframe_do_fde (xlate_ctx, dw_fde);
1350 1.1 christos if (err || xlate_ctx->num_xlate_fres == 0)
1351 1.1 christos {
1352 1.1 christos sframe_xlate_ctx_cleanup (xlate_ctx);
1353 1.1 christos sframe_fde_free (sframe_fde);
1354 1.1 christos }
1355 1.1 christos else
1356 1.1 christos {
1357 1.1 christos /* All done. Transfer the state from the SFrame translation
1358 1.1 christos context to the SFrame FDE. */
1359 1.1 christos sframe_xlate_ctx_finalize (xlate_ctx, sframe_fde);
1360 1.1 christos sframe_fde_link (sframe_fde);
1361 1.1 christos }
1362 1.1 christos }
1363 1.1 christos }
1364 1.1 christos
1365 1.1 christos void
1366 1.1 christos output_sframe (segT sframe_seg)
1367 1.1 christos {
1368 1.1 christos (void) sframe_seg;
1369 1.1 christos
1370 1.1 christos /* Setup the version specific access functions. */
1371 1.1 christos sframe_set_version (SFRAME_VERSION_2);
1372 1.1 christos
1373 1.1 christos /* Process all fdes and create SFrame stack trace information. */
1374 1.1 christos create_sframe_all ();
1375 1.1 christos
1376 1.1 christos output_sframe_internal ();
1377 1.1 christos }
1378 1.1 christos
1379 1.1 christos #else /* support_sframe_p */
1380 1.1 christos
1381 1.1 christos void
1382 1.1 christos output_sframe (segT sframe_seg ATTRIBUTE_UNUSED)
1383 1.1 christos {
1384 1.1 christos }
1385 1.1 christos
1386 1.1 christos #endif /* support_sframe_p */
1387