xref: /netbsd-src/external/gpl3/binutils/dist/gas/ginsn.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* ginsn.h - GAS instruction representation.
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 "subsegs.h"
23 #include "ginsn.h"
24 #include "scfi.h"
25 
26 #ifdef TARGET_USE_GINSN
27 
28 static const char *const ginsn_type_names[] =
29 {
30 #define _GINSN_TYPE_ITEM(NAME, STR) STR,
31   _GINSN_TYPES
32 #undef _GINSN_TYPE_ITEM
33 };
34 
35 static ginsnS *
ginsn_alloc(void)36 ginsn_alloc (void)
37 {
38   ginsnS *ginsn = XCNEW (ginsnS);
39   return ginsn;
40 }
41 
42 static ginsnS *
ginsn_init(enum ginsn_type type,const symbolS * sym,bool real_p)43 ginsn_init (enum ginsn_type type, const symbolS *sym, bool real_p)
44 {
45   ginsnS *ginsn = ginsn_alloc ();
46   ginsn->type = type;
47   ginsn->sym = sym;
48   if (real_p)
49     ginsn->flags |= GINSN_F_INSN_REAL;
50   return ginsn;
51 }
52 
53 static void
ginsn_cleanup(ginsnS ** ginsnp)54 ginsn_cleanup (ginsnS **ginsnp)
55 {
56   ginsnS *ginsn;
57 
58   if (!ginsnp || !*ginsnp)
59     return;
60 
61   ginsn = *ginsnp;
62   if (ginsn->scfi_ops)
63     {
64       scfi_ops_cleanup (ginsn->scfi_ops);
65       ginsn->scfi_ops = NULL;
66     }
67 
68   free (ginsn);
69   *ginsnp = NULL;
70 }
71 
72 static void
ginsn_set_src(struct ginsn_src * src,enum ginsn_src_type type,unsigned int reg,offsetT immdisp)73 ginsn_set_src (struct ginsn_src *src, enum ginsn_src_type type, unsigned int reg,
74 	       offsetT immdisp)
75 {
76   if (!src)
77     return;
78 
79   src->type = type;
80   /* Even when the use-case is SCFI, the value of reg may be > SCFI_MAX_REG_ID.
81      E.g., in AMD64, push fs etc.  */
82   src->reg = reg;
83   src->immdisp = immdisp;
84 }
85 
86 static void
ginsn_set_dst(struct ginsn_dst * dst,enum ginsn_dst_type type,unsigned int reg,offsetT disp)87 ginsn_set_dst (struct ginsn_dst *dst, enum ginsn_dst_type type, unsigned int reg,
88 	       offsetT disp)
89 {
90   if (!dst)
91     return;
92 
93   dst->type = type;
94   dst->reg = reg;
95 
96   if (type == GINSN_DST_INDIRECT)
97     dst->disp = disp;
98 }
99 
100 static void
ginsn_set_file_line(ginsnS * ginsn,const char * file,unsigned int line)101 ginsn_set_file_line (ginsnS *ginsn, const char *file, unsigned int line)
102 {
103   if (!ginsn)
104     return;
105 
106   ginsn->file = file;
107   ginsn->line = line;
108 }
109 
110 struct ginsn_src *
ginsn_get_src1(ginsnS * ginsn)111 ginsn_get_src1 (ginsnS *ginsn)
112 {
113   return &ginsn->src[0];
114 }
115 
116 struct ginsn_src *
ginsn_get_src2(ginsnS * ginsn)117 ginsn_get_src2 (ginsnS *ginsn)
118 {
119   return &ginsn->src[1];
120 }
121 
122 struct ginsn_dst *
ginsn_get_dst(ginsnS * ginsn)123 ginsn_get_dst (ginsnS *ginsn)
124 {
125   return &ginsn->dst;
126 }
127 
128 unsigned int
ginsn_get_src_reg(struct ginsn_src * src)129 ginsn_get_src_reg (struct ginsn_src *src)
130 {
131   return src->reg;
132 }
133 
134 enum ginsn_src_type
ginsn_get_src_type(struct ginsn_src * src)135 ginsn_get_src_type (struct ginsn_src *src)
136 {
137   return src->type;
138 }
139 
140 offsetT
ginsn_get_src_disp(struct ginsn_src * src)141 ginsn_get_src_disp (struct ginsn_src *src)
142 {
143   return src->immdisp;
144 }
145 
146 offsetT
ginsn_get_src_imm(struct ginsn_src * src)147 ginsn_get_src_imm (struct ginsn_src *src)
148 {
149   return src->immdisp;
150 }
151 
152 unsigned int
ginsn_get_dst_reg(struct ginsn_dst * dst)153 ginsn_get_dst_reg (struct ginsn_dst *dst)
154 {
155   return dst->reg;
156 }
157 
158 enum ginsn_dst_type
ginsn_get_dst_type(struct ginsn_dst * dst)159 ginsn_get_dst_type (struct ginsn_dst *dst)
160 {
161   return dst->type;
162 }
163 
164 offsetT
ginsn_get_dst_disp(struct ginsn_dst * dst)165 ginsn_get_dst_disp (struct ginsn_dst *dst)
166 {
167   return dst->disp;
168 }
169 
170 void
label_ginsn_map_insert(const symbolS * label,ginsnS * ginsn)171 label_ginsn_map_insert (const symbolS *label, ginsnS *ginsn)
172 {
173   const char *name = S_GET_NAME (label);
174   str_hash_insert (frchain_now->frch_ginsn_data->label_ginsn_map,
175 		   name, ginsn, 0 /* noreplace.  */);
176 }
177 
178 ginsnS *
label_ginsn_map_find(const symbolS * label)179 label_ginsn_map_find (const symbolS *label)
180 {
181   const char *name = S_GET_NAME (label);
182   ginsnS *ginsn
183     = (ginsnS *) str_hash_find (frchain_now->frch_ginsn_data->label_ginsn_map,
184 				name);
185   return ginsn;
186 }
187 
188 ginsnS *
ginsn_new_phantom(const symbolS * sym)189 ginsn_new_phantom (const symbolS *sym)
190 {
191   ginsnS *ginsn = ginsn_alloc ();
192   ginsn->type = GINSN_TYPE_PHANTOM;
193   ginsn->sym = sym;
194   /* By default, GINSN_F_INSN_REAL is not set in ginsn->flags.  */
195   return ginsn;
196 }
197 
198 ginsnS *
ginsn_new_symbol(const symbolS * sym,bool func_begin_p)199 ginsn_new_symbol (const symbolS *sym, bool func_begin_p)
200 {
201   ginsnS *ginsn = ginsn_alloc ();
202   ginsn->type = GINSN_TYPE_SYMBOL;
203   ginsn->sym = sym;
204   if (func_begin_p)
205     ginsn->flags |= GINSN_F_FUNC_MARKER;
206   return ginsn;
207 }
208 
209 ginsnS *
ginsn_new_symbol_func_begin(const symbolS * sym)210 ginsn_new_symbol_func_begin (const symbolS *sym)
211 {
212   return ginsn_new_symbol (sym, true);
213 }
214 
215 ginsnS *
ginsn_new_symbol_func_end(const symbolS * sym)216 ginsn_new_symbol_func_end (const symbolS *sym)
217 {
218   return ginsn_new_symbol (sym, false);
219 }
220 
221 ginsnS *
ginsn_new_symbol_user_label(const symbolS * sym)222 ginsn_new_symbol_user_label (const symbolS *sym)
223 {
224   ginsnS *ginsn = ginsn_new_symbol (sym, false);
225   ginsn->flags |= GINSN_F_USER_LABEL;
226   return ginsn;
227 }
228 
229 ginsnS *
ginsn_new_add(const symbolS * sym,bool real_p,enum ginsn_src_type src1_type,unsigned int src1_reg,offsetT src1_disp,enum ginsn_src_type src2_type,unsigned int src2_reg,offsetT src2_disp,enum ginsn_dst_type dst_type,unsigned int dst_reg,offsetT dst_disp)230 ginsn_new_add (const symbolS *sym, bool real_p,
231 	       enum ginsn_src_type src1_type, unsigned int src1_reg, offsetT src1_disp,
232 	       enum ginsn_src_type src2_type, unsigned int src2_reg, offsetT src2_disp,
233 	       enum ginsn_dst_type dst_type, unsigned int dst_reg, offsetT dst_disp)
234 {
235   ginsnS *ginsn = ginsn_init (GINSN_TYPE_ADD, sym, real_p);
236   /* src info.  */
237   ginsn_set_src (&ginsn->src[0], src1_type, src1_reg, src1_disp);
238   ginsn_set_src (&ginsn->src[1], src2_type, src2_reg, src2_disp);
239   /* dst info.  */
240   ginsn_set_dst (&ginsn->dst, dst_type, dst_reg, dst_disp);
241 
242   return ginsn;
243 }
244 
245 ginsnS *
ginsn_new_and(const symbolS * sym,bool real_p,enum ginsn_src_type src1_type,unsigned int src1_reg,offsetT src1_disp,enum ginsn_src_type src2_type,unsigned int src2_reg,offsetT src2_disp,enum ginsn_dst_type dst_type,unsigned int dst_reg,offsetT dst_disp)246 ginsn_new_and (const symbolS *sym, bool real_p,
247 	       enum ginsn_src_type src1_type, unsigned int src1_reg, offsetT src1_disp,
248 	       enum ginsn_src_type src2_type, unsigned int src2_reg, offsetT src2_disp,
249 	       enum ginsn_dst_type dst_type, unsigned int dst_reg, offsetT dst_disp)
250 {
251   ginsnS *ginsn = ginsn_init (GINSN_TYPE_AND, sym, real_p);
252   /* src info.  */
253   ginsn_set_src (&ginsn->src[0], src1_type, src1_reg, src1_disp);
254   ginsn_set_src (&ginsn->src[1], src2_type, src2_reg, src2_disp);
255   /* dst info.  */
256   ginsn_set_dst (&ginsn->dst, dst_type, dst_reg, dst_disp);
257 
258   return ginsn;
259 }
260 
261 ginsnS *
ginsn_new_call(const symbolS * sym,bool real_p,enum ginsn_src_type src_type,unsigned int src_reg,const symbolS * src_text_sym)262 ginsn_new_call (const symbolS *sym, bool real_p,
263 		enum ginsn_src_type src_type, unsigned int src_reg,
264 		const symbolS *src_text_sym)
265 
266 {
267   ginsnS *ginsn = ginsn_init (GINSN_TYPE_CALL, sym, real_p);
268   /* src info.  */
269   ginsn_set_src (&ginsn->src[0], src_type, src_reg, 0);
270 
271   if (src_type == GINSN_SRC_SYMBOL)
272     ginsn->src[0].sym = src_text_sym;
273 
274   return ginsn;
275 }
276 
277 ginsnS *
ginsn_new_jump(const symbolS * sym,bool real_p,enum ginsn_src_type src_type,unsigned int src_reg,const symbolS * src_ginsn_sym)278 ginsn_new_jump (const symbolS *sym, bool real_p,
279 		enum ginsn_src_type src_type, unsigned int src_reg,
280 		const symbolS *src_ginsn_sym)
281 {
282   ginsnS *ginsn = ginsn_init (GINSN_TYPE_JUMP, sym, real_p);
283   /* src info.  */
284   ginsn_set_src (&ginsn->src[0], src_type, src_reg, 0);
285 
286   if (src_type == GINSN_SRC_SYMBOL)
287     ginsn->src[0].sym = src_ginsn_sym;
288 
289   return ginsn;
290 }
291 
292 ginsnS *
ginsn_new_jump_cond(const symbolS * sym,bool real_p,enum ginsn_src_type src_type,unsigned int src_reg,const symbolS * src_ginsn_sym)293 ginsn_new_jump_cond (const symbolS *sym, bool real_p,
294 		     enum ginsn_src_type src_type, unsigned int src_reg,
295 		     const symbolS *src_ginsn_sym)
296 {
297   ginsnS *ginsn = ginsn_init (GINSN_TYPE_JUMP_COND, sym, real_p);
298   /* src info.  */
299   ginsn_set_src (&ginsn->src[0], src_type, src_reg, 0);
300 
301   if (src_type == GINSN_SRC_SYMBOL)
302     ginsn->src[0].sym = src_ginsn_sym;
303 
304   return ginsn;
305 }
306 
307 ginsnS *
ginsn_new_mov(const symbolS * sym,bool real_p,enum ginsn_src_type src_type,unsigned int src_reg,offsetT src_disp,enum ginsn_dst_type dst_type,unsigned int dst_reg,offsetT dst_disp)308 ginsn_new_mov (const symbolS *sym, bool real_p,
309 	       enum ginsn_src_type src_type, unsigned int src_reg, offsetT src_disp,
310 	       enum ginsn_dst_type dst_type, unsigned int dst_reg, offsetT dst_disp)
311 {
312   ginsnS *ginsn = ginsn_init (GINSN_TYPE_MOV, sym, real_p);
313   /* src info.  */
314   ginsn_set_src (&ginsn->src[0], src_type, src_reg, src_disp);
315   /* dst info.  */
316   ginsn_set_dst (&ginsn->dst, dst_type, dst_reg, dst_disp);
317 
318   return ginsn;
319 }
320 
321 ginsnS *
ginsn_new_store(const symbolS * sym,bool real_p,enum ginsn_src_type src_type,unsigned int src_reg,enum ginsn_dst_type dst_type,unsigned int dst_reg,offsetT dst_disp)322 ginsn_new_store (const symbolS *sym, bool real_p,
323 		 enum ginsn_src_type src_type, unsigned int src_reg,
324 		 enum ginsn_dst_type dst_type, unsigned int dst_reg, offsetT dst_disp)
325 {
326   ginsnS *ginsn = ginsn_init (GINSN_TYPE_STORE, sym, real_p);
327   /* src info.  */
328   ginsn_set_src (&ginsn->src[0], src_type, src_reg, 0);
329   /* dst info.  */
330   gas_assert (dst_type == GINSN_DST_INDIRECT);
331   ginsn_set_dst (&ginsn->dst, dst_type, dst_reg, dst_disp);
332 
333   return ginsn;
334 }
335 
336 ginsnS *
ginsn_new_load(const symbolS * sym,bool real_p,enum ginsn_src_type src_type,unsigned int src_reg,offsetT src_disp,enum ginsn_dst_type dst_type,unsigned int dst_reg)337 ginsn_new_load (const symbolS *sym, bool real_p,
338 		enum ginsn_src_type src_type, unsigned int src_reg, offsetT src_disp,
339 		enum ginsn_dst_type dst_type, unsigned int dst_reg)
340 {
341   ginsnS *ginsn = ginsn_init (GINSN_TYPE_LOAD, sym, real_p);
342   /* src info.  */
343   gas_assert (src_type == GINSN_SRC_INDIRECT);
344   ginsn_set_src (&ginsn->src[0], src_type, src_reg, src_disp);
345   /* dst info.  */
346   ginsn_set_dst (&ginsn->dst, dst_type, dst_reg, 0);
347 
348   return ginsn;
349 }
350 
351 ginsnS *
ginsn_new_sub(const symbolS * sym,bool real_p,enum ginsn_src_type src1_type,unsigned int src1_reg,offsetT src1_disp,enum ginsn_src_type src2_type,unsigned int src2_reg,offsetT src2_disp,enum ginsn_dst_type dst_type,unsigned int dst_reg,offsetT dst_disp)352 ginsn_new_sub (const symbolS *sym, bool real_p,
353 	       enum ginsn_src_type src1_type, unsigned int src1_reg, offsetT src1_disp,
354 	       enum ginsn_src_type src2_type, unsigned int src2_reg, offsetT src2_disp,
355 	       enum ginsn_dst_type dst_type, unsigned int dst_reg, offsetT dst_disp)
356 {
357   ginsnS *ginsn = ginsn_init (GINSN_TYPE_SUB, sym, real_p);
358   /* src info.  */
359   ginsn_set_src (&ginsn->src[0], src1_type, src1_reg, src1_disp);
360   ginsn_set_src (&ginsn->src[1], src2_type, src2_reg, src2_disp);
361   /* dst info.  */
362   ginsn_set_dst (&ginsn->dst, dst_type, dst_reg, dst_disp);
363 
364   return ginsn;
365 }
366 
367 /* PS: Note this API does not identify the displacement values of
368    src1/src2/dst.  At this time, it is unnecessary for correctness to support
369    the additional argument.  */
370 
371 ginsnS *
ginsn_new_other(const symbolS * sym,bool real_p,enum ginsn_src_type src1_type,unsigned int src1_val,enum ginsn_src_type src2_type,unsigned int src2_val,enum ginsn_dst_type dst_type,unsigned int dst_reg)372 ginsn_new_other (const symbolS *sym, bool real_p,
373 		 enum ginsn_src_type src1_type, unsigned int src1_val,
374 		 enum ginsn_src_type src2_type, unsigned int src2_val,
375 		 enum ginsn_dst_type dst_type, unsigned int dst_reg)
376 {
377   ginsnS *ginsn = ginsn_init (GINSN_TYPE_OTHER, sym, real_p);
378   /* src info.  */
379   ginsn_set_src (&ginsn->src[0], src1_type, src1_val, src1_val);
380   /* GINSN_SRC_INDIRECT src2_type is not expected.  */
381   gas_assert (src2_type != GINSN_SRC_INDIRECT);
382   ginsn_set_src (&ginsn->src[1], src2_type, src2_val, src2_val);
383   /* dst info.  */
384   ginsn_set_dst (&ginsn->dst, dst_type, dst_reg, 0);
385 
386   return ginsn;
387 }
388 
389 ginsnS *
ginsn_new_return(const symbolS * sym,bool real_p)390 ginsn_new_return (const symbolS *sym, bool real_p)
391 {
392   ginsnS *ginsn = ginsn_init (GINSN_TYPE_RETURN, sym, real_p);
393   return ginsn;
394 }
395 
396 void
ginsn_set_where(ginsnS * ginsn)397 ginsn_set_where (ginsnS *ginsn)
398 {
399   const char *file;
400   unsigned int line;
401   file = as_where (&line);
402   ginsn_set_file_line (ginsn, file, line);
403 }
404 
405 int
ginsn_link_next(ginsnS * ginsn,ginsnS * next)406 ginsn_link_next (ginsnS *ginsn, ginsnS *next)
407 {
408   int ret = 0;
409 
410   /* Avoid data corruption by limiting the scope of the API.  */
411   if (!ginsn || ginsn->next)
412     return 1;
413 
414   ginsn->next = next;
415 
416   return ret;
417 }
418 
419 bool
ginsn_track_reg_p(unsigned int dw2reg,enum ginsn_gen_mode gmode)420 ginsn_track_reg_p (unsigned int dw2reg, enum ginsn_gen_mode gmode)
421 {
422   bool track_p = false;
423 
424   if (gmode == GINSN_GEN_SCFI && dw2reg <= SCFI_MAX_REG_ID)
425     {
426       /* FIXME - rename this to tc_ ? */
427       track_p |= SCFI_CALLEE_SAVED_REG_P (dw2reg);
428       track_p |= (dw2reg == REG_FP);
429       track_p |= (dw2reg == REG_SP);
430     }
431 
432   return track_p;
433 }
434 
435 static bool
ginsn_indirect_jump_p(ginsnS * ginsn)436 ginsn_indirect_jump_p (ginsnS *ginsn)
437 {
438   bool ret_p = false;
439   if (!ginsn)
440     return ret_p;
441 
442   ret_p = (ginsn->type == GINSN_TYPE_JUMP
443 	   && ginsn->src[0].type == GINSN_SRC_REG);
444   return ret_p;
445 }
446 
447 static bool
ginsn_direct_local_jump_p(ginsnS * ginsn)448 ginsn_direct_local_jump_p (ginsnS *ginsn)
449 {
450   bool ret_p = false;
451   if (!ginsn)
452     return ret_p;
453 
454   ret_p |= (ginsn->type == GINSN_TYPE_JUMP
455 	    && ginsn->src[0].type == GINSN_SRC_SYMBOL);
456   return ret_p;
457 }
458 
459 static char *
ginsn_src_print(struct ginsn_src * src)460 ginsn_src_print (struct ginsn_src *src)
461 {
462   size_t len = 40;
463   char *src_str = XNEWVEC (char, len);
464 
465   memset (src_str, 0, len);
466 
467   switch (src->type)
468     {
469     case GINSN_SRC_REG:
470       snprintf (src_str, len, "%%r%d, ", ginsn_get_src_reg (src));
471       break;
472     case GINSN_SRC_IMM:
473       snprintf (src_str, len, "%lld, ",
474 		(long long int) ginsn_get_src_imm (src));
475       break;
476     case GINSN_SRC_INDIRECT:
477       snprintf (src_str, len, "[%%r%d+%lld], ", ginsn_get_src_reg (src),
478 		(long long int) ginsn_get_src_disp (src));
479       break;
480     default:
481       break;
482     }
483 
484   return src_str;
485 }
486 
487 static char*
ginsn_dst_print(struct ginsn_dst * dst)488 ginsn_dst_print (struct ginsn_dst *dst)
489 {
490   size_t len = GINSN_LISTING_OPND_LEN;
491   char *dst_str = XNEWVEC (char, len);
492 
493   memset (dst_str, 0, len);
494 
495   if (dst->type == GINSN_DST_REG)
496     {
497       char *buf = XNEWVEC (char, 32);
498       sprintf (buf, "%%r%d", ginsn_get_dst_reg (dst));
499       strcat (dst_str, buf);
500     }
501   else if (dst->type == GINSN_DST_INDIRECT)
502     {
503       char *buf = XNEWVEC (char, 32);
504       sprintf (buf, "[%%r%d+%lld]", ginsn_get_dst_reg (dst),
505 		 (long long int) ginsn_get_dst_disp (dst));
506       strcat (dst_str, buf);
507     }
508 
509   gas_assert (strlen (dst_str) < GINSN_LISTING_OPND_LEN);
510 
511   return dst_str;
512 }
513 
514 static const char*
ginsn_type_func_marker_print(ginsnS * ginsn)515 ginsn_type_func_marker_print (ginsnS *ginsn)
516 {
517   int id = 0;
518   static const char * const ginsn_sym_strs[] =
519     { "", "FUNC_BEGIN", "FUNC_END" };
520 
521   if (GINSN_F_FUNC_BEGIN_P (ginsn))
522     id = 1;
523   else if (GINSN_F_FUNC_END_P (ginsn))
524     id = 2;
525 
526   return ginsn_sym_strs[id];
527 }
528 
529 static char*
ginsn_print(ginsnS * ginsn)530 ginsn_print (ginsnS *ginsn)
531 {
532   struct ginsn_src *src;
533   struct ginsn_dst *dst;
534   int str_size = 0;
535   size_t len = GINSN_LISTING_LEN;
536   char *ginsn_str = XNEWVEC (char, len);
537 
538   memset (ginsn_str, 0, len);
539 
540   str_size = snprintf (ginsn_str, GINSN_LISTING_LEN, "ginsn: %s",
541 		       ginsn_type_names[ginsn->type]);
542   gas_assert (str_size >= 0 && str_size < GINSN_LISTING_LEN);
543 
544   /* For some ginsn types, no further information is printed for now.  */
545   if (ginsn->type == GINSN_TYPE_CALL
546       || ginsn->type == GINSN_TYPE_RETURN)
547     goto end;
548   else if (ginsn->type == GINSN_TYPE_SYMBOL)
549     {
550       if (GINSN_F_USER_LABEL_P (ginsn))
551 	str_size += snprintf (ginsn_str + str_size,
552 			      GINSN_LISTING_LEN - str_size,
553 			      " %s", S_GET_NAME (ginsn->sym));
554       else
555 	str_size += snprintf (ginsn_str + str_size,
556 			      GINSN_LISTING_LEN - str_size,
557 			      " %s", ginsn_type_func_marker_print (ginsn));
558       goto end;
559     }
560 
561   /* src 1.  */
562   src = ginsn_get_src1 (ginsn);
563   str_size += snprintf (ginsn_str + str_size, GINSN_LISTING_LEN - str_size,
564 			" %s", ginsn_src_print (src));
565   gas_assert (str_size >= 0 && str_size < GINSN_LISTING_LEN);
566 
567   /* src 2.  */
568   src = ginsn_get_src2 (ginsn);
569   str_size += snprintf (ginsn_str + str_size, GINSN_LISTING_LEN - str_size,
570 			"%s", ginsn_src_print (src));
571   gas_assert (str_size >= 0 && str_size < GINSN_LISTING_LEN);
572 
573   /* dst.  */
574   dst = ginsn_get_dst (ginsn);
575   str_size += snprintf (ginsn_str + str_size, GINSN_LISTING_LEN - str_size,
576 			"%s", ginsn_dst_print (dst));
577 
578 end:
579   gas_assert (str_size >= 0 && str_size < GINSN_LISTING_LEN);
580   return ginsn_str;
581 }
582 
583 static void
gbb_cleanup(gbbS ** bbp)584 gbb_cleanup (gbbS **bbp)
585 {
586   gbbS *bb = NULL;
587 
588   if (!bbp && !*bbp)
589     return;
590 
591   bb = *bbp;
592 
593   if (bb->entry_state)
594     {
595       free (bb->entry_state);
596       bb->entry_state = NULL;
597     }
598   if (bb->exit_state)
599     {
600       free (bb->exit_state);
601       bb->exit_state = NULL;
602     }
603   free (bb);
604   *bbp = NULL;
605 }
606 
607 static void
bb_add_edge(gbbS * from_bb,gbbS * to_bb)608 bb_add_edge (gbbS* from_bb, gbbS *to_bb)
609 {
610   gedgeS *tmpedge = NULL;
611   gedgeS *gedge;
612   bool exists = false;
613 
614   if (!from_bb || !to_bb)
615     return;
616 
617   /* Create a new edge object.  */
618   gedge = XCNEW (gedgeS);
619   gedge->dst_bb = to_bb;
620   gedge->next = NULL;
621   gedge->visited = false;
622 
623   /* Add it in.  */
624   if (from_bb->out_gedges == NULL)
625     {
626       from_bb->out_gedges = gedge;
627       from_bb->num_out_gedges++;
628     }
629   else
630     {
631       /* Get the tail of the list.  */
632       tmpedge = from_bb->out_gedges;
633       while (tmpedge)
634 	{
635 	  /* Do not add duplicate edges.  Duplicated edges will cause unwanted
636 	     failures in the forward and backward passes for SCFI.  */
637 	  if (tmpedge->dst_bb == to_bb)
638 	    {
639 	      exists = true;
640 	      break;
641 	    }
642 	  if (tmpedge->next)
643 	    tmpedge = tmpedge->next;
644 	  else
645 	    break;
646 	}
647 
648       if (!exists)
649 	{
650 	  tmpedge->next = gedge;
651 	  from_bb->num_out_gedges++;
652 	}
653       else
654 	free (gedge);
655     }
656 }
657 
658 static void
cfg_add_bb(gcfgS * gcfg,gbbS * gbb)659 cfg_add_bb (gcfgS *gcfg, gbbS *gbb)
660 {
661   gbbS *last_bb = NULL;
662 
663   if (!gcfg->root_bb)
664     gcfg->root_bb = gbb;
665   else
666     {
667       last_bb = gcfg->root_bb;
668       while (last_bb->next)
669 	last_bb = last_bb->next;
670 
671       last_bb->next = gbb;
672     }
673   gcfg->num_gbbs++;
674 
675   gbb->id = gcfg->num_gbbs;
676 }
677 
678 static gbbS *
679 add_bb_at_ginsn (const symbolS *func, gcfgS *gcfg, ginsnS *ginsn, gbbS *prev_bb,
680 		 int *errp);
681 
682 static gbbS *
find_bb(gcfgS * gcfg,ginsnS * ginsn)683 find_bb (gcfgS *gcfg, ginsnS *ginsn)
684 {
685   gbbS *found_bb = NULL;
686   gbbS *gbb = NULL;
687 
688   if (!ginsn)
689     return found_bb;
690 
691   if (ginsn->visited)
692     {
693       cfg_for_each_bb (gcfg, gbb)
694 	{
695 	  if (gbb->first_ginsn == ginsn)
696 	    {
697 	      found_bb = gbb;
698 	      break;
699 	    }
700 	}
701       /* Must be found if ginsn is visited.  */
702       gas_assert (found_bb);
703     }
704 
705   return found_bb;
706 }
707 
708 static gbbS *
find_or_make_bb(const symbolS * func,gcfgS * gcfg,ginsnS * ginsn,gbbS * prev_bb,int * errp)709 find_or_make_bb (const symbolS *func, gcfgS *gcfg, ginsnS *ginsn, gbbS *prev_bb,
710 		 int *errp)
711 {
712   gbbS *found_bb = NULL;
713 
714   found_bb = find_bb (gcfg, ginsn);
715   if (found_bb)
716     return found_bb;
717 
718   return add_bb_at_ginsn (func, gcfg, ginsn, prev_bb, errp);
719 }
720 
721 /* Add the basic block starting at GINSN to the given GCFG.
722    Also adds an edge from the PREV_BB to the newly added basic block.
723 
724    This is a recursive function which returns the root of the added
725    basic blocks.  */
726 
727 static gbbS *
add_bb_at_ginsn(const symbolS * func,gcfgS * gcfg,ginsnS * ginsn,gbbS * prev_bb,int * errp)728 add_bb_at_ginsn (const symbolS *func, gcfgS *gcfg, ginsnS *ginsn, gbbS *prev_bb,
729 		 int *errp)
730 {
731   gbbS *current_bb = NULL;
732   ginsnS *target_ginsn = NULL;
733   const symbolS *taken_label;
734 
735   while (ginsn)
736     {
737       /* Skip these as they may be right after a GINSN_TYPE_RETURN.
738 	 For GINSN_TYPE_RETURN, we have already considered that as
739 	 end of bb, and a logical exit from function.  */
740       if (GINSN_F_FUNC_END_P (ginsn))
741 	{
742 	  ginsn = ginsn->next;
743 	  continue;
744 	}
745 
746       if (ginsn->visited)
747 	{
748 	  /* If the ginsn has been visited earlier, the bb must exist by now
749 	     in the cfg.  */
750 	  prev_bb = current_bb;
751 	  current_bb = find_bb (gcfg, ginsn);
752 	  gas_assert (current_bb);
753 	  /* Add edge from the prev_bb.  */
754 	  if (prev_bb)
755 	    bb_add_edge (prev_bb, current_bb);
756 	  break;
757 	}
758       else if (current_bb && GINSN_F_USER_LABEL_P (ginsn))
759 	{
760 	  /* Create new bb starting at this label ginsn.  */
761 	  prev_bb = current_bb;
762 	  find_or_make_bb (func, gcfg, ginsn, prev_bb, errp);
763 	  break;
764 	}
765 
766       if (current_bb == NULL)
767 	{
768 	  /* Create a new bb.  */
769 	  current_bb = XCNEW (gbbS);
770 	  cfg_add_bb (gcfg, current_bb);
771 	  /* Add edge for the Not Taken, or Fall-through path.  */
772 	  if (prev_bb)
773 	    bb_add_edge (prev_bb, current_bb);
774 	}
775 
776       if (current_bb->first_ginsn == NULL)
777 	current_bb->first_ginsn = ginsn;
778 
779       ginsn->visited = true;
780       current_bb->num_ginsns++;
781       current_bb->last_ginsn = ginsn;
782 
783       /* Note that BB is _not_ split on ginsn of type GINSN_TYPE_CALL.  */
784       if (ginsn->type == GINSN_TYPE_JUMP
785 	  || ginsn->type == GINSN_TYPE_JUMP_COND
786 	  || ginsn->type == GINSN_TYPE_RETURN)
787 	{
788 	  /* Indirect Jumps or direct jumps to symbols non-local to the
789 	     function must not be seen here.  The caller must have already
790 	     checked for that.  */
791 	  gas_assert (!ginsn_indirect_jump_p (ginsn));
792 	  if (ginsn->type == GINSN_TYPE_JUMP)
793 	    gas_assert (ginsn_direct_local_jump_p (ginsn));
794 
795 	  /* Direct Jumps.  May include conditional or unconditional change of
796 	     flow.  What is important for CFG creation is that the target be
797 	     local to function.  */
798 	  if (ginsn->type == GINSN_TYPE_JUMP_COND
799 	      || ginsn_direct_local_jump_p (ginsn))
800 	    {
801 	      gas_assert (ginsn->src[0].type == GINSN_SRC_SYMBOL);
802 	      taken_label = ginsn->src[0].sym;
803 	      gas_assert (taken_label);
804 
805 	      /* Preserve the prev_bb to be the dominator bb as we are
806 		 going to follow the taken path of the conditional branch
807 		 soon.  */
808 	      prev_bb = current_bb;
809 
810 	      /* Follow the target on the taken path.  */
811 	      target_ginsn = label_ginsn_map_find (taken_label);
812 	      /* Add the bb for the target of the taken branch.  */
813 	      if (target_ginsn)
814 		find_or_make_bb (func, gcfg, target_ginsn, prev_bb, errp);
815 	      else
816 		{
817 		  *errp = GCFG_JLABEL_NOT_PRESENT;
818 		  as_warn_where (ginsn->file, ginsn->line,
819 				 _("missing label '%s' in func '%s' may result in imprecise cfg"),
820 				 S_GET_NAME (taken_label), S_GET_NAME (func));
821 		}
822 	      /* Add the bb for the fall through path.  */
823 	      find_or_make_bb (func, gcfg, ginsn->next, prev_bb, errp);
824 	    }
825 	 else if (ginsn->type == GINSN_TYPE_RETURN)
826 	   {
827 	     /* We'll come back to the ginsns following GINSN_TYPE_RETURN
828 		from another path if they are indeed reachable code.  */
829 	     break;
830 	   }
831 
832 	 /* Current BB has been processed.  */
833 	 current_bb = NULL;
834 	}
835       ginsn = ginsn->next;
836     }
837 
838   return current_bb;
839 }
840 
841 static int
gbbs_compare(const void * v1,const void * v2)842 gbbs_compare (const void *v1, const void *v2)
843 {
844   const gbbS *bb1 = *(const gbbS **) v1;
845   const gbbS *bb2 = *(const gbbS **) v2;
846 
847   if (bb1->first_ginsn->id < bb2->first_ginsn->id)
848     return -1;
849   else if (bb1->first_ginsn->id > bb2->first_ginsn->id)
850     return 1;
851   else if (bb1->first_ginsn->id == bb2->first_ginsn->id)
852     return 0;
853 
854   return 0;
855 }
856 
857 /* Synthesize DWARF CFI and emit it.  */
858 
859 static int
ginsn_pass_execute_scfi(const symbolS * func,gcfgS * gcfg,gbbS * root_bb)860 ginsn_pass_execute_scfi (const symbolS *func, gcfgS *gcfg, gbbS *root_bb)
861 {
862   int err = scfi_synthesize_dw2cfi (func, gcfg, root_bb);
863   if (!err)
864     scfi_emit_dw2cfi (func);
865 
866   return err;
867 }
868 
869 /* Traverse the list of ginsns for the function and warn if some
870    ginsns are not visited.
871 
872    FIXME - this code assumes the caller has already performed a pass over
873    ginsns such that the reachable ginsns are already marked.  Revisit this - we
874    should ideally make this pass self-sufficient.  */
875 
876 static int
ginsn_pass_warn_unreachable_code(const symbolS * func,gcfgS * gcfg ATTRIBUTE_UNUSED,ginsnS * root_ginsn)877 ginsn_pass_warn_unreachable_code (const symbolS *func,
878 				  gcfgS *gcfg ATTRIBUTE_UNUSED,
879 				  ginsnS *root_ginsn)
880 {
881   ginsnS *ginsn;
882   bool unreach_p = false;
883 
884   if (!gcfg || !func || !root_ginsn)
885     return 0;
886 
887   ginsn = root_ginsn;
888 
889   while (ginsn)
890     {
891       /* Some ginsns of type GINSN_TYPE_SYMBOL remain unvisited.  Some
892 	 may even be excluded from the CFG as they are not reachable, given
893 	 their function, e.g., user labels after return machine insn.  */
894       if (!ginsn->visited
895 	  && !GINSN_F_FUNC_END_P (ginsn)
896 	  && !GINSN_F_USER_LABEL_P (ginsn))
897 	{
898 	  unreach_p = true;
899 	  break;
900 	}
901       ginsn = ginsn->next;
902     }
903 
904   if (unreach_p)
905     as_warn_where (ginsn->file, ginsn->line,
906 		   _("GINSN: found unreachable code in func '%s'"),
907 		   S_GET_NAME (func));
908 
909   return unreach_p;
910 }
911 
912 void
gcfg_get_bbs_in_prog_order(gcfgS * gcfg,gbbS ** prog_order_bbs)913 gcfg_get_bbs_in_prog_order (gcfgS *gcfg, gbbS **prog_order_bbs)
914 {
915   uint64_t i = 0;
916   gbbS *gbb;
917 
918   if (!prog_order_bbs)
919     return;
920 
921   cfg_for_each_bb (gcfg, gbb)
922     {
923       gas_assert (i < gcfg->num_gbbs);
924       prog_order_bbs[i++] = gbb;
925     }
926 
927   qsort (prog_order_bbs, gcfg->num_gbbs, sizeof (gbbS *), gbbs_compare);
928 }
929 
930 /* Build the control flow graph for the ginsns of the function.
931 
932    It is important that the target adds an appropriate ginsn:
933      - GINSN_TYPE_JUMP,
934      - GINSN_TYPE_JUMP_COND,
935      - GINSN_TYPE_CALL,
936      - GINSN_TYPE_RET
937   at the associated points in the function.  The correctness of the CFG
938   depends on the accuracy of these 'change of flow instructions'.  */
939 
940 gcfgS *
gcfg_build(const symbolS * func,int * errp)941 gcfg_build (const symbolS *func, int *errp)
942 {
943   gcfgS *gcfg;
944   ginsnS *first_ginsn;
945 
946   gcfg = XCNEW (gcfgS);
947   first_ginsn = frchain_now->frch_ginsn_data->gins_rootP;
948   add_bb_at_ginsn (func, gcfg, first_ginsn, NULL /* prev_bb.  */, errp);
949 
950   return gcfg;
951 }
952 
953 void
gcfg_cleanup(gcfgS ** gcfgp)954 gcfg_cleanup (gcfgS **gcfgp)
955 {
956   gcfgS *cfg;
957   gbbS *bb, *next_bb;
958   gedgeS *edge, *next_edge;
959 
960   if (!gcfgp || !*gcfgp)
961     return;
962 
963   cfg = *gcfgp;
964   bb = gcfg_get_rootbb (cfg);
965 
966   while (bb)
967     {
968       next_bb = bb->next;
969 
970       /* Cleanup all the edges.  */
971       edge = bb->out_gedges;
972       while (edge)
973 	{
974 	  next_edge = edge->next;
975 	  free (edge);
976 	  edge = next_edge;
977 	}
978 
979       gbb_cleanup (&bb);
980       bb = next_bb;
981     }
982 
983   free (cfg);
984   *gcfgp = NULL;
985 }
986 
987 gbbS *
gcfg_get_rootbb(gcfgS * gcfg)988 gcfg_get_rootbb (gcfgS *gcfg)
989 {
990   gbbS *rootbb = NULL;
991 
992   if (!gcfg || !gcfg->num_gbbs)
993     return NULL;
994 
995   rootbb = gcfg->root_bb;
996 
997   return rootbb;
998 }
999 
1000 void
gcfg_print(const gcfgS * gcfg,FILE * outfile)1001 gcfg_print (const gcfgS *gcfg, FILE *outfile)
1002 {
1003   gbbS *gbb = NULL;
1004   gedgeS *gedge = NULL;
1005   uint64_t total_ginsns = 0;
1006 
1007   cfg_for_each_bb(gcfg, gbb)
1008     {
1009       fprintf (outfile, "BB [%" PRIu64 "] with num insns: %" PRIu64,
1010 	       gbb->id, gbb->num_ginsns);
1011       fprintf (outfile, " [insns: %u to %u]\n",
1012 	       gbb->first_ginsn->line, gbb->last_ginsn->line);
1013       total_ginsns += gbb->num_ginsns;
1014       bb_for_each_edge(gbb, gedge)
1015 	fprintf (outfile, "  outgoing edge to %" PRIu64 "\n",
1016 		 gedge->dst_bb->id);
1017     }
1018   fprintf (outfile, "\nTotal ginsns in all GBBs = %" PRIu64 "\n",
1019 	   total_ginsns);
1020 }
1021 
1022 void
frch_ginsn_data_init(const symbolS * func,symbolS * start_addr,enum ginsn_gen_mode gmode)1023 frch_ginsn_data_init (const symbolS *func, symbolS *start_addr,
1024 		      enum ginsn_gen_mode gmode)
1025 {
1026   /* FIXME - error out if prev object is not free'd ?  */
1027   frchain_now->frch_ginsn_data = XCNEW (struct frch_ginsn_data);
1028 
1029   frchain_now->frch_ginsn_data->mode = gmode;
1030   /* Annotate with the current function symbol.  */
1031   frchain_now->frch_ginsn_data->func = func;
1032   /* Create a new start address symbol now.  */
1033   frchain_now->frch_ginsn_data->start_addr = start_addr;
1034   /* Assume the set of ginsn are apt for CFG creation, by default.  */
1035   frchain_now->frch_ginsn_data->gcfg_apt_p = true;
1036 
1037   frchain_now->frch_ginsn_data->label_ginsn_map = str_htab_create ();
1038 }
1039 
1040 void
frch_ginsn_data_cleanup(void)1041 frch_ginsn_data_cleanup (void)
1042 {
1043   ginsnS *ginsn = NULL;
1044   ginsnS *next_ginsn = NULL;
1045 
1046   ginsn = frchain_now->frch_ginsn_data->gins_rootP;
1047   while (ginsn)
1048     {
1049       next_ginsn = ginsn->next;
1050       ginsn_cleanup (&ginsn);
1051       ginsn = next_ginsn;
1052     }
1053 
1054   if (frchain_now->frch_ginsn_data->label_ginsn_map)
1055     htab_delete (frchain_now->frch_ginsn_data->label_ginsn_map);
1056 
1057   free (frchain_now->frch_ginsn_data);
1058   frchain_now->frch_ginsn_data = NULL;
1059 }
1060 
1061 /* Append GINSN to the list of ginsns for the current function being
1062    assembled.  */
1063 
1064 int
frch_ginsn_data_append(ginsnS * ginsn)1065 frch_ginsn_data_append (ginsnS *ginsn)
1066 {
1067   ginsnS *last = NULL;
1068   ginsnS *temp = NULL;
1069   uint64_t id = 0;
1070 
1071   if (!ginsn)
1072     return 1;
1073 
1074   if (frchain_now->frch_ginsn_data->gins_lastP)
1075     id = frchain_now->frch_ginsn_data->gins_lastP->id;
1076 
1077   /* Do the necessary preprocessing on the set of input GINSNs:
1078        - Update each ginsn with its ID.
1079      While you iterate, also keep gcfg_apt_p updated by checking whether any
1080      ginsn is inappropriate for GCFG creation.  */
1081   temp = ginsn;
1082   while (temp)
1083     {
1084       temp->id = ++id;
1085 
1086       if (ginsn_indirect_jump_p (temp)
1087 	  || (ginsn->type == GINSN_TYPE_JUMP
1088 	      && !ginsn_direct_local_jump_p (temp)))
1089 	frchain_now->frch_ginsn_data->gcfg_apt_p = false;
1090 
1091       if (listing & LISTING_GINSN_SCFI)
1092 	listing_newline (ginsn_print (temp));
1093 
1094       /* The input GINSN may be a linked list of multiple ginsns chained
1095 	 together.  Find the last ginsn in the input chain of ginsns.  */
1096       last = temp;
1097 
1098       temp = temp->next;
1099     }
1100 
1101   /* Link in the ginsn to the tail.  */
1102   if (!frchain_now->frch_ginsn_data->gins_rootP)
1103     frchain_now->frch_ginsn_data->gins_rootP = ginsn;
1104   else
1105     ginsn_link_next (frchain_now->frch_ginsn_data->gins_lastP, ginsn);
1106 
1107   frchain_now->frch_ginsn_data->gins_lastP = last;
1108 
1109   return 0;
1110 }
1111 
1112 enum ginsn_gen_mode
frch_ginsn_gen_mode(void)1113 frch_ginsn_gen_mode (void)
1114 {
1115   enum ginsn_gen_mode gmode = GINSN_GEN_NONE;
1116 
1117   if (frchain_now->frch_ginsn_data)
1118     gmode = frchain_now->frch_ginsn_data->mode;
1119 
1120   return gmode;
1121 }
1122 
1123 int
ginsn_data_begin(const symbolS * func)1124 ginsn_data_begin (const symbolS *func)
1125 {
1126   ginsnS *ginsn;
1127 
1128   /* The previous block of asm must have been processed by now.  */
1129   if (frchain_now->frch_ginsn_data)
1130     as_bad (_("GINSN process for prev func not done"));
1131 
1132   /* FIXME - hard code the mode to GINSN_GEN_SCFI.
1133      This can be changed later when other passes on ginsns are formalised.  */
1134   frch_ginsn_data_init (func, symbol_temp_new_now (), GINSN_GEN_SCFI);
1135 
1136   /* Create and insert ginsn with function begin marker.  */
1137   ginsn = ginsn_new_symbol_func_begin (func);
1138   frch_ginsn_data_append (ginsn);
1139 
1140   return 0;
1141 }
1142 
1143 int
ginsn_data_end(const symbolS * label)1144 ginsn_data_end (const symbolS *label)
1145 {
1146   ginsnS *ginsn;
1147   gbbS *root_bb;
1148   gcfgS *gcfg = NULL;
1149   const symbolS *func;
1150   int err = 0;
1151 
1152   if (!frchain_now->frch_ginsn_data)
1153     return err;
1154 
1155   /* Insert Function end marker.  */
1156   ginsn = ginsn_new_symbol_func_end (label);
1157   frch_ginsn_data_append (ginsn);
1158 
1159   func = frchain_now->frch_ginsn_data->func;
1160 
1161   /* Build the cfg of ginsn(s) of the function.  */
1162   if (!frchain_now->frch_ginsn_data->gcfg_apt_p)
1163     {
1164       as_bad (_("untraceable control flow for func '%s'"),
1165 	      S_GET_NAME (func));
1166       goto end;
1167     }
1168 
1169   gcfg = gcfg_build (func, &err);
1170 
1171   root_bb = gcfg_get_rootbb (gcfg);
1172   if (!root_bb)
1173     {
1174       as_bad (_("Bad cfg of ginsn of func '%s'"), S_GET_NAME (func));
1175       goto end;
1176     }
1177 
1178   /* Execute the desired passes on ginsns.  */
1179   err = ginsn_pass_execute_scfi (func, gcfg, root_bb);
1180   if (err)
1181     goto end;
1182 
1183   /* Other passes, e.g., warn for unreachable code can be enabled too.  */
1184   ginsn = frchain_now->frch_ginsn_data->gins_rootP;
1185   err = ginsn_pass_warn_unreachable_code (func, gcfg, ginsn);
1186 
1187 end:
1188   if (gcfg)
1189     gcfg_cleanup (&gcfg);
1190   frch_ginsn_data_cleanup ();
1191 
1192   return err;
1193 }
1194 
1195 /* Add GINSN_TYPE_SYMBOL type ginsn for user-defined labels.  These may be
1196    branch targets, and hence are necessary for control flow graph.  */
1197 
1198 void
ginsn_frob_label(const symbolS * label)1199 ginsn_frob_label (const symbolS *label)
1200 {
1201   ginsnS *label_ginsn;
1202   const char *file;
1203   unsigned int line;
1204 
1205   if (frchain_now->frch_ginsn_data)
1206     {
1207       /* PS: Note how we keep the actual LABEL symbol as ginsn->sym.
1208 	 Take care to avoid inadvertent updates or cleanups of symbols.  */
1209       label_ginsn = ginsn_new_symbol_user_label (label);
1210       /* Keep the location updated.  */
1211       file = as_where (&line);
1212       ginsn_set_file_line (label_ginsn, file, line);
1213 
1214       frch_ginsn_data_append (label_ginsn);
1215 
1216       label_ginsn_map_insert (label, label_ginsn);
1217     }
1218 }
1219 
1220 const symbolS *
ginsn_data_func_symbol(void)1221 ginsn_data_func_symbol (void)
1222 {
1223   const symbolS *func = NULL;
1224 
1225   if (frchain_now->frch_ginsn_data)
1226     func = frchain_now->frch_ginsn_data->func;
1227 
1228   return func;
1229 }
1230 
1231 #else
1232 
1233 int
ginsn_data_begin(const symbolS * func ATTRIBUTE_UNUSED)1234 ginsn_data_begin (const symbolS *func ATTRIBUTE_UNUSED)
1235 {
1236   as_bad (_("ginsn unsupported for target"));
1237   return 1;
1238 }
1239 
1240 int
ginsn_data_end(const symbolS * label ATTRIBUTE_UNUSED)1241 ginsn_data_end (const symbolS *label ATTRIBUTE_UNUSED)
1242 {
1243   as_bad (_("ginsn unsupported for target"));
1244   return 1;
1245 }
1246 
1247 void
ginsn_frob_label(const symbolS * sym ATTRIBUTE_UNUSED)1248 ginsn_frob_label (const symbolS *sym ATTRIBUTE_UNUSED)
1249 {
1250   return;
1251 }
1252 
1253 const symbolS *
ginsn_data_func_symbol(void)1254 ginsn_data_func_symbol (void)
1255 {
1256   return NULL;
1257 }
1258 
1259 #endif  /* TARGET_USE_GINSN.  */
1260