Coverage Report

Created: 2023-08-28 06:31

/src/binutils-gdb/gas/cond.c
Line
Count
Source (jump to first uncovered line)
1
/* cond.c - conditional assembly pseudo-ops, and .include
2
   Copyright (C) 1990-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 "sb.h"
23
#include "macro.h"
24
25
#include "obstack.h"
26
27
/* This is allocated to grow and shrink as .ifdef/.endif pairs are
28
   scanned.  */
29
struct obstack cond_obstack;
30
31
struct file_line
32
{
33
  const char *file;
34
  unsigned int line;
35
};
36
37
/* We push one of these structures for each .if, and pop it at the
38
   .endif.  */
39
40
struct conditional_frame
41
{
42
  /* The source file & line number of the "if".  */
43
  struct file_line if_file_line;
44
  /* The source file & line of the "else".  */
45
  struct file_line else_file_line;
46
  /* The previous conditional.  */
47
  struct conditional_frame *previous_cframe;
48
  /* Have we seen an else yet?  */
49
  int else_seen;
50
  /* Whether we are currently ignoring input.  */
51
  int ignoring;
52
  /* Whether a conditional at a higher level is ignoring input.
53
     Set also when a branch of an "if .. elseif .." tree has matched
54
     to prevent further matches.  */
55
  int dead_tree;
56
  /* Macro nesting level at which this conditional was created.  */
57
  int macro_nest;
58
};
59
60
static void initialize_cframe (struct conditional_frame *cframe);
61
static char *get_mri_string (int, int *);
62
63
static struct conditional_frame *current_cframe = NULL;
64
65
/* Performs the .ifdef (test_defined == 1) and
66
   the .ifndef (test_defined == 0) pseudo op.  */
67
68
void
69
s_ifdef (int test_defined)
70
53
{
71
  /* Points to name of symbol.  */
72
53
  char *name;
73
  /* Points to symbol.  */
74
53
  symbolS *symbolP;
75
53
  struct conditional_frame cframe;
76
53
  char c;
77
78
  /* Leading whitespace is part of operand.  */
79
53
  SKIP_WHITESPACE ();
80
53
  name = input_line_pointer;
81
82
53
  if (!is_name_beginner (*name) && *name != '"')
83
48
    {
84
48
      as_bad (_("invalid identifier for \".ifdef\""));
85
48
      obstack_1grow (&cond_obstack, 0);
86
48
      ignore_rest_of_line ();
87
48
      return;
88
48
    }
89
90
5
  c = get_symbol_name (& name);
91
5
  symbolP = symbol_find (name);
92
5
  (void) restore_line_pointer (c);
93
94
5
  initialize_cframe (&cframe);
95
96
5
  if (cframe.dead_tree)
97
4
    cframe.ignoring = 1;
98
1
  else
99
1
    {
100
1
      int is_defined;
101
102
      /* Use the same definition of 'defined' as .equiv so that a symbol
103
   which has been referenced but not yet given a value/address is
104
   considered to be undefined.  */
105
1
      is_defined =
106
1
  symbolP != NULL
107
1
  && (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
108
1
  && S_GET_SEGMENT (symbolP) != reg_section;
109
110
1
      cframe.ignoring = ! (test_defined ^ is_defined);
111
1
    }
112
113
5
  current_cframe =
114
5
    (struct conditional_frame *) obstack_alloc (&cond_obstack, sizeof cframe);
115
5
  memcpy (current_cframe, &cframe, sizeof cframe);
116
117
5
  if (LISTING_SKIP_COND ()
118
5
      && cframe.ignoring
119
5
      && (cframe.previous_cframe == NULL
120
0
    || ! cframe.previous_cframe->ignoring))
121
0
    listing_list (2);
122
123
5
  demand_empty_rest_of_line ();
124
5
}
125
126
void
127
s_if (int arg)
128
6.35k
{
129
6.35k
  expressionS operand;
130
6.35k
  struct conditional_frame cframe;
131
6.35k
  int t;
132
6.35k
  char *stop = NULL;
133
6.35k
  char stopc = 0;
134
135
6.35k
  if (flag_mri)
136
3.36k
    stop = mri_comment_field (&stopc);
137
138
  /* Leading whitespace is part of operand.  */
139
6.35k
  SKIP_WHITESPACE ();
140
141
6.35k
  if (current_cframe != NULL && current_cframe->ignoring)
142
302
    {
143
302
      operand.X_add_number = 0;
144
3.89k
      while (! is_end_of_line[(unsigned char) *input_line_pointer])
145
3.59k
  ++input_line_pointer;
146
302
    }
147
6.05k
  else
148
6.05k
    {
149
6.05k
      expression_and_evaluate (&operand);
150
6.05k
      if (operand.X_op != O_constant)
151
3.09k
  as_bad (_("non-constant expression in \".if\" statement"));
152
6.05k
    }
153
154
6.35k
  switch ((operatorT) arg)
155
6.35k
    {
156
5
    case O_eq: t = operand.X_add_number == 0; break;
157
1.06k
    case O_ne: t = operand.X_add_number != 0; break;
158
72
    case O_lt: t = operand.X_add_number < 0; break;
159
3.98k
    case O_le: t = operand.X_add_number <= 0; break;
160
1.21k
    case O_ge: t = operand.X_add_number >= 0; break;
161
18
    case O_gt: t = operand.X_add_number > 0; break;
162
0
    default:
163
0
      abort ();
164
0
      return;
165
6.35k
    }
166
167
  /* If the above error is signaled, this will dispatch
168
     using an undefined result.  No big deal.  */
169
6.35k
  initialize_cframe (&cframe);
170
6.35k
  cframe.ignoring = cframe.dead_tree || ! t;
171
6.35k
  current_cframe =
172
6.35k
    (struct conditional_frame *) obstack_alloc (&cond_obstack, sizeof cframe);
173
6.35k
  memcpy (current_cframe, & cframe, sizeof cframe);
174
175
6.35k
  if (LISTING_SKIP_COND ()
176
6.35k
      && cframe.ignoring
177
6.35k
      && (cframe.previous_cframe == NULL
178
0
    || ! cframe.previous_cframe->ignoring))
179
0
    listing_list (2);
180
181
6.35k
  if (flag_mri)
182
3.36k
    mri_comment_end (stop, stopc);
183
184
6.35k
  demand_empty_rest_of_line ();
185
6.35k
}
186
187
/* Performs the .ifb (test_blank == 1) and
188
   the .ifnb (test_blank == 0) pseudo op.  */
189
190
void
191
s_ifb (int test_blank)
192
192
{
193
192
  struct conditional_frame cframe;
194
195
192
  initialize_cframe (&cframe);
196
197
192
  if (cframe.dead_tree)
198
16
    cframe.ignoring = 1;
199
176
  else
200
176
    {
201
176
      int is_eol;
202
203
176
      SKIP_WHITESPACE ();
204
176
      is_eol = is_end_of_line[(unsigned char) *input_line_pointer];
205
176
      cframe.ignoring = (test_blank == !is_eol);
206
176
    }
207
208
192
  current_cframe =
209
192
    (struct conditional_frame *) obstack_alloc (&cond_obstack, sizeof cframe);
210
192
  memcpy (current_cframe, &cframe, sizeof cframe);
211
212
192
  if (LISTING_SKIP_COND ()
213
192
      && cframe.ignoring
214
192
      && (cframe.previous_cframe == NULL
215
0
    || ! cframe.previous_cframe->ignoring))
216
0
    listing_list (2);
217
218
192
  ignore_rest_of_line ();
219
192
}
220
221
/* Get a string for the MRI IFC or IFNC pseudo-ops.  */
222
223
static char *
224
get_mri_string (int terminator, int *len)
225
630
{
226
630
  char *ret;
227
630
  char *s;
228
229
630
  SKIP_WHITESPACE ();
230
630
  s = ret = input_line_pointer;
231
630
  if (*input_line_pointer == '\'')
232
147
    {
233
147
      ++s;
234
147
      ++input_line_pointer;
235
455
      while (! is_end_of_line[(unsigned char) *input_line_pointer])
236
410
  {
237
410
    *s++ = *input_line_pointer++;
238
410
    if (s[-1] == '\'')
239
213
      {
240
213
        if (*input_line_pointer != '\'')
241
102
    break;
242
111
        ++input_line_pointer;
243
111
      }
244
410
  }
245
147
      SKIP_WHITESPACE ();
246
147
    }
247
483
  else
248
483
    {
249
3.23k
      while (*input_line_pointer != terminator
250
3.23k
       && ! is_end_of_line[(unsigned char) *input_line_pointer])
251
2.75k
  ++input_line_pointer;
252
483
      s = input_line_pointer;
253
486
      while (s > ret && (s[-1] == ' ' || s[-1] == '\t'))
254
3
  --s;
255
483
    }
256
257
630
  *len = s - ret;
258
630
  return ret;
259
630
}
260
261
/* The MRI IFC and IFNC pseudo-ops.  */
262
263
void
264
s_ifc (int arg)
265
315
{
266
315
  char *stop = NULL;
267
315
  char stopc = 0;
268
315
  char *s1, *s2;
269
315
  int len1, len2;
270
315
  int res;
271
315
  struct conditional_frame cframe;
272
273
315
  if (flag_mri)
274
150
    stop = mri_comment_field (&stopc);
275
276
315
  s1 = get_mri_string (',', &len1);
277
278
315
  if (*input_line_pointer != ',')
279
198
    as_bad (_("bad format for ifc or ifnc"));
280
117
  else
281
117
    ++input_line_pointer;
282
283
315
  s2 = get_mri_string (';', &len2);
284
285
315
  res = len1 == len2 && strncmp (s1, s2, len1) == 0;
286
287
315
  initialize_cframe (&cframe);
288
315
  cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
289
315
  current_cframe =
290
315
    (struct conditional_frame *) obstack_alloc (&cond_obstack, sizeof cframe);
291
315
  memcpy (current_cframe, &cframe, sizeof cframe);
292
  
293
315
 if (LISTING_SKIP_COND ()
294
315
      && cframe.ignoring
295
315
      && (cframe.previous_cframe == NULL
296
0
    || ! cframe.previous_cframe->ignoring))
297
0
    listing_list (2);
298
299
315
  if (flag_mri)
300
150
    mri_comment_end (stop, stopc);
301
302
315
  demand_empty_rest_of_line ();
303
315
}
304
305
void
306
s_elseif (int arg)
307
27.6k
{
308
27.6k
  if (current_cframe == NULL)
309
27.4k
    {
310
27.4k
      as_bad (_("\".elseif\" without matching \".if\""));
311
27.4k
    }
312
247
  else if (current_cframe->else_seen)
313
181
    {
314
181
      as_bad (_("\".elseif\" after \".else\""));
315
181
      as_bad_where (current_cframe->else_file_line.file,
316
181
        current_cframe->else_file_line.line,
317
181
        _("here is the previous \".else\""));
318
181
      as_bad_where (current_cframe->if_file_line.file,
319
181
        current_cframe->if_file_line.line,
320
181
        _("here is the previous \".if\""));
321
181
    }
322
66
  else
323
66
    {
324
66
      current_cframe->else_file_line.file
325
66
        = as_where (&current_cframe->else_file_line.line);
326
327
66
      current_cframe->dead_tree |= !current_cframe->ignoring;
328
66
      current_cframe->ignoring = current_cframe->dead_tree;
329
66
    }
330
331
27.6k
  if (current_cframe == NULL || current_cframe->ignoring)
332
27.6k
    {
333
383k
      while (! is_end_of_line[(unsigned char) *input_line_pointer])
334
355k
  ++input_line_pointer;
335
336
27.6k
      if (current_cframe == NULL)
337
27.4k
  return;
338
27.6k
    }
339
3
  else
340
3
    {
341
3
      expressionS operand;
342
3
      int t;
343
344
      /* Leading whitespace is part of operand.  */
345
3
      SKIP_WHITESPACE ();
346
347
3
      expression_and_evaluate (&operand);
348
3
      if (operand.X_op != O_constant)
349
3
  as_bad (_("non-constant expression in \".elseif\" statement"));
350
351
3
      switch ((operatorT) arg)
352
3
  {
353
0
  case O_eq: t = operand.X_add_number == 0; break;
354
3
  case O_ne: t = operand.X_add_number != 0; break;
355
0
  case O_lt: t = operand.X_add_number < 0; break;
356
0
  case O_le: t = operand.X_add_number <= 0; break;
357
0
  case O_ge: t = operand.X_add_number >= 0; break;
358
0
  case O_gt: t = operand.X_add_number > 0; break;
359
0
  default:
360
0
    abort ();
361
0
    return;
362
3
  }
363
364
3
      current_cframe->ignoring = current_cframe->dead_tree || ! t;
365
3
    }
366
367
247
  if (LISTING_SKIP_COND ()
368
247
      && (current_cframe->previous_cframe == NULL
369
0
    || ! current_cframe->previous_cframe->ignoring))
370
0
    {
371
0
      if (! current_cframe->ignoring)
372
0
  listing_list (1);
373
0
      else
374
0
  listing_list (2);
375
0
    }
376
377
247
  demand_empty_rest_of_line ();
378
247
}
379
380
void
381
s_endif (int arg ATTRIBUTE_UNUSED)
382
954
{
383
954
  struct conditional_frame *hold;
384
385
954
  if (current_cframe == NULL)
386
920
    {
387
920
      as_bad (_("\".endif\" without \".if\""));
388
920
    }
389
34
  else
390
34
    {
391
34
      if (LISTING_SKIP_COND ()
392
34
    && current_cframe->ignoring
393
34
    && (current_cframe->previous_cframe == NULL
394
0
        || ! current_cframe->previous_cframe->ignoring))
395
0
  listing_list (1);
396
397
34
      hold = current_cframe;
398
34
      current_cframe = current_cframe->previous_cframe;
399
34
      obstack_free (&cond_obstack, hold);
400
34
    }        /* if one pop too many */
401
402
954
  if (flag_mri)
403
138
    {
404
586
      while (! is_end_of_line[(unsigned char) *input_line_pointer])
405
448
  ++input_line_pointer;
406
138
    }
407
408
954
  demand_empty_rest_of_line ();
409
954
}
410
411
void
412
s_else (int arg ATTRIBUTE_UNUSED)
413
192
{
414
192
  if (current_cframe == NULL)
415
89
    {
416
89
      as_bad (_("\".else\" without matching \".if\""));
417
89
    }
418
103
  else if (current_cframe->else_seen)
419
81
    {
420
81
      as_bad (_("duplicate \".else\""));
421
81
      as_bad_where (current_cframe->else_file_line.file,
422
81
        current_cframe->else_file_line.line,
423
81
        _("here is the previous \".else\""));
424
81
      as_bad_where (current_cframe->if_file_line.file,
425
81
        current_cframe->if_file_line.line,
426
81
        _("here is the previous \".if\""));
427
81
    }
428
22
  else
429
22
    {
430
22
      current_cframe->else_file_line.file
431
22
        = as_where (&current_cframe->else_file_line.line);
432
433
22
      current_cframe->ignoring =
434
22
  current_cframe->dead_tree | !current_cframe->ignoring;
435
436
22
      if (LISTING_SKIP_COND ()
437
22
    && (current_cframe->previous_cframe == NULL
438
0
        || ! current_cframe->previous_cframe->ignoring))
439
0
  {
440
0
    if (! current_cframe->ignoring)
441
0
      listing_list (1);
442
0
    else
443
0
      listing_list (2);
444
0
  }
445
446
22
      current_cframe->else_seen = 1;
447
22
    }
448
449
192
  if (flag_mri)
450
73
    {
451
423
      while (! is_end_of_line[(unsigned char) *input_line_pointer])
452
350
  ++input_line_pointer;
453
73
    }
454
455
192
  demand_empty_rest_of_line ();
456
192
}
457
458
void
459
s_ifeqs (int arg)
460
507
{
461
507
  char *s1, *s2;
462
507
  int len1, len2;
463
507
  int res;
464
507
  struct conditional_frame cframe;
465
466
507
  s1 = demand_copy_C_string (&len1);
467
468
507
  SKIP_WHITESPACE ();
469
507
  if (*input_line_pointer != ',')
470
503
    {
471
503
      as_bad (_(".ifeqs syntax error"));
472
503
      ignore_rest_of_line ();
473
503
      return;
474
503
    }
475
476
4
  ++input_line_pointer;
477
478
4
  s2 = demand_copy_C_string (&len2);
479
480
4
  res = len1 == len2 && strncmp (s1, s2, len1) == 0;
481
482
4
  initialize_cframe (&cframe);
483
4
  cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
484
4
  current_cframe =
485
4
    (struct conditional_frame *) obstack_alloc (&cond_obstack, sizeof cframe);
486
4
  memcpy (current_cframe, &cframe, sizeof cframe);
487
488
4
  if (LISTING_SKIP_COND ()
489
4
      && cframe.ignoring
490
4
      && (cframe.previous_cframe == NULL
491
0
    || ! cframe.previous_cframe->ignoring))
492
0
    listing_list (2);
493
494
4
  demand_empty_rest_of_line ();
495
4
}
496
497
int
498
ignore_input (void)
499
6.92M
{
500
6.92M
  char *s;
501
502
6.92M
  s = input_line_pointer;
503
504
6.92M
  if (NO_PSEUDO_DOT || flag_m68k_mri)
505
0
    {
506
0
      if (s[-1] != '.')
507
0
  --s;
508
0
    }
509
6.92M
  else
510
6.92M
    {
511
6.92M
      if (s[-1] != '.')
512
4.87M
  return (current_cframe != NULL) && (current_cframe->ignoring);
513
6.92M
    }
514
515
  /* We cannot ignore certain pseudo ops.  */
516
2.05M
  switch (s[0])
517
2.05M
    {
518
125k
    case 'i': case  'I':
519
125k
      if (s[1] == 'f' || s[1] == 'F')
520
19.6k
  return 0;
521
105k
      break;
522
192k
    case 'e': case 'E':
523
192k
      if (!strncasecmp (s, "else", 4)
524
192k
    || !strncasecmp (s, "endif", 5)
525
192k
    || !strncasecmp (s, "endc", 4))
526
31.3k
  return 0;
527
161k
      break;
528
598k
    case 'l': case 'L':
529
598k
      if (!strncasecmp (s, "linefile", 8))
530
551k
  return 0;
531
46.6k
      break;
532
2.05M
    }
533
534
1.44M
  return (current_cframe != NULL) && (current_cframe->ignoring);
535
2.05M
}
536
537
static void
538
initialize_cframe (struct conditional_frame *cframe)
539
6.86k
{
540
6.86k
  memset (cframe, 0, sizeof (*cframe));
541
6.86k
  cframe->if_file_line.file
542
6.86k
      = as_where (&cframe->if_file_line.line);
543
6.86k
  cframe->previous_cframe = current_cframe;
544
6.86k
  cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
545
6.86k
  cframe->macro_nest = macro_nest;
546
6.86k
}
547
548
/* Give an error if a conditional is unterminated inside a macro or
549
   the assembly as a whole.  If NEST is non negative, we are being
550
   called because of the end of a macro expansion.  If NEST is
551
   negative, we are being called at the of the input files.  */
552
553
void
554
cond_finish_check (int nest)
555
30.1k
{
556
30.1k
  if (current_cframe != NULL && current_cframe->macro_nest >= nest)
557
391
    {
558
391
      if (nest >= 0)
559
7
  as_bad (_("end of macro inside conditional"));
560
384
      else
561
384
  as_bad (_("end of file inside conditional"));
562
563
391
      as_bad_where (current_cframe->if_file_line.file,
564
391
        current_cframe->if_file_line.line,
565
391
        _("here is the start of the unterminated conditional"));
566
391
      if (current_cframe->else_seen)
567
5
  as_bad_where (current_cframe->else_file_line.file,
568
5
          current_cframe->else_file_line.line,
569
5
          _("here is the \"else\" of the unterminated conditional"));
570
391
      cond_exit_macro (nest);
571
391
    }
572
30.1k
}
573
574
/* This function is called when we exit out of a macro.  We assume
575
   that any conditionals which began within the macro are correctly
576
   nested, and just pop them off the stack.  */
577
578
void
579
cond_exit_macro (int nest)
580
391
{
581
7.22k
  while (current_cframe != NULL && current_cframe->macro_nest >= nest)
582
6.83k
    {
583
6.83k
      struct conditional_frame *hold;
584
585
6.83k
      hold = current_cframe;
586
6.83k
      current_cframe = current_cframe->previous_cframe;
587
6.83k
      obstack_free (&cond_obstack, hold);
588
6.83k
    }
589
391
}