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