1 /* gen-sframe.c - Support for generating SFrame section.
2 Copyright (C) 2022 Free Software Foundation, Inc.
4 This file is part of GAS, the GNU Assembler.
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)
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.
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
24 #include "gen-sframe.h"
25 #include "dw2gencfi.h"
27 #ifdef support_sframe_p
29 /* By default, use 32-bit relocations from .sframe into .text. */
30 #ifndef SFRAME_RELOC_SIZE
31 # define SFRAME_RELOC_SIZE 4
34 /* Whether frame row entries track RA.
36 A target may not need return address tracking for stack unwinding. If it
37 does need the same, SFRAME_CFA_RA_REG must be defined with the return
38 address register number. */
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
46 /* SFrame FRE type selection optimization is an optimization for size.
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.
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.
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.
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.
63 This optimization (for size) is enabled by default. */
65 #ifndef SFRAME_FRE_TYPE_SELECTION_OPT
66 # define SFRAME_FRE_TYPE_SELECTION_OPT 1
69 /* Emit a single byte into the current segment. */
74 FRAG_APPEND_1_CHAR (byte);
77 /* Emit a two-byte word into the current segment. */
82 md_number_to_chars (frag_more (2), data, 2);
85 /* Emit a four byte word into the current segment. */
90 md_number_to_chars (frag_more (4), data, 4);
93 /* Get the start address symbol from the DWARF FDE. */
96 get_dw_fde_start_addrS (const struct fde_entry *dw_fde)
98 return dw_fde->start_address;
101 /* Get the start address symbol from the DWARF FDE. */
104 get_dw_fde_end_addrS (const struct fde_entry *dw_fde)
106 return dw_fde->end_address;
109 /* SFrame Frame Row Entry (FRE) related functions. */
112 sframe_fre_set_begin_addr (struct sframe_row_entry *fre, symbolS *beginS)
114 fre->pc_begin = beginS;
118 sframe_fre_set_end_addr (struct sframe_row_entry *fre, symbolS *endS)
124 sframe_fre_set_cfa_base_reg (struct sframe_row_entry *fre,
125 unsigned int cfa_base_reg)
127 fre->cfa_base_reg = cfa_base_reg;
128 fre->merge_candidate = false;
132 sframe_fre_set_cfa_offset (struct sframe_row_entry *fre,
135 fre->cfa_offset = cfa_offset;
136 fre->merge_candidate = false;
139 #ifdef SFRAME_FRE_RA_TRACKING
141 sframe_fre_set_ra_track (struct sframe_row_entry *fre, offsetT ra_offset)
143 fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK;
144 fre->ra_offset = ra_offset;
145 fre->merge_candidate = false;
150 sframe_fre_set_bp_track (struct sframe_row_entry *fre, offsetT bp_offset)
152 fre->bp_loc = SFRAME_FRE_ELEM_LOC_STACK;
153 fre->bp_offset = bp_offset;
154 fre->merge_candidate = false;
157 /* All stack offset values within an FRE are uniformly encoded in the same
158 number of bytes. The size of the stack offset values will, however, vary
161 #define VALUE_8BIT 0x7f
162 #define VALUE_16BIT 0x7fff
163 #define VALUE_32BIT 0x7fffffff
164 #define VALUE_64BIT 0x7fffffffffffffff
166 /* Given a signed offset, return the size in bytes needed to represent it. */
169 get_offset_size_in_bytes (offsetT value)
171 unsigned int size = 0;
173 if (value <= VALUE_8BIT && value >= (offsetT) -VALUE_8BIT)
175 else if (value <= VALUE_16BIT && value >= (offsetT) -VALUE_16BIT)
177 else if (value <= VALUE_32BIT && value >= (offsetT) -VALUE_32BIT)
179 else if ((sizeof (offsetT) > 4) && (value <= (offsetT) VALUE_64BIT
180 && value >= (offsetT) -VALUE_64BIT))
186 #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B 0 /* SFRAME_FRE_OFFSET_1B. */
187 #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B 1 /* SFRAME_FRE_OFFSET_2B. */
188 #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B 2 /* SFRAME_FRE_OFFSET_4B. */
189 #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B 3 /* Not supported in SFrame. */
190 #define SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_8B
192 /* Helper struct for mapping offset size to output functions. */
194 struct sframe_fre_offset_func_map
196 unsigned int offset_size;
197 void (*out_func)(int);
200 /* Given an OFFSET_SIZE, return the size in bytes needed to represent it. */
203 sframe_fre_offset_func_map_index (unsigned int offset_size)
205 unsigned int idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX;
209 case SFRAME_FRE_OFFSET_1B:
210 idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B;
212 case SFRAME_FRE_OFFSET_2B:
213 idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B;
215 case SFRAME_FRE_OFFSET_4B:
216 idx = SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B;
219 /* Not supported in SFrame. */
226 /* Mapping from offset size to the output function to emit the value. */
229 struct sframe_fre_offset_func_map
230 fre_offset_func_map[SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX+1] =
232 { SFRAME_FRE_OFFSET_1B, out_one },
233 { SFRAME_FRE_OFFSET_2B, out_two },
234 { SFRAME_FRE_OFFSET_4B, out_four },
235 { -1, NULL } /* Not Supported in SFrame. */
238 /* SFrame version specific operations access. */
240 static struct sframe_version_ops sframe_ver_ops;
242 /* SFrame (SFRAME_VERSION_1) set FRE info. */
245 sframe_v1_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
246 unsigned int offset_size)
248 unsigned char fre_info;
249 fre_info = SFRAME_V1_FRE_INFO (base_reg, num_offsets, offset_size);
253 /* SFrame (SFRAME_VERSION_1) set function info. */
255 sframe_v1_set_func_info (unsigned int fde_type, unsigned int fre_type)
257 unsigned char func_info;
258 func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
262 /* SFrame version specific operations setup. */
265 sframe_set_version (uint32_t sframe_version __attribute__((unused)))
267 sframe_ver_ops.format_version = SFRAME_VERSION_1;
269 sframe_ver_ops.set_fre_info = sframe_v1_set_fre_info;
271 sframe_ver_ops.set_func_info = sframe_v1_set_func_info;
274 /* SFrame set FRE info. */
277 sframe_set_fre_info (unsigned int base_reg, unsigned int num_offsets,
278 unsigned int offset_size)
280 return sframe_ver_ops.set_fre_info (base_reg, num_offsets,
284 /* SFrame set func info. */
286 ATTRIBUTE_UNUSED static unsigned char
287 sframe_set_func_info (unsigned int fde_type, unsigned int fre_type)
289 return sframe_ver_ops.set_func_info (fde_type, fre_type);
292 /* Get the number of SFrame FDEs for the current file. */
295 get_num_sframe_fdes (void);
297 /* Get the number of SFrame frame row entries for the current file. */
300 get_num_sframe_fres (void);
302 /* Get CFA base register ID as represented in SFrame Frame Row Entry. */
305 get_fre_base_reg_id (struct sframe_row_entry *sframe_fre)
307 unsigned int cfi_insn_cfa_base_reg = sframe_fre->cfa_base_reg;
308 unsigned fre_base_reg = SFRAME_BASE_REG_SP;
310 if (cfi_insn_cfa_base_reg == SFRAME_CFA_FP_REG)
311 fre_base_reg = SFRAME_BASE_REG_FP;
313 /* Only one bit is reserved in SFRAME_VERSION_1. */
314 gas_assert (fre_base_reg == SFRAME_BASE_REG_SP
315 || fre_base_reg == SFRAME_BASE_REG_FP);
320 /* Get number of offsets necessary for the SFrame Frame Row Entry. */
323 get_fre_num_offsets (struct sframe_row_entry *sframe_fre)
325 /* Atleast 1 must always be present (to recover CFA). */
326 unsigned int fre_num_offsets = 1;
328 if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
330 #ifdef SFRAME_FRE_RA_TRACKING
331 if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
334 return fre_num_offsets;
337 /* Get the minimum necessary offset size (in bytes) for this
338 SFrame frame row entry. */
341 sframe_get_fre_offset_size (struct sframe_row_entry *sframe_fre)
343 unsigned int max_offset_size = 0;
344 unsigned int cfa_offset_size = 0;
345 unsigned int bp_offset_size = 0;
346 unsigned int ra_offset_size = 0;
348 unsigned int fre_offset_size = 0;
350 /* What size of offsets appear in this frame row entry. */
351 cfa_offset_size = get_offset_size_in_bytes (sframe_fre->cfa_offset);
352 if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
353 bp_offset_size = get_offset_size_in_bytes (sframe_fre->bp_offset);
354 #ifdef SFRAME_FRE_RA_TRACKING
355 if (sframe_ra_tracking_p ()
356 && sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
357 ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
360 /* Get the maximum size needed to represent the offsets. */
361 max_offset_size = cfa_offset_size;
362 if (bp_offset_size > max_offset_size)
363 max_offset_size = bp_offset_size;
364 if (ra_offset_size > max_offset_size)
365 max_offset_size = ra_offset_size;
367 gas_assert (max_offset_size);
369 switch (max_offset_size)
372 fre_offset_size = SFRAME_FRE_OFFSET_1B;
375 fre_offset_size = SFRAME_FRE_OFFSET_2B;
378 fre_offset_size = SFRAME_FRE_OFFSET_4B;
381 /* Offset of size 8 bytes is not supported in SFrame format
383 as_fatal (_("SFrame unsupported offset value\n"));
387 return fre_offset_size;
390 #if SFRAME_FRE_TYPE_SELECTION_OPT
392 /* Create a composite exression CEXP (for SFrame FRE start address) such that:
394 exp = <val> OP_absent <width>, where,
396 - <val> and <width> are themselves expressionS.
397 - <val> stores the expression which when evaluated gives the value of the
398 start address offset of the FRE.
399 - <width> stores the expression when evaluated gives the number of bytes
400 needed to encode the start address offset of the FRE.
402 The use of OP_absent as the X_op_symbol helps identify this expression
403 later when fragments are fixed up. */
406 create_fre_start_addr_exp (expressionS *cexp, symbolS *fre_pc_begin,
407 symbolS *fde_start_address,
408 symbolS *fde_end_address)
413 /* val expression stores the FDE start address offset from the start PC
415 val.X_op = O_subtract;
416 val.X_add_symbol = fre_pc_begin;
417 val.X_op_symbol = fde_start_address;
418 val.X_add_number = 0;
420 /* width expressions stores the size of the function. This is used later
421 to determine the number of bytes to be used to encode the FRE start
422 address of each FRE of the function. */
423 width.X_op = O_subtract;
424 width.X_add_symbol = fde_end_address;
425 width.X_op_symbol = fde_start_address;
426 width.X_add_number = 0;
428 cexp->X_op = O_absent;
429 cexp->X_add_symbol = make_expr_symbol (&val);
430 cexp->X_op_symbol = make_expr_symbol (&width);
431 cexp->X_add_number = 0;
434 /* Create a composite exression CEXP (for SFrame FDE function info) such that:
436 exp = <rest_of_func_info> OP_modulus <width>, where,
438 - <rest_of_func_info> and <width> are themselves expressionS.
439 - <rest_of_func_info> stores a constant expression where X_add_number is
440 used to stash away the func_info. The upper 4-bits of the func_info are copied
441 back to the resulting byte by the fragment fixup logic.
442 - <width> stores the expression when evaluated gives the size of the
443 funtion in number of bytes.
445 The use of OP_modulus as the X_op_symbol helps identify this expression
446 later when fragments are fixed up. */
449 create_func_info_exp (expressionS *cexp, symbolS *dw_fde_end_addrS,
450 symbolS *dw_fde_start_addrS, uint8_t func_info)
453 expressionS rest_of_func_info;
455 width.X_op = O_subtract;
456 width.X_add_symbol = dw_fde_end_addrS;
457 width.X_op_symbol = dw_fde_start_addrS;
458 width.X_add_number = 0;
460 rest_of_func_info.X_op = O_constant;
461 rest_of_func_info.X_add_number = func_info;
463 cexp->X_op = O_modulus;
464 cexp->X_add_symbol = make_expr_symbol (&rest_of_func_info);
465 cexp->X_op_symbol = make_expr_symbol (&width);
466 cexp->X_add_number = 0;
472 output_sframe_row_entry (symbolS *fde_start_addr,
473 symbolS *fde_end_addr,
474 struct sframe_row_entry *sframe_fre)
476 unsigned char fre_info;
477 unsigned int fre_num_offsets;
478 unsigned int fre_offset_size;
479 unsigned int fre_base_reg;
481 unsigned int fre_addr_size;
483 unsigned int idx = 0;
484 unsigned int fre_write_offsets = 0;
486 fre_addr_size = 4; /* 4 bytes by default. FIXME tie it to fre_type? */
488 /* SFrame FRE Start Address. */
489 #if SFRAME_FRE_TYPE_SELECTION_OPT
490 create_fre_start_addr_exp (&exp, sframe_fre->pc_begin, fde_start_addr,
492 frag_grow (fre_addr_size);
493 frag_var (rs_sframe, fre_addr_size, 0, (relax_substateT) 0,
494 make_expr_symbol (&exp), 0, (char *) frag_now);
496 gas_assert (fde_end_addr);
497 exp.X_op = O_subtract;
498 exp.X_add_symbol = sframe_fre->pc_begin; /* to. */
499 exp.X_op_symbol = fde_start_addr; /* from. */
500 exp.X_add_number = 0;
501 emit_expr (&exp, fre_addr_size);
504 /* Create the fre_info using the CFA base register, number of offsets and max
505 size of offset in this frame row entry. */
506 fre_base_reg = get_fre_base_reg_id (sframe_fre);
507 fre_num_offsets = get_fre_num_offsets (sframe_fre);
508 fre_offset_size = sframe_get_fre_offset_size (sframe_fre);
509 fre_info = sframe_set_fre_info (fre_base_reg, fre_num_offsets,
513 idx = sframe_fre_offset_func_map_index (fre_offset_size);
514 gas_assert (idx < SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX);
516 /* Write out the offsets in order - cfa, bp, ra. */
517 fre_offset_func_map[idx].out_func (sframe_fre->cfa_offset);
520 #ifdef SFRAME_FRE_RA_TRACKING
521 if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
523 fre_offset_func_map[idx].out_func (sframe_fre->ra_offset);
527 if (sframe_fre->bp_loc == SFRAME_FRE_ELEM_LOC_STACK)
529 fre_offset_func_map[idx].out_func (sframe_fre->bp_offset);
533 /* Check if the expected number offsets have been written out
535 gas_assert (fre_write_offsets == fre_num_offsets);
539 output_sframe_funcdesc (symbolS *start_of_fre_section,
541 struct sframe_func_entry *sframe_fde)
544 unsigned int addr_size;
545 symbolS *dw_fde_start_addrS, *dw_fde_end_addrS;
547 addr_size = SFRAME_RELOC_SIZE;
548 dw_fde_start_addrS = get_dw_fde_start_addrS (sframe_fde->dw_fde);
549 dw_fde_end_addrS = get_dw_fde_end_addrS (sframe_fde->dw_fde);
551 /* Start address of the function. */
552 exp.X_op = O_subtract;
553 exp.X_add_symbol = dw_fde_start_addrS; /* to location. */
554 exp.X_op_symbol = symbol_temp_new_now (); /* from location. */
555 exp.X_add_number = 0;
556 emit_expr (&exp, addr_size);
558 /* Size of the function in bytes. */
559 exp.X_op = O_subtract;
560 exp.X_add_symbol = dw_fde_end_addrS;
561 exp.X_op_symbol = dw_fde_start_addrS;
562 exp.X_add_number = 0;
563 emit_expr (&exp, addr_size);
565 /* Offset to the first frame row entry. */
566 exp.X_op = O_subtract;
567 exp.X_add_symbol = fre_symbol; /* Minuend. */
568 exp.X_op_symbol = start_of_fre_section; /* Subtrahend. */
569 exp.X_add_number = 0;
570 emit_expr (&exp, addr_size);
572 /* Number of FREs. */
573 out_four (sframe_fde->num_fres);
575 /* SFrame FDE function info. */
576 unsigned char func_info;
577 func_info = sframe_set_func_info (SFRAME_FDE_TYPE_PCINC,
578 SFRAME_FRE_TYPE_ADDR4);
579 #if SFRAME_FRE_TYPE_SELECTION_OPT
581 create_func_info_exp (&cexp, dw_fde_end_addrS, dw_fde_start_addrS,
583 frag_grow (1); /* Size of func info is unsigned char. */
584 frag_var (rs_sframe, 1, 0, (relax_substateT) 0,
585 make_expr_symbol (&cexp), 0, (char *) frag_now);
592 output_sframe_internal (void)
597 symbolS *end_of_frame_hdr;
598 symbolS *end_of_frame_section;
599 symbolS *start_of_func_desc_section;
600 symbolS *start_of_fre_section;
601 struct sframe_func_entry *sframe_fde;
602 struct sframe_row_entry *sframe_fre;
603 unsigned char abi_arch = 0;
604 int fixed_bp_offset = SFRAME_CFA_FIXED_FP_INVALID;
605 int fixed_ra_offset = SFRAME_CFA_FIXED_RA_INVALID;
606 unsigned int addr_size;
608 addr_size = SFRAME_RELOC_SIZE;
610 /* The function desciptor entries as dumped by the assembler are not
612 unsigned char sframe_flags = 0;
613 sframe_flags |= !SFRAME_F_FDE_SORTED;
615 unsigned int num_fdes = get_num_sframe_fdes ();
616 unsigned int num_fres = get_num_sframe_fres ();
617 symbolS **fre_symbols = XNEWVEC (symbolS *, num_fres);
618 for (i = 0; i < num_fres; i++)
619 fre_symbols[i] = symbol_temp_make ();
621 end_of_frame_hdr = symbol_temp_make ();
622 start_of_fre_section = symbol_temp_make ();
623 start_of_func_desc_section = symbol_temp_make ();
624 end_of_frame_section = symbol_temp_make ();
626 /* Output the preamble of SFrame section. */
627 out_two (SFRAME_MAGIC);
628 out_one (SFRAME_VERSION);
629 out_one (sframe_flags);
631 #ifdef sframe_get_abi_arch
632 abi_arch = sframe_get_abi_arch ();
634 gas_assert (abi_arch);
637 /* Offset for the BP register from CFA. Neither of the AMD64 or AAPCS64
638 ABIs have a fixed offset for the BP register from the CFA. This may be
639 useful in future (but not without additional support in the toolchain)
640 for specialized handling/encoding for cases where, for example,
641 -fno-omit-frame-pointer is used. */
642 out_one (fixed_bp_offset);
644 /* Offset for the return address from CFA is fixed for some ABIs
645 (e.g., AMD64), output a zero otherwise. */
646 #ifdef sframe_ra_tracking_p
647 if (!sframe_ra_tracking_p ())
648 fixed_ra_offset = sframe_cfa_ra_offset ();
650 out_one (fixed_ra_offset);
652 /* None of the AMD64, or AARCH64 ABIs need the auxilliary header.
653 When the need does arise to use this field, the appropriate backend
654 must provide this information. */
655 out_one (0); /* Auxilliary SFrame header length. */
657 out_four (num_fdes); /* Number of FDEs. */
658 out_four (num_fres); /* Number of FREs. */
660 /* FRE sub-section len. */
661 exp.X_op = O_subtract;
662 exp.X_add_symbol = end_of_frame_section;
663 exp.X_op_symbol = start_of_fre_section;
664 exp.X_add_number = 0;
665 emit_expr (&exp, addr_size);
667 /* Offset of Function Index sub-section. */
668 exp.X_op = O_subtract;
669 exp.X_add_symbol = end_of_frame_hdr;
670 exp.X_op_symbol = start_of_func_desc_section;
671 exp.X_add_number = 0;
672 emit_expr (&exp, addr_size);
674 /* Offset of FRE sub-section. */
675 exp.X_op = O_subtract;
676 exp.X_add_symbol = start_of_fre_section;
677 exp.X_op_symbol = end_of_frame_hdr;
678 exp.X_add_number = 0;
679 emit_expr (&exp, addr_size);
681 symbol_set_value_now (end_of_frame_hdr);
682 symbol_set_value_now (start_of_func_desc_section);
684 /* Output the SFrame function descriptor entries. */
686 for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
688 output_sframe_funcdesc (start_of_fre_section,
689 fre_symbols[i], sframe_fde);
690 i += sframe_fde->num_fres;
693 symbol_set_value_now (start_of_fre_section);
695 /* Output the SFrame FREs. */
697 sframe_fde = all_sframe_fdes;
699 for (sframe_fde = all_sframe_fdes; sframe_fde; sframe_fde = sframe_fde->next)
701 for (sframe_fre = sframe_fde->sframe_fres;
703 sframe_fre = sframe_fre->next)
705 symbol_set_value_now (fre_symbols[i]);
706 output_sframe_row_entry (get_dw_fde_start_addrS (sframe_fde->dw_fde),
707 get_dw_fde_end_addrS (sframe_fde->dw_fde),
713 symbol_set_value_now (end_of_frame_section);
715 gas_assert (i == num_fres);
721 /* List of SFrame FDE entries. */
723 struct sframe_func_entry *all_sframe_fdes;
725 /* Tail of the list to add to. */
727 static struct sframe_func_entry **last_sframe_fde = &all_sframe_fdes;
730 get_num_sframe_fdes (void)
732 struct sframe_func_entry *sframe_fde;
733 unsigned int total_fdes = 0;
735 for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
741 /* Get the total number of SFrame row entries across the FDEs. */
744 get_num_sframe_fres (void)
746 struct sframe_func_entry *sframe_fde;
747 unsigned int total_fres = 0;
749 for (sframe_fde = all_sframe_fdes; sframe_fde ; sframe_fde = sframe_fde->next)
750 total_fres += sframe_fde->num_fres;
755 /* Allocate an SFrame FDE. */
757 static struct sframe_func_entry*
758 sframe_fde_alloc (void)
760 struct sframe_func_entry *sframe_fde = XCNEW (struct sframe_func_entry);
764 /* Link the SFrame FDE in. */
767 sframe_fde_link (struct sframe_func_entry *sframe_fde)
769 *last_sframe_fde = sframe_fde;
770 last_sframe_fde = &sframe_fde->next;
775 /* Free up the SFrame FDE. */
778 sframe_fde_free (struct sframe_func_entry *sframe_fde)
780 XDELETE (sframe_fde);
784 /* SFrame translation context functions. */
786 /* Allocate a new SFrame translation context. */
788 static struct sframe_xlate_ctx*
789 sframe_xlate_ctx_alloc (void)
791 struct sframe_xlate_ctx* xlate_ctx = XCNEW (struct sframe_xlate_ctx);
795 /* Initialize the given SFrame translation context. */
798 sframe_xlate_ctx_init (struct sframe_xlate_ctx *xlate_ctx)
800 xlate_ctx->dw_fde = NULL;
801 xlate_ctx->first_fre = NULL;
802 xlate_ctx->last_fre = NULL;
803 xlate_ctx->cur_fre = NULL;
804 xlate_ctx->remember_fre = NULL;
805 xlate_ctx->num_xlate_fres = 0;
808 /* Cleanup the given SFrame translation context. */
811 sframe_xlate_ctx_cleanup (struct sframe_xlate_ctx *xlate_ctx)
813 struct sframe_row_entry *fre, *fre_next;
815 if (xlate_ctx->num_xlate_fres)
817 fre = xlate_ctx->first_fre;
820 fre_next = fre->next;
826 sframe_xlate_ctx_init (xlate_ctx);
829 /* Transfer the state from the SFrame translation context to the SFrame FDE. */
832 sframe_xlate_ctx_finalize (struct sframe_xlate_ctx *xlate_ctx,
833 struct sframe_func_entry *sframe_fde)
835 sframe_fde->dw_fde = xlate_ctx->dw_fde;
836 sframe_fde->sframe_fres = xlate_ctx->first_fre;
837 sframe_fde->num_fres = xlate_ctx->num_xlate_fres;
840 static struct sframe_row_entry*
841 sframe_row_entry_new (void)
843 struct sframe_row_entry *fre = XCNEW (struct sframe_row_entry);
844 /* Reset cfa_base_reg to -1. A value of 0 will imply some valid register
845 for the supported arches. */
846 fre->cfa_base_reg = -1;
847 fre->merge_candidate = true;
852 /* Add the given FRE in the list of frame row entries in the given FDE
853 translation context. */
856 sframe_xlate_ctx_add_fre (struct sframe_xlate_ctx *xlate_ctx,
857 struct sframe_row_entry *fre)
859 gas_assert (xlate_ctx && fre);
861 /* Add the frame row entry. */
862 if (!xlate_ctx->first_fre)
863 xlate_ctx->first_fre = fre;
864 else if (xlate_ctx->last_fre)
865 xlate_ctx->last_fre->next = fre;
867 xlate_ctx->last_fre = fre;
869 /* Keep track of the total number of SFrame frame row entries. */
870 xlate_ctx->num_xlate_fres++;
873 /* A SFrame Frame Row Entry is self-sufficient in terms of unwind information
874 for a given PC. It contains information assimilated from multiple CFI
875 instructions, and hence, a new SFrame FRE is initialized with the data from
876 the previous known FRE, if any.
878 Understandably, not all information (especially the instruction begin
879 and end boundaries) needs to be relayed. Hence, the caller of this API
880 must set the pc_begin and pc_end as applicable. */
883 sframe_row_entry_initialize (struct sframe_row_entry *cur_fre,
884 struct sframe_row_entry *prev_fre)
886 gas_assert (prev_fre);
887 cur_fre->cfa_base_reg = prev_fre->cfa_base_reg;
888 cur_fre->cfa_offset = prev_fre->cfa_offset;
889 cur_fre->bp_loc = prev_fre->bp_loc;
890 cur_fre->bp_offset = prev_fre->bp_offset;
891 cur_fre->ra_loc = prev_fre->ra_loc;
892 cur_fre->ra_offset = prev_fre->ra_offset;
895 /* Translate DW_CFA_advance_loc into SFrame context.
896 Return SFRAME_XLATE_OK if success. */
899 sframe_xlate_do_advance_loc (struct sframe_xlate_ctx *xlate_ctx,
900 struct cfi_insn_data *cfi_insn)
902 struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
903 /* Get the scratchpad FRE currently being updated as the cfi_insn's
904 get interpreted. This FRE eventually gets linked in into the
905 list of FREs for the specific function. */
906 struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
910 if (!cur_fre->merge_candidate)
912 sframe_fre_set_end_addr (cur_fre, cfi_insn->u.ll.lab2);
914 sframe_xlate_ctx_add_fre (xlate_ctx, cur_fre);
915 last_fre = xlate_ctx->last_fre;
917 xlate_ctx->cur_fre = sframe_row_entry_new ();
918 cur_fre = xlate_ctx->cur_fre;
921 sframe_row_entry_initialize (cur_fre, last_fre);
925 sframe_fre_set_end_addr (last_fre, cfi_insn->u.ll.lab2);
926 gas_assert (last_fre->merge_candidate == false);
931 xlate_ctx->cur_fre = sframe_row_entry_new ();
932 cur_fre = xlate_ctx->cur_fre;
935 gas_assert (cur_fre);
936 sframe_fre_set_begin_addr (cur_fre, cfi_insn->u.ll.lab2);
938 return SFRAME_XLATE_OK;
941 /* Translate DW_CFA_def_cfa into SFrame context.
942 Return SFRAME_XLATE_OK if success. */
945 sframe_xlate_do_def_cfa (struct sframe_xlate_ctx *xlate_ctx,
946 struct cfi_insn_data *cfi_insn)
949 /* Get the scratchpad FRE. This FRE will eventually get linked in. */
950 struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
953 xlate_ctx->cur_fre = sframe_row_entry_new ();
954 cur_fre = xlate_ctx->cur_fre;
955 sframe_fre_set_begin_addr (cur_fre,
956 get_dw_fde_start_addrS (xlate_ctx->dw_fde));
958 /* Define the current CFA rule to use the provided register and
960 sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
961 sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.ri.offset);
962 cur_fre->merge_candidate = false;
964 return SFRAME_XLATE_OK;
967 /* Translate DW_CFA_def_cfa_register into SFrame context.
968 Return SFRAME_XLATE_OK if success. */
971 sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx *xlate_ctx,
972 struct cfi_insn_data *cfi_insn)
974 struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
975 /* Get the scratchpad FRE. This FRE will eventually get linked in. */
976 struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
977 gas_assert (cur_fre);
978 /* Define the current CFA rule to use the provided register (but to
979 keep the old offset). */
980 sframe_fre_set_cfa_base_reg (cur_fre, cfi_insn->u.ri.reg);
981 sframe_fre_set_cfa_offset (cur_fre, last_fre->cfa_offset);
982 cur_fre->merge_candidate = false;
984 return SFRAME_XLATE_OK;
987 /* Translate DW_CFA_def_cfa_offset into SFrame context.
988 Return SFRAME_XLATE_OK if success. */
991 sframe_xlate_do_def_cfa_offset (struct sframe_xlate_ctx *xlate_ctx,
992 struct cfi_insn_data *cfi_insn)
994 /* The scratchpad FRE currently being updated with each cfi_insn
995 being interpreted. This FRE eventually gets linked in into the
996 list of FREs for the specific function. */
997 struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
999 gas_assert (cur_fre);
1000 /* Define the current CFA rule to use the provided offset (but to keep
1001 the old register). However, if the old register is not FP/SP,
1002 skip creating SFrame unwind info for the function. */
1003 if ((cur_fre->cfa_base_reg == SFRAME_CFA_FP_REG)
1004 || (cur_fre->cfa_base_reg == SFRAME_CFA_SP_REG))
1006 sframe_fre_set_cfa_offset (cur_fre, cfi_insn->u.i);
1007 cur_fre->merge_candidate = false;
1010 return SFRAME_XLATE_ERR_NOTREPRESENTED;
1012 return SFRAME_XLATE_OK;
1015 /* Translate DW_CFA_offset into SFrame context.
1016 Return SFRAME_XLATE_OK if success. */
1019 sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx,
1020 struct cfi_insn_data *cfi_insn)
1022 /* The scratchpad FRE currently being updated with each cfi_insn
1023 being interpreted. This FRE eventually gets linked in into the
1024 list of FREs for the specific function. */
1025 struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1027 gas_assert (cur_fre);
1028 /* Change the rule for the register indicated by the register number to
1029 be the specified offset. */
1030 if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1032 gas_assert (!cur_fre->base_reg);
1033 sframe_fre_set_bp_track (cur_fre, cfi_insn->u.ri.offset);
1034 cur_fre->merge_candidate = false;
1036 #ifdef SFRAME_FRE_RA_TRACKING
1037 else if (sframe_ra_tracking_p ()
1038 && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1040 sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset);
1041 cur_fre->merge_candidate = false;
1044 /* This is used to track changes to non-rsp registers, skip all others
1045 except FP / RA for now. */
1046 return SFRAME_XLATE_OK;
1049 /* Translate DW_CFA_val_offset into SFrame context.
1050 Return SFRAME_XLATE_OK if success. */
1053 sframe_xlate_do_val_offset (struct sframe_xlate_ctx *xlate_ctx ATTRIBUTE_UNUSED,
1054 struct cfi_insn_data *cfi_insn)
1056 /* Previous value of register is CFA + offset. However, if the specified
1057 register is not interesting (FP or RA reg), the current DW_CFA_val_offset
1058 instruction can be safely skipped without sacrificing the asynchonicity of
1059 unwind information. */
1060 if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1061 return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
1062 #ifdef SFRAME_FRE_RA_TRACKING
1063 else if (sframe_ra_tracking_p ()
1064 && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1065 return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
1069 return SFRAME_XLATE_OK;
1072 /* Translate DW_CFA_remember_state into SFrame context.
1073 Return SFRAME_XLATE_OK if success. */
1076 sframe_xlate_do_remember_state (struct sframe_xlate_ctx *xlate_ctx)
1078 struct sframe_row_entry *last_fre = xlate_ctx->last_fre;
1080 /* If there is no FRE state to remember, nothing to do here. Return
1081 early with non-zero error code, this will cause no SFrame unwind info
1082 for the function involved. */
1084 return SFRAME_XLATE_ERR_INVAL;
1086 if (!xlate_ctx->remember_fre)
1087 xlate_ctx->remember_fre = sframe_row_entry_new ();
1088 sframe_row_entry_initialize (xlate_ctx->remember_fre, last_fre);
1090 return SFRAME_XLATE_OK;
1093 /* Translate DW_CFA_restore_state into SFrame context.
1094 Return SFRAME_XLATE_OK if success. */
1097 sframe_xlate_do_restore_state (struct sframe_xlate_ctx *xlate_ctx)
1099 /* The scratchpad FRE currently being updated with each cfi_insn
1100 being interpreted. This FRE eventually gets linked in into the
1101 list of FREs for the specific function. */
1102 struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1104 gas_assert (xlate_ctx->remember_fre);
1105 gas_assert (cur_fre && cur_fre->merge_candidate);
1107 /* Get the CFA state from the DW_CFA_remember_state insn. */
1108 sframe_row_entry_initialize (cur_fre, xlate_ctx->remember_fre);
1109 /* The PC boundaries of the current SFrame FRE are updated
1110 via other machinery. */
1111 cur_fre->merge_candidate = false;
1112 return SFRAME_XLATE_OK;
1115 /* Translate DW_CFA_restore into SFrame context.
1116 Return SFRAME_XLATE_OK if success. */
1119 sframe_xlate_do_restore (struct sframe_xlate_ctx *xlate_ctx,
1120 struct cfi_insn_data *cfi_insn)
1122 struct sframe_row_entry *cie_fre = xlate_ctx->first_fre;
1123 /* The scratchpad FRE currently being updated with each cfi_insn
1124 being interpreted. This FRE eventually gets linked in into the
1125 list of FREs for the specific function. */
1126 struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre;
1128 /* Change the rule for the indicated register to the rule assigned to
1129 it by the initial_instructions in the CIE. */
1130 gas_assert (cie_fre);
1131 /* SFrame FREs track only CFA and FP / RA for backtracing purposes;
1132 skip the other .cfi_restore directives. */
1133 if (cfi_insn->u.r == SFRAME_CFA_FP_REG)
1135 gas_assert (cur_fre);
1136 cur_fre->bp_loc = cie_fre->bp_loc;
1137 cur_fre->bp_offset = cie_fre->bp_offset;
1138 cur_fre->merge_candidate = false;
1140 #ifdef SFRAME_FRE_RA_TRACKING
1141 else if (sframe_ra_tracking_p ()
1142 && cfi_insn->u.r == SFRAME_CFA_RA_REG)
1144 gas_assert (cur_fre);
1145 cur_fre->ra_loc = cie_fre->ra_loc;
1146 cur_fre->ra_offset = cie_fre->ra_offset;
1147 cur_fre->merge_candidate = false;
1150 return SFRAME_XLATE_OK;
1153 /* Process CFI_INSN and update the translation context with the FRE
1156 Returns an error code (sframe_xlate_err) if CFI_INSN is not successfully
1160 sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx,
1161 struct cfi_insn_data *cfi_insn)
1165 /* Atleast one cfi_insn per FDE is expected. */
1166 gas_assert (cfi_insn);
1167 int op = cfi_insn->insn;
1171 case DW_CFA_advance_loc:
1172 err = sframe_xlate_do_advance_loc (xlate_ctx, cfi_insn);
1174 case DW_CFA_def_cfa:
1175 err = sframe_xlate_do_def_cfa (xlate_ctx, cfi_insn);
1177 case DW_CFA_def_cfa_register:
1178 err = sframe_xlate_do_def_cfa_register (xlate_ctx, cfi_insn);
1180 case DW_CFA_def_cfa_offset:
1181 err = sframe_xlate_do_def_cfa_offset (xlate_ctx, cfi_insn);
1184 err = sframe_xlate_do_offset (xlate_ctx, cfi_insn);
1186 case DW_CFA_val_offset:
1187 err = sframe_xlate_do_val_offset (xlate_ctx, cfi_insn);
1189 case DW_CFA_remember_state:
1190 err = sframe_xlate_do_remember_state (xlate_ctx);
1192 case DW_CFA_restore_state:
1193 err = sframe_xlate_do_restore_state (xlate_ctx);
1195 case DW_CFA_restore:
1196 err = sframe_xlate_do_restore (xlate_ctx, cfi_insn);
1198 case DW_CFA_undefined:
1199 case DW_CFA_same_value:
1203 /* Other CFI opcodes are not processed at this time.
1204 These do not impact the coverage of the basic stack unwinding
1205 information as conveyed in the SFrame format.
1209 Following skipped operations do, however, impact the asynchronicity:
1211 - DW_CFA_GNU_window_save,
1212 - DW_CFA_AARCH64_negate_ra_state (multiplexed with
1213 DW_CFA_GNU_window_save) */
1215 err = SFRAME_XLATE_ERR_NOTREPRESENTED;
1216 // printf (_("SFrame Unsupported or unknown Dwarf CFI number: %#x\n"), op);
1225 sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
1226 const struct fde_entry *dw_fde)
1228 struct cfi_insn_data *cfi_insn;
1229 int err = SFRAME_XLATE_OK;
1231 xlate_ctx->dw_fde = dw_fde;
1233 /* If the return column is not RIP, SFrame format cannot represent it. */
1234 if (xlate_ctx->dw_fde->return_column != DWARF2_DEFAULT_RETURN_COLUMN)
1235 return SFRAME_XLATE_ERR_NOTREPRESENTED;
1237 /* Iterate over the CFIs and create SFrame FREs. */
1238 for (cfi_insn = dw_fde->data; cfi_insn; cfi_insn = cfi_insn->next)
1240 /* Translate each CFI, and buffer the state in translation context. */
1241 err = sframe_do_cfi_insn (xlate_ctx, cfi_insn);
1242 if (err != SFRAME_XLATE_OK)
1244 /* Skip generating SFrame unwind info for the function if any
1245 offending CFI is encountered by sframe_do_cfi_insn (). */
1246 return err; /* Return the error code. */
1250 /* No errors encountered. */
1252 /* Link in the scratchpad FRE that the last few CFI insns helped create. */
1253 if (xlate_ctx->cur_fre)
1255 sframe_xlate_ctx_add_fre (xlate_ctx, xlate_ctx->cur_fre);
1256 xlate_ctx->cur_fre = NULL;
1258 /* Designate the end of the last SFrame FRE. */
1259 if (xlate_ctx->last_fre)
1261 xlate_ctx->last_fre->pc_end
1262 = get_dw_fde_end_addrS (xlate_ctx->dw_fde);
1265 return SFRAME_XLATE_OK;
1268 /* Create SFrame unwind info for all functions.
1270 This function consumes the already generated FDEs (by dw2gencfi) and
1271 generates unwind data in SFrame format. */
1274 create_sframe_all (void)
1276 struct fde_entry *dw_fde = NULL;
1277 struct sframe_func_entry *sframe_fde = NULL;
1279 struct sframe_xlate_ctx *xlate_ctx = sframe_xlate_ctx_alloc ();
1281 for (dw_fde = all_fde_data; dw_fde ; dw_fde = dw_fde->next)
1283 sframe_fde = sframe_fde_alloc ();
1284 /* Initialize the translation context with information anew. */
1285 sframe_xlate_ctx_init (xlate_ctx);
1287 /* Process and link SFrame FDEs if no error. Also skip adding an SFrame
1288 FDE if it does not contain any SFrame FREs. There is little use of an
1289 SFrame FDE if there is no unwind information about the function. */
1290 int err = sframe_do_fde (xlate_ctx, dw_fde);
1291 if (err || xlate_ctx->num_xlate_fres == 0)
1293 sframe_xlate_ctx_cleanup (xlate_ctx);
1294 sframe_fde_free (sframe_fde);
1298 /* All done. Transfer the state from the SFrame translation
1299 context to the SFrame FDE. */
1300 sframe_xlate_ctx_finalize (xlate_ctx, sframe_fde);
1301 sframe_fde_link (sframe_fde);
1307 output_sframe (segT sframe_seg)
1311 /* Setup the version specific access functions. */
1312 sframe_set_version (SFRAME_VERSION_1);
1314 /* Process all fdes and create SFrame unwind information. */
1315 create_sframe_all ();
1317 output_sframe_internal ();
1320 #else /* support_sframe_p */
1323 output_sframe (segT sframe_seg __attribute__((unused)))
1327 #endif /* support_sframe_p */