Coverage Report

Created: 2024-05-21 06:29

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