Coverage Report

Created: 2026-05-11 07:54

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