Coverage Report

Created: 2026-04-04 08:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/binutils-gdb/gas/messages.c
Line
Count
Source
1
/* messages.c - error reporter -
2
   Copyright (C) 1987-2026 Free Software Foundation, Inc.
3
   This file is part of GAS, the GNU Assembler.
4
5
   GAS is free software; you can redistribute it and/or modify
6
   it under the terms of the GNU General Public License as published by
7
   the Free Software Foundation; either version 3, or (at your option)
8
   any later version.
9
10
   GAS is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
   GNU General Public License for more details.
14
15
   You should have received a copy of the GNU General Public License
16
   along with GAS; see the file COPYING.  If not, write to the Free
17
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
18
   02110-1301, USA.  */
19
20
#include "as.h"
21
#include <limits.h>
22
#include <signal.h>
23
24
/* If the system doesn't provide strsignal, we get it defined in
25
   libiberty but no declaration is supplied.  Because, reasons. */
26
#if !defined (HAVE_STRSIGNAL) && !defined (strsignal)
27
extern const char *strsignal (int);
28
#endif
29
30
/* Despite the rest of the comments in this file, (FIXME-SOON),
31
   here is the current scheme for error messages etc:
32
33
   as_fatal() is used when gas is quite confused and
34
   continuing the assembly is pointless.  In this case we
35
   exit immediately with error status.
36
37
   as_bad() is used to mark errors that result in what we
38
   presume to be a useless object file.  Say, we ignored
39
   something that might have been vital.  If we see any of
40
   these, assembly will continue to the end of the source,
41
   no object file will be produced, and we will terminate
42
   with error status.  The new option, -Z, tells us to
43
   produce an object file anyway but we still exit with
44
   error status.  The assumption here is that you don't want
45
   this object file but we could be wrong.
46
47
   as_warn() is used when we have an error from which we
48
   have a plausible error recovery.  eg, masking the top
49
   bits of a constant that is longer than will fit in the
50
   destination.  In this case we will continue to assemble
51
   the source, although we may have made a bad assumption,
52
   and we will produce an object file and return normal exit
53
   status (ie, no error).  The new option -X tells us to
54
   treat all as_warn() errors as as_bad() errors.  That is,
55
   no object file will be produced and we will exit with
56
   error status.  The idea here is that we don't kill an
57
   entire make because of an error that we knew how to
58
   correct.  On the other hand, sometimes you might want to
59
   stop the make at these points.
60
61
   as_tsktsk() is used when we see a minor error for which
62
   our error recovery action is almost certainly correct.
63
   In this case, we print a message and then assembly
64
   continues as though no error occurred.
65
66
   as_abort () is used for logic failure (assert or abort, signal).
67
*/
68
69
static const char *ident_name;
70
71
void
72
set_identify_name (const char *name)
73
567
{
74
567
  ident_name = name;
75
567
}
76
77
static void
78
identify (void)
79
796k
{
80
796k
  static int identified;
81
82
796k
  if (identified)
83
796k
    return;
84
1
  identified++;
85
86
1
  if (ident_name && *ident_name)
87
1
    fprintf (stderr, "%s: ", ident_name);
88
1
  fprintf (stderr, _("Assembler messages:\n"));
89
1
}
90
91
/* The number of warnings issued.  */
92
static int warning_count;
93
94
int
95
had_warnings (void)
96
0
{
97
0
  return warning_count;
98
0
}
99
100
/* Nonzero if we've hit a 'bad error', and should not write an obj file,
101
   and exit with a nonzero error code.  */
102
103
static int error_count;
104
105
int
106
had_errors (void)
107
567
{
108
567
  return error_count;
109
567
}
110
111
/* Print the current location to stderr.  */
112
113
static void
114
as_show_where (void)
115
0
{
116
0
  const char *file;
117
0
  unsigned int line;
118
119
0
  file = as_where_top (&line);
120
0
  identify ();
121
0
  if (file)
122
0
    {
123
0
      if (line != 0)
124
0
  fprintf (stderr, "%s:%u: ", file, line);
125
0
      else
126
0
  fprintf (stderr, "%s: ", file);
127
0
    }
128
0
}
129
130
/* The common portion of as_info, and as_info_where.  */
131
132
static void
133
as_info_internal (const char *file, unsigned int line, unsigned int indent,
134
      const char *buffer)
135
69.4k
{
136
69.4k
  if (file == NULL)
137
0
    file = as_where_top (&line);
138
139
69.4k
  if (file)
140
69.4k
    {
141
69.4k
      if (line != 0)
142
69.3k
  fprintf (stderr, "%s:%u: %*s%s%s\n",
143
69.3k
     file, line, (int)indent, "", _("Info: "), buffer);
144
54
      else
145
54
  fprintf (stderr, "%s: %s%s\n", file, _("Info: "), buffer);
146
69.4k
    }
147
0
  else
148
0
    fprintf (stderr, "%s%s\n", _("Info: "), buffer);
149
69.4k
}
150
151
/* Send to stderr a string as a information, and locate information
152
   in input file(s).  */
153
154
void
155
as_info (unsigned int indent, const char *format, ...)
156
0
{
157
0
  if (flag_no_information)
158
0
    return;
159
160
0
  va_list args;
161
0
  char buffer[2000];
162
163
0
  va_start (args, format);
164
0
  vsnprintf (buffer, sizeof (buffer), format, args);
165
0
  va_end (args);
166
0
  as_info_internal (NULL, 0, indent, buffer);
167
0
}
168
169
/* Send to stderr a string as information, with location data passed in.
170
   Note that for now this is not intended for general use.  */
171
172
void
173
as_info_where (const char *file, unsigned int line, unsigned int indent,
174
         const char *format, ...)
175
69.4k
{
176
69.4k
  if (flag_no_information)
177
0
    return;
178
179
69.4k
  va_list args;
180
69.4k
  char buffer[2000];
181
182
69.4k
  va_start (args, format);
183
69.4k
  vsnprintf (buffer, sizeof (buffer), format, args);
184
69.4k
  va_end (args);
185
69.4k
  as_info_internal (file, line, indent, buffer);
186
69.4k
}
187
188
/* The common portion of as_warn, as_warn_where, and as_tsktsk.  */
189
190
static void
191
as_warn_internal (const char *file, unsigned int line, char *buffer)
192
431k
{
193
431k
  bool context = false;
194
195
431k
  if (file == NULL)
196
431k
    {
197
431k
      file = as_where_top (&line);
198
431k
      context = true;
199
431k
    }
200
201
431k
  identify ();
202
431k
  if (file)
203
431k
    {
204
431k
      if (line != 0)
205
431k
  fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Warning: "), buffer);
206
540
      else
207
540
  fprintf (stderr, "%s: %s%s\n", file, _("Warning: "), buffer);
208
431k
    }
209
0
  else
210
0
    fprintf (stderr, "%s%s\n", _("Warning: "), buffer);
211
212
431k
  if (context)
213
431k
    as_report_context ();
214
215
431k
#ifndef NO_LISTING
216
431k
  listing_warning (buffer);
217
431k
#endif
218
431k
}
219
220
/* Send to stderr a string as a warning, and locate warning
221
   in input file(s).
222
   Please only use this for when we have some recovery action.
223
   Please explain in string (which may have '\n's) what recovery was
224
   done.  */
225
226
void
227
as_warn (const char *format, ...)
228
431k
{
229
431k
  va_list args;
230
431k
  char buffer[2000];
231
232
431k
  if (!flag_no_warnings)
233
431k
    {
234
431k
      ++warning_count;
235
236
431k
      va_start (args, format);
237
431k
      vsnprintf (buffer, sizeof (buffer), format, args);
238
431k
      va_end (args);
239
431k
      as_warn_internal (NULL, 0, buffer);
240
431k
    }
241
431k
}
242
243
/* Like as_warn but the file name and line number are passed in.
244
   Unfortunately, we have to repeat the function in order to handle
245
   the varargs correctly and portably.  */
246
247
void
248
as_warn_where (const char *file, unsigned int line, const char *format, ...)
249
346
{
250
346
  va_list args;
251
346
  char buffer[2000];
252
253
346
  if (!flag_no_warnings)
254
346
    {
255
346
      ++warning_count;
256
257
346
      va_start (args, format);
258
346
      vsnprintf (buffer, sizeof (buffer), format, args);
259
346
      va_end (args);
260
346
      as_warn_internal (file, line, buffer);
261
346
    }
262
346
}
263
264
/* Send to stderr a string as a warning, and locate warning
265
   in input file(s).
266
   Please only use this for when we have some recovery action.
267
   Please explain in string (which may have '\n's) what recovery was
268
   done.  */
269
270
void
271
as_tsktsk (const char *format, ...)
272
0
{
273
0
  va_list args;
274
0
  char buffer[2000];
275
276
0
  va_start (args, format);
277
0
  vsnprintf (buffer, sizeof (buffer), format, args);
278
0
  va_end (args);
279
0
  as_warn_internal (NULL, 0, buffer);
280
0
}
281
282
/* The common portion of as_bad and as_bad_where.  */
283
284
static void
285
as_bad_internal (const char *file, unsigned int line, char *buffer)
286
365k
{
287
365k
  bool context = false;
288
289
365k
  ++error_count;
290
291
365k
  if (file == NULL)
292
364k
    {
293
364k
      file = as_where_top (&line);
294
364k
      context = true;
295
364k
    }
296
297
365k
  identify ();
298
365k
  if (file)
299
365k
    {
300
365k
      if (line != 0)
301
364k
  fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Error: "), buffer);
302
303
      else
303
303
  fprintf (stderr, "%s: %s%s\n", file, _("Error: "), buffer);
304
365k
    }
305
0
  else
306
0
    fprintf (stderr, "%s%s\n", _("Error: "), buffer);
307
308
365k
  if (context)
309
364k
    as_report_context ();
310
311
365k
#ifndef NO_LISTING
312
365k
  listing_error (buffer);
313
365k
#endif
314
365k
}
315
316
/* Send to stderr a string as a warning, and locate warning in input
317
   file(s).  Please use when there is no recovery, but we want to
318
   continue processing but not produce an object file.
319
   Please explain in string (which may have '\n's) what recovery was
320
   done.  */
321
322
void
323
as_bad (const char *format, ...)
324
364k
{
325
364k
  va_list args;
326
364k
  char buffer[2000];
327
328
364k
  va_start (args, format);
329
364k
  vsnprintf (buffer, sizeof (buffer), format, args);
330
364k
  va_end (args);
331
332
364k
  as_bad_internal (NULL, 0, buffer);
333
364k
}
334
335
/* Like as_bad but the file name and line number are passed in.
336
   Unfortunately, we have to repeat the function in order to handle
337
   the varargs correctly and portably.  */
338
339
void
340
as_bad_where (const char *file, unsigned int line, const char *format, ...)
341
650
{
342
650
  va_list args;
343
650
  char buffer[2000];
344
345
650
  va_start (args, format);
346
650
  vsnprintf (buffer, sizeof (buffer), format, args);
347
650
  va_end (args);
348
349
650
  as_bad_internal (file, line, buffer);
350
650
}
351
352
/* Send to stderr a string as a fatal message, and print location of
353
   error in input file(s).
354
   Please only use this for when we DON'T have some recovery action.
355
   It xexit()s with a warning status.  */
356
357
void
358
as_fatal (const char *format, ...)
359
0
{
360
0
  va_list args;
361
362
0
  as_show_where ();
363
0
  va_start (args, format);
364
0
  fprintf (stderr, _("Fatal error: "));
365
0
  vfprintf (stderr, format, args);
366
0
  (void) putc ('\n', stderr);
367
0
  va_end (args);
368
0
  as_report_context ();
369
  /* Delete the output file, if it exists.  This will prevent make from
370
     thinking that a file was created and hence does not need rebuilding.  */
371
0
  if (out_file_name != NULL)
372
0
    unlink_if_ordinary (out_file_name);
373
0
  xexit (EXIT_FAILURE);
374
0
}
375
376
/* Indicate internal constency error.
377
   Arguments: Filename, line number, optional function name.
378
   FILENAME may be NULL, which we use for crash-via-signal.  */
379
380
void
381
as_abort (const char *file, int line, const char *fn)
382
0
{
383
0
  as_show_where ();
384
385
0
  if (!file)
386
0
    fprintf (stderr, _("Internal error (%s).\n"), fn ? fn : "unknown");
387
0
  else if (fn)
388
0
    fprintf (stderr, _("Internal error in %s at %s:%d.\n"), fn, file, line);
389
0
  else
390
0
    fprintf (stderr, _("Internal error at %s:%d.\n"), file, line);
391
0
  as_report_context ();
392
393
0
  fprintf (stderr, _("Please report this bug.\n"));
394
395
0
  xexit (EXIT_FAILURE);
396
0
}
397
398
/* Handler for fatal signals, such as SIGSEGV. */
399
400
static void
401
signal_crash (int signo)
402
0
{
403
  /* Reset, to prevent unbounded recursion.  */
404
0
  signal (signo, SIG_DFL);
405
406
0
  as_abort (NULL, 0, strsignal (signo));
407
0
}
408
409
/* Register signal handlers, for less abrubt crashes.  */
410
411
void
412
signal_init (void)
413
567
{
414
567
#ifdef SIGSEGV
415
567
  signal (SIGSEGV, signal_crash);
416
567
#endif
417
567
#ifdef SIGILL
418
567
  signal (SIGILL, signal_crash);
419
567
#endif
420
567
#ifdef SIGBUS
421
567
  signal (SIGBUS, signal_crash);
422
567
#endif
423
567
#ifdef SIGABRT
424
567
  signal (SIGABRT, signal_crash);
425
567
#endif
426
#if defined SIGIOT && (!defined SIGABRT || SIGABRT != SIGIOT)
427
  signal (SIGIOT, signal_crash);
428
#endif
429
567
#ifdef SIGFPE
430
567
  signal (SIGFPE, signal_crash);
431
567
#endif
432
567
}
433
434
/* Support routines.  */
435
436
48
#define HEX_MAX_THRESHOLD 1024
437
24
#define HEX_MIN_THRESHOLD -(HEX_MAX_THRESHOLD)
438
439
static void
440
as_internal_value_out_of_range (const char *prefix,
441
        offsetT val,
442
        offsetT min,
443
        offsetT max,
444
        const char *file,
445
        unsigned line,
446
        bool bad)
447
8
{
448
8
  const char * err;
449
450
8
  if (prefix == NULL)
451
0
    prefix = "";
452
453
8
  if (val >= min && val <= max)
454
0
    {
455
0
      addressT right = max & -max;
456
457
0
      if (max <= 1)
458
0
  abort ();
459
460
      /* xgettext:c-format  */
461
0
      err = _("%s out of domain (%" PRId64
462
0
        " is not a multiple of %" PRId64 ")");
463
464
0
      if (bad)
465
0
  as_bad_where (file, line, err, prefix, (int64_t) val, (int64_t) right);
466
0
      else
467
0
  as_warn_where (file, line, err, prefix, (int64_t) val, (int64_t) right);
468
0
    }
469
8
  else if (   val < HEX_MAX_THRESHOLD
470
4
     && min < HEX_MAX_THRESHOLD
471
4
     && max < HEX_MAX_THRESHOLD
472
4
     && val > HEX_MIN_THRESHOLD
473
2
     && min > HEX_MIN_THRESHOLD
474
2
     && max > HEX_MIN_THRESHOLD)
475
2
    {
476
      /* xgettext:c-format.  */
477
2
      err = _("%s out of range (%" PRId64
478
2
        " is not between %" PRId64 " and %" PRId64 ")");
479
480
2
      if (bad)
481
0
  as_bad_where (file, line, err, prefix,
482
0
          (int64_t) val, (int64_t) min, (int64_t) max);
483
2
      else
484
2
  as_warn_where (file, line, err, prefix,
485
2
           (int64_t) val, (int64_t) min, (int64_t) max);
486
2
    }
487
6
  else
488
6
    {
489
      /* xgettext:c-format.  */
490
6
      err = _("%s out of range (0x%" PRIx64
491
6
        " is not between 0x%" PRIx64 " and 0x%" PRIx64 ")");
492
493
6
      if (bad)
494
0
  as_bad_where (file, line, err, prefix,
495
0
          (int64_t) val, (int64_t) min, (int64_t) max);
496
6
      else
497
6
  as_warn_where (file, line, err, prefix,
498
6
           (int64_t) val, (int64_t) min, (int64_t) max);
499
6
    }
500
8
}
501
502
void
503
as_warn_value_out_of_range (const char *prefix,
504
         offsetT value,
505
         offsetT min,
506
         offsetT max,
507
         const char *file,
508
         unsigned line)
509
8
{
510
8
  as_internal_value_out_of_range (prefix, value, min, max, file, line, false);
511
8
}
512
513
void
514
as_bad_value_out_of_range (const char *prefix,
515
         offsetT value,
516
         offsetT min,
517
         offsetT max,
518
         const char *file,
519
         unsigned line)
520
0
{
521
  as_internal_value_out_of_range (prefix, value, min, max, file, line, true);
522
0
}