]>
Commit | Line | Data |
---|---|---|
252b5132 | 1 | /* messages.c - error reporter - |
d87bef3a | 2 | Copyright (C) 1987-2023 Free Software Foundation, Inc. |
252b5132 RH |
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 | |
ec2655a6 | 7 | the Free Software Foundation; either version 3, or (at your option) |
252b5132 RH |
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 | |
4b4da160 NC |
17 | Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA |
18 | 02110-1301, USA. */ | |
252b5132 RH |
19 | |
20 | #include "as.h" | |
969b9a36 | 21 | #include <limits.h> |
1ec4b9f2 NS |
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 | |
252b5132 | 29 | |
3b4dbbbf | 30 | static void identify (const char *); |
254d758c | 31 | static void as_show_where (void); |
3b4dbbbf TS |
32 | static void as_warn_internal (const char *, unsigned int, char *); |
33 | static void as_bad_internal (const char *, unsigned int, char *); | |
1ec4b9f2 | 34 | static void signal_crash (int) ATTRIBUTE_NORETURN; |
252b5132 | 35 | |
ef99799a | 36 | /* Despite the rest of the comments in this file, (FIXME-SOON), |
5a1964ec NC |
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 | |
1ec4b9f2 NS |
70 | continues as though no error occurred. |
71 | ||
72 | as_abort () is used for logic failure (assert or abort, signal). | |
73 | */ | |
252b5132 RH |
74 | |
75 | static void | |
3b4dbbbf | 76 | identify (const char *file) |
252b5132 RH |
77 | { |
78 | static int identified; | |
5a1964ec | 79 | |
252b5132 RH |
80 | if (identified) |
81 | return; | |
82 | identified++; | |
83 | ||
84 | if (!file) | |
85 | { | |
86 | unsigned int x; | |
3b4dbbbf | 87 | file = as_where (&x); |
252b5132 RH |
88 | } |
89 | ||
90 | if (file) | |
91 | fprintf (stderr, "%s: ", file); | |
92 | fprintf (stderr, _("Assembler messages:\n")); | |
93 | } | |
94 | ||
ef99799a KH |
95 | /* The number of warnings issued. */ |
96 | static int warning_count; | |
252b5132 | 97 | |
c488923f | 98 | int |
254d758c | 99 | had_warnings (void) |
252b5132 | 100 | { |
5a1964ec | 101 | return warning_count; |
252b5132 RH |
102 | } |
103 | ||
104 | /* Nonzero if we've hit a 'bad error', and should not write an obj file, | |
ef99799a | 105 | and exit with a nonzero error code. */ |
252b5132 RH |
106 | |
107 | static int error_count; | |
108 | ||
c488923f | 109 | int |
254d758c | 110 | had_errors (void) |
252b5132 | 111 | { |
5a1964ec | 112 | return error_count; |
252b5132 RH |
113 | } |
114 | ||
252b5132 RH |
115 | /* Print the current location to stderr. */ |
116 | ||
117 | static void | |
254d758c | 118 | as_show_where (void) |
252b5132 | 119 | { |
3b4dbbbf | 120 | const char *file; |
252b5132 RH |
121 | unsigned int line; |
122 | ||
969b9a36 | 123 | file = as_where_top (&line); |
252b5132 RH |
124 | identify (file); |
125 | if (file) | |
144886fa AM |
126 | { |
127 | if (line != 0) | |
128 | fprintf (stderr, "%s:%u: ", file, line); | |
129 | else | |
130 | fprintf (stderr, "%s: ", file); | |
131 | } | |
252b5132 RH |
132 | } |
133 | ||
969b9a36 JB |
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 | ||
ef99799a KH |
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. */ | |
252b5132 | 158 | |
c488923f | 159 | void |
ef99799a | 160 | as_tsktsk (const char *format, ...) |
252b5132 RH |
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); | |
969b9a36 | 169 | as_report_context (); |
ef99799a | 170 | } |
252b5132 RH |
171 | |
172 | /* The common portion of as_warn and as_warn_where. */ | |
173 | ||
174 | static void | |
3b4dbbbf | 175 | as_warn_internal (const char *file, unsigned int line, char *buffer) |
252b5132 | 176 | { |
969b9a36 JB |
177 | bool context = false; |
178 | ||
252b5132 RH |
179 | ++warning_count; |
180 | ||
181 | if (file == NULL) | |
969b9a36 JB |
182 | { |
183 | file = as_where_top (&line); | |
184 | context = true; | |
185 | } | |
252b5132 RH |
186 | |
187 | identify (file); | |
188 | if (file) | |
144886fa AM |
189 | { |
190 | if (line != 0) | |
b52855e7 | 191 | fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Warning: "), buffer); |
144886fa | 192 | else |
b52855e7 | 193 | fprintf (stderr, "%s: %s%s\n", file, _("Warning: "), buffer); |
144886fa | 194 | } |
39128ec0 | 195 | else |
b52855e7 | 196 | fprintf (stderr, "%s%s\n", _("Warning: "), buffer); |
969b9a36 JB |
197 | |
198 | if (context) | |
199 | as_report_context (); | |
200 | ||
252b5132 RH |
201 | #ifndef NO_LISTING |
202 | listing_warning (buffer); | |
203 | #endif | |
204 | } | |
205 | ||
ef99799a KH |
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. */ | |
252b5132 | 211 | |
c488923f | 212 | void |
ef99799a | 213 | as_warn (const char *format, ...) |
252b5132 RH |
214 | { |
215 | va_list args; | |
216 | char buffer[2000]; | |
217 | ||
218 | if (!flag_no_warnings) | |
219 | { | |
220 | va_start (args, format); | |
a9bfff94 | 221 | vsnprintf (buffer, sizeof (buffer), format, args); |
252b5132 RH |
222 | va_end (args); |
223 | as_warn_internal ((char *) NULL, 0, buffer); | |
224 | } | |
ef99799a | 225 | } |
252b5132 | 226 | |
969b9a36 | 227 | /* Like as_warn but the file name and line number are passed in. |
ef99799a KH |
228 | Unfortunately, we have to repeat the function in order to handle |
229 | the varargs correctly and portably. */ | |
252b5132 | 230 | |
c488923f | 231 | void |
3b4dbbbf | 232 | as_warn_where (const char *file, unsigned int line, const char *format, ...) |
252b5132 RH |
233 | { |
234 | va_list args; | |
235 | char buffer[2000]; | |
236 | ||
237 | if (!flag_no_warnings) | |
238 | { | |
239 | va_start (args, format); | |
a9bfff94 | 240 | vsnprintf (buffer, sizeof (buffer), format, args); |
252b5132 RH |
241 | va_end (args); |
242 | as_warn_internal (file, line, buffer); | |
243 | } | |
ef99799a | 244 | } |
252b5132 RH |
245 | |
246 | /* The common portion of as_bad and as_bad_where. */ | |
247 | ||
248 | static void | |
3b4dbbbf | 249 | as_bad_internal (const char *file, unsigned int line, char *buffer) |
252b5132 | 250 | { |
969b9a36 JB |
251 | bool context = false; |
252 | ||
252b5132 RH |
253 | ++error_count; |
254 | ||
255 | if (file == NULL) | |
969b9a36 JB |
256 | { |
257 | file = as_where_top (&line); | |
258 | context = true; | |
259 | } | |
252b5132 RH |
260 | |
261 | identify (file); | |
262 | if (file) | |
144886fa AM |
263 | { |
264 | if (line != 0) | |
b52855e7 | 265 | fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Error: "), buffer); |
144886fa | 266 | else |
b52855e7 | 267 | fprintf (stderr, "%s: %s%s\n", file, _("Error: "), buffer); |
144886fa | 268 | } |
39128ec0 | 269 | else |
b52855e7 | 270 | fprintf (stderr, "%s%s\n", _("Error: "), buffer); |
969b9a36 JB |
271 | |
272 | if (context) | |
273 | as_report_context (); | |
274 | ||
252b5132 RH |
275 | #ifndef NO_LISTING |
276 | listing_error (buffer); | |
277 | #endif | |
278 | } | |
279 | ||
ef99799a | 280 | /* Send to stderr a string as a warning, and locate warning in input |
08918cc8 | 281 | file(s). Please use when there is no recovery, but we want to |
ef99799a KH |
282 | continue processing but not produce an object file. |
283 | Please explain in string (which may have '\n's) what recovery was | |
43ad3147 | 284 | done. */ |
252b5132 | 285 | |
c488923f | 286 | void |
ef99799a | 287 | as_bad (const char *format, ...) |
252b5132 RH |
288 | { |
289 | va_list args; | |
290 | char buffer[2000]; | |
291 | ||
292 | va_start (args, format); | |
a9bfff94 | 293 | vsnprintf (buffer, sizeof (buffer), format, args); |
252b5132 RH |
294 | va_end (args); |
295 | ||
296 | as_bad_internal ((char *) NULL, 0, buffer); | |
297 | } | |
298 | ||
ef99799a KH |
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. */ | |
252b5132 | 302 | |
c488923f | 303 | void |
3b4dbbbf | 304 | as_bad_where (const char *file, unsigned int line, const char *format, ...) |
252b5132 RH |
305 | { |
306 | va_list args; | |
307 | char buffer[2000]; | |
308 | ||
309 | va_start (args, format); | |
a9bfff94 | 310 | vsnprintf (buffer, sizeof (buffer), format, args); |
252b5132 RH |
311 | va_end (args); |
312 | ||
313 | as_bad_internal (file, line, buffer); | |
314 | } | |
315 | ||
ef99799a KH |
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. */ | |
252b5132 | 320 | |
c488923f | 321 | void |
ef99799a | 322 | as_fatal (const char *format, ...) |
252b5132 RH |
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); | |
969b9a36 | 332 | as_report_context (); |
d4887adc NC |
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) | |
bb14f524 | 336 | unlink_if_ordinary (out_file_name); |
252b5132 | 337 | xexit (EXIT_FAILURE); |
ef99799a | 338 | } |
252b5132 | 339 | |
1ec4b9f2 NS |
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. */ | |
252b5132 RH |
343 | |
344 | void | |
1ec4b9f2 | 345 | as_abort (const char *file, int line, const char *fn) |
252b5132 RH |
346 | { |
347 | as_show_where (); | |
1ec4b9f2 NS |
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); | |
252b5132 | 353 | else |
1ec4b9f2 | 354 | fprintf (stderr, _("Internal error at %s:%d.\n"), file, line); |
969b9a36 | 355 | as_report_context (); |
1ec4b9f2 | 356 | |
252b5132 | 357 | fprintf (stderr, _("Please report this bug.\n")); |
1ec4b9f2 | 358 | |
252b5132 RH |
359 | xexit (EXIT_FAILURE); |
360 | } | |
361 | ||
1ec4b9f2 NS |
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. */ | |
ef99799a | 374 | |
252b5132 | 375 | void |
1ec4b9f2 | 376 | signal_init (void) |
252b5132 | 377 | { |
1ec4b9f2 NS |
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 | |
252b5132 RH |
396 | } |
397 | ||
398 | /* Support routines. */ | |
399 | ||
e5976317 NC |
400 | #define HEX_MAX_THRESHOLD 1024 |
401 | #define HEX_MIN_THRESHOLD -(HEX_MAX_THRESHOLD) | |
402 | ||
403 | static void | |
6d4af3c2 AM |
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, | |
ffa5352c | 410 | bool bad) |
e5976317 NC |
411 | { |
412 | const char * err; | |
413 | ||
414 | if (prefix == NULL) | |
415 | prefix = ""; | |
416 | ||
b84bf58a AM |
417 | if (val >= min && val <= max) |
418 | { | |
419 | addressT right = max & -max; | |
420 | ||
421 | if (max <= 1) | |
422 | abort (); | |
423 | ||
424 | /* xgettext:c-format */ | |
f493c217 AM |
425 | err = _("%s out of domain (%" PRId64 |
426 | " is not a multiple of %" PRId64 ")"); | |
ffa5352c | 427 | |
b84bf58a | 428 | if (bad) |
f493c217 | 429 | as_bad_where (file, line, err, prefix, (int64_t) val, (int64_t) right); |
b84bf58a | 430 | else |
f493c217 | 431 | as_warn_where (file, line, err, prefix, (int64_t) val, (int64_t) right); |
b84bf58a | 432 | } |
ffa5352c NC |
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) | |
e5976317 | 439 | { |
ffa5352c | 440 | /* xgettext:c-format. */ |
f493c217 AM |
441 | err = _("%s out of range (%" PRId64 |
442 | " is not between %" PRId64 " and %" PRId64 ")"); | |
e5976317 NC |
443 | |
444 | if (bad) | |
f493c217 AM |
445 | as_bad_where (file, line, err, prefix, |
446 | (int64_t) val, (int64_t) min, (int64_t) max); | |
e5976317 | 447 | else |
f493c217 AM |
448 | as_warn_where (file, line, err, prefix, |
449 | (int64_t) val, (int64_t) min, (int64_t) max); | |
e5976317 | 450 | } |
e5976317 NC |
451 | else |
452 | { | |
e5976317 | 453 | /* xgettext:c-format. */ |
f493c217 AM |
454 | err = _("%s out of range (0x%" PRIx64 |
455 | " is not between 0x%" PRIx64 " and 0x%" PRIx64 ")"); | |
e5976317 NC |
456 | |
457 | if (bad) | |
f493c217 AM |
458 | as_bad_where (file, line, err, prefix, |
459 | (int64_t) val, (int64_t) min, (int64_t) max); | |
e5976317 | 460 | else |
f493c217 AM |
461 | as_warn_where (file, line, err, prefix, |
462 | (int64_t) val, (int64_t) min, (int64_t) max); | |
e5976317 | 463 | } |
e5976317 NC |
464 | } |
465 | ||
466 | void | |
6d4af3c2 AM |
467 | as_warn_value_out_of_range (const char *prefix, |
468 | offsetT value, | |
469 | offsetT min, | |
470 | offsetT max, | |
471 | const char *file, | |
e5976317 NC |
472 | unsigned line) |
473 | { | |
ffa5352c | 474 | as_internal_value_out_of_range (prefix, value, min, max, file, line, false); |
e5976317 NC |
475 | } |
476 | ||
477 | void | |
6d4af3c2 AM |
478 | as_bad_value_out_of_range (const char *prefix, |
479 | offsetT value, | |
480 | offsetT min, | |
481 | offsetT max, | |
482 | const char *file, | |
e5976317 NC |
483 | unsigned line) |
484 | { | |
ffa5352c | 485 | as_internal_value_out_of_range (prefix, value, min, max, file, line, true); |
e5976317 | 486 | } |