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_fre
->ra_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
352 return fre_num_offsets
;
355 /* Get the minimum necessary offset size (in bytes) for this
356 SFrame frame row entry. */
359 sframe_get_fre_offset_size (struct sframe_row_entry
*sframe_fre
)
361 unsigned int max_offset_size
= 0;
362 unsigned int cfa_offset_size
= 0;
363 unsigned int bp_offset_size
= 0;
364 unsigned int ra_offset_size
= 0;
366 unsigned int fre_offset_size
= 0;
368 /* What size of offsets appear in this frame row entry. */
369 cfa_offset_size
= get_offset_size_in_bytes (sframe_fre
->cfa_offset
);
370 if (sframe_fre
->bp_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
371 bp_offset_size
= get_offset_size_in_bytes (sframe_fre
->bp_offset
);
372 #ifdef SFRAME_FRE_RA_TRACKING
373 if (sframe_ra_tracking_p ()
374 && sframe_fre
->ra_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
375 ra_offset_size
= get_offset_size_in_bytes (sframe_fre
->ra_offset
);
378 /* Get the maximum size needed to represent the offsets. */
379 max_offset_size
= cfa_offset_size
;
380 if (bp_offset_size
> max_offset_size
)
381 max_offset_size
= bp_offset_size
;
382 if (ra_offset_size
> max_offset_size
)
383 max_offset_size
= ra_offset_size
;
385 gas_assert (max_offset_size
);
387 switch (max_offset_size
)
390 fre_offset_size
= SFRAME_FRE_OFFSET_1B
;
393 fre_offset_size
= SFRAME_FRE_OFFSET_2B
;
396 fre_offset_size
= SFRAME_FRE_OFFSET_4B
;
399 /* Offset of size 8 bytes is not supported in SFrame format
401 as_fatal (_("SFrame unsupported offset value\n"));
405 return fre_offset_size
;
408 #if SFRAME_FRE_TYPE_SELECTION_OPT
410 /* Create a composite expression CEXP (for SFrame FRE start address) such that:
412 exp = <val> OP_absent <width>, where,
414 - <val> and <width> are themselves expressionS.
415 - <val> stores the expression which when evaluated gives the value of the
416 start address offset of the FRE.
417 - <width> stores the expression when evaluated gives the number of bytes
418 needed to encode the start address offset of the FRE.
420 The use of OP_absent as the X_op_symbol helps identify this expression
421 later when fragments are fixed up. */
424 create_fre_start_addr_exp (expressionS
*cexp
, symbolS
*fre_pc_begin
,
425 symbolS
*fde_start_address
,
426 symbolS
*fde_end_address
)
431 /* val expression stores the FDE start address offset from the start PC
433 val
.X_op
= O_subtract
;
434 val
.X_add_symbol
= fre_pc_begin
;
435 val
.X_op_symbol
= fde_start_address
;
436 val
.X_add_number
= 0;
438 /* width expressions stores the size of the function. This is used later
439 to determine the number of bytes to be used to encode the FRE start
440 address of each FRE of the function. */
441 width
.X_op
= O_subtract
;
442 width
.X_add_symbol
= fde_end_address
;
443 width
.X_op_symbol
= fde_start_address
;
444 width
.X_add_number
= 0;
446 cexp
->X_op
= O_absent
;
447 cexp
->X_add_symbol
= make_expr_symbol (&val
);
448 cexp
->X_op_symbol
= make_expr_symbol (&width
);
449 cexp
->X_add_number
= 0;
452 /* Create a composite expression CEXP (for SFrame FDE function info) such that:
454 exp = <rest_of_func_info> OP_modulus <width>, where,
456 - <rest_of_func_info> and <width> are themselves expressionS.
457 - <rest_of_func_info> stores a constant expression where X_add_number is
458 used to stash away the func_info. The upper 4-bits of the func_info are copied
459 back to the resulting byte by the fragment fixup logic.
460 - <width> stores the expression when evaluated gives the size of the
461 function in number of bytes.
463 The use of OP_modulus as the X_op_symbol helps identify this expression
464 later when fragments are fixed up. */
467 create_func_info_exp (expressionS
*cexp
, symbolS
*dw_fde_end_addrS
,
468 symbolS
*dw_fde_start_addrS
, uint8_t func_info
)
471 expressionS rest_of_func_info
;
473 width
.X_op
= O_subtract
;
474 width
.X_add_symbol
= dw_fde_end_addrS
;
475 width
.X_op_symbol
= dw_fde_start_addrS
;
476 width
.X_add_number
= 0;
478 rest_of_func_info
.X_op
= O_constant
;
479 rest_of_func_info
.X_add_number
= func_info
;
481 cexp
->X_op
= O_modulus
;
482 cexp
->X_add_symbol
= make_expr_symbol (&rest_of_func_info
);
483 cexp
->X_op_symbol
= make_expr_symbol (&width
);
484 cexp
->X_add_number
= 0;
490 output_sframe_row_entry (symbolS
*fde_start_addr
,
491 symbolS
*fde_end_addr
,
492 struct sframe_row_entry
*sframe_fre
)
494 unsigned char fre_info
;
495 unsigned int fre_num_offsets
;
496 unsigned int fre_offset_size
;
497 unsigned int fre_base_reg
;
499 unsigned int fre_addr_size
;
501 unsigned int idx
= 0;
502 unsigned int fre_write_offsets
= 0;
504 fre_addr_size
= 4; /* 4 bytes by default. FIXME tie it to fre_type? */
506 /* SFrame FRE Start Address. */
507 #if SFRAME_FRE_TYPE_SELECTION_OPT
508 create_fre_start_addr_exp (&exp
, sframe_fre
->pc_begin
, fde_start_addr
,
510 frag_grow (fre_addr_size
);
511 frag_var (rs_sframe
, fre_addr_size
, 0, (relax_substateT
) 0,
512 make_expr_symbol (&exp
), 0, (char *) frag_now
);
514 gas_assert (fde_end_addr
);
515 exp
.X_op
= O_subtract
;
516 exp
.X_add_symbol
= sframe_fre
->pc_begin
; /* to. */
517 exp
.X_op_symbol
= fde_start_addr
; /* from. */
518 exp
.X_add_number
= 0;
519 emit_expr (&exp
, fre_addr_size
);
522 /* Create the fre_info using the CFA base register, number of offsets and max
523 size of offset in this frame row entry. */
524 fre_base_reg
= get_fre_base_reg_id (sframe_fre
);
525 fre_num_offsets
= get_fre_num_offsets (sframe_fre
);
526 fre_offset_size
= sframe_get_fre_offset_size (sframe_fre
);
527 fre_info
= sframe_set_fre_info (fre_base_reg
, fre_num_offsets
,
528 fre_offset_size
, sframe_fre
->mangled_ra_p
);
531 idx
= sframe_fre_offset_func_map_index (fre_offset_size
);
532 gas_assert (idx
< SFRAME_FRE_OFFSET_FUNC_MAP_INDEX_MAX
);
534 /* Write out the offsets in order - cfa, bp, ra. */
535 fre_offset_func_map
[idx
].out_func (sframe_fre
->cfa_offset
);
538 #ifdef SFRAME_FRE_RA_TRACKING
539 if (sframe_fre
->ra_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
541 fre_offset_func_map
[idx
].out_func (sframe_fre
->ra_offset
);
545 if (sframe_fre
->bp_loc
== SFRAME_FRE_ELEM_LOC_STACK
)
547 fre_offset_func_map
[idx
].out_func (sframe_fre
->bp_offset
);
551 /* Check if the expected number offsets have been written out
553 gas_assert (fre_write_offsets
== fre_num_offsets
);
557 output_sframe_funcdesc (symbolS
*start_of_fre_section
,
559 struct sframe_func_entry
*sframe_fde
)
562 unsigned int addr_size
;
563 symbolS
*dw_fde_start_addrS
, *dw_fde_end_addrS
;
564 unsigned int pauth_key
;
566 addr_size
= SFRAME_RELOC_SIZE
;
567 dw_fde_start_addrS
= get_dw_fde_start_addrS (sframe_fde
->dw_fde
);
568 dw_fde_end_addrS
= get_dw_fde_end_addrS (sframe_fde
->dw_fde
);
570 /* Start address of the function. */
571 exp
.X_op
= O_subtract
;
572 exp
.X_add_symbol
= dw_fde_start_addrS
; /* to location. */
573 exp
.X_op_symbol
= symbol_temp_new_now (); /* from location. */
574 exp
.X_add_number
= 0;
575 emit_expr (&exp
, addr_size
);
577 /* Size of the function in bytes. */
578 exp
.X_op
= O_subtract
;
579 exp
.X_add_symbol
= dw_fde_end_addrS
;
580 exp
.X_op_symbol
= dw_fde_start_addrS
;
581 exp
.X_add_number
= 0;
582 emit_expr (&exp
, addr_size
);
584 /* Offset to the first frame row entry. */
585 exp
.X_op
= O_subtract
;
586 exp
.X_add_symbol
= fre_symbol
; /* Minuend. */
587 exp
.X_op_symbol
= start_of_fre_section
; /* Subtrahend. */
588 exp
.X_add_number
= 0;
589 emit_expr (&exp
, addr_size
);
591 /* Number of FREs. */
592 out_four (sframe_fde
->num_fres
);
594 /* SFrame FDE function info. */
595 unsigned char func_info
;
596 pauth_key
= (get_dw_fde_pauth_b_key_p (sframe_fde
->dw_fde
)
597 ? SFRAME_AARCH64_PAUTH_KEY_B
: SFRAME_AARCH64_PAUTH_KEY_A
);
598 func_info
= sframe_set_func_info (SFRAME_FDE_TYPE_PCINC
,
599 SFRAME_FRE_TYPE_ADDR4
,
601 #if SFRAME_FRE_TYPE_SELECTION_OPT
603 create_func_info_exp (&cexp
, dw_fde_end_addrS
, dw_fde_start_addrS
,
605 frag_grow (1); /* Size of func info is unsigned char. */
606 frag_var (rs_sframe
, 1, 0, (relax_substateT
) 0,
607 make_expr_symbol (&cexp
), 0, (char *) frag_now
);
616 output_sframe_internal (void)
621 symbolS
*end_of_frame_hdr
;
622 symbolS
*end_of_frame_section
;
623 symbolS
*start_of_func_desc_section
;
624 symbolS
*start_of_fre_section
;
625 struct sframe_func_entry
*sframe_fde
;
626 struct sframe_row_entry
*sframe_fre
;
627 unsigned char abi_arch
= 0;
628 int fixed_bp_offset
= SFRAME_CFA_FIXED_FP_INVALID
;
629 int fixed_ra_offset
= SFRAME_CFA_FIXED_RA_INVALID
;
630 unsigned int addr_size
;
632 addr_size
= SFRAME_RELOC_SIZE
;
634 /* The function descriptor entries as dumped by the assembler are not
636 unsigned char sframe_flags
= 0;
637 sframe_flags
|= !SFRAME_F_FDE_SORTED
;
639 unsigned int num_fdes
= get_num_sframe_fdes ();
640 unsigned int num_fres
= get_num_sframe_fres ();
641 symbolS
**fre_symbols
= XNEWVEC (symbolS
*, num_fres
);
642 for (i
= 0; i
< num_fres
; i
++)
643 fre_symbols
[i
] = symbol_temp_make ();
645 end_of_frame_hdr
= symbol_temp_make ();
646 start_of_fre_section
= symbol_temp_make ();
647 start_of_func_desc_section
= symbol_temp_make ();
648 end_of_frame_section
= symbol_temp_make ();
650 /* Output the preamble of SFrame section. */
651 out_two (SFRAME_MAGIC
);
652 out_one (SFRAME_VERSION
);
653 out_one (sframe_flags
);
655 #ifdef sframe_get_abi_arch
656 abi_arch
= sframe_get_abi_arch ();
658 gas_assert (abi_arch
);
661 /* Offset for the BP register from CFA. Neither of the AMD64 or AAPCS64
662 ABIs have a fixed offset for the BP register from the CFA. This may be
663 useful in future (but not without additional support in the toolchain)
664 for specialized handling/encoding for cases where, for example,
665 -fno-omit-frame-pointer is used. */
666 out_one (fixed_bp_offset
);
668 /* Offset for the return address from CFA is fixed for some ABIs
669 (e.g., AMD64), output a SFRAME_CFA_FIXED_RA_INVALID otherwise. */
670 #ifdef sframe_ra_tracking_p
671 if (!sframe_ra_tracking_p ())
672 fixed_ra_offset
= sframe_cfa_ra_offset ();
674 out_one (fixed_ra_offset
);
676 /* None of the AMD64, or AARCH64 ABIs need the auxiliary header.
677 When the need does arise to use this field, the appropriate backend
678 must provide this information. */
679 out_one (0); /* Auxiliary SFrame header length. */
681 out_four (num_fdes
); /* Number of FDEs. */
682 out_four (num_fres
); /* Number of FREs. */
684 /* FRE sub-section len. */
685 exp
.X_op
= O_subtract
;
686 exp
.X_add_symbol
= end_of_frame_section
;
687 exp
.X_op_symbol
= start_of_fre_section
;
688 exp
.X_add_number
= 0;
689 emit_expr (&exp
, addr_size
);
691 /* Offset of Function Index sub-section. */
692 exp
.X_op
= O_subtract
;
693 exp
.X_add_symbol
= end_of_frame_hdr
;
694 exp
.X_op_symbol
= start_of_func_desc_section
;
695 exp
.X_add_number
= 0;
696 emit_expr (&exp
, addr_size
);
698 /* Offset of FRE sub-section. */
699 exp
.X_op
= O_subtract
;
700 exp
.X_add_symbol
= start_of_fre_section
;
701 exp
.X_op_symbol
= end_of_frame_hdr
;
702 exp
.X_add_number
= 0;
703 emit_expr (&exp
, addr_size
);
705 symbol_set_value_now (end_of_frame_hdr
);
706 symbol_set_value_now (start_of_func_desc_section
);
708 /* Output the SFrame function descriptor entries. */
710 for (sframe_fde
= all_sframe_fdes
; sframe_fde
; sframe_fde
= sframe_fde
->next
)
712 output_sframe_funcdesc (start_of_fre_section
,
713 fre_symbols
[i
], sframe_fde
);
714 i
+= sframe_fde
->num_fres
;
717 symbol_set_value_now (start_of_fre_section
);
719 /* Output the SFrame FREs. */
721 sframe_fde
= all_sframe_fdes
;
723 for (sframe_fde
= all_sframe_fdes
; sframe_fde
; sframe_fde
= sframe_fde
->next
)
725 for (sframe_fre
= sframe_fde
->sframe_fres
;
727 sframe_fre
= sframe_fre
->next
)
729 symbol_set_value_now (fre_symbols
[i
]);
730 output_sframe_row_entry (get_dw_fde_start_addrS (sframe_fde
->dw_fde
),
731 get_dw_fde_end_addrS (sframe_fde
->dw_fde
),
737 symbol_set_value_now (end_of_frame_section
);
739 gas_assert (i
== num_fres
);
745 /* List of SFrame FDE entries. */
747 struct sframe_func_entry
*all_sframe_fdes
;
749 /* Tail of the list to add to. */
751 static struct sframe_func_entry
**last_sframe_fde
= &all_sframe_fdes
;
754 get_num_sframe_fdes (void)
756 struct sframe_func_entry
*sframe_fde
;
757 unsigned int total_fdes
= 0;
759 for (sframe_fde
= all_sframe_fdes
; sframe_fde
; sframe_fde
= sframe_fde
->next
)
765 /* Get the total number of SFrame row entries across the FDEs. */
768 get_num_sframe_fres (void)
770 struct sframe_func_entry
*sframe_fde
;
771 unsigned int total_fres
= 0;
773 for (sframe_fde
= all_sframe_fdes
; sframe_fde
; sframe_fde
= sframe_fde
->next
)
774 total_fres
+= sframe_fde
->num_fres
;
779 /* Allocate an SFrame FDE. */
781 static struct sframe_func_entry
*
782 sframe_fde_alloc (void)
784 struct sframe_func_entry
*sframe_fde
= XCNEW (struct sframe_func_entry
);
788 /* Link the SFrame FDE in. */
791 sframe_fde_link (struct sframe_func_entry
*sframe_fde
)
793 *last_sframe_fde
= sframe_fde
;
794 last_sframe_fde
= &sframe_fde
->next
;
799 /* Free up the SFrame FDE. */
802 sframe_fde_free (struct sframe_func_entry
*sframe_fde
)
804 XDELETE (sframe_fde
);
808 /* SFrame translation context functions. */
810 /* Allocate a new SFrame translation context. */
812 static struct sframe_xlate_ctx
*
813 sframe_xlate_ctx_alloc (void)
815 struct sframe_xlate_ctx
* xlate_ctx
= XCNEW (struct sframe_xlate_ctx
);
819 /* Initialize the given SFrame translation context. */
822 sframe_xlate_ctx_init (struct sframe_xlate_ctx
*xlate_ctx
)
824 xlate_ctx
->dw_fde
= NULL
;
825 xlate_ctx
->first_fre
= NULL
;
826 xlate_ctx
->last_fre
= NULL
;
827 xlate_ctx
->cur_fre
= NULL
;
828 xlate_ctx
->remember_fre
= NULL
;
829 xlate_ctx
->num_xlate_fres
= 0;
832 /* Cleanup the given SFrame translation context. */
835 sframe_xlate_ctx_cleanup (struct sframe_xlate_ctx
*xlate_ctx
)
837 struct sframe_row_entry
*fre
, *fre_next
;
839 if (xlate_ctx
->num_xlate_fres
)
841 fre
= xlate_ctx
->first_fre
;
844 fre_next
= fre
->next
;
850 XDELETE (xlate_ctx
->cur_fre
);
852 sframe_xlate_ctx_init (xlate_ctx
);
855 /* Transfer the state from the SFrame translation context to the SFrame FDE. */
858 sframe_xlate_ctx_finalize (struct sframe_xlate_ctx
*xlate_ctx
,
859 struct sframe_func_entry
*sframe_fde
)
861 sframe_fde
->dw_fde
= xlate_ctx
->dw_fde
;
862 sframe_fde
->sframe_fres
= xlate_ctx
->first_fre
;
863 sframe_fde
->num_fres
= xlate_ctx
->num_xlate_fres
;
866 static struct sframe_row_entry
*
867 sframe_row_entry_new (void)
869 struct sframe_row_entry
*fre
= XCNEW (struct sframe_row_entry
);
870 /* Reset cfa_base_reg to -1. A value of 0 will imply some valid register
871 for the supported arches. */
872 fre
->cfa_base_reg
= -1;
873 fre
->merge_candidate
= true;
874 /* Reset the mangled RA status bit to zero by default. We will initialize it in
875 sframe_row_entry_initialize () with the sticky bit if set. */
876 fre
->mangled_ra_p
= false;
881 /* Add the given FRE in the list of frame row entries in the given FDE
882 translation context. */
885 sframe_xlate_ctx_add_fre (struct sframe_xlate_ctx
*xlate_ctx
,
886 struct sframe_row_entry
*fre
)
888 gas_assert (xlate_ctx
&& fre
);
890 /* Add the frame row entry. */
891 if (!xlate_ctx
->first_fre
)
892 xlate_ctx
->first_fre
= fre
;
893 else if (xlate_ctx
->last_fre
)
894 xlate_ctx
->last_fre
->next
= fre
;
896 xlate_ctx
->last_fre
= fre
;
898 /* Keep track of the total number of SFrame frame row entries. */
899 xlate_ctx
->num_xlate_fres
++;
902 /* A SFrame Frame Row Entry is self-sufficient in terms of stack tracing info
903 for a given PC. It contains information assimilated from multiple CFI
904 instructions, and hence, a new SFrame FRE is initialized with the data from
905 the previous known FRE, if any.
907 Understandably, not all information (especially the instruction begin
908 and end boundaries) needs to be relayed. Hence, the caller of this API
909 must set the pc_begin and pc_end as applicable. */
912 sframe_row_entry_initialize (struct sframe_row_entry
*cur_fre
,
913 struct sframe_row_entry
*prev_fre
)
915 gas_assert (prev_fre
);
916 cur_fre
->cfa_base_reg
= prev_fre
->cfa_base_reg
;
917 cur_fre
->cfa_offset
= prev_fre
->cfa_offset
;
918 cur_fre
->bp_loc
= prev_fre
->bp_loc
;
919 cur_fre
->bp_offset
= prev_fre
->bp_offset
;
920 cur_fre
->ra_loc
= prev_fre
->ra_loc
;
921 cur_fre
->ra_offset
= prev_fre
->ra_offset
;
922 /* Treat RA mangling as a sticky bit. It retains its value until another
923 .cfi_negate_ra_state is seen. */
924 cur_fre
->mangled_ra_p
= prev_fre
->mangled_ra_p
;
927 /* Translate DW_CFA_advance_loc into SFrame context.
928 Return SFRAME_XLATE_OK if success. */
931 sframe_xlate_do_advance_loc (struct sframe_xlate_ctx
*xlate_ctx
,
932 struct cfi_insn_data
*cfi_insn
)
934 struct sframe_row_entry
*last_fre
= xlate_ctx
->last_fre
;
935 /* Get the scratchpad FRE currently being updated as the cfi_insn's
936 get interpreted. This FRE eventually gets linked in into the
937 list of FREs for the specific function. */
938 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
942 if (!cur_fre
->merge_candidate
)
944 sframe_fre_set_end_addr (cur_fre
, cfi_insn
->u
.ll
.lab2
);
946 sframe_xlate_ctx_add_fre (xlate_ctx
, cur_fre
);
947 last_fre
= xlate_ctx
->last_fre
;
949 xlate_ctx
->cur_fre
= sframe_row_entry_new ();
950 cur_fre
= xlate_ctx
->cur_fre
;
953 sframe_row_entry_initialize (cur_fre
, last_fre
);
957 sframe_fre_set_end_addr (last_fre
, cfi_insn
->u
.ll
.lab2
);
958 gas_assert (last_fre
->merge_candidate
== false);
963 xlate_ctx
->cur_fre
= sframe_row_entry_new ();
964 cur_fre
= xlate_ctx
->cur_fre
;
967 gas_assert (cur_fre
);
968 sframe_fre_set_begin_addr (cur_fre
, cfi_insn
->u
.ll
.lab2
);
970 return SFRAME_XLATE_OK
;
973 /* Translate DW_CFA_def_cfa into SFrame context.
974 Return SFRAME_XLATE_OK if success. */
977 sframe_xlate_do_def_cfa (struct sframe_xlate_ctx
*xlate_ctx
,
978 struct cfi_insn_data
*cfi_insn
)
981 /* Get the scratchpad FRE. This FRE will eventually get linked in. */
982 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
985 xlate_ctx
->cur_fre
= sframe_row_entry_new ();
986 cur_fre
= xlate_ctx
->cur_fre
;
987 sframe_fre_set_begin_addr (cur_fre
,
988 get_dw_fde_start_addrS (xlate_ctx
->dw_fde
));
990 /* Define the current CFA rule to use the provided register and
992 sframe_fre_set_cfa_base_reg (cur_fre
, cfi_insn
->u
.ri
.reg
);
993 sframe_fre_set_cfa_offset (cur_fre
, cfi_insn
->u
.ri
.offset
);
994 cur_fre
->merge_candidate
= false;
996 return SFRAME_XLATE_OK
;
999 /* Translate DW_CFA_def_cfa_register into SFrame context.
1000 Return SFRAME_XLATE_OK if success. */
1003 sframe_xlate_do_def_cfa_register (struct sframe_xlate_ctx
*xlate_ctx
,
1004 struct cfi_insn_data
*cfi_insn
)
1006 struct sframe_row_entry
*last_fre
= xlate_ctx
->last_fre
;
1007 /* Get the scratchpad FRE. This FRE will eventually get linked in. */
1008 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1009 gas_assert (cur_fre
);
1010 /* Define the current CFA rule to use the provided register (but to
1011 keep the old offset). */
1012 sframe_fre_set_cfa_base_reg (cur_fre
, cfi_insn
->u
.ri
.reg
);
1013 sframe_fre_set_cfa_offset (cur_fre
, last_fre
->cfa_offset
);
1014 cur_fre
->merge_candidate
= false;
1016 return SFRAME_XLATE_OK
;
1019 /* Translate DW_CFA_def_cfa_offset into SFrame context.
1020 Return SFRAME_XLATE_OK if success. */
1023 sframe_xlate_do_def_cfa_offset (struct sframe_xlate_ctx
*xlate_ctx
,
1024 struct cfi_insn_data
*cfi_insn
)
1026 /* The scratchpad FRE currently being updated with each cfi_insn
1027 being interpreted. This FRE eventually gets linked in into the
1028 list of FREs for the specific function. */
1029 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1031 gas_assert (cur_fre
);
1032 /* Define the current CFA rule to use the provided offset (but to keep
1033 the old register). However, if the old register is not FP/SP,
1034 skip creating SFrame stack trace info for the function. */
1035 if ((cur_fre
->cfa_base_reg
== SFRAME_CFA_FP_REG
)
1036 || (cur_fre
->cfa_base_reg
== SFRAME_CFA_SP_REG
))
1038 sframe_fre_set_cfa_offset (cur_fre
, cfi_insn
->u
.i
);
1039 cur_fre
->merge_candidate
= false;
1042 return SFRAME_XLATE_ERR_NOTREPRESENTED
;
1044 return SFRAME_XLATE_OK
;
1047 /* Translate DW_CFA_offset into SFrame context.
1048 Return SFRAME_XLATE_OK if success. */
1051 sframe_xlate_do_offset (struct sframe_xlate_ctx
*xlate_ctx
,
1052 struct cfi_insn_data
*cfi_insn
)
1054 /* The scratchpad FRE currently being updated with each cfi_insn
1055 being interpreted. This FRE eventually gets linked in into the
1056 list of FREs for the specific function. */
1057 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1059 gas_assert (cur_fre
);
1060 /* Change the rule for the register indicated by the register number to
1061 be the specified offset. */
1062 if (cfi_insn
->u
.r
== SFRAME_CFA_FP_REG
)
1064 gas_assert (!cur_fre
->base_reg
);
1065 sframe_fre_set_bp_track (cur_fre
, cfi_insn
->u
.ri
.offset
);
1066 cur_fre
->merge_candidate
= false;
1068 #ifdef SFRAME_FRE_RA_TRACKING
1069 else if (sframe_ra_tracking_p ()
1070 && cfi_insn
->u
.r
== SFRAME_CFA_RA_REG
)
1072 sframe_fre_set_ra_track (cur_fre
, cfi_insn
->u
.ri
.offset
);
1073 cur_fre
->merge_candidate
= false;
1076 /* This is used to track changes to non-rsp registers, skip all others
1077 except FP / RA for now. */
1078 return SFRAME_XLATE_OK
;
1081 /* Translate DW_CFA_val_offset into SFrame context.
1082 Return SFRAME_XLATE_OK if success. */
1085 sframe_xlate_do_val_offset (struct sframe_xlate_ctx
*xlate_ctx ATTRIBUTE_UNUSED
,
1086 struct cfi_insn_data
*cfi_insn
)
1088 /* Previous value of register is CFA + offset. However, if the specified
1089 register is not interesting (FP or RA reg), the current DW_CFA_val_offset
1090 instruction can be safely skipped without sacrificing the asynchronicity of
1091 stack trace information. */
1092 if (cfi_insn
->u
.r
== SFRAME_CFA_FP_REG
)
1093 return SFRAME_XLATE_ERR_NOTREPRESENTED
; /* Not represented. */
1094 #ifdef SFRAME_FRE_RA_TRACKING
1095 else if (sframe_ra_tracking_p ()
1096 && cfi_insn
->u
.r
== SFRAME_CFA_RA_REG
)
1097 return SFRAME_XLATE_ERR_NOTREPRESENTED
; /* Not represented. */
1101 return SFRAME_XLATE_OK
;
1104 /* Translate DW_CFA_remember_state into SFrame context.
1105 Return SFRAME_XLATE_OK if success. */
1108 sframe_xlate_do_remember_state (struct sframe_xlate_ctx
*xlate_ctx
)
1110 struct sframe_row_entry
*last_fre
= xlate_ctx
->last_fre
;
1112 /* If there is no FRE state to remember, nothing to do here. Return
1113 early with non-zero error code, this will cause no SFrame stack trace
1114 info for the function involved. */
1116 return SFRAME_XLATE_ERR_INVAL
;
1118 if (!xlate_ctx
->remember_fre
)
1119 xlate_ctx
->remember_fre
= sframe_row_entry_new ();
1120 sframe_row_entry_initialize (xlate_ctx
->remember_fre
, last_fre
);
1122 return SFRAME_XLATE_OK
;
1125 /* Translate DW_CFA_restore_state into SFrame context.
1126 Return SFRAME_XLATE_OK if success. */
1129 sframe_xlate_do_restore_state (struct sframe_xlate_ctx
*xlate_ctx
)
1131 /* The scratchpad FRE currently being updated with each cfi_insn
1132 being interpreted. This FRE eventually gets linked in into the
1133 list of FREs for the specific function. */
1134 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1136 gas_assert (xlate_ctx
->remember_fre
);
1137 gas_assert (cur_fre
&& cur_fre
->merge_candidate
);
1139 /* Get the CFA state from the DW_CFA_remember_state insn. */
1140 sframe_row_entry_initialize (cur_fre
, xlate_ctx
->remember_fre
);
1141 /* The PC boundaries of the current SFrame FRE are updated
1142 via other machinery. */
1143 cur_fre
->merge_candidate
= false;
1144 return SFRAME_XLATE_OK
;
1147 /* Translate DW_CFA_restore into SFrame context.
1148 Return SFRAME_XLATE_OK if success. */
1151 sframe_xlate_do_restore (struct sframe_xlate_ctx
*xlate_ctx
,
1152 struct cfi_insn_data
*cfi_insn
)
1154 struct sframe_row_entry
*cie_fre
= xlate_ctx
->first_fre
;
1155 /* The scratchpad FRE currently being updated with each cfi_insn
1156 being interpreted. This FRE eventually gets linked in into the
1157 list of FREs for the specific function. */
1158 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1160 /* Change the rule for the indicated register to the rule assigned to
1161 it by the initial_instructions in the CIE. */
1162 gas_assert (cie_fre
);
1163 /* SFrame FREs track only CFA and FP / RA for backtracing purposes;
1164 skip the other .cfi_restore directives. */
1165 if (cfi_insn
->u
.r
== SFRAME_CFA_FP_REG
)
1167 gas_assert (cur_fre
);
1168 cur_fre
->bp_loc
= cie_fre
->bp_loc
;
1169 cur_fre
->bp_offset
= cie_fre
->bp_offset
;
1170 cur_fre
->merge_candidate
= false;
1172 #ifdef SFRAME_FRE_RA_TRACKING
1173 else if (sframe_ra_tracking_p ()
1174 && cfi_insn
->u
.r
== SFRAME_CFA_RA_REG
)
1176 gas_assert (cur_fre
);
1177 cur_fre
->ra_loc
= cie_fre
->ra_loc
;
1178 cur_fre
->ra_offset
= cie_fre
->ra_offset
;
1179 cur_fre
->merge_candidate
= false;
1182 return SFRAME_XLATE_OK
;
1185 /* Translate DW_CFA_GNU_window_save into SFrame context.
1186 Return SFRAME_XLATE_OK if success. */
1189 sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx
*xlate_ctx
,
1190 struct cfi_insn_data
*cfi_insn ATTRIBUTE_UNUSED
)
1192 struct sframe_row_entry
*cur_fre
= xlate_ctx
->cur_fre
;
1194 gas_assert (cur_fre
);
1195 /* Toggle the mangled RA status bit. */
1196 cur_fre
->mangled_ra_p
= !cur_fre
->mangled_ra_p
;
1197 cur_fre
->merge_candidate
= false;
1199 return SFRAME_XLATE_OK
;
1202 /* Process CFI_INSN and update the translation context with the FRE
1205 Returns an error code (sframe_xlate_err) if CFI_INSN is not successfully
1209 sframe_do_cfi_insn (struct sframe_xlate_ctx
*xlate_ctx
,
1210 struct cfi_insn_data
*cfi_insn
)
1214 /* Atleast one cfi_insn per FDE is expected. */
1215 gas_assert (cfi_insn
);
1216 int op
= cfi_insn
->insn
;
1220 case DW_CFA_advance_loc
:
1221 err
= sframe_xlate_do_advance_loc (xlate_ctx
, cfi_insn
);
1223 case DW_CFA_def_cfa
:
1224 err
= sframe_xlate_do_def_cfa (xlate_ctx
, cfi_insn
);
1226 case DW_CFA_def_cfa_register
:
1227 err
= sframe_xlate_do_def_cfa_register (xlate_ctx
, cfi_insn
);
1229 case DW_CFA_def_cfa_offset
:
1230 err
= sframe_xlate_do_def_cfa_offset (xlate_ctx
, cfi_insn
);
1233 err
= sframe_xlate_do_offset (xlate_ctx
, cfi_insn
);
1235 case DW_CFA_val_offset
:
1236 err
= sframe_xlate_do_val_offset (xlate_ctx
, cfi_insn
);
1238 case DW_CFA_remember_state
:
1239 err
= sframe_xlate_do_remember_state (xlate_ctx
);
1241 case DW_CFA_restore_state
:
1242 err
= sframe_xlate_do_restore_state (xlate_ctx
);
1244 case DW_CFA_restore
:
1245 err
= sframe_xlate_do_restore (xlate_ctx
, cfi_insn
);
1247 /* DW_CFA_AARCH64_negate_ra_state is multiplexed with
1248 DW_CFA_GNU_window_save. */
1249 case DW_CFA_GNU_window_save
:
1250 err
= sframe_xlate_do_gnu_window_save (xlate_ctx
, cfi_insn
);
1252 /* Other CFI opcodes are not processed at this time.
1253 These do not impact the coverage of the basic stack tracing
1254 information as conveyed in the SFrame format.
1257 case DW_CFA_register
:
1258 if (cfi_insn
->u
.rr
.reg1
== SFRAME_CFA_SP_REG
1259 #ifdef SFRAME_FRE_RA_TRACKING
1260 || cfi_insn
->u
.rr
.reg1
== SFRAME_CFA_RA_REG
1262 || cfi_insn
->u
.rr
.reg1
== SFRAME_CFA_FP_REG
)
1263 err
= SFRAME_XLATE_ERR_NOTREPRESENTED
;
1265 case DW_CFA_undefined
:
1266 case DW_CFA_same_value
:
1269 /* Following skipped operations do, however, impact the asynchronicity:
1271 err
= SFRAME_XLATE_ERR_NOTREPRESENTED
;
1274 /* An error here will cause no SFrame FDE later. Warn the user because this
1275 will affect the overall coverage and hence, asynchronicity. */
1277 as_warn (_("skipping SFrame FDE due to DWARF CFI op %#x"), op
);
1284 sframe_do_fde (struct sframe_xlate_ctx
*xlate_ctx
,
1285 const struct fde_entry
*dw_fde
)
1287 struct cfi_insn_data
*cfi_insn
;
1288 int err
= SFRAME_XLATE_OK
;
1290 xlate_ctx
->dw_fde
= dw_fde
;
1292 /* If the return column is not RIP, SFrame format cannot represent it. */
1293 if (xlate_ctx
->dw_fde
->return_column
!= DWARF2_DEFAULT_RETURN_COLUMN
)
1294 return SFRAME_XLATE_ERR_NOTREPRESENTED
;
1296 /* Iterate over the CFIs and create SFrame FREs. */
1297 for (cfi_insn
= dw_fde
->data
; cfi_insn
; cfi_insn
= cfi_insn
->next
)
1299 /* Translate each CFI, and buffer the state in translation context. */
1300 err
= sframe_do_cfi_insn (xlate_ctx
, cfi_insn
);
1301 if (err
!= SFRAME_XLATE_OK
)
1303 /* Skip generating SFrame stack trace info for the function if any
1304 offending CFI is encountered by sframe_do_cfi_insn (). */
1305 return err
; /* Return the error code. */
1309 /* No errors encountered. */
1311 /* Link in the scratchpad FRE that the last few CFI insns helped create. */
1312 if (xlate_ctx
->cur_fre
)
1314 sframe_xlate_ctx_add_fre (xlate_ctx
, xlate_ctx
->cur_fre
);
1315 xlate_ctx
->cur_fre
= NULL
;
1317 /* Designate the end of the last SFrame FRE. */
1318 if (xlate_ctx
->last_fre
)
1320 xlate_ctx
->last_fre
->pc_end
1321 = get_dw_fde_end_addrS (xlate_ctx
->dw_fde
);
1324 return SFRAME_XLATE_OK
;
1327 /* Create SFrame stack trace info for all functions.
1329 This function consumes the already generated DWARF FDEs (by dw2gencfi) and
1330 generates data which is later emitted as stack trace information encoded in
1331 the SFrame format. */
1334 create_sframe_all (void)
1336 struct fde_entry
*dw_fde
= NULL
;
1337 struct sframe_func_entry
*sframe_fde
= NULL
;
1339 struct sframe_xlate_ctx
*xlate_ctx
= sframe_xlate_ctx_alloc ();
1341 for (dw_fde
= all_fde_data
; dw_fde
; dw_fde
= dw_fde
->next
)
1343 sframe_fde
= sframe_fde_alloc ();
1344 /* Initialize the translation context with information anew. */
1345 sframe_xlate_ctx_init (xlate_ctx
);
1347 /* Process and link SFrame FDEs if no error. Also skip adding an SFrame
1348 FDE if it does not contain any SFrame FREs. There is little use of an
1349 SFrame FDE if there is no stack tracing information for the
1351 int err
= sframe_do_fde (xlate_ctx
, dw_fde
);
1352 if (err
|| xlate_ctx
->num_xlate_fres
== 0)
1354 sframe_xlate_ctx_cleanup (xlate_ctx
);
1355 sframe_fde_free (sframe_fde
);
1359 /* All done. Transfer the state from the SFrame translation
1360 context to the SFrame FDE. */
1361 sframe_xlate_ctx_finalize (xlate_ctx
, sframe_fde
);
1362 sframe_fde_link (sframe_fde
);
1366 XDELETE (xlate_ctx
);
1370 output_sframe (segT sframe_seg
)
1374 /* Setup the version specific access functions. */
1375 sframe_set_version (SFRAME_VERSION_2
);
1377 /* Process all fdes and create SFrame stack trace information. */
1378 create_sframe_all ();
1380 output_sframe_internal ();
1383 #else /* support_sframe_p */
1386 output_sframe (segT sframe_seg ATTRIBUTE_UNUSED
)
1390 #endif /* support_sframe_p */