X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gas%2Fmessages.c;h=3b34466e99817cf6577206fe1394eeb1833459ef;hb=dcefca4019c6f7646d633e71639f6faf4f2702bf;hp=90e1f9589e514786f628cc83e0ae42b24b2ffa12;hpb=fecd2382e77b89f12c9d630ed4e42e9a54ba6953;p=binutils-gdb.git diff --git a/gas/messages.c b/gas/messages.c index 90e1f9589e5..3b34466e998 100644 --- a/gas/messages.c +++ b/gas/messages.c @@ -1,11 +1,10 @@ /* messages.c - error reporter - - Copyright (C) 1987, 1991 Free Software Foundation, Inc. - + Copyright (C) 1987-2022 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 1, 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, @@ -14,378 +13,443 @@ GNU General Public License for more details. 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* $Id$ */ - -#include /* define stderr */ -#include + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ #include "as.h" +#include -#ifndef NO_STDARG -#include -#else -#ifndef NO_VARARGS -#include -#endif /* NO_VARARGS */ -#endif /* NO_STDARG */ - -/* - * 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. - */ - -/* - ERRORS - - JF: this is now bogus. We now print more standard error messages - that try to look like everyone else's. - - We print the error message 1st, beginning in column 1. - All ancillary info starts in column 2 on lines after the - key error text. - We try to print a location in logical and physical file - just after the main error text. - Caller then prints any appendices after that, begining all - lines with at least 1 space. - - Optionally, we may die. - There is no need for a trailing '\n' in your error text format - because we supply one. - - as_warn(fmt,args) Like fprintf(stderr,fmt,args) but also call errwhere(). - - as_fatal(fmt,args) Like as_warn() but exit with a fatal status. - - */ - -static int warning_count = 0; /* Count of number of warnings issued */ - -int had_warnings() { - return(warning_count); -} /* had_err() */ +/* 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 -/* Nonzero if we've hit a 'bad error', and should not write an obj file, - and exit with a nonzero error code */ +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 (const char *file) +{ + static int identified; + + if (identified) + return; + identified++; -static int error_count = 0; + if (!file) + { + unsigned int x; + file = as_where (&x); + } -int had_errors() { - return(error_count); -} /* had_errors() */ + if (file) + fprintf (stderr, "%s: ", file); + fprintf (stderr, _("Assembler messages:\n")); +} +/* The number of warnings issued. */ +static int warning_count; -/* - * a s _ p e r r o r - * - * Like perror(3), but with more info. - */ -void as_perror(gripe, filename) -char *gripe; /* Unpunctuated error theme. */ -char *filename; +int +had_warnings (void) { - extern int sys_nerr; - extern char *sys_errlist[]; - - as_where(); - fprintf(stderr,gripe,filename); - - if (errno > sys_nerr) - fprintf(stderr, "Unknown error #%d.\n", errno); - else - fprintf(stderr, "%s.\n", sys_errlist[errno]); - errno = 0; /* After reporting, clear it. */ -} /* as_perror() */ - -/* - * a s _ t s k t s k () - * - * Send to stderr a string (with bell) (JF: Bell is obnoxious!) 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. - */ - -#ifndef NO_STDARG -void as_tsktsk(Format) -const char *Format; + 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. */ + +static int error_count; + +int +had_errors (void) { - va_list args; - - as_where(); - va_start(args, Format); - vfprintf(stderr, Format, args); - va_end(args); - (void) putc('\n', stderr); -} /* as_tsktsk() */ -#else -#ifndef NO_VARARGS -void as_tsktsk(Format,va_alist) -char *Format; -va_dcl + return error_count; +} + +/* Print the current location to stderr. */ + +static void +as_show_where (void) { - va_list args; - - as_where(); - va_start(args); - vfprintf(stderr, Format, args); - va_end(args); - (void) putc('\n', stderr); -} /* as_tsktsk() */ -#else -/*VARARGS1 */ -as_tsktsk(Format,args) -char *Format; + const char *file; + unsigned int line; + + file = as_where (&line); + identify (file); + if (file) + { + if (line != 0) + fprintf (stderr, "%s:%u: ", file, line); + else + fprintf (stderr, "%s: ", file); + } +} + +/* 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. */ + +void +as_tsktsk (const char *format, ...) { - as_where(); - _doprnt (Format, &args, stderr); - (void)putc ('\n', stderr); - /* as_where(); */ -} /* as_tsktsk */ -#endif /* not NO_VARARGS */ -#endif /* not NO_STDARG */ - -#ifdef DONTDEF -void as_tsktsk(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) -char *format; + va_list args; + + as_show_where (); + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + (void) putc ('\n', stderr); +} + +/* The common portion of as_warn and as_warn_where. */ + +static void +as_warn_internal (const char *file, unsigned int line, char *buffer) { - as_where(); - fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); - (void)putc('\n',stderr); -} /* as_tsktsk() */ + ++warning_count; + + if (file == NULL) + file = as_where (&line); + + identify (file); + if (file) + { + 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 (with bell) (JF: Bell is obnoxious!) 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. - */ - -#ifndef NO_STDARG -void as_warn(Format) -const char *Format; -{ - va_list args; - - if(!flagseen['W']) { - ++warning_count; - as_where(); - va_start(args, Format); - vfprintf(stderr, Format, args); - va_end(args); - (void) putc('\n', stderr); - } -} /* as_warn() */ -#else -#ifndef NO_VARARGS -void as_warn(Format,va_alist) -char *Format; -va_dcl +} + +/* 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. */ + +void +as_warn (const char *format, ...) { - va_list args; - - if(!flagseen['W']) { - ++warning_count; - as_where(); - va_start(args); - vfprintf(stderr, Format, args); - va_end(args); - (void) putc('\n', stderr); - } -} /* as_warn() */ -#else -/*VARARGS1 */ -as_warn(Format,args) -char *Format; + va_list args; + char buffer[2000]; + + if (!flag_no_warnings) + { + va_start (args, format); + vsnprintf (buffer, sizeof (buffer), format, args); + va_end (args); + as_warn_internal ((char *) NULL, 0, buffer); + } +} + +/* 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. */ + +void +as_warn_where (const char *file, unsigned int line, const char *format, ...) { - /* -W supresses warning messages. */ - if (! flagseen ['W']) { - ++warning_count; - as_where(); - _doprnt (Format, &args, stderr); - (void)putc ('\n', stderr); - /* as_where(); */ - } -} /* as_warn() */ -#endif /* not NO_VARARGS */ -#endif /* not NO_STDARG */ - -#ifdef DONTDEF -void as_warn(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) -char *format; + va_list args; + char buffer[2000]; + + if (!flag_no_warnings) + { + va_start (args, format); + vsnprintf (buffer, sizeof (buffer), format, args); + va_end (args); + as_warn_internal (file, line, buffer); + } +} + +/* The common portion of as_bad and as_bad_where. */ + +static void +as_bad_internal (const char *file, unsigned int line, char *buffer) { - if(!flagseen['W']) { - ++warning_count; - as_where(); - fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); - (void)putc('\n',stderr); - } -} /* as_warn() */ + ++error_count; + + if (file == NULL) + file = as_where (&line); + + identify (file); + if (file) + { + 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 (with bell) (JF: Bell is obnoxious!) 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. - */ - -#ifndef NO_STDARG -void as_bad(Format) -const char *Format; -{ - va_list args; - - ++error_count; - as_where(); - va_start(args, Format); - vfprintf(stderr, Format, args); - va_end(args); - (void) putc('\n', stderr); -} /* as_bad() */ -#else -#ifndef NO_VARARGS -void as_bad(Format,va_alist) -char *Format; -va_dcl -{ - va_list args; - - ++error_count; - as_where(); - va_start(args); - vfprintf(stderr, Format, args); - va_end(args); - (void) putc('\n', stderr); -} /* as_bad() */ -#else -/*VARARGS1 */ -as_bad(Format,args) -char *Format; +} + +/* 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. */ + +void +as_bad (const char *format, ...) { - ++error_count; - as_where(); - _doprnt (Format, &args, stderr); - (void)putc ('\n', stderr); - /* as_where(); */ -} /* as_bad() */ -#endif /* not NO_VARARGS */ -#endif /* not NO_STDARG */ - -#ifdef DONTDEF -void as_bad(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) -char *format; + va_list args; + char buffer[2000]; + + va_start (args, format); + vsnprintf (buffer, sizeof (buffer), format, args); + va_end (args); + + as_bad_internal ((char *) NULL, 0, buffer); +} + +/* 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. */ + +void +as_bad_where (const char *file, unsigned int line, const char *format, ...) { - ++error_count; - as_where(); - fprintf(stderr,Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); - (void)putc('\n',stderr); -} /* as_bad() */ -#endif + va_list args; + char buffer[2000]; + + va_start (args, format); + vsnprintf (buffer, sizeof (buffer), format, args); + va_end (args); + + as_bad_internal (file, line, buffer); +} + +/* 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. */ -/* - * a s _ f a t a l () - * - * Send to stderr a string (with bell) (JF: Bell is obnoxious!) as a fatal - * message, and locate stdsource in input file(s). - * Please only use this for when we DON'T have some recovery action. - * It exit()s with a warning status. - */ - -#ifndef NO_STDARG -void as_fatal(Format) -const char *Format; +void +as_fatal (const char *format, ...) { - va_list args; - - as_where(); - va_start(args, Format); - fprintf (stderr, "FATAL:"); - vfprintf(stderr, Format, args); - (void) putc('\n', stderr); - va_end(args); - exit(42); -} /* as_fatal() */ -#else -#ifndef NO_VARARGS -void as_fatal(Format,va_alist) -char *Format; -va_dcl + va_list args; + + as_show_where (); + va_start (args, format); + fprintf (stderr, _("Fatal error: ")); + 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); +} + +/* Indicate internal constency error. + Arguments: Filename, line number, optional function name. + FILENAME may be NULL, which we use for crash-via-signal. */ + +void +as_abort (const char *file, int line, const char *fn) { - va_list args; - - as_where(); - va_start(args); - fprintf (stderr, "FATAL:"); - vfprintf(stderr, Format, args); - (void) putc('\n', stderr); - va_end(args); - exit(42); -} /* as_fatal() */ -#else -/*VARARGS1 */ -as_fatal(Format, args) -char *Format; + as_show_where (); + + 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, _("Internal error at %s:%d.\n"), file, line); + + fprintf (stderr, _("Please report this bug.\n")); + + xexit (EXIT_FAILURE); +} + +/* Handler for fatal signals, such as SIGSEGV. */ + +static void +signal_crash (int signo) { - as_where(); - fprintf(stderr,"FATAL:"); - _doprnt (Format, &args, stderr); - (void)putc ('\n', stderr); - /* as_where(); */ - exit(42); /* What is a good exit status? */ -} /* as_fatal() */ -#endif /* not NO_VARARGS */ -#endif /* not NO_STDARG */ - -#ifdef DONTDEF -void as_fatal(Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an) -char *Format; + /* Reset, to prevent unbounded recursion. */ + signal (signo, SIG_DFL); + + as_abort (NULL, 0, strsignal (signo)); +} + +/* Register signal handlers, for less abrubt crashes. */ + +void +signal_init (void) { - as_where(); - fprintf (stderr, "FATAL:"); - fprintf(stderr, Format,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an); - (void) putc('\n', stderr); - exit(42); -} /* as_fatal() */ +#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. */ + +#define HEX_MAX_THRESHOLD 1024 +#define HEX_MIN_THRESHOLD -(HEX_MAX_THRESHOLD) -/* end: messages.c */ +static void +as_internal_value_out_of_range (const char *prefix, + offsetT val, + offsetT min, + offsetT max, + const char *file, + unsigned line, + bool bad) +{ + const char * err; + /* These buffer sizes are excessive, but better to be safe than sorry. + Note - these buffers are used in order to make the error message + string translateable. */ + char val_buf [128]; + char min_buf [128]; + char max_buf [128]; + + if (prefix == NULL) + prefix = ""; + + if (val >= min && val <= max) + { + addressT right = max & -max; + + if (max <= 1) + abort (); + + sprintf (val_buf, "%" BFD_VMA_FMT "d", val); + sprintf (min_buf, "%" BFD_VMA_FMT "d", right); + + /* xgettext:c-format */ + err = _("%s out of domain (%s is not a multiple of %s)"); + + if (bad) + as_bad_where (file, line, err, prefix, val_buf, min_buf); + else + as_warn_where (file, line, err, prefix, val_buf, min_buf); + } + else 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 (val_buf, "%" BFD_VMA_FMT "d", val); + sprintf (min_buf, "%" BFD_VMA_FMT "d", min); + sprintf (max_buf, "%" BFD_VMA_FMT "d", max); + + /* xgettext:c-format. */ + err = _("%s out of range (%s is not between %s and %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); + } + else + { + 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, false); +} + +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, true); +}