/src/binutils-gdb/gas/scfidw2gen.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
35 | 0 | gas_assert (flag_synth_cfi); |
36 | | |
37 | 0 | if (!scfi_ignore_warn_once) |
38 | 0 | { |
39 | 0 | as_warn (_("SCFI ignores most user-specified CFI directives")); |
40 | 0 | scfi_ignore_warn_once = true; |
41 | 0 | } |
42 | 0 | ignore_rest_of_line (); |
43 | 0 | } |
44 | | |
45 | | static void |
46 | | scfi_process_cfi_label (void) |
47 | 0 | { |
48 | 0 | char *name; |
49 | 0 | ginsnS *ginsn; |
50 | |
|
51 | 0 | name = read_symbol_name (); |
52 | 0 | if (name == NULL) |
53 | 0 | return; |
54 | | |
55 | | /* Add a new ginsn. */ |
56 | 0 | ginsn = ginsn_new_phantom (symbol_temp_new_now ()); |
57 | 0 | frch_ginsn_data_append (ginsn); |
58 | |
|
59 | 0 | 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 | 0 | demand_empty_rest_of_line (); |
64 | 0 | } |
65 | | |
66 | | static void |
67 | | scfi_process_cfi_signal_frame (void) |
68 | 0 | { |
69 | 0 | ginsnS *ginsn; |
70 | |
|
71 | 0 | ginsn = ginsn_new_phantom (symbol_temp_new_now ()); |
72 | 0 | frch_ginsn_data_append (ginsn); |
73 | |
|
74 | 0 | scfi_op_add_signal_frame (ginsn); |
75 | 0 | } |
76 | | |
77 | | static void |
78 | | dot_scfi (int arg) |
79 | 0 | { |
80 | 0 | switch (arg) |
81 | 0 | { |
82 | 0 | case CFI_label: |
83 | 0 | scfi_process_cfi_label (); |
84 | 0 | break; |
85 | 0 | case CFI_signal_frame: |
86 | 0 | scfi_process_cfi_signal_frame (); |
87 | 0 | break; |
88 | 0 | default: |
89 | 0 | abort (); |
90 | 0 | } |
91 | 0 | } |
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 | 0 | { |
130 | 0 | if (frchain_now->frch_cfi_data != NULL) |
131 | 0 | { |
132 | 0 | as_bad (_("SCFI: missing previous SCFI endproc marker")); |
133 | 0 | return; |
134 | 0 | } |
135 | | |
136 | 0 | cfi_new_fde ((symbolS *)start_sym, false); |
137 | |
|
138 | 0 | cfi_set_sections (); |
139 | |
|
140 | 0 | 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 | 0 | tc_cfi_frame_initial_instructions (); |
145 | |
|
146 | 0 | if ((all_cfi_sections & CFI_EMIT_target) != 0) |
147 | 0 | tc_cfi_startproc (); |
148 | 0 | } |
149 | | |
150 | | void |
151 | | scfi_dot_cfi_endproc (const symbolS *end_sym) |
152 | 0 | { |
153 | 0 | struct fde_entry *fde_last; |
154 | |
|
155 | 0 | if (frchain_now->frch_cfi_data == NULL) |
156 | 0 | { |
157 | 0 | as_bad (_(".cfi_endproc without corresponding .cfi_startproc")); |
158 | 0 | return; |
159 | 0 | } |
160 | | |
161 | 0 | fde_last = frchain_now->frch_cfi_data->cur_fde_data; |
162 | 0 | cfi_set_last_fde (fde_last); |
163 | |
|
164 | 0 | cfi_end_fde ((symbolS *)end_sym); |
165 | |
|
166 | 0 | if ((all_cfi_sections & CFI_EMIT_target) != 0) |
167 | 0 | tc_cfi_endproc (fde_last); |
168 | 0 | } |
169 | | |
170 | | void |
171 | | scfi_dot_cfi (int arg, unsigned reg1, unsigned reg2, offsetT offset, |
172 | | const char *name, const symbolS *advloc) |
173 | 0 | { |
174 | 0 | if (frchain_now->frch_cfi_data == NULL) |
175 | 0 | { |
176 | 0 | as_bad (_("CFI instruction used without previous .cfi_startproc")); |
177 | 0 | return; |
178 | 0 | } |
179 | | |
180 | | /* If the last address was not at the current PC, advance to current. */ |
181 | 0 | if (frchain_now->frch_cfi_data->last_address != advloc) |
182 | 0 | cfi_add_advance_loc ((symbolS *)advloc); |
183 | |
|
184 | 0 | switch (arg) |
185 | 0 | { |
186 | 0 | case DW_CFA_offset: |
187 | 0 | cfi_add_CFA_offset (reg1, offset); |
188 | 0 | break; |
189 | | |
190 | 0 | case DW_CFA_val_offset: |
191 | 0 | cfi_add_CFA_val_offset (reg1, offset); |
192 | 0 | break; |
193 | | |
194 | 0 | case CFI_rel_offset: |
195 | 0 | cfi_add_CFA_offset (reg1, |
196 | 0 | offset - frchain_now->frch_cfi_data->cur_cfa_offset); |
197 | 0 | break; |
198 | | |
199 | 0 | case DW_CFA_def_cfa: |
200 | 0 | cfi_add_CFA_def_cfa (reg1, offset); |
201 | 0 | break; |
202 | | |
203 | 0 | case DW_CFA_register: |
204 | 0 | cfi_add_CFA_register (reg1, reg2); |
205 | 0 | break; |
206 | | |
207 | 0 | case DW_CFA_def_cfa_register: |
208 | 0 | cfi_add_CFA_def_cfa_register (reg1); |
209 | 0 | break; |
210 | | |
211 | 0 | case DW_CFA_def_cfa_offset: |
212 | 0 | cfi_add_CFA_def_cfa_offset (offset); |
213 | 0 | break; |
214 | | |
215 | 0 | case CFI_adjust_cfa_offset: |
216 | 0 | cfi_add_CFA_def_cfa_offset (frchain_now->frch_cfi_data->cur_cfa_offset |
217 | 0 | + offset); |
218 | 0 | break; |
219 | | |
220 | 0 | case DW_CFA_restore: |
221 | 0 | cfi_add_CFA_restore (reg1); |
222 | 0 | break; |
223 | | |
224 | 0 | case DW_CFA_remember_state: |
225 | 0 | cfi_add_CFA_remember_state (); |
226 | 0 | break; |
227 | | |
228 | 0 | case DW_CFA_restore_state: |
229 | 0 | cfi_add_CFA_restore_state (); |
230 | 0 | break; |
231 | | |
232 | 0 | case CFI_label: |
233 | 0 | cfi_add_label (name); |
234 | 0 | break; |
235 | | |
236 | 0 | case CFI_signal_frame: |
237 | 0 | frchain_now->frch_cfi_data->cur_fde_data->signal_frame = 1; |
238 | 0 | 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 | 0 | default: |
269 | 0 | abort (); |
270 | 0 | } |
271 | 0 | } |
272 | | |
273 | | #endif |