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