1 /* gen-sframe.c - Support for generating SFrame section.
2 Copyright (C) 2022-2024 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 tracing. 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 /* Get whether PAUTH B key is used. */
111 get_dw_fde_pauth_b_key_p (const struct fde_entry
*dw_fde ATTRIBUTE_UNUSED
)
113 #ifdef tc_fde_entry_extras
114 return (dw_fde
->pauth_key
== AARCH64_PAUTH_KEY_B
);
120 /* SFrame Frame Row Entry (FRE) related functions. */
123 sframe_fre_set_begin_addr (struct sframe_row_entry
*fre
, symbolS
*beginS
)
125 fre
->pc_begin
= beginS
;
129 sframe_fre_set_end_addr (struct sframe_row_entry
*fre
, symbolS
*endS
)
135 sframe_fre_set_cfa_base_reg (struct sframe_row_entry
*fre
,
136 unsigned int cfa_base_reg
)
138 fre
->cfa_base_reg
= cfa_base_reg
;
139 fre
->merge_candidate
= false;
143 sframe_fre_set_cfa_offset (struct sframe_row_entry
*fre
,
146 fre
->cfa_offset
= cfa_offset
;
147 fre
->merge_candidate
= false;
150 #ifdef SFRAME_FRE_RA_TRACKING
152 sframe_fre_set_ra_track (struct sframe_row_entry
*fre
, offsetT ra_offset
)
154 fre
->ra_loc
= SFRAME_FRE_ELEM_LOC_STACK
;
155 fre
->ra_offset
= ra_offset
;
156 fre
->merge_candidate
= false;
161 sframe_fre_set_bp_track (struct sframe_row_entry
*fre
, offsetT bp_offset
)
163 fre
->bp_loc
= SFRAME_FRE_ELEM_LOC_STACK
;
164 fre
->bp_offset
= bp_offset
;
165 fre
->merge_candidate
= false;
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
172 #define VALUE_8BIT 0x7f
173 #define VALUE_16BIT 0x7fff
174 #define VALUE_32BIT 0x7fffffff
175 #define VALUE_64BIT 0x7fffffffffffffff
177 /* Given a signed offset, return the size in bytes needed to represent it. */
180 get_offset_size_in_bytes (offsetT value
)
182 unsigned int size
= 0;
184 if (value
<= VALUE_8BIT
&& value
>= (offsetT
) -VALUE_8BIT
)
186 else if (value
<= VALUE_16BIT
&& value
>= (offsetT
) -VALUE_16BIT
)
188 else if (value
<= VALUE_32BIT
&& value
>= (offsetT
) -VALUE_32BIT
)
190 else if ((sizeof (offsetT
) > 4) && (value
<= (offsetT
) VALUE_64BIT
191 && value
>= (offsetT
) -VALUE_64BIT
))
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
203 /* Helper struct for mapping offset size to output functions. */
205 struct sframe_fre_offset_func_map
207 unsigned int offset_size
;
208 void (*out_func
)(int);
211 /* Given an OFFSET_SIZE, return the size in bytes needed to represent it. */
214 sframe_fre_offset_func_map_index (unsigned int offset_size
)
216 unsigned int idx
= SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX
;
220 case SFRAME_FRE_OFFSET_1B
:
221 idx
= SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_1B
;
223 case SFRAME_FRE_OFFSET_2B
:
224 idx
= SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_2B
;
226 case SFRAME_FRE_OFFSET_4B
:
227 idx
= SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_4B
;
230 /* Not supported in SFrame. */
237 /* Mapping from offset size to the output function to emit the value. */
240 struct sframe_fre_offset_func_map
241 fre_offset_func_map
[SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX
+1] =
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. */
249 /* SFrame version specific operations access. */
251 static struct sframe_version_ops sframe_ver_ops
;
253 /* SFrame (SFRAME_VERSION_1) set FRE info. */
256 sframe_v1_set_fre_info (unsigned int base_reg
, unsigned int num_offsets
,
257 unsigned int offset_size
, bool mangled_ra_p
)
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
);
265 /* SFrame (SFRAME_VERSION_1) set function info. */
267 sframe_v1_set_func_info (unsigned int fde_type
, unsigned int fre_type
,
268 unsigned int pauth_key
)
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
);
276 /* SFrame version specific operations setup. */
279 sframe_set_version (uint32_t sframe_version ATTRIBUTE_UNUSED
)
281 sframe_ver_ops
.format_version
= SFRAME_VERSION_2
;
283 /* These operations remain the same for SFRAME_VERSION_2 as fre_info and
284 func_info have not changed from SFRAME_VERSION_1. */
286 sframe_ver_ops
.set_fre_info
= sframe_v1_set_fre_info
;
288 sframe_ver_ops
.set_func_info
= sframe_v1_set_func_info
;
291 /* SFrame set FRE info. */
294 sframe_set_fre_info (unsigned int base_reg
, unsigned int num_offsets
,
295 unsigned int offset_size
, bool mangled_ra_p
)
297 return sframe_ver_ops
.set_fre_info (base_reg
, num_offsets
,
298 offset_size
, mangled_ra_p
);
301 /* SFrame set func info. */
304 sframe_set_func_info (unsigned int fde_type
, unsigned int fre_type
,
305 unsigned int pauth_key
)
307 return sframe_ver_ops
.set_func_info (fde_type
, fre_type
, pauth_key
);
310 /* Get the number of SFrame FDEs for the current file. */
313 get_num_sframe_fdes (void);
315 /* Get the number of SFrame frame row entries for the current file. */
318 get_num_sframe_fres (void);
320 /* Get CFA base register ID as represented in SFrame Frame Row Entry. */
323 get_fre_base_reg_id (struct sframe_row_entry
*sframe_fre
)
325 unsigned int cfi_insn_cfa_base_reg
= sframe_fre
->cfa_base_reg
;
326 unsigned fre_base_reg
= SFRAME_BASE_REG_SP
;
328 if (cfi_insn_cfa_base_reg
== SFRAME_CFA_FP_REG
)
329 fre_base_reg
= SFRAME_BASE_REG_FP
;
331 /* Only one bit is reserved in SFRAME_VERSION_1. */
332 gas_assert (fre_base_reg
== SFRAME_BASE_REG_SP
333 || fre_base_reg
== SFRAME_BASE_REG_FP
);
338 /* Get number of offsets necessary for the SFrame Frame Row Entry. */
341 get_fre_num_offsets (struct sframe_row_entry
*sframe_fre
)
343 /* Atleast 1 must always be present (to recover CFA). */
344 unsigned int fre_num_offsets
= 1;
346 if (sframe_fre
->bp_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
348 #ifdef SFRAME_FRE_RA_TRACKING
349 if (sframe_ra_tracking_p ()
350 && sframe_fre
->ra_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
353 return fre_num_offsets
;
356 /* Get the minimum necessary offset size (in bytes) for this
357 SFrame frame row entry. */
360 sframe_get_fre_offset_size (struct sframe_row_entry
*sframe_fre
)
362 unsigned int max_offset_size
= 0;
363 unsigned int cfa_offset_size
= 0;
364 unsigned int bp_offset_size
= 0;
365 unsigned int ra_offset_size
= 0;
367 unsigned int fre_offset_size
= 0;
369 /* What size of offsets appear in this frame row entry. */
370 cfa_offset_size
= get_offset_size_in_bytes (sframe_fre
->cfa_offset
);
371 if (sframe_fre
->bp_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
372 bp_offset_size
= get_offset_size_in_bytes (sframe_fre
->bp_offset
);
373 #ifdef SFRAME_FRE_RA_TRACKING
374 if (sframe_ra_tracking_p ()
375 && sframe_fre
->ra_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
376 ra_offset_size
= get_offset_size_in_bytes (sframe_fre
->ra_offset
);
379 /* Get the maximum size needed to represent the offsets. */
380 max_offset_size
= cfa_offset_size
;
381 if (bp_offset_size
> max_offset_size
)
382 max_offset_size
= bp_offset_size
;
383 if (ra_offset_size
> max_offset_size
)
384 max_offset_size
= ra_offset_size
;
386 gas_assert (max_offset_size
);
388 switch (max_offset_size
)
391 fre_offset_size
= SFRAME_FRE_OFFSET_1B
;
394 fre_offset_size
= SFRAME_FRE_OFFSET_2B
;
397 fre_offset_size
= SFRAME_FRE_OFFSET_4B
;
400 /* Offset of size 8 bytes is not supported in SFrame format
402 as_fatal (_("SFrame unsupported offset value\n"));
406 return fre_offset_size
;
409 #if SFRAME_FRE_TYPE_SELECTION_OPT
411 /* Create a composite expression CEXP (for SFrame FRE start address) such that:
413 exp = <val> OP_absent <width>, where,
415 - <val> and <width> are themselves expressionS.
416 - <val> stores the expression which when evaluated gives the value of the
417 start address offset of the FRE.
418 - <width> stores the expression when evaluated gives the number of bytes
419 needed to encode the start address offset of the FRE.
421 The use of OP_absent as the X_op_symbol helps identify this expression
422 later when fragments are fixed up. */
425 create_fre_start_addr_exp (expressionS
*cexp
, symbolS
*fre_pc_begin
,
426 symbolS
*fde_start_address
,
427 symbolS
*fde_end_address
)
432 /* val expression stores the FDE start address offset from the start PC
434 val
.X_op
= O_subtract
;
435 val
.X_add_symbol
= fre_pc_begin
;
436 val
.X_op_symbol
= fde_start_address
;
437 val
.X_add_number
= 0;
439 /* width expressions stores the size of the function. This is used later
440 to determine the number of bytes to be used to encode the FRE start
441 address of each FRE of the function. */
442 width
.X_op
= O_subtract
;
443 width
.X_add_symbol
= fde_end_address
;
444 width
.X_op_symbol
= fde_start_address
;
445 width
.X_add_number
= 0;
447 cexp
->X_op
= O_absent
;
448 cexp
->X_add_symbol
= make_expr_symbol (&val
);
449 cexp
->X_op_symbol
= make_expr_symbol (&width
);
450 cexp
->X_add_number
= 0;
453 /* Create a composite expression CEXP (for SFrame FDE function info) such that:
455 exp = <rest_of_func_info> OP_modulus <width>, where,
457 - <rest_of_func_info> and <width> are themselves expressionS.
458 - <rest_of_func_info> stores a constant expression where X_add_number is
459 used to stash away the func_info. The upper 4-bits of the func_info are copied
460 back to the resulting byte by the fragment fixup logic.
461 - <width> stores the expression when evaluated gives the size of the
462 function in number of bytes.
464 The use of OP_modulus as the X_op_symbol helps identify this expression
465 later when fragments are fixed up. */
468 create_func_info_exp (expressionS
*cexp
, symbolS
*dw_fde_end_addrS
,
469 symbolS
*dw_fde_start_addrS
, uint8_t func_info
)
472 expressionS rest_of_func_info
;
474 width
.X_op
= O_subtract
;
475 width
.X_add_symbol
= dw_fde_end_addrS
;
476 width
.X_op_symbol
= dw_fde_start_addrS
;
477 width
.X_add_number
= 0;
479 rest_of_func_info
.X_op
= O_constant
;
480 rest_of_func_info
.X_add_number
= func_info
;
482 cexp
->X_op
= O_modulus
;
483 cexp
->X_add_symbol
= make_expr_symbol (&rest_of_func_info
);
484 cexp
->X_op_symbol
= make_expr_symbol (&width
);
485 cexp
->X_add_number
= 0;
491 output_sframe_row_entry (symbolS
*fde_start_addr
,
492 symbolS
*fde_end_addr
,
493 struct sframe_row_entry
*sframe_fre
)
495 unsigned char fre_info
;
496 unsigned int fre_num_offsets
;
497 unsigned int fre_offset_size
;
498 unsigned int fre_base_reg
;
500 unsigned int fre_addr_size
;
502 unsigned int idx
= 0;
503 unsigned int fre_write_offsets
= 0;
505 fre_addr_size
= 4; /* 4 bytes by default. FIXME tie it to fre_type? */
507 /* SFrame FRE Start Address. */
508 #if SFRAME_FRE_TYPE_SELECTION_OPT
509 create_fre_start_addr_exp (&exp
, sframe_fre
->pc_begin
, fde_start_addr
,
511 frag_grow (fre_addr_size
);
512 frag_var (rs_sframe
, fre_addr_size
, 0, (relax_substateT
) 0,
513 make_expr_symbol (&exp
), 0, (char *) frag_now
);
515 gas_assert (fde_end_addr
);
516 exp
.X_op
= O_subtract
;
517 exp
.X_add_symbol
= sframe_fre
->pc_begin
; /* to. */
518 exp
.X_op_symbol
= fde_start_addr
; /* from. */
519 exp
.X_add_number
= 0;
520 emit_expr (&exp
, fre_addr_size
);
523 /* Create the fre_info using the CFA base register, number of offsets and max
524 size of offset in this frame row entry. */
525 fre_base_reg
= get_fre_base_reg_id (sframe_fre
);
526 fre_num_offsets
= get_fre_num_offsets (sframe_fre
);
527 fre_offset_size
= sframe_get_fre_offset_size (sframe_fre
);
528 fre_info
= sframe_set_fre_info (fre_base_reg
, fre_num_offsets
,
529 fre_offset_size
, sframe_fre
->mangled_ra_p
);
532 idx
= sframe_fre_offset_func_map_index (fre_offset_size
);
533 gas_assert (idx
< SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX
);
535 /* Write out the offsets in order - cfa, bp, ra. */
536 fre_offset_func_map
[idx
].out_func (sframe_fre
->cfa_offset
);
539 #ifdef SFRAME_FRE_RA_TRACKING
540 if (sframe_ra_tracking_p ()
541 && sframe_fre
->ra_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
543 fre_offset_func_map
[idx
].out_func (sframe_fre
->ra_offset
);
547 if (sframe_fre
->bp_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
549 fre_offset_func_map
[idx
].out_func (sframe_fre
->bp_offset
);
553 /* Check if the expected number offsets have been written out
555 gas_assert (fre_write_offsets
== fre_num_offsets
);
559 output_sframe_funcdesc (symbolS
*start_of_fre_section
,
561 struct sframe_func_entry
*sframe_fde
)
564 unsigned int addr_size
;
565 symbolS
*dw_fde_start_addrS
, *dw_fde_end_addrS
;
566 unsigned int pauth_key
;
568 addr_size
= SFRAME_RELOC_SIZE
;
569 dw_fde_start_addrS
= get_dw_fde_start_addrS (sframe_fde
->dw_fde
);
570 dw_fde_end_addrS
= get_dw_fde_end_addrS (sframe_fde
->dw_fde
);
572 /* Start address of the function. */
573 exp
.X_op
= O_subtract
;
574 exp
.X_add_symbol
= dw_fde_start_addrS
; /* to location. */
575 exp
.X_op_symbol
= symbol_temp_new_now (); /* from location. */
576 exp
.X_add_number
= 0;
577 emit_expr (&exp
, addr_size
);
579 /* Size of the function in bytes. */
580 exp
.X_op
= O_subtract
;
581 exp
.X_add_symbol
= dw_fde_end_addrS
;
582 exp
.X_op_symbol
= dw_fde_start_addrS
;
583 exp
.X_add_number
= 0;
584 emit_expr (&exp
, addr_size
);
586 /* Offset to the first frame row entry. */
587 exp
.X_op
= O_subtract
;
588 exp
.X_add_symbol
= fre_symbol
; /* Minuend. */
589 exp
.X_op_symbol
= start_of_fre_section
; /* Subtrahend. */
590 exp
.X_add_number
= 0;
591 emit_expr (&exp
, addr_size
);
593 /* Number of FREs. */
594 out_four (sframe_fde
->num_fres
);
596 /* SFrame FDE function info. */
597 unsigned char func_info
;
598 pauth_key
= (get_dw_fde_pauth_b_key_p (sframe_fde
->dw_fde
)
599 ? SFRAME_AARCH64_PAUTH_KEY_B
: SFRAME_AARCH64_PAUTH_KEY_A
);
600 func_info
= sframe_set_func_info (SFRAME_FDE_TYPE_PCINC
,
601 SFRAME_FRE_TYPE_ADDR4
,
603 #if SFRAME_FRE_TYPE_SELECTION_OPT
605 create_func_info_exp (&cexp
, dw_fde_end_addrS
, dw_fde_start_addrS
,
607 frag_grow (1); /* Size of func info is unsigned char. */
608 frag_var (rs_sframe
, 1, 0, (relax_substateT
) 0,
609 make_expr_symbol (&cexp
), 0, (char *) frag_now
);
618 output_sframe_internal (void)
623 symbolS
*end_of_frame_hdr
;
624 symbolS
*end_of_frame_section
;
625 symbolS
*start_of_func_desc_section
;
626 symbolS
*start_of_fre_section
;
627 struct sframe_func_entry
*sframe_fde
;
628 struct sframe_row_entry
*sframe_fre
;
629 unsigned char abi_arch
= 0;
630 int fixed_fp_offset
= SFRAME_CFA_FIXED_FP_INVALID
;
631 int fixed_ra_offset
= SFRAME_CFA_FIXED_RA_INVALID
;
632 unsigned int addr_size
;
634 addr_size
= SFRAME_RELOC_SIZE
;
636 /* The function descriptor entries as dumped by the assembler are not
638 unsigned char sframe_flags
= 0;
639 sframe_flags
|= !SFRAME_F_FDE_SORTED
;
641 unsigned int num_fdes
= get_num_sframe_fdes ();
642 unsigned int num_fres
= get_num_sframe_fres ();
643 symbolS
**fre_symbols
= XNEWVEC (symbolS
*, num_fres
);
644 for (i
= 0; i
< num_fres
; i
++)
645 fre_symbols
[i
] = symbol_temp_make ();
647 end_of_frame_hdr
= symbol_temp_make ();
648 start_of_fre_section
= symbol_temp_make ();
649 start_of_func_desc_section
= symbol_temp_make ();
650 end_of_frame_section
= symbol_temp_make ();
652 /* Output the preamble of SFrame section. */
653 out_two (SFRAME_MAGIC
);
654 out_one (SFRAME_VERSION
);
655 out_one (sframe_flags
);
657 #ifdef sframe_get_abi_arch
658 abi_arch
= sframe_get_abi_arch ();
660 gas_assert (abi_arch
);
663 /* Offset for the FP register from CFA. Neither of the AMD64 or AAPCS64
664 ABIs have a fixed offset for the FP register from the CFA. This may be
665 useful in future (but not without additional support in the toolchain)
666 for specialized handling/encoding for cases where, for example,
667 -fno-omit-frame-pointer is used. */
668 out_one (fixed_fp_offset
);
670 /* All ABIs participating in SFrame generation must define
671 sframe_ra_tracking_p.
672 When RA tracking (in FREs) is not needed (e.g., AMD64), SFrame assumes
673 the RA is going to be at a fixed offset from CFA. Check that the fixed RA
674 offset is appropriately defined in all cases. */
675 if (!sframe_ra_tracking_p ())
677 fixed_ra_offset
= sframe_cfa_ra_offset ();
678 gas_assert (fixed_ra_offset
!= SFRAME_CFA_FIXED_RA_INVALID
);
680 out_one (fixed_ra_offset
);
682 /* None of the AMD64, or AARCH64 ABIs need the auxiliary header.
683 When the need does arise to use this field, the appropriate backend
684 must provide this information. */
685 out_one (0); /* Auxiliary SFrame header length. */
687 out_four (num_fdes
); /* Number of FDEs. */
688 out_four (num_fres
); /* Number of FREs. */
690 /* FRE sub-section len. */
691 exp
.X_op
= O_subtract
;
692 exp
.X_add_symbol
= end_of_frame_section
;
693 exp
.X_op_symbol
= start_of_fre_section
;
694 exp
.X_add_number
= 0;
695 emit_expr (&exp
, addr_size
);
697 /* Offset of Function Index sub-section. */
698 exp
.X_op
= O_subtract
;
699 exp
.X_add_symbol
= end_of_frame_hdr
;
700 exp
.X_op_symbol
= start_of_func_desc_section
;
701 exp
.X_add_number
= 0;
702 emit_expr (&exp
, addr_size
);
704 /* Offset of FRE sub-section. */
705 exp
.X_op
= O_subtract
;
706 exp
.X_add_symbol
= start_of_fre_section
;
707 exp
.X_op_symbol
= end_of_frame_hdr
;
708 exp
.X_add_number
= 0;
709 emit_expr (&exp
, addr_size
);
711 symbol_set_value_now (end_of_frame_hdr
);
712 symbol_set_value_now (start_of_func_desc_section
);
714 /* Output the SFrame function descriptor entries. */
716 for (sframe_fde
= all_sframe_fdes
; sframe_fde
; sframe_fde
= sframe_fde
->next
)
718 output_sframe_funcdesc (start_of_fre_section
,
719 fre_symbols
[i
], sframe_fde
);
720 i
+= sframe_fde
->num_fres
;
723 symbol_set_value_now (start_of_fre_section
);
725 /* Output the SFrame FREs. */
727 sframe_fde
= all_sframe_fdes
;
729 for (sframe_fde
= all_sframe_fdes
; sframe_fde
; sframe_fde
= sframe_fde
->next
)
731 for (sframe_fre
= sframe_fde
->sframe_fres
;
733 sframe_fre
= sframe_fre
->next
)
735 symbol_set_value_now (fre_symbols
[i
]);
736 output_sframe_row_entry (get_dw_fde_start_addrS (sframe_fde
->dw_fde
),
737 get_dw_fde_end_addrS (sframe_fde
->dw_fde
),
743 symbol_set_value_now (end_of_frame_section
);
745 gas_assert (i
== num_fres
);
751 /* List of SFrame FDE entries. */
753 struct sframe_func_entry
*all_sframe_fdes
;
755 /* Tail of the list to add to. */
757 static struct sframe_func_entry
**last_sframe_fde
= &all_sframe_fdes
;
760 get_num_sframe_fdes (void)
762 struct sframe_func_entry
*sframe_fde
;
763 unsigned int total_fdes
= 0;
765 for (sframe_fde
= all_sframe_fdes
; sframe_fde
; sframe_fde
= sframe_fde
->next
)
771 /* Get the total number of SFrame row entries across the FDEs. */
774 get_num_sframe_fres (void)
776 struct sframe_func_entry
*sframe_fde
;
777 unsigned int total_fres
= 0;
779 for (sframe_fde
= all_sframe_fdes
; sframe_fde
; sframe_fde
= sframe_fde
->next
)
780 total_fres
+= sframe_fde
->num_fres
;
785 /* Allocate an SFrame FDE. */
787 static struct sframe_func_entry
*
788 sframe_fde_alloc (void)
790 struct sframe_func_entry
*sframe_fde
= XCNEW (struct sframe_func_entry
);
794 /* Link the SFrame FDE in. */
797 sframe_fde_link (struct sframe_func_entry
*sframe_fde
)
799 *last_sframe_fde
= sframe_fde
;
800 last_sframe_fde
= &sframe_fde
->next
;
805 /* Free up the SFrame FDE. */
808 sframe_fde_free (struct sframe_func_entry
*sframe_fde
)
810 XDELETE (sframe_fde
);
814 /* SFrame translation context functions. */
816 /* Allocate a new SFrame translation context. */
818 static struct sframe_xlate_ctx
*
819 sframe_xlate_ctx_alloc (void)
821 struct sframe_xlate_ctx
* xlate_ctx
= XCNEW (struct sframe_xlate_ctx
);
825 /* Initialize the given SFrame translation context. */
828 sframe_xlate_ctx_init (struct sframe_xlate_ctx
*xlate_ctx
)
830 xlate_ctx
->dw_fde
= NULL
;
831 xlate_ctx
->first_fre
= NULL
;
832 xlate_ctx
->last_fre
= NULL
;
833 xlate_ctx
->cur_fre
= NULL
;
834 xlate_ctx
->remember_fre
= NULL
;
835 xlate_ctx
->num_xlate_fres
= 0;
838 /* Cleanup the given SFrame translation context. */
841 sframe_xlate_ctx_cleanup (struct sframe_xlate_ctx
*xlate_ctx
)
843 struct sframe_row_entry
*fre
, *fre_next
;
845 if (xlate_ctx
->num_xlate_fres
)
847 fre
= xlate_ctx
->first_fre
;
850 fre_next
= fre
->next
;
856 XDELETE (xlate_ctx
->cur_fre
);
858 sframe_xlate_ctx_init (xlate_ctx
);
861 /* Transfer the state from the SFrame translation context to the SFrame FDE. */
864 sframe_xlate_ctx_finalize (struct sframe_xlate_ctx
*xlate_ctx
,
865 struct sframe_func_entry
*sframe_fde
)
867 sframe_fde
->dw_fde
= xlate_ctx
->dw_fde
;
868 sframe_fde
->sframe_fres
= xlate_ctx
->first_fre
;
869 sframe_fde
->num_fres
= xlate_ctx
->num_xlate_fres
;
872 static struct sframe_row_entry
*
873 sframe_row_entry_new (void)
875 struct sframe_row_entry
*fre
= XCNEW (struct sframe_row_entry
);
876 /* Reset cfa_base_reg to -1. A value of 0 will imply some valid register
877 for the supported arches. */
878 fre
->cfa_base_reg
= SFRAME_FRE_BASE_REG_INVAL
;
879 fre
->merge_candidate
= true;
880 /* Reset the mangled RA status bit to zero by default. We will initialize it in
881 sframe_row_entry_initialize () with the sticky bit if set. */
882 fre
->mangled_ra_p
= false;
887 /* Add the given FRE in the list of frame row entries in the given FDE
888 translation context. */
891 sframe_xlate_ctx_add_fre (struct sframe_xlate_ctx
*xlate_ctx
,
892 struct sframe_row_entry
*fre
)
894 gas_assert (xlate_ctx
&& fre
);
896 /* Add the frame row entry. */
897 if (!xlate_ctx
->first_fre
)
898 xlate_ctx
->first_fre
= fre
;
899 else if (xlate_ctx
->last_fre
)
900 xlate_ctx
->last_fre
->next
= fre
;
902 xlate_ctx
->last_fre
= fre
;
904 /* Keep track of the total number of SFrame frame row entries. */
905 xlate_ctx
->num_xlate_fres
++;
908 /* A SFrame Frame Row Entry is self-sufficient in terms of stack tracing info
909 for a given PC. It contains information assimilated from multiple CFI
910 instructions, and hence, a new SFrame FRE is initialized with the data from
911 the previous known FRE, if any.
913 Understandably, not all information (especially the instruction begin
914 and end boundaries) needs to be relayed. Hence, the caller of this API
915 must set the pc_begin and pc_end as applicable. */
918 sframe_row_entry_initialize (struct sframe_row_entry
*cur_fre
,
919 struct sframe_row_entry
*prev_fre
)
921 gas_assert (prev_fre
);
922 cur_fre
->cfa_base_reg
= prev_fre
->cfa_base_reg
;
923 cur_fre
->cfa_offset
= prev_fre
->cfa_offset
;
924 cur_fre
->bp_loc
= prev_fre
->bp_loc
;
925 cur_fre
->bp_offset
= prev_fre
->bp_offset
;
926 cur_fre
->ra_loc
= prev_fre
->ra_loc
;
927 cur_fre
->ra_offset
= prev_fre
->ra_offset
;
928 /* Treat RA mangling as a sticky bit. It retains its value until another
929 .cfi_negate_ra_state is seen. */
930 cur_fre
->mangled_ra_p
= prev_fre
->mangled_ra_p
;
933 /* Return SFrame register name for SP, FP, and RA, or NULL if other. */
936 sframe_register_name (unsigned int reg
)
938 if (reg
== SFRAME_CFA_SP_REG
)
940 else if (reg
== SFRAME_CFA_FP_REG
)
942 #ifdef SFRAME_FRE_RA_TRACKING
943 else if (reg
== SFRAME_CFA_RA_REG
)
950 /* Translate DW_CFA_advance_loc into SFrame context.
951 Return SFRAME_XLATE_OK if success. */
954 sframe_xlate_do_advance_loc (struct sframe_xlate_ctx
*xlate_ctx
,
955 struct cfi_insn_data
*cfi_insn
)
957 struct sframe_row_entry
*last_fre
= xlate_ctx
->last_fre
;
958 /* Get the scratchpad FRE currently being updated as the cfi_insn's
959 get interpreted. This FRE eventually gets linked in into the
960 list of FREs for the specific function. */
961 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
965 if (!cur_fre
->merge_candidate
)
967 sframe_fre_set_end_addr (cur_fre
, cfi_insn
->u
.ll
.lab2
);
969 sframe_xlate_ctx_add_fre (xlate_ctx
, cur_fre
);
970 last_fre
= xlate_ctx
->last_fre
;
972 xlate_ctx
->cur_fre
= sframe_row_entry_new ();
973 cur_fre
= xlate_ctx
->cur_fre
;
976 sframe_row_entry_initialize (cur_fre
, last_fre
);
980 sframe_fre_set_end_addr (last_fre
, cfi_insn
->u
.ll
.lab2
);
981 gas_assert (last_fre
->merge_candidate
== false);
986 xlate_ctx
->cur_fre
= sframe_row_entry_new ();
987 cur_fre
= xlate_ctx
->cur_fre
;
990 gas_assert (cur_fre
);
991 sframe_fre_set_begin_addr (cur_fre
, cfi_insn
->u
.ll
.lab2
);
993 return SFRAME_XLATE_OK
;
996 /* Translate DW_CFA_def_cfa into SFrame context.
997 Return SFRAME_XLATE_OK if success. */
1000 sframe_xlate_do_def_cfa (struct sframe_xlate_ctx
*xlate_ctx
,
1001 struct cfi_insn_data
*cfi_insn
)
1004 /* Get the scratchpad FRE. This FRE will eventually get linked in. */
1005 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1008 xlate_ctx
->cur_fre
= sframe_row_entry_new ();
1009 cur_fre
= xlate_ctx
->cur_fre
;
1010 sframe_fre_set_begin_addr (cur_fre
,
1011 get_dw_fde_start_addrS (xlate_ctx
->dw_fde
));
1013 /* Define the current CFA rule to use the provided register and
1014 offset. However, if the register is not FP/SP, skip creating
1015 SFrame stack trace info for the function. */
1016 if (cfi_insn
->u
.r
!= SFRAME_CFA_SP_REG
1017 && cfi_insn
->u
.r
!= SFRAME_CFA_FP_REG
)
1019 as_warn (_("skipping SFrame FDE; non-SP/FP register %u in .cfi_def_cfa"),
1021 return SFRAME_XLATE_ERR_NOTREPRESENTED
; /* Not represented. */
1023 sframe_fre_set_cfa_base_reg (cur_fre
, cfi_insn
->u
.ri
.reg
);
1024 sframe_fre_set_cfa_offset (cur_fre
, cfi_insn
->u
.ri
.offset
);
1025 cur_fre
->merge_candidate
= false;
1027 return SFRAME_XLATE_OK
;
1030 /* Translate DW_CFA_def_cfa_register into SFrame context.
1031 Return SFRAME_XLATE_OK if success. */
1034 sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx
*xlate_ctx
,
1035 struct cfi_insn_data
*cfi_insn
)
1037 struct sframe_row_entry
*last_fre
= xlate_ctx
->last_fre
;
1038 /* Get the scratchpad FRE. This FRE will eventually get linked in. */
1039 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1041 gas_assert (cur_fre
);
1042 /* Define the current CFA rule to use the provided register (but to
1043 keep the old offset). However, if the register is not FP/SP,
1044 skip creating SFrame stack trace info for the function. */
1045 if (cfi_insn
->u
.r
!= SFRAME_CFA_SP_REG
1046 && cfi_insn
->u
.r
!= SFRAME_CFA_FP_REG
)
1048 as_warn (_("skipping SFrame FDE; "
1049 "non-SP/FP register %u in .cfi_def_cfa_register"),
1051 return SFRAME_XLATE_ERR_NOTREPRESENTED
; /* Not represented. */
1053 sframe_fre_set_cfa_base_reg (cur_fre
, cfi_insn
->u
.ri
.reg
);
1054 sframe_fre_set_cfa_offset (cur_fre
, last_fre
->cfa_offset
);
1055 cur_fre
->merge_candidate
= false;
1057 return SFRAME_XLATE_OK
;
1060 /* Translate DW_CFA_def_cfa_offset into SFrame context.
1061 Return SFRAME_XLATE_OK if success. */
1064 sframe_xlate_do_def_cfa_offset (struct sframe_xlate_ctx
*xlate_ctx
,
1065 struct cfi_insn_data
*cfi_insn
)
1067 /* The scratchpad FRE currently being updated with each cfi_insn
1068 being interpreted. This FRE eventually gets linked in into the
1069 list of FREs for the specific function. */
1070 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1072 gas_assert (cur_fre
);
1073 /* Define the current CFA rule to use the provided offset (but to keep
1074 the old register). However, if the old register is not FP/SP,
1075 skip creating SFrame stack trace info for the function. */
1076 if ((cur_fre
->cfa_base_reg
== SFRAME_CFA_FP_REG
)
1077 || (cur_fre
->cfa_base_reg
== SFRAME_CFA_SP_REG
))
1079 sframe_fre_set_cfa_offset (cur_fre
, cfi_insn
->u
.i
);
1080 cur_fre
->merge_candidate
= false;
1084 /* No CFA base register in effect. Non-SP/FP CFA base register should
1085 not occur, as sframe_xlate_do_def_cfa[_register] would detect this. */
1086 as_warn (_("skipping SFrame FDE; "
1087 ".cfi_def_cfa_offset without CFA base register in effect"));
1088 return SFRAME_XLATE_ERR_NOTREPRESENTED
;
1091 return SFRAME_XLATE_OK
;
1094 /* Translate DW_CFA_offset into SFrame context.
1095 Return SFRAME_XLATE_OK if success. */
1098 sframe_xlate_do_offset (struct sframe_xlate_ctx
*xlate_ctx
,
1099 struct cfi_insn_data
*cfi_insn
)
1101 /* The scratchpad FRE currently being updated with each cfi_insn
1102 being interpreted. This FRE eventually gets linked in into the
1103 list of FREs for the specific function. */
1104 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1106 gas_assert (cur_fre
);
1107 /* Change the rule for the register indicated by the register number to
1108 be the specified offset. */
1109 /* Ignore SP reg, as it can be recovered from the CFA tracking info. */
1110 if (cfi_insn
->u
.r
== SFRAME_CFA_FP_REG
)
1112 gas_assert (!cur_fre
->base_reg
);
1113 sframe_fre_set_bp_track (cur_fre
, cfi_insn
->u
.ri
.offset
);
1114 cur_fre
->merge_candidate
= false;
1116 #ifdef SFRAME_FRE_RA_TRACKING
1117 else if (sframe_ra_tracking_p ()
1118 && cfi_insn
->u
.r
== SFRAME_CFA_RA_REG
)
1120 sframe_fre_set_ra_track (cur_fre
, cfi_insn
->u
.ri
.offset
);
1121 cur_fre
->merge_candidate
= false;
1124 /* This is used to track changes to non-rsp registers, skip all others
1125 except FP / RA for now. */
1126 return SFRAME_XLATE_OK
;
1129 /* Translate DW_CFA_val_offset into SFrame context.
1130 Return SFRAME_XLATE_OK if success. */
1133 sframe_xlate_do_val_offset (struct sframe_xlate_ctx
*xlate_ctx ATTRIBUTE_UNUSED
,
1134 struct cfi_insn_data
*cfi_insn
)
1136 /* Previous value of register is CFA + offset. However, if the specified
1137 register is not interesting (FP or RA reg), the current DW_CFA_val_offset
1138 instruction can be safely skipped without sacrificing the asynchronicity of
1139 stack trace information. */
1140 if (cfi_insn
->u
.r
== SFRAME_CFA_FP_REG
1141 #ifdef SFRAME_FRE_RA_TRACKING
1142 || (sframe_ra_tracking_p () && cfi_insn
->u
.r
== SFRAME_CFA_RA_REG
)
1144 /* Ignore SP reg, as it can be recovered from the CFA tracking info. */
1147 as_warn (_("skipping SFrame FDE; %s register %u in .cfi_val_offset"),
1148 sframe_register_name (cfi_insn
->u
.r
), cfi_insn
->u
.r
);
1149 return SFRAME_XLATE_ERR_NOTREPRESENTED
; /* Not represented. */
1153 return SFRAME_XLATE_OK
;
1156 /* Translate DW_CFA_register into SFrame context.
1157 Return SFRAME_XLATE_OK if success. */
1160 sframe_xlate_do_register (struct sframe_xlate_ctx
*xlate_ctx ATTRIBUTE_UNUSED
,
1161 struct cfi_insn_data
*cfi_insn
)
1163 /* Previous value of register1 is register2. However, if the specified
1164 register1 is not interesting (FP or RA reg), the current DW_CFA_register
1165 instruction can be safely skipped without sacrificing the asynchronicity of
1166 stack trace information. */
1167 if (cfi_insn
->u
.rr
.reg1
== SFRAME_CFA_FP_REG
1168 #ifdef SFRAME_FRE_RA_TRACKING
1169 || (sframe_ra_tracking_p () && cfi_insn
->u
.rr
.reg1
== SFRAME_CFA_RA_REG
)
1171 /* Ignore SP reg, as it can be recovered from the CFA tracking info. */
1174 as_warn (_("skipping SFrame FDE; %s register %u in .cfi_register"),
1175 sframe_register_name (cfi_insn
->u
.rr
.reg1
), cfi_insn
->u
.rr
.reg1
);
1176 return SFRAME_XLATE_ERR_NOTREPRESENTED
; /* Not represented. */
1180 return SFRAME_XLATE_OK
;
1183 /* Translate DW_CFA_remember_state into SFrame context.
1184 Return SFRAME_XLATE_OK if success. */
1187 sframe_xlate_do_remember_state (struct sframe_xlate_ctx
*xlate_ctx
)
1189 struct sframe_row_entry
*last_fre
= xlate_ctx
->last_fre
;
1191 /* If there is no FRE state to remember, nothing to do here. Return
1192 early with non-zero error code, this will cause no SFrame stack trace
1193 info for the function involved. */
1196 as_warn (_("skipping SFrame FDE; "
1197 ".cfi_remember_state without prior SFrame FRE state"));
1198 return SFRAME_XLATE_ERR_INVAL
;
1201 if (!xlate_ctx
->remember_fre
)
1202 xlate_ctx
->remember_fre
= sframe_row_entry_new ();
1203 sframe_row_entry_initialize (xlate_ctx
->remember_fre
, last_fre
);
1205 return SFRAME_XLATE_OK
;
1208 /* Translate DW_CFA_restore_state into SFrame context.
1209 Return SFRAME_XLATE_OK if success. */
1212 sframe_xlate_do_restore_state (struct sframe_xlate_ctx
*xlate_ctx
)
1214 /* The scratchpad FRE currently being updated with each cfi_insn
1215 being interpreted. This FRE eventually gets linked in into the
1216 list of FREs for the specific function. */
1217 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1219 gas_assert (xlate_ctx
->remember_fre
);
1220 gas_assert (cur_fre
&& cur_fre
->merge_candidate
);
1222 /* Get the CFA state from the DW_CFA_remember_state insn. */
1223 sframe_row_entry_initialize (cur_fre
, xlate_ctx
->remember_fre
);
1224 /* The PC boundaries of the current SFrame FRE are updated
1225 via other machinery. */
1226 cur_fre
->merge_candidate
= false;
1227 return SFRAME_XLATE_OK
;
1230 /* Translate DW_CFA_restore into SFrame context.
1231 Return SFRAME_XLATE_OK if success. */
1234 sframe_xlate_do_restore (struct sframe_xlate_ctx
*xlate_ctx
,
1235 struct cfi_insn_data
*cfi_insn
)
1237 struct sframe_row_entry
*cie_fre
= xlate_ctx
->first_fre
;
1238 /* The scratchpad FRE currently being updated with each cfi_insn
1239 being interpreted. This FRE eventually gets linked in into the
1240 list of FREs for the specific function. */
1241 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1243 /* Change the rule for the indicated register to the rule assigned to
1244 it by the initial_instructions in the CIE. */
1245 gas_assert (cie_fre
);
1246 /* SFrame FREs track only CFA and FP / RA for backtracing purposes;
1247 skip the other .cfi_restore directives. */
1248 if (cfi_insn
->u
.r
== SFRAME_CFA_FP_REG
)
1250 gas_assert (cur_fre
);
1251 cur_fre
->bp_loc
= cie_fre
->bp_loc
;
1252 cur_fre
->bp_offset
= cie_fre
->bp_offset
;
1253 cur_fre
->merge_candidate
= false;
1255 #ifdef SFRAME_FRE_RA_TRACKING
1256 else if (sframe_ra_tracking_p ()
1257 && cfi_insn
->u
.r
== SFRAME_CFA_RA_REG
)
1259 gas_assert (cur_fre
);
1260 cur_fre
->ra_loc
= cie_fre
->ra_loc
;
1261 cur_fre
->ra_offset
= cie_fre
->ra_offset
;
1262 cur_fre
->merge_candidate
= false;
1265 return SFRAME_XLATE_OK
;
1268 /* Translate DW_CFA_AARCH64_negate_ra_state into SFrame context.
1269 Return SFRAME_XLATE_OK if success. */
1272 sframe_xlate_do_aarch64_negate_ra_state (struct sframe_xlate_ctx
*xlate_ctx
,
1273 struct cfi_insn_data
*cfi_insn ATTRIBUTE_UNUSED
)
1275 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1277 gas_assert (cur_fre
);
1278 /* Toggle the mangled RA status bit. */
1279 cur_fre
->mangled_ra_p
= !cur_fre
->mangled_ra_p
;
1280 cur_fre
->merge_candidate
= false;
1282 return SFRAME_XLATE_OK
;
1285 /* Translate DW_CFA_GNU_window_save into SFrame context.
1286 DW_CFA_AARCH64_negate_ra_state is multiplexed with DW_CFA_GNU_window_save.
1287 Return SFRAME_XLATE_OK if success. */
1290 sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx
*xlate_ctx
,
1291 struct cfi_insn_data
*cfi_insn
)
1293 unsigned char abi_arch
= sframe_get_abi_arch ();
1295 /* Translate DW_CFA_AARCH64_negate_ra_state into SFrame context. */
1296 if (abi_arch
== SFRAME_ABI_AARCH64_ENDIAN_BIG
1297 || abi_arch
== SFRAME_ABI_AARCH64_ENDIAN_LITTLE
)
1298 return sframe_xlate_do_aarch64_negate_ra_state (xlate_ctx
, cfi_insn
);
1300 as_warn (_("skipping SFrame FDE; .cfi_window_save"));
1301 return SFRAME_XLATE_ERR_NOTREPRESENTED
; /* Not represented. */
1304 /* Returns the DWARF call frame instruction name or fake CFI name for the
1305 specified CFI opcode, or NULL if the value is not recognized. */
1308 sframe_get_cfi_name (int cfi_opc
)
1310 const char *cfi_name
;
1314 /* Fake CFI type; outside the byte range of any real CFI insn. */
1315 /* See gas/dw2gencfi.h. */
1316 case CFI_adjust_cfa_offset
:
1317 cfi_name
= "CFI_adjust_cfa_offset";
1319 case CFI_return_column
:
1320 cfi_name
= "CFI_return_column";
1322 case CFI_rel_offset
:
1323 cfi_name
= "CFI_rel_offset";
1326 cfi_name
= "CFI_escape";
1328 case CFI_signal_frame
:
1329 cfi_name
= "CFI_signal_frame";
1331 case CFI_val_encoded_addr
:
1332 cfi_name
= "CFI_val_encoded_addr";
1335 cfi_name
= "CFI_label";
1338 cfi_name
= get_DW_CFA_name (cfi_opc
);
1344 /* Process CFI_INSN and update the translation context with the FRE
1347 Returns an error code (sframe_xlate_err) if CFI_INSN is not successfully
1351 sframe_do_cfi_insn (struct sframe_xlate_ctx
*xlate_ctx
,
1352 struct cfi_insn_data
*cfi_insn
)
1356 /* Atleast one cfi_insn per FDE is expected. */
1357 gas_assert (cfi_insn
);
1358 int op
= cfi_insn
->insn
;
1362 case DW_CFA_advance_loc
:
1363 err
= sframe_xlate_do_advance_loc (xlate_ctx
, cfi_insn
);
1365 case DW_CFA_def_cfa
:
1366 err
= sframe_xlate_do_def_cfa (xlate_ctx
, cfi_insn
);
1368 case DW_CFA_def_cfa_register
:
1369 err
= sframe_xlate_do_def_cfa_register (xlate_ctx
, cfi_insn
);
1371 case DW_CFA_def_cfa_offset
:
1372 err
= sframe_xlate_do_def_cfa_offset (xlate_ctx
, cfi_insn
);
1375 err
= sframe_xlate_do_offset (xlate_ctx
, cfi_insn
);
1377 case DW_CFA_val_offset
:
1378 err
= sframe_xlate_do_val_offset (xlate_ctx
, cfi_insn
);
1380 case DW_CFA_remember_state
:
1381 err
= sframe_xlate_do_remember_state (xlate_ctx
);
1383 case DW_CFA_restore_state
:
1384 err
= sframe_xlate_do_restore_state (xlate_ctx
);
1386 case DW_CFA_restore
:
1387 err
= sframe_xlate_do_restore (xlate_ctx
, cfi_insn
);
1389 /* DW_CFA_AARCH64_negate_ra_state is multiplexed with
1390 DW_CFA_GNU_window_save. */
1391 case DW_CFA_GNU_window_save
:
1392 err
= sframe_xlate_do_gnu_window_save (xlate_ctx
, cfi_insn
);
1394 case DW_CFA_register
:
1395 err
= sframe_xlate_do_register (xlate_ctx
, cfi_insn
);
1397 /* Following CFI opcodes are not processed at this time.
1398 These do not impact the coverage of the basic stack tracing
1399 information as conveyed in the SFrame format. */
1400 case DW_CFA_undefined
:
1401 case DW_CFA_same_value
:
1404 /* Following skipped operations do, however, impact the asynchronicity:
1407 const char *cfi_name
= sframe_get_cfi_name (op
);
1410 cfi_name
= _("(unknown)");
1411 as_warn (_("skipping SFrame FDE; CFI insn %s (%#x)"),
1413 err
= SFRAME_XLATE_ERR_NOTREPRESENTED
;
1417 /* Any error will cause no SFrame FDE later. The user has already been
1424 sframe_do_fde (struct sframe_xlate_ctx
*xlate_ctx
,
1425 const struct fde_entry
*dw_fde
)
1427 struct cfi_insn_data
*cfi_insn
;
1428 int err
= SFRAME_XLATE_OK
;
1430 xlate_ctx
->dw_fde
= dw_fde
;
1432 /* SFrame format cannot represent a non-default DWARF return column reg. */
1433 if (xlate_ctx
->dw_fde
->return_column
!= DWARF2_DEFAULT_RETURN_COLUMN
)
1435 as_warn (_("skipping SFrame FDE; non-default RA register %u"),
1436 xlate_ctx
->dw_fde
->return_column
);
1437 return SFRAME_XLATE_ERR_NOTREPRESENTED
;
1440 /* Iterate over the CFIs and create SFrame FREs. */
1441 for (cfi_insn
= dw_fde
->data
; cfi_insn
; cfi_insn
= cfi_insn
->next
)
1443 /* Translate each CFI, and buffer the state in translation context. */
1444 err
= sframe_do_cfi_insn (xlate_ctx
, cfi_insn
);
1445 if (err
!= SFRAME_XLATE_OK
)
1447 /* Skip generating SFrame stack trace info for the function if any
1448 offending CFI is encountered by sframe_do_cfi_insn (). Warning
1449 message already printed by sframe_do_cfi_insn (). */
1450 return err
; /* Return the error code. */
1454 /* Link in the scratchpad FRE that the last few CFI insns helped create. */
1455 if (xlate_ctx
->cur_fre
)
1457 sframe_xlate_ctx_add_fre (xlate_ctx
, xlate_ctx
->cur_fre
);
1458 xlate_ctx
->cur_fre
= NULL
;
1460 /* Designate the end of the last SFrame FRE. */
1461 if (xlate_ctx
->last_fre
)
1463 xlate_ctx
->last_fre
->pc_end
1464 = get_dw_fde_end_addrS (xlate_ctx
->dw_fde
);
1467 #ifdef SFRAME_FRE_RA_TRACKING
1468 if (sframe_ra_tracking_p ())
1470 struct sframe_row_entry
*fre
;
1472 /* Iterate over the scratchpad FREs and validate them. */
1473 for (fre
= xlate_ctx
->first_fre
; fre
; fre
= fre
->next
)
1475 /* SFrame format cannot represent FP on stack without RA on stack. */
1476 if (fre
->ra_loc
!= SFRAME_FRE_ELEM_LOC_STACK
1477 && fre
->bp_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
1479 as_warn (_("skipping SFrame FDE; FP without RA on stack"));
1480 return SFRAME_XLATE_ERR_NOTREPRESENTED
;
1484 #endif /* SFRAME_FRE_RA_TRACKING */
1486 return SFRAME_XLATE_OK
;
1489 /* Create SFrame stack trace info for all functions.
1491 This function consumes the already generated DWARF FDEs (by dw2gencfi) and
1492 generates data which is later emitted as stack trace information encoded in
1493 the SFrame format. */
1496 create_sframe_all (void)
1498 struct fde_entry
*dw_fde
= NULL
;
1499 struct sframe_func_entry
*sframe_fde
= NULL
;
1501 struct sframe_xlate_ctx
*xlate_ctx
= sframe_xlate_ctx_alloc ();
1503 for (dw_fde
= all_fde_data
; dw_fde
; dw_fde
= dw_fde
->next
)
1505 sframe_fde
= sframe_fde_alloc ();
1506 /* Initialize the translation context with information anew. */
1507 sframe_xlate_ctx_init (xlate_ctx
);
1509 /* Process and link SFrame FDEs if no error. Also skip adding an SFrame
1510 FDE if it does not contain any SFrame FREs. There is little use of an
1511 SFrame FDE if there is no stack tracing information for the
1513 int err
= sframe_do_fde (xlate_ctx
, dw_fde
);
1514 if (err
|| xlate_ctx
->num_xlate_fres
== 0)
1516 sframe_xlate_ctx_cleanup (xlate_ctx
);
1517 sframe_fde_free (sframe_fde
);
1521 /* All done. Transfer the state from the SFrame translation
1522 context to the SFrame FDE. */
1523 sframe_xlate_ctx_finalize (xlate_ctx
, sframe_fde
);
1524 sframe_fde_link (sframe_fde
);
1528 XDELETE (xlate_ctx
);
1532 output_sframe (segT sframe_seg
)
1536 /* Setup the version specific access functions. */
1537 sframe_set_version (SFRAME_VERSION_2
);
1539 /* Process all fdes and create SFrame stack trace information. */
1540 create_sframe_all ();
1542 output_sframe_internal ();
1545 #else /* support_sframe_p */
1548 output_sframe (segT sframe_seg ATTRIBUTE_UNUSED
)
1552 #endif /* support_sframe_p */