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