Coverage Report

Created: 2023-06-29 07:13

/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
4.02M
{
78
4.02M
  static int identified;
79
80
4.02M
  if (identified)
81
4.02M
    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
633
{
112
633
  return error_count;
113
633
}
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
16.4k
{
141
16.4k
  va_list args;
142
16.4k
  char buffer[2000];
143
144
16.4k
  va_start (args, format);
145
16.4k
  vsnprintf (buffer, sizeof (buffer), format, args);
146
16.4k
  va_end (args);
147
16.4k
  fprintf (stderr, "%s:%u: %*s%s%s\n",
148
16.4k
     file, line, (int)indent, "", _("Info: "), buffer);
149
16.4k
}
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
289k
{
175
289k
  bool context = false;
176
177
289k
  ++warning_count;
178
179
289k
  if (file == NULL)
180
289k
    {
181
289k
      file = as_where_top (&line);
182
289k
      context = true;
183
289k
    }
184
185
289k
  identify (file);
186
289k
  if (file)
187
289k
    {
188
289k
      if (line != 0)
189
289k
  fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Warning: "), buffer);
190
282
      else
191
282
  fprintf (stderr, "%s: %s%s\n", file, _("Warning: "), buffer);
192
289k
    }
193
0
  else
194
0
    fprintf (stderr, "%s%s\n", _("Warning: "), buffer);
195
196
289k
  if (context)
197
289k
    as_report_context ();
198
199
289k
#ifndef NO_LISTING
200
289k
  listing_warning (buffer);
201
289k
#endif
202
289k
}
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
289k
{
213
289k
  va_list args;
214
289k
  char buffer[2000];
215
216
289k
  if (!flag_no_warnings)
217
289k
    {
218
289k
      va_start (args, format);
219
289k
      vsnprintf (buffer, sizeof (buffer), format, args);
220
289k
      va_end (args);
221
289k
      as_warn_internal ((char *) NULL, 0, buffer);
222
289k
    }
223
289k
}
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
156
{
232
156
  va_list args;
233
156
  char buffer[2000];
234
235
156
  if (!flag_no_warnings)
236
156
    {
237
156
      va_start (args, format);
238
156
      vsnprintf (buffer, sizeof (buffer), format, args);
239
156
      va_end (args);
240
156
      as_warn_internal (file, line, buffer);
241
156
    }
242
156
}
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
3.73M
{
249
3.73M
  bool context = false;
250
251
3.73M
  ++error_count;
252
253
3.73M
  if (file == NULL)
254
3.71M
    {
255
3.71M
      file = as_where_top (&line);
256
3.71M
      context = true;
257
3.71M
    }
258
259
3.73M
  identify (file);
260
3.73M
  if (file)
261
3.73M
    {
262
3.73M
      if (line != 0)
263
2.35M
  fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Error: "), buffer);
264
1.38M
      else
265
1.38M
  fprintf (stderr, "%s: %s%s\n", file, _("Error: "), buffer);
266
3.73M
    }
267
0
  else
268
0
    fprintf (stderr, "%s%s\n", _("Error: "), buffer);
269
270
3.73M
  if (context)
271
3.71M
    as_report_context ();
272
273
3.73M
#ifndef NO_LISTING
274
3.73M
  listing_error (buffer);
275
3.73M
#endif
276
3.73M
}
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
3.71M
{
287
3.71M
  va_list args;
288
3.71M
  char buffer[2000];
289
290
3.71M
  va_start (args, format);
291
3.71M
  vsnprintf (buffer, sizeof (buffer), format, args);
292
3.71M
  va_end (args);
293
294
3.71M
  as_bad_internal ((char *) NULL, 0, buffer);
295
3.71M
}
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
16.4k
{
304
16.4k
  va_list args;
305
16.4k
  char buffer[2000];
306
307
16.4k
  va_start (args, format);
308
16.4k
  vsnprintf (buffer, sizeof (buffer), format, args);
309
16.4k
  va_end (args);
310
311
16.4k
  as_bad_internal (file, line, buffer);
312
16.4k
}
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
633
{
376
633
#ifdef SIGSEGV
377
633
  signal (SIGSEGV, signal_crash);
378
633
#endif
379
633
#ifdef SIGILL
380
633
  signal (SIGILL, signal_crash);
381
633
#endif
382
633
#ifdef SIGBUS
383
633
  signal (SIGBUS, signal_crash);
384
633
#endif
385
633
#ifdef SIGABRT
386
633
  signal (SIGABRT, signal_crash);
387
633
#endif
388
#if defined SIGIOT && (!defined SIGABRT || SIGABRT != SIGIOT)
389
  signal (SIGIOT, signal_crash);
390
#endif
391
633
#ifdef SIGFPE
392
633
  signal (SIGFPE, signal_crash);
393
633
#endif
394
633
}
395
396
/* Support routines.  */
397
398
669
#define HEX_MAX_THRESHOLD 1024
399
339
#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
150
{
410
150
  const char * err;
411
412
150
  if (prefix == NULL)
413
0
    prefix = "";
414
415
150
  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
150
  else if (   val < HEX_MAX_THRESHOLD
432
150
     && min < HEX_MAX_THRESHOLD
433
150
     && max < HEX_MAX_THRESHOLD
434
150
     && val > HEX_MIN_THRESHOLD
435
150
     && min > HEX_MIN_THRESHOLD
436
150
     && max > HEX_MIN_THRESHOLD)
437
12
    {
438
      /* xgettext:c-format.  */
439
12
      err = _("%s out of range (%" PRId64
440
12
        " is not between %" PRId64 " and %" PRId64 ")");
441
442
12
      if (bad)
443
0
  as_bad_where (file, line, err, prefix,
444
0
          (int64_t) val, (int64_t) min, (int64_t) max);
445
12
      else
446
12
  as_warn_where (file, line, err, prefix,
447
12
           (int64_t) val, (int64_t) min, (int64_t) max);
448
12
    }
449
138
  else
450
138
    {
451
      /* xgettext:c-format.  */
452
138
      err = _("%s out of range (0x%" PRIx64
453
138
        " is not between 0x%" PRIx64 " and 0x%" PRIx64 ")");
454
455
138
      if (bad)
456
0
  as_bad_where (file, line, err, prefix,
457
0
          (int64_t) val, (int64_t) min, (int64_t) max);
458
138
      else
459
138
  as_warn_where (file, line, err, prefix,
460
138
           (int64_t) val, (int64_t) min, (int64_t) max);
461
138
    }
462
150
}
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
150
{
472
150
  as_internal_value_out_of_range (prefix, value, min, max, file, line, false);
473
150
}
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
}