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
30static bool scfi_ignore_warn_once;
31
32static void
33dot_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
45static void
46scfi_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
66static void
67scfi_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
77static void
78dot_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
93const 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
126void
127scfi_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
149void
150scfi_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
169void
170scfi_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