Coverage Report

Created: 2025-06-24 06:45

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