xref: /netbsd-src/external/gpl3/binutils/dist/gas/scfidw2gen.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* scfidw2gen.c - Support for emission of synthesized Dwarf2 CFI.
2    Copyright (C) 2023 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
dot_scfi_ignore(int ignored ATTRIBUTE_UNUSED)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
scfi_process_cfi_label(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   /* TODO.  */
61   // free (name);
62 
63   demand_empty_rest_of_line ();
64 }
65 
66 static void
scfi_process_cfi_signal_frame(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
dot_scfi(int arg)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_escape", dot_scfi_ignore, 0 },
117     { "cfi_personality", dot_scfi_ignore, 0 },
118     { "cfi_personality_id", dot_scfi_ignore, 0 },
119     { "cfi_lsda", dot_scfi_ignore, 0 },
120     { "cfi_val_encoded_addr", dot_scfi_ignore, 0 },
121     { "cfi_inline_lsda", dot_scfi_ignore, 0 },
122     { "cfi_val_offset", dot_scfi_ignore, 0 },
123     { NULL, NULL, 0 }
124   };
125 
126 void
scfi_dot_cfi_startproc(const symbolS * start_sym)127 scfi_dot_cfi_startproc (const symbolS *start_sym)
128 {
129   if (frchain_now->frch_cfi_data != NULL)
130     {
131       as_bad (_("SCFI: missing previous SCFI endproc marker"));
132       return;
133     }
134 
135   cfi_new_fde ((symbolS *)start_sym);
136 
137   cfi_set_sections ();
138 
139   frchain_now->frch_cfi_data->cur_cfa_offset = 0;
140 
141   /* By default, SCFI machinery assumes .cfi_startproc is used without
142      parameter simple.  */
143   tc_cfi_frame_initial_instructions ();
144 
145   if ((all_cfi_sections & CFI_EMIT_target) != 0)
146     tc_cfi_startproc ();
147 }
148 
149 void
scfi_dot_cfi_endproc(const symbolS * end_sym)150 scfi_dot_cfi_endproc (const symbolS *end_sym)
151 {
152   struct fde_entry *fde_last;
153 
154   if (frchain_now->frch_cfi_data == NULL)
155     {
156       as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
157       return;
158     }
159 
160   fde_last = frchain_now->frch_cfi_data->cur_fde_data;
161   cfi_set_last_fde (fde_last);
162 
163   cfi_end_fde ((symbolS *)end_sym);
164 
165   if ((all_cfi_sections & CFI_EMIT_target) != 0)
166     tc_cfi_endproc (fde_last);
167 }
168 
169 void
scfi_dot_cfi(int arg,unsigned reg1,unsigned reg2,offsetT offset,const char * name,const symbolS * advloc)170 scfi_dot_cfi (int arg, unsigned reg1, unsigned reg2, offsetT offset,
171 	      const char *name, const symbolS *advloc)
172 {
173   if (frchain_now->frch_cfi_data == NULL)
174     {
175       as_bad (_("CFI instruction used without previous .cfi_startproc"));
176       return;
177     }
178 
179   /* If the last address was not at the current PC, advance to current.  */
180   if (frchain_now->frch_cfi_data->last_address != advloc)
181     cfi_add_advance_loc ((symbolS *)advloc);
182 
183   switch (arg)
184     {
185     case DW_CFA_offset:
186       cfi_add_CFA_offset (reg1, offset);
187       break;
188 
189     case DW_CFA_val_offset:
190       cfi_add_CFA_val_offset (reg1, offset);
191       break;
192 
193     case CFI_rel_offset:
194       cfi_add_CFA_offset (reg1,
195 			  offset - frchain_now->frch_cfi_data->cur_cfa_offset);
196       break;
197 
198     case DW_CFA_def_cfa:
199       cfi_add_CFA_def_cfa (reg1, offset);
200       break;
201 
202     case DW_CFA_register:
203       cfi_add_CFA_register (reg1, reg2);
204       break;
205 
206     case DW_CFA_def_cfa_register:
207       cfi_add_CFA_def_cfa_register (reg1);
208       break;
209 
210     case DW_CFA_def_cfa_offset:
211       cfi_add_CFA_def_cfa_offset (offset);
212       break;
213 
214     case CFI_adjust_cfa_offset:
215       cfi_add_CFA_def_cfa_offset (frchain_now->frch_cfi_data->cur_cfa_offset
216 				  + offset);
217       break;
218 
219     case DW_CFA_restore:
220       cfi_add_CFA_restore (reg1);
221       break;
222 
223     case DW_CFA_remember_state:
224       cfi_add_CFA_remember_state ();
225       break;
226 
227     case DW_CFA_restore_state:
228       cfi_add_CFA_restore_state ();
229       break;
230 
231     case CFI_label:
232       cfi_add_label (name);
233       break;
234 
235     case CFI_signal_frame:
236       frchain_now->frch_cfi_data->cur_fde_data->signal_frame = 1;
237       break;
238 
239 /*
240     case DW_CFA_undefined:
241       for (;;)
242 	{
243 	  reg1 = cfi_parse_reg ();
244 	  cfi_add_CFA_undefined (reg1);
245 	  SKIP_WHITESPACE ();
246 	  if (*input_line_pointer != ',')
247 	    break;
248 	  ++input_line_pointer;
249 	}
250       break;
251 
252     case DW_CFA_same_value:
253       reg1 = cfi_parse_reg ();
254       cfi_add_CFA_same_value (reg1);
255       break;
256 
257     case CFI_return_column:
258       reg1 = cfi_parse_reg ();
259       cfi_set_return_column (reg1);
260       break;
261 
262     case DW_CFA_GNU_window_save:
263       cfi_add_CFA_insn (DW_CFA_GNU_window_save);
264       break;
265 
266 */
267     default:
268       abort ();
269     }
270 }
271 
272 #endif
273