Home | History | Annotate | Line # | Download | only in gas
      1 /* scfidw2gen.c - Support for emission of synthesized Dwarf2 CFI.
      2    Copyright (C) 2023-2025 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 "ginsn.h"
     23 #include "scfi.h"
     24 #include "dw2gencfi.h"
     25 #include "subsegs.h"
     26 #include "scfidw2gen.h"
     27 
     28 #if defined (TARGET_USE_SCFI) && defined (TARGET_USE_GINSN)
     29 
     30 static bool scfi_ignore_warn_once;
     31 
     32 static void
     33 dot_scfi_ignore (int ignored ATTRIBUTE_UNUSED)
     34 {
     35   gas_assert (flag_synth_cfi);
     36 
     37   if (!scfi_ignore_warn_once)
     38     {
     39       as_warn (_("SCFI ignores most user-specified CFI directives"));
     40       scfi_ignore_warn_once = true;
     41     }
     42   ignore_rest_of_line ();
     43 }
     44 
     45 static void
     46 scfi_process_cfi_label (void)
     47 {
     48   char *name;
     49   ginsnS *ginsn;
     50 
     51   name = read_symbol_name ();
     52   if (name == NULL)
     53     return;
     54 
     55   /* Add a new ginsn.  */
     56   ginsn = ginsn_new_phantom (symbol_temp_new_now ());
     57   frch_ginsn_data_append (ginsn);
     58 
     59   scfi_op_add_cfi_label (ginsn, name);
     60   /* NB: Can't free NAME here since it will be used later.  Free it in
     61      handle_scfi_dot_cfi after it is unused.  */
     62 
     63   demand_empty_rest_of_line ();
     64 }
     65 
     66 static void
     67 scfi_process_cfi_signal_frame (void)
     68 {
     69   ginsnS *ginsn;
     70 
     71   ginsn = ginsn_new_phantom (symbol_temp_new_now ());
     72   frch_ginsn_data_append (ginsn);
     73 
     74   scfi_op_add_signal_frame (ginsn);
     75 }
     76 
     77 static void
     78 dot_scfi (int arg)
     79 {
     80   switch (arg)
     81     {
     82       case CFI_label:
     83 	scfi_process_cfi_label ();
     84 	break;
     85       case CFI_signal_frame:
     86 	scfi_process_cfi_signal_frame ();
     87 	break;
     88       default:
     89 	abort ();
     90     }
     91 }
     92 
     93 const pseudo_typeS scfi_pseudo_table[] =
     94   {
     95     { "cfi_sections", dot_cfi_sections, 0 }, /* No ignore.  */
     96     { "cfi_signal_frame", dot_scfi, CFI_signal_frame }, /* No ignore.  */
     97     { "cfi_label", dot_scfi, CFI_label }, /* No ignore.  */
     98     { "cfi_startproc", dot_scfi_ignore, 0 },
     99     { "cfi_endproc", dot_scfi_ignore, 0 },
    100     { "cfi_fde_data", dot_scfi_ignore, 0 },
    101     { "cfi_def_cfa", dot_scfi_ignore, 0 },
    102     { "cfi_def_cfa_register", dot_scfi_ignore, 0 },
    103     { "cfi_def_cfa_offset", dot_scfi_ignore, 0 },
    104     { "cfi_adjust_cfa_offset", dot_scfi_ignore, 0 },
    105     { "cfi_offset", dot_scfi_ignore, 0 },
    106     { "cfi_rel_offset", dot_scfi_ignore, 0 },
    107     { "cfi_register", dot_scfi_ignore, 0 },
    108     { "cfi_return_column", dot_scfi_ignore, 0 },
    109     { "cfi_restore", dot_scfi_ignore, 0 },
    110     { "cfi_undefined", dot_scfi_ignore, 0 },
    111     { "cfi_same_value", dot_scfi_ignore, 0 },
    112     { "cfi_remember_state", dot_scfi_ignore, 0 },
    113     { "cfi_restore_state", dot_scfi_ignore, 0 },
    114     { "cfi_window_save", dot_scfi_ignore, 0 },
    115     { "cfi_negate_ra_state", dot_scfi_ignore, 0 },
    116     { "cfi_negate_ra_state_with_pc", dot_scfi_ignore, 0 },
    117     { "cfi_escape", dot_scfi_ignore, 0 },
    118     { "cfi_personality", dot_scfi_ignore, 0 },
    119     { "cfi_personality_id", dot_scfi_ignore, 0 },
    120     { "cfi_lsda", dot_scfi_ignore, 0 },
    121     { "cfi_val_encoded_addr", dot_scfi_ignore, 0 },
    122     { "cfi_inline_lsda", dot_scfi_ignore, 0 },
    123     { "cfi_val_offset", dot_scfi_ignore, 0 },
    124     { NULL, NULL, 0 }
    125   };
    126 
    127 void
    128 scfi_dot_cfi_startproc (const symbolS *start_sym)
    129 {
    130   if (frchain_now->frch_cfi_data != NULL)
    131     {
    132       as_bad (_("SCFI: missing previous SCFI endproc marker"));
    133       return;
    134     }
    135 
    136   cfi_new_fde ((symbolS *)start_sym, false);
    137 
    138   cfi_set_sections ();
    139 
    140   frchain_now->frch_cfi_data->cur_cfa_offset = 0;
    141 
    142   /* By default, SCFI machinery assumes .cfi_startproc is used without
    143      parameter simple.  */
    144   tc_cfi_frame_initial_instructions ();
    145 
    146   if ((all_cfi_sections & CFI_EMIT_target) != 0)
    147     tc_cfi_startproc ();
    148 }
    149 
    150 void
    151 scfi_dot_cfi_endproc (const symbolS *end_sym)
    152 {
    153   struct fde_entry *fde_last;
    154 
    155   if (frchain_now->frch_cfi_data == NULL)
    156     {
    157       as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
    158       return;
    159     }
    160 
    161   fde_last = frchain_now->frch_cfi_data->cur_fde_data;
    162   cfi_set_last_fde (fde_last);
    163 
    164   cfi_end_fde ((symbolS *)end_sym);
    165 
    166   if ((all_cfi_sections & CFI_EMIT_target) != 0)
    167     tc_cfi_endproc (fde_last);
    168 }
    169 
    170 void
    171 scfi_dot_cfi (int arg, unsigned reg1, unsigned reg2, offsetT offset,
    172 	      const char *name, const symbolS *advloc)
    173 {
    174   if (frchain_now->frch_cfi_data == NULL)
    175     {
    176       as_bad (_("CFI instruction used without previous .cfi_startproc"));
    177       return;
    178     }
    179 
    180   /* If the last address was not at the current PC, advance to current.  */
    181   if (frchain_now->frch_cfi_data->last_address != advloc)
    182     cfi_add_advance_loc ((symbolS *)advloc);
    183 
    184   switch (arg)
    185     {
    186     case DW_CFA_offset:
    187       cfi_add_CFA_offset (reg1, offset);
    188       break;
    189 
    190     case DW_CFA_val_offset:
    191       cfi_add_CFA_val_offset (reg1, offset);
    192       break;
    193 
    194     case CFI_rel_offset:
    195       cfi_add_CFA_offset (reg1,
    196 			  offset - frchain_now->frch_cfi_data->cur_cfa_offset);
    197       break;
    198 
    199     case DW_CFA_def_cfa:
    200       cfi_add_CFA_def_cfa (reg1, offset);
    201       break;
    202 
    203     case DW_CFA_register:
    204       cfi_add_CFA_register (reg1, reg2);
    205       break;
    206 
    207     case DW_CFA_def_cfa_register:
    208       cfi_add_CFA_def_cfa_register (reg1);
    209       break;
    210 
    211     case DW_CFA_def_cfa_offset:
    212       cfi_add_CFA_def_cfa_offset (offset);
    213       break;
    214 
    215     case CFI_adjust_cfa_offset:
    216       cfi_add_CFA_def_cfa_offset (frchain_now->frch_cfi_data->cur_cfa_offset
    217 				  + offset);
    218       break;
    219 
    220     case DW_CFA_restore:
    221       cfi_add_CFA_restore (reg1);
    222       break;
    223 
    224     case DW_CFA_remember_state:
    225       cfi_add_CFA_remember_state ();
    226       break;
    227 
    228     case DW_CFA_restore_state:
    229       cfi_add_CFA_restore_state ();
    230       break;
    231 
    232     case CFI_label:
    233       cfi_add_label (name);
    234       break;
    235 
    236     case CFI_signal_frame:
    237       frchain_now->frch_cfi_data->cur_fde_data->signal_frame = 1;
    238       break;
    239 
    240 /*
    241     case DW_CFA_undefined:
    242       for (;;)
    243 	{
    244 	  reg1 = cfi_parse_reg ();
    245 	  cfi_add_CFA_undefined (reg1);
    246 	  SKIP_WHITESPACE ();
    247 	  if (*input_line_pointer != ',')
    248 	    break;
    249 	  ++input_line_pointer;
    250 	}
    251       break;
    252 
    253     case DW_CFA_same_value:
    254       reg1 = cfi_parse_reg ();
    255       cfi_add_CFA_same_value (reg1);
    256       break;
    257 
    258     case CFI_return_column:
    259       reg1 = cfi_parse_reg ();
    260       cfi_set_return_column (reg1);
    261       break;
    262 
    263     case DW_CFA_GNU_window_save:
    264       cfi_add_CFA_insn (DW_CFA_GNU_window_save);
    265       break;
    266 
    267 */
    268     default:
    269       abort ();
    270     }
    271 }
    272 
    273 #endif
    274