Coverage Report

Created: 2024-05-21 06:29

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