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