Coverage Report

Created: 2024-05-21 06:29

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