Coverage Report

Created: 2026-07-25 10:20

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
535
{
74
535
  ident_name = name;
75
535
}
76
77
static void
78
identify (void)
79
1.45M
{
80
1.45M
  static int identified;
81
82
1.45M
  if (identified)
83
1.45M
    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
537
{
108
537
  return error_count;
109
537
}
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
1.83k
{
136
1.83k
  if (file == NULL)
137
0
    file = as_where_top (&line);
138
139
1.83k
  if (file)
140
1.83k
    {
141
1.83k
      if (line != 0)
142
1.65k
  fprintf (stderr, "%s:%u: %*s%s%s\n",
143
1.65k
     file, line, (int)indent, "", _("Info: "), buffer);
144
178
      else
145
178
  fprintf (stderr, "%s: %s%s\n", file, _("Info: "), buffer);
146
1.83k
    }
147
0
  else
148
0
    fprintf (stderr, "%s%s\n", _("Info: "), buffer);
149
1.83k
}
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
1.83k
{
176
1.83k
  if (flag_no_information)
177
0
    return;
178
179
1.83k
  va_list args;
180
1.83k
  char buffer[2000];
181
182
1.83k
  va_start (args, format);
183
1.83k
  vsnprintf (buffer, sizeof (buffer), format, args);
184
1.83k
  va_end (args);
185
1.83k
  as_info_internal (file, line, indent, buffer);
186
1.83k
}
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
105k
{
193
105k
  bool context = false;
194
195
105k
  if (file == NULL)
196
104k
    {
197
104k
      file = as_where_top (&line);
198
104k
      context = true;
199
104k
    }
200
201
105k
  identify ();
202
105k
  if (file)
203
105k
    {
204
105k
      if (line != 0)
205
104k
  fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Warning: "), buffer);
206
556
      else
207
556
  fprintf (stderr, "%s: %s%s\n", file, _("Warning: "), buffer);
208
105k
    }
209
0
  else
210
0
    fprintf (stderr, "%s%s\n", _("Warning: "), buffer);
211
212
105k
  if (context)
213
104k
    as_report_context ();
214
215
105k
#ifndef NO_LISTING
216
105k
  listing_warning (buffer);
217
105k
#endif
218
105k
}
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
104k
{
229
104k
  va_list args;
230
104k
  char buffer[2000];
231
232
104k
  if (!flag_no_warnings)
233
104k
    {
234
104k
      ++warning_count;
235
236
104k
      va_start (args, format);
237
104k
      vsnprintf (buffer, sizeof (buffer), format, args);
238
104k
      va_end (args);
239
104k
      as_warn_internal (NULL, 0, buffer);
240
104k
    }
241
104k
}
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
700
{
250
700
  va_list args;
251
700
  char buffer[2000];
252
253
700
  if (!flag_no_warnings)
254
700
    {
255
700
      ++warning_count;
256
257
700
      va_start (args, format);
258
700
      vsnprintf (buffer, sizeof (buffer), format, args);
259
700
      va_end (args);
260
700
      as_warn_internal (file, line, buffer);
261
700
    }
262
700
}
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
1.34M
{
287
1.34M
  bool context = false;
288
289
1.34M
  ++error_count;
290
291
1.34M
  if (file == NULL)
292
1.34M
    {
293
1.34M
      file = as_where_top (&line);
294
1.34M
      context = true;
295
1.34M
    }
296
297
1.34M
  identify ();
298
1.34M
  if (file)
299
1.34M
    {
300
1.34M
      if (line != 0)
301
914k
  fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Error: "), buffer);
302
431k
      else
303
431k
  fprintf (stderr, "%s: %s%s\n", file, _("Error: "), buffer);
304
1.34M
    }
305
0
  else
306
0
    fprintf (stderr, "%s%s\n", _("Error: "), buffer);
307
308
1.34M
  if (context)
309
1.34M
    as_report_context ();
310
311
1.34M
#ifndef NO_LISTING
312
1.34M
  listing_error (buffer);
313
1.34M
#endif
314
1.34M
}
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
1.34M
{
325
1.34M
  va_list args;
326
1.34M
  char buffer[2000];
327
328
1.34M
  va_start (args, format);
329
1.34M
  vsnprintf (buffer, sizeof (buffer), format, args);
330
1.34M
  va_end (args);
331
332
1.34M
  as_bad_internal (NULL, 0, buffer);
333
1.34M
}
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
4.89k
{
342
4.89k
  va_list args;
343
4.89k
  char buffer[2000];
344
345
4.89k
  va_start (args, format);
346
4.89k
  vsnprintf (buffer, sizeof (buffer), format, args);
347
4.89k
  va_end (args);
348
349
4.89k
  as_bad_internal (file, line, buffer);
350
4.89k
}
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
535
{
414
535
#ifdef SIGSEGV
415
535
  signal (SIGSEGV, signal_crash);
416
535
#endif
417
535
#ifdef SIGILL
418
535
  signal (SIGILL, signal_crash);
419
535
#endif
420
535
#ifdef SIGBUS
421
535
  signal (SIGBUS, signal_crash);
422
535
#endif
423
535
#ifdef SIGABRT
424
535
  signal (SIGABRT, signal_crash);
425
535
#endif
426
#if defined SIGIOT && (!defined SIGABRT || SIGABRT != SIGIOT)
427
  signal (SIGIOT, signal_crash);
428
#endif
429
535
#ifdef SIGFPE
430
535
  signal (SIGFPE, signal_crash);
431
535
#endif
432
535
}
433
434
/* Support routines.  */
435
436
35
#define HEX_MAX_THRESHOLD 1024
437
17
#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
1
     && min < HEX_MAX_THRESHOLD
471
1
     && max < HEX_MAX_THRESHOLD
472
1
     && val > HEX_MIN_THRESHOLD
473
0
     && min > HEX_MIN_THRESHOLD
474
0
     && max > HEX_MIN_THRESHOLD)
475
0
    {
476
      /* xgettext:c-format.  */
477
0
      err = _("%s out of range (%" PRId64
478
0
        " is not between %" PRId64 " and %" PRId64 ")");
479
480
0
      if (bad)
481
0
  as_bad_where (file, line, err, prefix,
482
0
          (int64_t) val, (int64_t) min, (int64_t) max);
483
0
      else
484
0
  as_warn_where (file, line, err, prefix,
485
0
           (int64_t) val, (int64_t) min, (int64_t) max);
486
0
    }
487
8
  else
488
8
    {
489
      /* xgettext:c-format.  */
490
8
      err = _("%s out of range (0x%" PRIx64
491
8
        " is not between 0x%" PRIx64 " and 0x%" PRIx64 ")");
492
493
8
      if (bad)
494
0
  as_bad_where (file, line, err, prefix,
495
0
          (int64_t) val, (int64_t) min, (int64_t) max);
496
8
      else
497
8
  as_warn_where (file, line, err, prefix,
498
8
           (int64_t) val, (int64_t) min, (int64_t) max);
499
8
    }
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
}