Coverage Report

Created: 2023-06-29 07:09

/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
10
{
71
  /* Points to name of symbol.  */
72
10
  char *name;
73
  /* Points to symbol.  */
74
10
  symbolS *symbolP;
75
10
  struct conditional_frame cframe;
76
10
  char c;
77
78
  /* Leading whitespace is part of operand.  */
79
10
  SKIP_WHITESPACE ();
80
10
  name = input_line_pointer;
81
82
10
  if (!is_name_beginner (*name) && *name != '"')
83
3
    {
84
3
      as_bad (_("invalid identifier for \".ifdef\""));
85
3
      obstack_1grow (&cond_obstack, 0);
86
3
      ignore_rest_of_line ();
87
3
      return;
88
3
    }
89
90
7
  c = get_symbol_name (& name);
91
7
  symbolP = symbol_find (name);
92
7
  (void) restore_line_pointer (c);
93
94
7
  initialize_cframe (&cframe);
95
96
7
  if (cframe.dead_tree)
97
7
    cframe.ignoring = 1;
98
0
  else
99
0
    {
100
0
      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
0
      is_defined =
106
0
  symbolP != NULL
107
0
  && (S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
108
0
  && S_GET_SEGMENT (symbolP) != reg_section;
109
110
0
      cframe.ignoring = ! (test_defined ^ is_defined);
111
0
    }
112
113
7
  current_cframe =
114
7
    (struct conditional_frame *) obstack_alloc (&cond_obstack, sizeof cframe);
115
7
  memcpy (current_cframe, &cframe, sizeof cframe);
116
117
7
  if (LISTING_SKIP_COND ()
118
7
      && cframe.ignoring
119
7
      && (cframe.previous_cframe == NULL
120
0
    || ! cframe.previous_cframe->ignoring))
121
0
    listing_list (2);
122
123
7
  demand_empty_rest_of_line ();
124
7
}
125
126
void
127
s_if (int arg)
128
7.30k
{
129
7.30k
  expressionS operand;
130
7.30k
  struct conditional_frame cframe;
131
7.30k
  int t;
132
7.30k
  char *stop = NULL;
133
7.30k
  char stopc = 0;
134
135
7.30k
  if (flag_mri)
136
5.77k
    stop = mri_comment_field (&stopc);
137
138
  /* Leading whitespace is part of operand.  */
139
7.30k
  SKIP_WHITESPACE ();
140
141
7.30k
  if (current_cframe != NULL && current_cframe->ignoring)
142
272
    {
143
272
      operand.X_add_number = 0;
144
3.14k
      while (! is_end_of_line[(unsigned char) *input_line_pointer])
145
2.87k
  ++input_line_pointer;
146
272
    }
147
7.02k
  else
148
7.02k
    {
149
7.02k
      expression_and_evaluate (&operand);
150
7.02k
      if (operand.X_op != O_constant)
151
4.98k
  as_bad (_("non-constant expression in \".if\" statement"));
152
7.02k
    }
153
154
7.30k
  switch ((operatorT) arg)
155
7.30k
    {
156
0
    case O_eq: t = operand.X_add_number == 0; break;
157
681
    case O_ne: t = operand.X_add_number != 0; break;
158
97
    case O_lt: t = operand.X_add_number < 0; break;
159
5.26k
    case O_le: t = operand.X_add_number <= 0; break;
160
1.21k
    case O_ge: t = operand.X_add_number >= 0; break;
161
42
    case O_gt: t = operand.X_add_number > 0; break;
162
0
    default:
163
0
      abort ();
164
0
      return;
165
7.30k
    }
166
167
  /* If the above error is signaled, this will dispatch
168
     using an undefined result.  No big deal.  */
169
7.30k
  initialize_cframe (&cframe);
170
7.30k
  cframe.ignoring = cframe.dead_tree || ! t;
171
7.30k
  current_cframe =
172
7.30k
    (struct conditional_frame *) obstack_alloc (&cond_obstack, sizeof cframe);
173
7.30k
  memcpy (current_cframe, & cframe, sizeof cframe);
174
175
7.30k
  if (LISTING_SKIP_COND ()
176
7.30k
      && cframe.ignoring
177
7.30k
      && (cframe.previous_cframe == NULL
178
0
    || ! cframe.previous_cframe->ignoring))
179
0
    listing_list (2);
180
181
7.30k
  if (flag_mri)
182
5.77k
    mri_comment_end (stop, stopc);
183
184
7.30k
  demand_empty_rest_of_line ();
185
7.30k
}
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
16
{
193
16
  struct conditional_frame cframe;
194
195
16
  initialize_cframe (&cframe);
196
197
16
  if (cframe.dead_tree)
198
5
    cframe.ignoring = 1;
199
11
  else
200
11
    {
201
11
      int is_eol;
202
203
11
      SKIP_WHITESPACE ();
204
11
      is_eol = is_end_of_line[(unsigned char) *input_line_pointer];
205
11
      cframe.ignoring = (test_blank == !is_eol);
206
11
    }
207
208
16
  current_cframe =
209
16
    (struct conditional_frame *) obstack_alloc (&cond_obstack, sizeof cframe);
210
16
  memcpy (current_cframe, &cframe, sizeof cframe);
211
212
16
  if (LISTING_SKIP_COND ()
213
16
      && cframe.ignoring
214
16
      && (cframe.previous_cframe == NULL
215
0
    || ! cframe.previous_cframe->ignoring))
216
0
    listing_list (2);
217
218
16
  ignore_rest_of_line ();
219
16
}
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
1.87k
{
226
1.87k
  char *ret;
227
1.87k
  char *s;
228
229
1.87k
  SKIP_WHITESPACE ();
230
1.87k
  s = ret = input_line_pointer;
231
1.87k
  if (*input_line_pointer == '\'')
232
38
    {
233
38
      ++s;
234
38
      ++input_line_pointer;
235
135
      while (! is_end_of_line[(unsigned char) *input_line_pointer])
236
119
  {
237
119
    *s++ = *input_line_pointer++;
238
119
    if (s[-1] == '\'')
239
62
      {
240
62
        if (*input_line_pointer != '\'')
241
22
    break;
242
40
        ++input_line_pointer;
243
40
      }
244
119
  }
245
38
      SKIP_WHITESPACE ();
246
38
    }
247
1.83k
  else
248
1.83k
    {
249
7.29k
      while (*input_line_pointer != terminator
250
7.29k
       && ! is_end_of_line[(unsigned char) *input_line_pointer])
251
5.45k
  ++input_line_pointer;
252
1.83k
      s = input_line_pointer;
253
1.83k
      while (s > ret && (s[-1] == ' ' || s[-1] == '\t'))
254
0
  --s;
255
1.83k
    }
256
257
1.87k
  *len = s - ret;
258
1.87k
  return ret;
259
1.87k
}
260
261
/* The MRI IFC and IFNC pseudo-ops.  */
262
263
void
264
s_ifc (int arg)
265
937
{
266
937
  char *stop = NULL;
267
937
  char stopc = 0;
268
937
  char *s1, *s2;
269
937
  int len1, len2;
270
937
  int res;
271
937
  struct conditional_frame cframe;
272
273
937
  if (flag_mri)
274
900
    stop = mri_comment_field (&stopc);
275
276
937
  s1 = get_mri_string (',', &len1);
277
278
937
  if (*input_line_pointer != ',')
279
799
    as_bad (_("bad format for ifc or ifnc"));
280
138
  else
281
138
    ++input_line_pointer;
282
283
937
  s2 = get_mri_string (';', &len2);
284
285
937
  res = len1 == len2 && strncmp (s1, s2, len1) == 0;
286
287
937
  initialize_cframe (&cframe);
288
937
  cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
289
937
  current_cframe =
290
937
    (struct conditional_frame *) obstack_alloc (&cond_obstack, sizeof cframe);
291
937
  memcpy (current_cframe, &cframe, sizeof cframe);
292
  
293
937
 if (LISTING_SKIP_COND ()
294
937
      && cframe.ignoring
295
937
      && (cframe.previous_cframe == NULL
296
0
    || ! cframe.previous_cframe->ignoring))
297
0
    listing_list (2);
298
299
937
  if (flag_mri)
300
900
    mri_comment_end (stop, stopc);
301
302
937
  demand_empty_rest_of_line ();
303
937
}
304
305
void
306
s_elseif (int arg)
307
870
{
308
870
  if (current_cframe == NULL)
309
635
    {
310
635
      as_bad (_("\".elseif\" without matching \".if\""));
311
635
    }
312
235
  else if (current_cframe->else_seen)
313
173
    {
314
173
      as_bad (_("\".elseif\" after \".else\""));
315
173
      as_bad_where (current_cframe->else_file_line.file,
316
173
        current_cframe->else_file_line.line,
317
173
        _("here is the previous \".else\""));
318
173
      as_bad_where (current_cframe->if_file_line.file,
319
173
        current_cframe->if_file_line.line,
320
173
        _("here is the previous \".if\""));
321
173
    }
322
62
  else
323
62
    {
324
62
      current_cframe->else_file_line.file
325
62
        = as_where (&current_cframe->else_file_line.line);
326
327
62
      current_cframe->dead_tree |= !current_cframe->ignoring;
328
62
      current_cframe->ignoring = current_cframe->dead_tree;
329
62
    }
330
331
870
  if (current_cframe == NULL || current_cframe->ignoring)
332
870
    {
333
2.80k
      while (! is_end_of_line[(unsigned char) *input_line_pointer])
334
1.93k
  ++input_line_pointer;
335
336
870
      if (current_cframe == NULL)
337
635
  return;
338
870
    }
339
0
  else
340
0
    {
341
0
      expressionS operand;
342
0
      int t;
343
344
      /* Leading whitespace is part of operand.  */
345
0
      SKIP_WHITESPACE ();
346
347
0
      expression_and_evaluate (&operand);
348
0
      if (operand.X_op != O_constant)
349
0
  as_bad (_("non-constant expression in \".elseif\" statement"));
350
351
0
      switch ((operatorT) arg)
352
0
  {
353
0
  case O_eq: t = operand.X_add_number == 0; break;
354
0
  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
0
  }
363
364
0
      current_cframe->ignoring = current_cframe->dead_tree || ! t;
365
0
    }
366
367
235
  if (LISTING_SKIP_COND ()
368
235
      && (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
235
  demand_empty_rest_of_line ();
378
235
}
379
380
void
381
s_endif (int arg ATTRIBUTE_UNUSED)
382
38
{
383
38
  struct conditional_frame *hold;
384
385
38
  if (current_cframe == NULL)
386
30
    {
387
30
      as_bad (_("\".endif\" without \".if\""));
388
30
    }
389
8
  else
390
8
    {
391
8
      if (LISTING_SKIP_COND ()
392
8
    && current_cframe->ignoring
393
8
    && (current_cframe->previous_cframe == NULL
394
0
        || ! current_cframe->previous_cframe->ignoring))
395
0
  listing_list (1);
396
397
8
      hold = current_cframe;
398
8
      current_cframe = current_cframe->previous_cframe;
399
8
      obstack_free (&cond_obstack, hold);
400
8
    }        /* if one pop too many */
401
402
38
  if (flag_mri)
403
22
    {
404
22
      while (! is_end_of_line[(unsigned char) *input_line_pointer])
405
0
  ++input_line_pointer;
406
22
    }
407
408
38
  demand_empty_rest_of_line ();
409
38
}
410
411
void
412
s_else (int arg ATTRIBUTE_UNUSED)
413
106
{
414
106
  if (current_cframe == NULL)
415
37
    {
416
37
      as_bad (_("\".else\" without matching \".if\""));
417
37
    }
418
69
  else if (current_cframe->else_seen)
419
48
    {
420
48
      as_bad (_("duplicate \".else\""));
421
48
      as_bad_where (current_cframe->else_file_line.file,
422
48
        current_cframe->else_file_line.line,
423
48
        _("here is the previous \".else\""));
424
48
      as_bad_where (current_cframe->if_file_line.file,
425
48
        current_cframe->if_file_line.line,
426
48
        _("here is the previous \".if\""));
427
48
    }
428
21
  else
429
21
    {
430
21
      current_cframe->else_file_line.file
431
21
        = as_where (&current_cframe->else_file_line.line);
432
433
21
      current_cframe->ignoring =
434
21
  current_cframe->dead_tree | !current_cframe->ignoring;
435
436
21
      if (LISTING_SKIP_COND ()
437
21
    && (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
21
      current_cframe->else_seen = 1;
447
21
    }
448
449
106
  if (flag_mri)
450
100
    {
451
116
      while (! is_end_of_line[(unsigned char) *input_line_pointer])
452
16
  ++input_line_pointer;
453
100
    }
454
455
106
  demand_empty_rest_of_line ();
456
106
}
457
458
void
459
s_ifeqs (int arg)
460
422
{
461
422
  char *s1, *s2;
462
422
  int len1, len2;
463
422
  int res;
464
422
  struct conditional_frame cframe;
465
466
422
  s1 = demand_copy_C_string (&len1);
467
468
422
  SKIP_WHITESPACE ();
469
422
  if (*input_line_pointer != ',')
470
400
    {
471
400
      as_bad (_(".ifeqs syntax error"));
472
400
      ignore_rest_of_line ();
473
400
      return;
474
400
    }
475
476
22
  ++input_line_pointer;
477
478
22
  s2 = demand_copy_C_string (&len2);
479
480
22
  res = len1 == len2 && strncmp (s1, s2, len1) == 0;
481
482
22
  initialize_cframe (&cframe);
483
22
  cframe.ignoring = cframe.dead_tree || ! (res ^ arg);
484
22
  current_cframe =
485
22
    (struct conditional_frame *) obstack_alloc (&cond_obstack, sizeof cframe);
486
22
  memcpy (current_cframe, &cframe, sizeof cframe);
487
488
22
  if (LISTING_SKIP_COND ()
489
22
      && cframe.ignoring
490
22
      && (cframe.previous_cframe == NULL
491
0
    || ! cframe.previous_cframe->ignoring))
492
0
    listing_list (2);
493
494
22
  demand_empty_rest_of_line ();
495
22
}
496
497
int
498
ignore_input (void)
499
2.63M
{
500
2.63M
  char *s;
501
502
2.63M
  s = input_line_pointer;
503
504
2.63M
  if (NO_PSEUDO_DOT || flag_m68k_mri)
505
0
    {
506
0
      if (s[-1] != '.')
507
0
  --s;
508
0
    }
509
2.63M
  else
510
2.63M
    {
511
2.63M
      if (s[-1] != '.')
512
1.95M
  return (current_cframe != NULL) && (current_cframe->ignoring);
513
2.63M
    }
514
515
  /* We cannot ignore certain pseudo ops.  */
516
673k
  switch (s[0])
517
673k
    {
518
26.2k
    case 'i': case  'I':
519
26.2k
      if (s[1] == 'f' || s[1] == 'F')
520
15.0k
  return 0;
521
11.1k
      break;
522
60.0k
    case 'e': case 'E':
523
60.0k
      if (!strncasecmp (s, "else", 4)
524
60.0k
    || !strncasecmp (s, "endif", 5)
525
60.0k
    || !strncasecmp (s, "endc", 4))
526
1.40k
  return 0;
527
58.6k
      break;
528
129k
    case 'l': case 'L':
529
129k
      if (!strncasecmp (s, "linefile", 8))
530
93.8k
  return 0;
531
35.4k
      break;
532
673k
    }
533
534
563k
  return (current_cframe != NULL) && (current_cframe->ignoring);
535
673k
}
536
537
static void
538
initialize_cframe (struct conditional_frame *cframe)
539
8.28k
{
540
8.28k
  memset (cframe, 0, sizeof (*cframe));
541
8.28k
  cframe->if_file_line.file
542
8.28k
      = as_where (&cframe->if_file_line.line);
543
8.28k
  cframe->previous_cframe = current_cframe;
544
8.28k
  cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring;
545
8.28k
  cframe->macro_nest = macro_nest;
546
8.28k
}
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
7.10k
{
556
7.10k
  if (current_cframe != NULL && current_cframe->macro_nest >= nest)
557
180
    {
558
180
      if (nest >= 0)
559
0
  as_bad (_("end of macro inside conditional"));
560
180
      else
561
180
  as_bad (_("end of file inside conditional"));
562
563
180
      as_bad_where (current_cframe->if_file_line.file,
564
180
        current_cframe->if_file_line.line,
565
180
        _("here is the start of the unterminated conditional"));
566
180
      if (current_cframe->else_seen)
567
4
  as_bad_where (current_cframe->else_file_line.file,
568
4
          current_cframe->else_file_line.line,
569
4
          _("here is the \"else\" of the unterminated conditional"));
570
180
      cond_exit_macro (nest);
571
180
    }
572
7.10k
}
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
180
{
581
8.45k
  while (current_cframe != NULL && current_cframe->macro_nest >= nest)
582
8.27k
    {
583
8.27k
      struct conditional_frame *hold;
584
585
8.27k
      hold = current_cframe;
586
8.27k
      current_cframe = current_cframe->previous_cframe;
587
8.27k
      obstack_free (&cond_obstack, hold);
588
8.27k
    }
589
180
}