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