Coverage Report

Created: 2025-06-24 06:45

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