Coverage Report

Created: 2023-08-28 06:31

/src/binutils-gdb/gas/messages.c
Line
Count
Source (jump to first uncovered line)
1
/* messages.c - error reporter -
2
   Copyright (C) 1987-2023 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
7.60M
{
78
7.60M
  static int identified;
79
80
7.60M
  if (identified)
81
7.60M
    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
1.15k
{
112
1.15k
  return error_count;
113
1.15k
}
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
27.5k
{
141
27.5k
  va_list args;
142
27.5k
  char buffer[2000];
143
144
27.5k
  va_start (args, format);
145
27.5k
  vsnprintf (buffer, sizeof (buffer), format, args);
146
27.5k
  va_end (args);
147
27.5k
  fprintf (stderr, "%s:%u: %*s%s%s\n",
148
27.5k
     file, line, (int)indent, "", _("Info: "), buffer);
149
27.5k
}
150
151
/* Send to stderr a string as a warning, and locate warning
152
   in input file(s).
153
   Please only use this for when we have some recovery action.
154
   Please explain in string (which may have '\n's) what recovery was
155
   done.  */
156
157
void
158
as_tsktsk (const char *format, ...)
159
0
{
160
0
  va_list args;
161
162
0
  as_show_where ();
163
0
  va_start (args, format);
164
0
  vfprintf (stderr, format, args);
165
0
  va_end (args);
166
0
  (void) putc ('\n', stderr);
167
0
  as_report_context ();
168
0
}
169
170
/* The common portion of as_warn and as_warn_where.  */
171
172
static void
173
as_warn_internal (const char *file, unsigned int line, char *buffer)
174
1.19M
{
175
1.19M
  bool context = false;
176
177
1.19M
  ++warning_count;
178
179
1.19M
  if (file == NULL)
180
1.19M
    {
181
1.19M
      file = as_where_top (&line);
182
1.19M
      context = true;
183
1.19M
    }
184
185
1.19M
  identify (file);
186
1.19M
  if (file)
187
1.19M
    {
188
1.19M
      if (line != 0)
189
1.19M
  fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Warning: "), buffer);
190
655
      else
191
655
  fprintf (stderr, "%s: %s%s\n", file, _("Warning: "), buffer);
192
1.19M
    }
193
0
  else
194
0
    fprintf (stderr, "%s%s\n", _("Warning: "), buffer);
195
196
1.19M
  if (context)
197
1.19M
    as_report_context ();
198
199
1.19M
#ifndef NO_LISTING
200
1.19M
  listing_warning (buffer);
201
1.19M
#endif
202
1.19M
}
203
204
/* Send to stderr a string as a warning, and locate warning
205
   in input file(s).
206
   Please only use this for when we have some recovery action.
207
   Please explain in string (which may have '\n's) what recovery was
208
   done.  */
209
210
void
211
as_warn (const char *format, ...)
212
1.19M
{
213
1.19M
  va_list args;
214
1.19M
  char buffer[2000];
215
216
1.19M
  if (!flag_no_warnings)
217
1.19M
    {
218
1.19M
      va_start (args, format);
219
1.19M
      vsnprintf (buffer, sizeof (buffer), format, args);
220
1.19M
      va_end (args);
221
1.19M
      as_warn_internal ((char *) NULL, 0, buffer);
222
1.19M
    }
223
1.19M
}
224
225
/* Like as_warn but the file name and line number are passed in.
226
   Unfortunately, we have to repeat the function in order to handle
227
   the varargs correctly and portably.  */
228
229
void
230
as_warn_where (const char *file, unsigned int line, const char *format, ...)
231
302
{
232
302
  va_list args;
233
302
  char buffer[2000];
234
235
302
  if (!flag_no_warnings)
236
302
    {
237
302
      va_start (args, format);
238
302
      vsnprintf (buffer, sizeof (buffer), format, args);
239
302
      va_end (args);
240
302
      as_warn_internal (file, line, buffer);
241
302
    }
242
302
}
243
244
/* The common portion of as_bad and as_bad_where.  */
245
246
static void
247
as_bad_internal (const char *file, unsigned int line, char *buffer)
248
6.41M
{
249
6.41M
  bool context = false;
250
251
6.41M
  ++error_count;
252
253
6.41M
  if (file == NULL)
254
6.33M
    {
255
6.33M
      file = as_where_top (&line);
256
6.33M
      context = true;
257
6.33M
    }
258
259
6.41M
  identify (file);
260
6.41M
  if (file)
261
6.41M
    {
262
6.41M
      if (line != 0)
263
5.28M
  fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Error: "), buffer);
264
1.13M
      else
265
1.13M
  fprintf (stderr, "%s: %s%s\n", file, _("Error: "), buffer);
266
6.41M
    }
267
0
  else
268
0
    fprintf (stderr, "%s%s\n", _("Error: "), buffer);
269
270
6.41M
  if (context)
271
6.33M
    as_report_context ();
272
273
6.41M
#ifndef NO_LISTING
274
6.41M
  listing_error (buffer);
275
6.41M
#endif
276
6.41M
}
277
278
/* Send to stderr a string as a warning, and locate warning in input
279
   file(s).  Please use when there is no recovery, but we want to
280
   continue processing but not produce an object file.
281
   Please explain in string (which may have '\n's) what recovery was
282
   done.  */
283
284
void
285
as_bad (const char *format, ...)
286
6.33M
{
287
6.33M
  va_list args;
288
6.33M
  char buffer[2000];
289
290
6.33M
  va_start (args, format);
291
6.33M
  vsnprintf (buffer, sizeof (buffer), format, args);
292
6.33M
  va_end (args);
293
294
6.33M
  as_bad_internal ((char *) NULL, 0, buffer);
295
6.33M
}
296
297
/* Like as_bad but the file name and line number are passed in.
298
   Unfortunately, we have to repeat the function in order to handle
299
   the varargs correctly and portably.  */
300
301
void
302
as_bad_where (const char *file, unsigned int line, const char *format, ...)
303
74.9k
{
304
74.9k
  va_list args;
305
74.9k
  char buffer[2000];
306
307
74.9k
  va_start (args, format);
308
74.9k
  vsnprintf (buffer, sizeof (buffer), format, args);
309
74.9k
  va_end (args);
310
311
74.9k
  as_bad_internal (file, line, buffer);
312
74.9k
}
313
314
/* Send to stderr a string as a fatal message, and print location of
315
   error in input file(s).
316
   Please only use this for when we DON'T have some recovery action.
317
   It xexit()s with a warning status.  */
318
319
void
320
as_fatal (const char *format, ...)
321
0
{
322
0
  va_list args;
323
324
0
  as_show_where ();
325
0
  va_start (args, format);
326
0
  fprintf (stderr, _("Fatal error: "));
327
0
  vfprintf (stderr, format, args);
328
0
  (void) putc ('\n', stderr);
329
0
  va_end (args);
330
0
  as_report_context ();
331
  /* Delete the output file, if it exists.  This will prevent make from
332
     thinking that a file was created and hence does not need rebuilding.  */
333
0
  if (out_file_name != NULL)
334
0
    unlink_if_ordinary (out_file_name);
335
0
  xexit (EXIT_FAILURE);
336
0
}
337
338
/* Indicate internal constency error.
339
   Arguments: Filename, line number, optional function name.
340
   FILENAME may be NULL, which we use for crash-via-signal.  */
341
342
void
343
as_abort (const char *file, int line, const char *fn)
344
0
{
345
0
  as_show_where ();
346
347
0
  if (!file)
348
0
    fprintf (stderr, _("Internal error (%s).\n"), fn ? fn : "unknown");
349
0
  else if (fn)
350
0
    fprintf (stderr, _("Internal error in %s at %s:%d.\n"), fn, file, line);
351
0
  else
352
0
    fprintf (stderr, _("Internal error at %s:%d.\n"), file, line);
353
0
  as_report_context ();
354
355
0
  fprintf (stderr, _("Please report this bug.\n"));
356
357
0
  xexit (EXIT_FAILURE);
358
0
}
359
360
/* Handler for fatal signals, such as SIGSEGV. */
361
362
static void
363
signal_crash (int signo)
364
0
{
365
  /* Reset, to prevent unbounded recursion.  */
366
0
  signal (signo, SIG_DFL);
367
368
0
  as_abort (NULL, 0, strsignal (signo));
369
0
}
370
371
/* Register signal handlers, for less abrubt crashes.  */
372
373
void
374
signal_init (void)
375
1.15k
{
376
1.15k
#ifdef SIGSEGV
377
1.15k
  signal (SIGSEGV, signal_crash);
378
1.15k
#endif
379
1.15k
#ifdef SIGILL
380
1.15k
  signal (SIGILL, signal_crash);
381
1.15k
#endif
382
1.15k
#ifdef SIGBUS
383
1.15k
  signal (SIGBUS, signal_crash);
384
1.15k
#endif
385
1.15k
#ifdef SIGABRT
386
1.15k
  signal (SIGABRT, signal_crash);
387
1.15k
#endif
388
#if defined SIGIOT && (!defined SIGABRT || SIGABRT != SIGIOT)
389
  signal (SIGIOT, signal_crash);
390
#endif
391
1.15k
#ifdef SIGFPE
392
1.15k
  signal (SIGFPE, signal_crash);
393
1.15k
#endif
394
1.15k
}
395
396
/* Support routines.  */
397
398
1.34k
#define HEX_MAX_THRESHOLD 1024
399
714
#define HEX_MIN_THRESHOLD -(HEX_MAX_THRESHOLD)
400
401
static void
402
as_internal_value_out_of_range (const char *prefix,
403
        offsetT val,
404
        offsetT min,
405
        offsetT max,
406
        const char *file,
407
        unsigned line,
408
        bool bad)
409
227
{
410
227
  const char * err;
411
412
227
  if (prefix == NULL)
413
0
    prefix = "";
414
415
227
  if (val >= min && val <= max)
416
0
    {
417
0
      addressT right = max & -max;
418
419
0
      if (max <= 1)
420
0
  abort ();
421
422
      /* xgettext:c-format  */
423
0
      err = _("%s out of domain (%" PRId64
424
0
        " is not a multiple of %" PRId64 ")");
425
426
0
      if (bad)
427
0
  as_bad_where (file, line, err, prefix, (int64_t) val, (int64_t) right);
428
0
      else
429
0
  as_warn_where (file, line, err, prefix, (int64_t) val, (int64_t) right);
430
0
    }
431
227
  else if (   val < HEX_MAX_THRESHOLD
432
227
     && min < HEX_MAX_THRESHOLD
433
227
     && max < HEX_MAX_THRESHOLD
434
227
     && val > HEX_MIN_THRESHOLD
435
227
     && min > HEX_MIN_THRESHOLD
436
227
     && max > HEX_MIN_THRESHOLD)
437
86
    {
438
      /* xgettext:c-format.  */
439
86
      err = _("%s out of range (%" PRId64
440
86
        " is not between %" PRId64 " and %" PRId64 ")");
441
442
86
      if (bad)
443
0
  as_bad_where (file, line, err, prefix,
444
0
          (int64_t) val, (int64_t) min, (int64_t) max);
445
86
      else
446
86
  as_warn_where (file, line, err, prefix,
447
86
           (int64_t) val, (int64_t) min, (int64_t) max);
448
86
    }
449
141
  else
450
141
    {
451
      /* xgettext:c-format.  */
452
141
      err = _("%s out of range (0x%" PRIx64
453
141
        " is not between 0x%" PRIx64 " and 0x%" PRIx64 ")");
454
455
141
      if (bad)
456
0
  as_bad_where (file, line, err, prefix,
457
0
          (int64_t) val, (int64_t) min, (int64_t) max);
458
141
      else
459
141
  as_warn_where (file, line, err, prefix,
460
141
           (int64_t) val, (int64_t) min, (int64_t) max);
461
141
    }
462
227
}
463
464
void
465
as_warn_value_out_of_range (const char *prefix,
466
         offsetT value,
467
         offsetT min,
468
         offsetT max,
469
         const char *file,
470
         unsigned line)
471
227
{
472
227
  as_internal_value_out_of_range (prefix, value, min, max, file, line, false);
473
227
}
474
475
void
476
as_bad_value_out_of_range (const char *prefix,
477
         offsetT value,
478
         offsetT min,
479
         offsetT max,
480
         const char *file,
481
         unsigned line)
482
0
{
483
0
  as_internal_value_out_of_range (prefix, value, min, max, file, line, true);
484
0
}