Coverage Report

Created: 2026-03-10 08:46

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