1 /* messages.c - error reporter -
2    Copyright (C) 1987-2021 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 <signal.h>
22 
23 /* If the system doesn't provide strsignal, we get it defined in
24    libiberty but no declaration is supplied.  Because, reasons. */
25 #if !defined (HAVE_STRSIGNAL) && !defined (strsignal)
26 extern const char *strsignal (int);
27 #endif
28 
29 static void identify (const char *);
30 static void as_show_where (void);
31 static void as_warn_internal (const char *, unsigned int, char *);
32 static void as_bad_internal (const char *, unsigned int, char *);
33 static void signal_crash (int) ATTRIBUTE_NORETURN;
34 
35 /* Despite the rest of the comments in this file, (FIXME-SOON),
36    here is the current scheme for error messages etc:
37 
38    as_fatal() is used when gas is quite confused and
39    continuing the assembly is pointless.  In this case we
40    exit immediately with error status.
41 
42    as_bad() is used to mark errors that result in what we
43    presume to be a useless object file.  Say, we ignored
44    something that might have been vital.  If we see any of
45    these, assembly will continue to the end of the source,
46    no object file will be produced, and we will terminate
47    with error status.  The new option, -Z, tells us to
48    produce an object file anyway but we still exit with
49    error status.  The assumption here is that you don't want
50    this object file but we could be wrong.
51 
52    as_warn() is used when we have an error from which we
53    have a plausible error recovery.  eg, masking the top
54    bits of a constant that is longer than will fit in the
55    destination.  In this case we will continue to assemble
56    the source, although we may have made a bad assumption,
57    and we will produce an object file and return normal exit
58    status (ie, no error).  The new option -X tells us to
59    treat all as_warn() errors as as_bad() errors.  That is,
60    no object file will be produced and we will exit with
61    error status.  The idea here is that we don't kill an
62    entire make because of an error that we knew how to
63    correct.  On the other hand, sometimes you might want to
64    stop the make at these points.
65 
66    as_tsktsk() is used when we see a minor error for which
67    our error recovery action is almost certainly correct.
68    In this case, we print a message and then assembly
69    continues as though no error occurred.
70 
71    as_abort () is used for logic failure (assert or abort, signal).
72 */
73 
74 static void
identify(const char * file)75 identify (const char *file)
76 {
77   static int identified;
78 
79   if (identified)
80     return;
81   identified++;
82 
83   if (!file)
84     {
85       unsigned int x;
86       file = as_where (&x);
87     }
88 
89   if (file)
90     fprintf (stderr, "%s: ", file);
91   fprintf (stderr, _("Assembler messages:\n"));
92 }
93 
94 /* The number of warnings issued.  */
95 static int warning_count;
96 
97 int
had_warnings(void)98 had_warnings (void)
99 {
100   return warning_count;
101 }
102 
103 /* Nonzero if we've hit a 'bad error', and should not write an obj file,
104    and exit with a nonzero error code.  */
105 
106 static int error_count;
107 
108 int
had_errors(void)109 had_errors (void)
110 {
111   return error_count;
112 }
113 
114 /* Print the current location to stderr.  */
115 
116 static void
as_show_where(void)117 as_show_where (void)
118 {
119   const char *file;
120   unsigned int line;
121 
122   file = as_where (&line);
123   identify (file);
124   if (file)
125     {
126       if (line != 0)
127 	fprintf (stderr, "%s:%u: ", file, line);
128       else
129 	fprintf (stderr, "%s: ", file);
130     }
131 }
132 
133 /* Send to stderr a string as a warning, and locate warning
134    in input file(s).
135    Please only use this for when we have some recovery action.
136    Please explain in string (which may have '\n's) what recovery was
137    done.  */
138 
139 void
as_tsktsk(const char * format,...)140 as_tsktsk (const char *format, ...)
141 {
142   va_list args;
143 
144   as_show_where ();
145   va_start (args, format);
146   vfprintf (stderr, format, args);
147   va_end (args);
148   (void) putc ('\n', stderr);
149 }
150 
151 /* The common portion of as_warn and as_warn_where.  */
152 
153 static void
as_warn_internal(const char * file,unsigned int line,char * buffer)154 as_warn_internal (const char *file, unsigned int line, char *buffer)
155 {
156   ++warning_count;
157 
158   if (file == NULL)
159     file = as_where (&line);
160 
161   identify (file);
162   if (file)
163     {
164       if (line != 0)
165 	fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Warning: "), buffer);
166       else
167 	fprintf (stderr, "%s: %s%s\n", file, _("Warning: "), buffer);
168     }
169   else
170     fprintf (stderr, "%s%s\n", _("Warning: "), buffer);
171 #ifndef NO_LISTING
172   listing_warning (buffer);
173 #endif
174 }
175 
176 /* Send to stderr a string as a warning, and locate warning
177    in input file(s).
178    Please only use this for when we have some recovery action.
179    Please explain in string (which may have '\n's) what recovery was
180    done.  */
181 
182 void
as_warn(const char * format,...)183 as_warn (const char *format, ...)
184 {
185   va_list args;
186   char buffer[2000];
187 
188   if (!flag_no_warnings)
189     {
190       va_start (args, format);
191       vsnprintf (buffer, sizeof (buffer), format, args);
192       va_end (args);
193       as_warn_internal ((char *) NULL, 0, buffer);
194     }
195 }
196 
197 /* Like as_bad but the file name and line number are passed in.
198    Unfortunately, we have to repeat the function in order to handle
199    the varargs correctly and portably.  */
200 
201 void
as_warn_where(const char * file,unsigned int line,const char * format,...)202 as_warn_where (const char *file, unsigned int line, const char *format, ...)
203 {
204   va_list args;
205   char buffer[2000];
206 
207   if (!flag_no_warnings)
208     {
209       va_start (args, format);
210       vsnprintf (buffer, sizeof (buffer), format, args);
211       va_end (args);
212       as_warn_internal (file, line, buffer);
213     }
214 }
215 
216 /* The common portion of as_bad and as_bad_where.  */
217 
218 static void
as_bad_internal(const char * file,unsigned int line,char * buffer)219 as_bad_internal (const char *file, unsigned int line, char *buffer)
220 {
221   ++error_count;
222 
223   if (file == NULL)
224     file = as_where (&line);
225 
226   identify (file);
227   if (file)
228     {
229       if (line != 0)
230 	fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Error: "), buffer);
231       else
232 	fprintf (stderr, "%s: %s%s\n", file, _("Error: "), buffer);
233     }
234   else
235     fprintf (stderr, "%s%s\n", _("Error: "), buffer);
236 #ifndef NO_LISTING
237   listing_error (buffer);
238 #endif
239 }
240 
241 /* Send to stderr a string as a warning, and locate warning in input
242    file(s).  Please use when there is no recovery, but we want to
243    continue processing but not produce an object file.
244    Please explain in string (which may have '\n's) what recovery was
245    done.  */
246 
247 void
as_bad(const char * format,...)248 as_bad (const char *format, ...)
249 {
250   va_list args;
251   char buffer[2000];
252 
253   va_start (args, format);
254   vsnprintf (buffer, sizeof (buffer), format, args);
255   va_end (args);
256 
257   as_bad_internal ((char *) NULL, 0, buffer);
258 }
259 
260 /* Like as_bad but the file name and line number are passed in.
261    Unfortunately, we have to repeat the function in order to handle
262    the varargs correctly and portably.  */
263 
264 void
as_bad_where(const char * file,unsigned int line,const char * format,...)265 as_bad_where (const char *file, unsigned int line, const char *format, ...)
266 {
267   va_list args;
268   char buffer[2000];
269 
270   va_start (args, format);
271   vsnprintf (buffer, sizeof (buffer), format, args);
272   va_end (args);
273 
274   as_bad_internal (file, line, buffer);
275 }
276 
277 /* Send to stderr a string as a fatal message, and print location of
278    error in input file(s).
279    Please only use this for when we DON'T have some recovery action.
280    It xexit()s with a warning status.  */
281 
282 void
as_fatal(const char * format,...)283 as_fatal (const char *format, ...)
284 {
285   va_list args;
286 
287   as_show_where ();
288   va_start (args, format);
289   fprintf (stderr, _("Fatal error: "));
290   vfprintf (stderr, format, args);
291   (void) putc ('\n', stderr);
292   va_end (args);
293   /* Delete the output file, if it exists.  This will prevent make from
294      thinking that a file was created and hence does not need rebuilding.  */
295   if (out_file_name != NULL)
296     unlink_if_ordinary (out_file_name);
297   xexit (EXIT_FAILURE);
298 }
299 
300 /* Indicate internal constency error.
301    Arguments: Filename, line number, optional function name.
302    FILENAME may be NULL, which we use for crash-via-signal.  */
303 
304 void
as_abort(const char * file,int line,const char * fn)305 as_abort (const char *file, int line, const char *fn)
306 {
307   as_show_where ();
308 
309   if (!file)
310     fprintf (stderr, _("Internal error (%s).\n"), fn ? fn : "unknown");
311   else if (fn)
312     fprintf (stderr, _("Internal error in %s at %s:%d.\n"), fn, file, line);
313   else
314     fprintf (stderr, _("Internal error at %s:%d.\n"), file, line);
315 
316   fprintf (stderr, _("Please report this bug.\n"));
317 
318   xexit (EXIT_FAILURE);
319 }
320 
321 /* Handler for fatal signals, such as SIGSEGV. */
322 
323 static void
signal_crash(int signo)324 signal_crash (int signo)
325 {
326   /* Reset, to prevent unbounded recursion.  */
327   signal (signo, SIG_DFL);
328 
329   as_abort (NULL, 0, strsignal (signo));
330 }
331 
332 /* Register signal handlers, for less abrubt crashes.  */
333 
334 void
signal_init(void)335 signal_init (void)
336 {
337 #ifdef SIGSEGV
338   signal (SIGSEGV, signal_crash);
339 #endif
340 #ifdef SIGILL
341   signal (SIGILL, signal_crash);
342 #endif
343 #ifdef SIGBUS
344   signal (SIGBUS, signal_crash);
345 #endif
346 #ifdef SIGABRT
347   signal (SIGABRT, signal_crash);
348 #endif
349 #if defined SIGIOT && (!defined SIGABRT || SIGABRT != SIGIOT)
350   signal (SIGIOT, signal_crash);
351 #endif
352 #ifdef SIGFPE
353   signal (SIGFPE, signal_crash);
354 #endif
355 }
356 
357 /* Support routines.  */
358 
359 #define HEX_MAX_THRESHOLD	1024
360 #define HEX_MIN_THRESHOLD	-(HEX_MAX_THRESHOLD)
361 
362 static void
as_internal_value_out_of_range(const char * prefix,offsetT val,offsetT min,offsetT max,const char * file,unsigned line,int bad)363 as_internal_value_out_of_range (const char *prefix,
364 				offsetT val,
365 				offsetT min,
366 				offsetT max,
367 				const char *file,
368 				unsigned line,
369 				int bad)
370 {
371   const char * err;
372 
373   if (prefix == NULL)
374     prefix = "";
375 
376   if (val >= min && val <= max)
377     {
378       addressT right = max & -max;
379 
380       if (max <= 1)
381 	abort ();
382 
383       /* xgettext:c-format  */
384       err = _("%s out of domain (%" BFD_VMA_FMT "d is not a multiple of %" \
385 	      BFD_VMA_FMT "d)");
386       if (bad)
387 	as_bad_where (file, line, err, prefix, val, right);
388       else
389 	as_warn_where (file, line, err, prefix, val, right);
390       return;
391     }
392 
393   if (   val < HEX_MAX_THRESHOLD
394       && min < HEX_MAX_THRESHOLD
395       && max < HEX_MAX_THRESHOLD
396       && val > HEX_MIN_THRESHOLD
397       && min > HEX_MIN_THRESHOLD
398       && max > HEX_MIN_THRESHOLD)
399     {
400       /* xgettext:c-format  */
401       err = _("%s out of range (%" BFD_VMA_FMT "d is not between %" \
402 	      BFD_VMA_FMT "d and %" BFD_VMA_FMT "d)");
403 
404       if (bad)
405 	as_bad_where (file, line, err, prefix, val, min, max);
406       else
407 	as_warn_where (file, line, err, prefix, val, min, max);
408     }
409   else
410     {
411       char val_buf [sizeof (val) * 3 + 2];
412       char min_buf [sizeof (val) * 3 + 2];
413       char max_buf [sizeof (val) * 3 + 2];
414 
415       if (sizeof (val) > sizeof (bfd_vma))
416 	abort ();
417 
418       sprintf_vma (val_buf, (bfd_vma) val);
419       sprintf_vma (min_buf, (bfd_vma) min);
420       sprintf_vma (max_buf, (bfd_vma) max);
421 
422       /* xgettext:c-format.  */
423       err = _("%s out of range (0x%s is not between 0x%s and 0x%s)");
424 
425       if (bad)
426 	as_bad_where (file, line, err, prefix, val_buf, min_buf, max_buf);
427       else
428 	as_warn_where (file, line, err, prefix, val_buf, min_buf, max_buf);
429     }
430 }
431 
432 void
as_warn_value_out_of_range(const char * prefix,offsetT value,offsetT min,offsetT max,const char * file,unsigned line)433 as_warn_value_out_of_range (const char *prefix,
434 			   offsetT value,
435 			   offsetT min,
436 			   offsetT max,
437 			   const char *file,
438 			   unsigned line)
439 {
440   as_internal_value_out_of_range (prefix, value, min, max, file, line, 0);
441 }
442 
443 void
as_bad_value_out_of_range(const char * prefix,offsetT value,offsetT min,offsetT max,const char * file,unsigned line)444 as_bad_value_out_of_range (const char *prefix,
445 			   offsetT value,
446 			   offsetT min,
447 			   offsetT max,
448 			   const char *file,
449 			   unsigned line)
450 {
451   as_internal_value_out_of_range (prefix, value, min, max, file, line, 1);
452 }
453