X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fmessages.c;h=83bda87919931154a1716a4e8ba65e0688ae72f9;hb=5496f3c635dce3e12348d6e81c3f74815fdfe7b5;hp=e4b7ad00a115226803f860243bd708424c17442b;hpb=ed288bb597072176e84fc8279707a3f2f475779b;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/messages.c b/gas/messages.c index e4b7ad00a1..83bda87919 100644 --- a/gas/messages.c +++ b/gas/messages.c @@ -1,11 +1,10 @@ /* messages.c - error reporter - - Copyright (C) 1987, 91, 92, 93, 94, 95, 96, 97, 1998 - Free Software Foundation, Inc. + Copyright (C) 1987-2020 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) + the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, @@ -15,81 +14,68 @@ You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free - Software Foundation, 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ #include "as.h" +#include -#include -#ifdef HAVE_ERRNO_H -#include +/* If the system doesn't provide strsignal, we get it defined in + libiberty but no declaration is supplied. Because, reasons. */ +#if !defined (HAVE_STRSIGNAL) && !defined (strsignal) +extern const char *strsignal (int); #endif -#ifdef USE_STDARG -#include -#endif - -#ifdef USE_VARARGS -#include -#endif - -#if !defined (USE_STDARG) && !defined (USE_VARARGS) -/* Roll our own. */ -#define va_alist REST -#define va_dcl -typedef int * va_list; -#define va_start(ARGS) ARGS = &REST -#define va_end(ARGS) -#endif - -static void identify PARAMS ((char *)); -static void as_show_where PARAMS ((void)); -static void as_warn_internal PARAMS ((char *, unsigned int, char *)); -static void as_bad_internal PARAMS ((char *, unsigned int, char *)); - -/* - * Despite the rest of the comments in this file, (FIXME-SOON), - * here is the current scheme for error messages etc: - * - * as_fatal() is used when gas is quite confused and - * continuing the assembly is pointless. In this case we - * exit immediately with error status. - * - * as_bad() is used to mark errors that result in what we - * presume to be a useless object file. Say, we ignored - * something that might have been vital. If we see any of - * these, assembly will continue to the end of the source, - * no object file will be produced, and we will terminate - * with error status. The new option, -Z, tells us to - * produce an object file anyway but we still exit with - * error status. The assumption here is that you don't want - * this object file but we could be wrong. - * - * as_warn() is used when we have an error from which we - * have a plausible error recovery. eg, masking the top - * bits of a constant that is longer than will fit in the - * destination. In this case we will continue to assemble - * the source, although we may have made a bad assumption, - * and we will produce an object file and return normal exit - * status (ie, no error). The new option -X tells us to - * treat all as_warn() errors as as_bad() errors. That is, - * no object file will be produced and we will exit with - * error status. The idea here is that we don't kill an - * entire make because of an error that we knew how to - * correct. On the other hand, sometimes you might want to - * stop the make at these points. - * - * as_tsktsk() is used when we see a minor error for which - * our error recovery action is almost certainly correct. - * In this case, we print a message and then assembly - * continues as though no error occurred. - */ +static void identify (const char *); +static void as_show_where (void); +static void as_warn_internal (const char *, unsigned int, char *); +static void as_bad_internal (const char *, unsigned int, char *); +static void signal_crash (int) ATTRIBUTE_NORETURN; + +/* Despite the rest of the comments in this file, (FIXME-SOON), + here is the current scheme for error messages etc: + + as_fatal() is used when gas is quite confused and + continuing the assembly is pointless. In this case we + exit immediately with error status. + + as_bad() is used to mark errors that result in what we + presume to be a useless object file. Say, we ignored + something that might have been vital. If we see any of + these, assembly will continue to the end of the source, + no object file will be produced, and we will terminate + with error status. The new option, -Z, tells us to + produce an object file anyway but we still exit with + error status. The assumption here is that you don't want + this object file but we could be wrong. + + as_warn() is used when we have an error from which we + have a plausible error recovery. eg, masking the top + bits of a constant that is longer than will fit in the + destination. In this case we will continue to assemble + the source, although we may have made a bad assumption, + and we will produce an object file and return normal exit + status (ie, no error). The new option -X tells us to + treat all as_warn() errors as as_bad() errors. That is, + no object file will be produced and we will exit with + error status. The idea here is that we don't kill an + entire make because of an error that we knew how to + correct. On the other hand, sometimes you might want to + stop the make at these points. + + as_tsktsk() is used when we see a minor error for which + our error recovery action is almost certainly correct. + In this case, we print a message and then assembly + continues as though no error occurred. + + as_abort () is used for logic failure (assert or abort, signal). +*/ static void -identify (file) - char *file; +identify (const char *file) { static int identified; + if (identified) return; identified++; @@ -97,7 +83,7 @@ identify (file) if (!file) { unsigned int x; - as_where (&file, &x); + file = as_where (&x); } if (file) @@ -105,79 +91,53 @@ identify (file) fprintf (stderr, _("Assembler messages:\n")); } -static int warning_count; /* Count of number of warnings issued */ +/* The number of warnings issued. */ +static int warning_count; -int -had_warnings () +int +had_warnings (void) { - return (warning_count); + return warning_count; } /* Nonzero if we've hit a 'bad error', and should not write an obj file, - and exit with a nonzero error code */ + and exit with a nonzero error code. */ static int error_count; -int -had_errors () +int +had_errors (void) { - return (error_count); + return error_count; } - /* Print the current location to stderr. */ static void -as_show_where () +as_show_where (void) { - char *file; + const char *file; unsigned int line; - as_where (&file, &line); + file = as_where (&line); identify (file); if (file) - fprintf (stderr, "%s:%u: ", file, line); + { + if (line != 0) + fprintf (stderr, "%s:%u: ", file, line); + else + fprintf (stderr, "%s: ", file); + } } -/* - * a s _ p e r r o r - * - * Like perror(3), but with more info. - */ - -void -as_perror (gripe, filename) - const char *gripe; /* Unpunctuated error theme. */ - const char *filename; -{ - const char *errtxt; +/* Send to stderr a string as a warning, and locate warning + in input file(s). + Please only use this for when we have some recovery action. + Please explain in string (which may have '\n's) what recovery was + done. */ - as_show_where (); - fprintf (stderr, gripe, filename); -#ifdef BFD_ASSEMBLER - errtxt = bfd_errmsg (bfd_get_error ()); -#else - errtxt = xstrerror (errno); -#endif - fprintf (stderr, ": %s\n", errtxt); - errno = 0; -#ifdef BFD_ASSEMBLER - bfd_set_error (bfd_error_no_error); -#endif -} - -/* - * a s _ t s k t s k () - * - * Send to stderr a string as a warning, and locate warning - * in input file(s). - * Please only use this for when we have some recovery action. - * Please explain in string (which may have '\n's) what recovery was done. - */ - -#ifdef USE_STDARG -void -as_tsktsk (const char *format,...) +void +as_tsktsk (const char *format, ...) { va_list args; @@ -186,98 +146,60 @@ as_tsktsk (const char *format,...) vfprintf (stderr, format, args); va_end (args); (void) putc ('\n', stderr); -} /* as_tsktsk() */ -#else -void -as_tsktsk (format, va_alist) - const char *format; - va_dcl -{ - va_list args; - - as_show_where (); - va_start (args); - vfprintf (stderr, format, args); - va_end (args); - (void) putc ('\n', stderr); -} /* as_tsktsk() */ -#endif /* not NO_STDARG */ +} /* The common portion of as_warn and as_warn_where. */ static void -as_warn_internal (file, line, buffer) - char *file; - unsigned int line; - char *buffer; +as_warn_internal (const char *file, unsigned int line, char *buffer) { ++warning_count; if (file == NULL) - as_where (&file, &line); + file = as_where (&line); identify (file); if (file) - fprintf (stderr, "%s:%u: ", file, line); - fprintf (stderr, _("Warning: ")); - fputs (buffer, stderr); - (void) putc ('\n', stderr); + { + if (line != 0) + fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Warning: "), buffer); + else + fprintf (stderr, "%s: %s%s\n", file, _("Warning: "), buffer); + } + else + fprintf (stderr, "%s%s\n", _("Warning: "), buffer); #ifndef NO_LISTING listing_warning (buffer); #endif } -/* - * a s _ w a r n () - * - * Send to stderr a string as a warning, and locate warning - * in input file(s). - * Please only use this for when we have some recovery action. - * Please explain in string (which may have '\n's) what recovery was done. - */ - -#ifdef USE_STDARG -void -as_warn (const char *format,...) -{ - va_list args; - char buffer[2000]; +/* Send to stderr a string as a warning, and locate warning + in input file(s). + Please only use this for when we have some recovery action. + Please explain in string (which may have '\n's) what recovery was + done. */ - if (!flag_no_warnings) - { - va_start (args, format); - vsprintf (buffer, format, args); - va_end (args); - as_warn_internal ((char *) NULL, 0, buffer); - } -} /* as_warn() */ -#else -/*VARARGS1 */ -void -as_warn (format, va_alist) - const char *format; - va_dcl +void +as_warn (const char *format, ...) { va_list args; char buffer[2000]; if (!flag_no_warnings) { - va_start (args); - vsprintf (buffer, format, args); + va_start (args, format); + vsnprintf (buffer, sizeof (buffer), format, args); va_end (args); as_warn_internal ((char *) NULL, 0, buffer); } -} /* as_warn() */ -#endif /* not NO_STDARG */ +} -/* as_warn_where, like as_bad but the file name and line number are - passed in. Unfortunately, we have to repeat the function in order - to handle the varargs correctly and portably. */ +/* Like as_bad but the file name and line number are passed in. + Unfortunately, we have to repeat the function in order to handle + the varargs correctly and portably. */ -#ifdef USE_STDARG -void -as_warn_where (char *file, unsigned int line, const char *format,...) +void +as_warn_where (const char *file, unsigned int line, const char *format, ...) { va_list args; char buffer[2000]; @@ -285,148 +207,80 @@ as_warn_where (char *file, unsigned int line, const char *format,...) if (!flag_no_warnings) { va_start (args, format); - vsprintf (buffer, format, args); - va_end (args); - as_warn_internal (file, line, buffer); - } -} /* as_warn() */ -#else -/*VARARGS1 */ -void -as_warn_where (file, line, format, va_alist) - char *file; - unsigned int line; - const char *format; - va_dcl -{ - va_list args; - char buffer[2000]; - - if (!flag_no_warnings) - { - va_start (args); - vsprintf (buffer, format, args); + vsnprintf (buffer, sizeof (buffer), format, args); va_end (args); as_warn_internal (file, line, buffer); } -} /* as_warn() */ -#endif /* not NO_STDARG */ +} /* The common portion of as_bad and as_bad_where. */ static void -as_bad_internal (file, line, buffer) - char *file; - unsigned int line; - char *buffer; +as_bad_internal (const char *file, unsigned int line, char *buffer) { ++error_count; if (file == NULL) - as_where (&file, &line); + file = as_where (&line); identify (file); if (file) - fprintf (stderr, "%s:%u: ", file, line); - fprintf (stderr, _("Error: ")); - fputs (buffer, stderr); - (void) putc ('\n', stderr); + { + if (line != 0) + fprintf (stderr, "%s:%u: %s%s\n", file, line, _("Error: "), buffer); + else + fprintf (stderr, "%s: %s%s\n", file, _("Error: "), buffer); + } + else + fprintf (stderr, "%s%s\n", _("Error: "), buffer); #ifndef NO_LISTING listing_error (buffer); #endif } -/* - * a s _ b a d () - * - * Send to stderr a string as a warning, and locate warning in input file(s). - * Please us when there is no recovery, but we want to continue processing - * but not produce an object file. - * Please explain in string (which may have '\n's) what recovery was done. - */ - -#ifdef USE_STDARG -void -as_bad (const char *format,...) -{ - va_list args; - char buffer[2000]; +/* Send to stderr a string as a warning, and locate warning in input + file(s). Please use when there is no recovery, but we want to + continue processing but not produce an object file. + Please explain in string (which may have '\n's) what recovery was + done. */ - va_start (args, format); - vsprintf (buffer, format, args); - va_end (args); - - as_bad_internal ((char *) NULL, 0, buffer); -} - -#else -/*VARARGS1 */ -void -as_bad (format, va_alist) - const char *format; - va_dcl +void +as_bad (const char *format, ...) { va_list args; char buffer[2000]; - va_start (args); - vsprintf (buffer, format, args); + va_start (args, format); + vsnprintf (buffer, sizeof (buffer), format, args); va_end (args); as_bad_internal ((char *) NULL, 0, buffer); } -#endif /* not NO_STDARG */ -/* as_bad_where, like as_bad but the file name and line number are - passed in. Unfortunately, we have to repeat the function in order - to handle the varargs correctly and portably. */ +/* Like as_bad but the file name and line number are passed in. + Unfortunately, we have to repeat the function in order to handle + the varargs correctly and portably. */ -#ifdef USE_STDARG -void -as_bad_where (char *file, unsigned int line, const char *format,...) +void +as_bad_where (const char *file, unsigned int line, const char *format, ...) { va_list args; char buffer[2000]; va_start (args, format); - vsprintf (buffer, format, args); + vsnprintf (buffer, sizeof (buffer), format, args); va_end (args); as_bad_internal (file, line, buffer); } -#else -/*VARARGS1 */ -void -as_bad_where (file, line, format, va_alist) - char *file; - unsigned int line; - const char *format; - va_dcl -{ - va_list args; - char buffer[2000]; - - va_start (args); - vsprintf (buffer, format, args); - va_end (args); +/* Send to stderr a string as a fatal message, and print location of + error in input file(s). + Please only use this for when we DON'T have some recovery action. + It xexit()s with a warning status. */ - as_bad_internal (file, line, buffer); -} -#endif /* not NO_STDARG */ - -/* - * a s _ f a t a l () - * - * Send to stderr a string as a fatal message, and print location of error in - * input file(s). - * Please only use this for when we DON'T have some recovery action. - * It xexit()s with a warning status. - */ - -#ifdef USE_STDARG -void -as_fatal (const char *format,...) +void +as_fatal (const char *format, ...) { va_list args; @@ -436,106 +290,179 @@ as_fatal (const char *format,...) vfprintf (stderr, format, args); (void) putc ('\n', stderr); va_end (args); + /* Delete the output file, if it exists. This will prevent make from + thinking that a file was created and hence does not need rebuilding. */ + if (out_file_name != NULL) + unlink_if_ordinary (out_file_name); xexit (EXIT_FAILURE); -} /* as_fatal() */ -#else -/*VARARGS1*/ -void -as_fatal (format, va_alist) - char *format; - va_dcl -{ - va_list args; - - as_show_where (); - va_start (args); - fprintf (stderr, _("Fatal error: ")); - vfprintf (stderr, format, args); - (void) putc ('\n', stderr); - va_end (args); - xexit (EXIT_FAILURE); -} /* as_fatal() */ -#endif /* not NO_STDARG */ +} -/* - * as_assert: Indicate assertion failure. - * Arguments: Filename, line number, optional function name. - */ +/* Indicate internal constency error. + Arguments: Filename, line number, optional function name. + FILENAME may be NULL, which we use for crash-via-signal. */ void -as_assert (file, line, fn) - const char *file, *fn; - int line; +as_abort (const char *file, int line, const char *fn) { as_show_where (); - fprintf (stderr, _("Internal error!\n")); - if (fn) - fprintf (stderr, _("Assertion failure in %s at %s line %d.\n"), - fn, file, line); + + if (!file) + fprintf (stderr, _("Internal error (%s).\n"), fn ? fn : "unknown"); + else if (fn) + fprintf (stderr, _("Internal error in %s at %s:%d.\n"), fn, file, line); else - fprintf (stderr, _("Assertion failure at %s line %d.\n"), file, line); + fprintf (stderr, _("Internal error at %s:%d.\n"), file, line); + fprintf (stderr, _("Please report this bug.\n")); + xexit (EXIT_FAILURE); } -/* as_abort: Print a friendly message saying how totally hosed we are, - and exit without producing a core file. */ +/* Handler for fatal signals, such as SIGSEGV. */ + +static void +signal_crash (int signo) +{ + /* Reset, to prevent unbounded recursion. */ + signal (signo, SIG_DFL); + + as_abort (NULL, 0, strsignal (signo)); +} + +/* Register signal handlers, for less abrubt crashes. */ + void -as_abort (file, line, fn) - const char *file, *fn; - int line; +signal_init (void) { - as_show_where (); - if (fn) - fprintf (stderr, _("Internal error, aborting at %s line %d in %s\n"), - file, line, fn); - else - fprintf (stderr, _("Internal error, aborting at %s line %d\n"), - file, line); - fprintf (stderr, _("Please report this bug.\n")); - xexit (EXIT_FAILURE); +#ifdef SIGSEGV + signal (SIGSEGV, signal_crash); +#endif +#ifdef SIGILL + signal (SIGILL, signal_crash); +#endif +#ifdef SIGBUS + signal (SIGBUS, signal_crash); +#endif +#ifdef SIGABRT + signal (SIGABRT, signal_crash); +#endif +#if defined SIGIOT && (!defined SIGABRT || SIGABRT != SIGIOT) + signal (SIGIOT, signal_crash); +#endif +#ifdef SIGFPE + signal (SIGFPE, signal_crash); +#endif } /* Support routines. */ void -fprint_value (file, val) - FILE *file; - valueT val; +sprint_value (char *buf, valueT val) { if (sizeof (val) <= sizeof (long)) { - fprintf (file, "%ld", (long) val); + sprintf (buf, "%ld", (long) val); return; } -#ifdef BFD_ASSEMBLER if (sizeof (val) <= sizeof (bfd_vma)) { - fprintf_vma (file, val); + sprintf_vma (buf, val); return; } -#endif abort (); } -void -sprint_value (buf, val) - char *buf; - valueT val; +#define HEX_MAX_THRESHOLD 1024 +#define HEX_MIN_THRESHOLD -(HEX_MAX_THRESHOLD) + +static void +as_internal_value_out_of_range (const char *prefix, + offsetT val, + offsetT min, + offsetT max, + const char *file, + unsigned line, + int bad) { - if (sizeof (val) <= sizeof (long)) + const char * err; + + if (prefix == NULL) + prefix = ""; + + if (val >= min && val <= max) { - sprintf (buf, "%ld", (long) val); + addressT right = max & -max; + + if (max <= 1) + abort (); + + /* xgettext:c-format */ + err = _("%s out of domain (%" BFD_VMA_FMT "d is not a multiple of %" \ + BFD_VMA_FMT "d)"); + if (bad) + as_bad_where (file, line, err, prefix, val, right); + else + as_warn_where (file, line, err, prefix, val, right); return; } -#ifdef BFD_ASSEMBLER - if (sizeof (val) <= sizeof (bfd_vma)) + + if ( val < HEX_MAX_THRESHOLD + && min < HEX_MAX_THRESHOLD + && max < HEX_MAX_THRESHOLD + && val > HEX_MIN_THRESHOLD + && min > HEX_MIN_THRESHOLD + && max > HEX_MIN_THRESHOLD) { - sprintf_vma (buf, val); - return; + /* xgettext:c-format */ + err = _("%s out of range (%" BFD_VMA_FMT "d is not between %" \ + BFD_VMA_FMT "d and %" BFD_VMA_FMT "d)"); + + if (bad) + as_bad_where (file, line, err, prefix, val, min, max); + else + as_warn_where (file, line, err, prefix, val, min, max); } -#endif - abort (); + else + { + char val_buf [sizeof (val) * 3 + 2]; + char min_buf [sizeof (val) * 3 + 2]; + char max_buf [sizeof (val) * 3 + 2]; + + if (sizeof (val) > sizeof (bfd_vma)) + abort (); + + sprintf_vma (val_buf, (bfd_vma) val); + sprintf_vma (min_buf, (bfd_vma) min); + sprintf_vma (max_buf, (bfd_vma) max); + + /* xgettext:c-format. */ + err = _("%s out of range (0x%s is not between 0x%s and 0x%s)"); + + if (bad) + as_bad_where (file, line, err, prefix, val_buf, min_buf, max_buf); + else + as_warn_where (file, line, err, prefix, val_buf, min_buf, max_buf); + } +} + +void +as_warn_value_out_of_range (const char *prefix, + offsetT value, + offsetT min, + offsetT max, + const char *file, + unsigned line) +{ + as_internal_value_out_of_range (prefix, value, min, max, file, line, 0); } -/* end of messages.c */ +void +as_bad_value_out_of_range (const char *prefix, + offsetT value, + offsetT min, + offsetT max, + const char *file, + unsigned line) +{ + as_internal_value_out_of_range (prefix, value, min, max, file, line, 1); +}