123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537 |
- /*
- * Error and warning reporting and related functions.
- *
- * Copyright (C) 2001-2007 Peter Johnson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
- #include "util.h"
- #include <ctype.h>
- #include <errno.h>
- #include <stdarg.h>
- #include "coretype.h"
- #include "linemap.h"
- #include "errwarn.h"
- #define MSG_MAXSIZE 1024
- #if !defined(HAVE_TOASCII) || defined(lint)
- # define toascii(c) ((c) & 0x7F)
- #endif
- /* Default handlers for replacable functions */
- static /*@exits@*/ void def_internal_error_
- (const char *file, unsigned int line, const char *message);
- static /*@exits@*/ void def_fatal(const char *message, va_list va);
- static const char *def_gettext_hook(const char *msgid);
- /* Storage for errwarn's "extern" functions */
- /*@exits@*/ void (*yasm_internal_error_)
- (const char *file, unsigned int line, const char *message)
- = def_internal_error_;
- /*@exits@*/ void (*yasm_fatal) (const char *message, va_list va) = def_fatal;
- const char * (*yasm_gettext_hook) (const char *msgid) = def_gettext_hook;
- /* Error indicator */
- /* yasm_eclass is not static so that yasm_error_occurred macro can access it */
- yasm_error_class yasm_eclass;
- static /*@only@*/ /*@null@*/ char *yasm_estr;
- static unsigned long yasm_exrefline;
- static /*@only@*/ /*@null@*/ char *yasm_exrefstr;
- /* Warning indicator */
- typedef struct warn {
- /*@reldef@*/ STAILQ_ENTRY(warn) link;
- yasm_warn_class wclass;
- /*@owned@*/ /*@null@*/ char *wstr;
- } warn;
- static STAILQ_HEAD(warn_head, warn) yasm_warns;
- /* Enabled warnings. See errwarn.h for a list. */
- static unsigned long warn_class_enabled;
- typedef struct errwarn_data {
- /*@reldef@*/ SLIST_ENTRY(errwarn_data) link;
- enum { WE_UNKNOWN, WE_ERROR, WE_WARNING, WE_PARSERERROR } type;
- unsigned long line;
- unsigned long xrefline;
- /*@owned@*/ char *msg;
- /*@owned@*/ char *xrefmsg;
- } errwarn_data;
- struct yasm_errwarns {
- /*@reldef@*/ SLIST_HEAD(errwarn_head, errwarn_data) errwarns;
- /* Total error count */
- unsigned int ecount;
- /* Total warning count */
- unsigned int wcount;
- /* Last inserted error/warning. Used to speed up insertions. */
- /*@null@*/ errwarn_data *previous_we;
- };
- /* Static buffer for use by conv_unprint(). */
- static char unprint[5];
- static const char *
- def_gettext_hook(const char *msgid)
- {
- return msgid;
- }
- void
- yasm_errwarn_initialize(void)
- {
- /* Default enabled warnings. See errwarn.h for a list. */
- warn_class_enabled =
- (1UL<<YASM_WARN_GENERAL) | (1UL<<YASM_WARN_UNREC_CHAR) |
- (1UL<<YASM_WARN_PREPROC) | (0UL<<YASM_WARN_ORPHAN_LABEL) |
- (1UL<<YASM_WARN_UNINIT_CONTENTS) | (0UL<<YASM_WARN_SIZE_OVERRIDE) |
- (1UL<<YASM_WARN_IMPLICIT_SIZE_OVERRIDE);
- yasm_eclass = YASM_ERROR_NONE;
- yasm_estr = NULL;
- yasm_exrefline = 0;
- yasm_exrefstr = NULL;
- STAILQ_INIT(&yasm_warns);
- }
- void
- yasm_errwarn_cleanup(void)
- {
- yasm_error_clear();
- yasm_warn_clear();
- }
- /* Convert a possibly unprintable character into a printable string, using
- * standard cat(1) convention for unprintable characters.
- */
- char *
- yasm__conv_unprint(int ch)
- {
- int pos = 0;
- if (((ch & ~0x7F) != 0) /*!isascii(ch)*/ && !isprint(ch)) {
- unprint[pos++] = 'M';
- unprint[pos++] = '-';
- ch &= toascii(ch);
- }
- if (iscntrl(ch)) {
- unprint[pos++] = '^';
- unprint[pos++] = (ch == '\177') ? '?' : ch | 0100;
- } else
- unprint[pos++] = ch;
- unprint[pos] = '\0';
- return unprint;
- }
- /* Report an internal error. Essentially a fatal error with trace info.
- * Exit immediately because it's essentially an assert() trap.
- */
- static void
- def_internal_error_(const char *file, unsigned int line, const char *message)
- {
- fprintf(stderr,
- yasm_gettext_hook(N_("INTERNAL ERROR at %s, line %u: %s\n")),
- file, line, yasm_gettext_hook(message));
- #ifdef HAVE_ABORT
- abort();
- #else
- exit(EXIT_FAILURE);
- #endif
- }
- /* Report a fatal error. These are unrecoverable (such as running out of
- * memory), so just exit immediately.
- */
- static void
- def_fatal(const char *fmt, va_list va)
- {
- fprintf(stderr, "%s: ", yasm_gettext_hook(N_("FATAL")));
- vfprintf(stderr, yasm_gettext_hook(fmt), va);
- fputc('\n', stderr);
- exit(EXIT_FAILURE);
- }
- /* Create an errwarn structure in the correct linked list location.
- * If replace_parser_error is nonzero, overwrites the last error if its
- * type is WE_PARSERERROR.
- */
- static errwarn_data *
- errwarn_data_new(yasm_errwarns *errwarns, unsigned long line,
- int replace_parser_error)
- {
- errwarn_data *first, *next, *ins_we, *we;
- enum { INS_NONE, INS_HEAD, INS_AFTER } action = INS_NONE;
- /* Find the entry with either line=line or the last one with line<line.
- * Start with the last entry added to speed the search.
- */
- ins_we = errwarns->previous_we;
- first = SLIST_FIRST(&errwarns->errwarns);
- if (!ins_we || !first)
- action = INS_HEAD;
- while (action == INS_NONE) {
- next = SLIST_NEXT(ins_we, link);
- if (line < ins_we->line) {
- if (ins_we == first)
- action = INS_HEAD;
- else
- ins_we = first;
- } else if (!next)
- action = INS_AFTER;
- else if (line >= ins_we->line && line < next->line)
- action = INS_AFTER;
- else
- ins_we = next;
- }
- if (replace_parser_error && ins_we && ins_we->type == WE_PARSERERROR) {
- /* overwrite last error */
- we = ins_we;
- } else {
- /* add a new error */
- we = yasm_xmalloc(sizeof(errwarn_data));
- we->type = WE_UNKNOWN;
- we->line = line;
- we->xrefline = 0;
- we->msg = NULL;
- we->xrefmsg = NULL;
- if (action == INS_HEAD)
- SLIST_INSERT_HEAD(&errwarns->errwarns, we, link);
- else if (action == INS_AFTER) {
- assert(ins_we != NULL);
- SLIST_INSERT_AFTER(ins_we, we, link);
- } else
- yasm_internal_error(N_("Unexpected errwarn insert action"));
- }
- /* Remember previous err/warn */
- errwarns->previous_we = we;
- return we;
- }
- void
- yasm_error_clear(void)
- {
- if (yasm_estr)
- yasm_xfree(yasm_estr);
- if (yasm_exrefstr)
- yasm_xfree(yasm_exrefstr);
- yasm_eclass = YASM_ERROR_NONE;
- yasm_estr = NULL;
- yasm_exrefline = 0;
- yasm_exrefstr = NULL;
- }
- int
- yasm_error_matches(yasm_error_class eclass)
- {
- if (yasm_eclass == YASM_ERROR_NONE)
- return eclass == YASM_ERROR_NONE;
- if (yasm_eclass == YASM_ERROR_GENERAL)
- return eclass == YASM_ERROR_GENERAL;
- return (yasm_eclass & eclass) == eclass;
- }
- void
- yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va)
- {
- if (yasm_eclass != YASM_ERROR_NONE)
- return;
- yasm_eclass = eclass;
- yasm_estr = yasm_xmalloc(MSG_MAXSIZE+1);
- #ifdef HAVE_VSNPRINTF
- vsnprintf(yasm_estr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
- #else
- vsprintf(yasm_estr, yasm_gettext_hook(format), va);
- #endif
- }
- void
- yasm_error_set(yasm_error_class eclass, const char *format, ...)
- {
- va_list va;
- va_start(va, format);
- yasm_error_set_va(eclass, format, va);
- va_end(va);
- }
- void
- yasm_error_set_xref_va(unsigned long xrefline, const char *format, va_list va)
- {
- if (yasm_eclass != YASM_ERROR_NONE)
- return;
- yasm_exrefline = xrefline;
- yasm_exrefstr = yasm_xmalloc(MSG_MAXSIZE+1);
- #ifdef HAVE_VSNPRINTF
- vsnprintf(yasm_exrefstr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
- #else
- vsprintf(yasm_exrefstr, yasm_gettext_hook(format), va);
- #endif
- }
- void
- yasm_error_set_xref(unsigned long xrefline, const char *format, ...)
- {
- va_list va;
- va_start(va, format);
- yasm_error_set_xref_va(xrefline, format, va);
- va_end(va);
- }
- void
- yasm_error_fetch(yasm_error_class *eclass, char **str, unsigned long *xrefline,
- char **xrefstr)
- {
- *eclass = yasm_eclass;
- *str = yasm_estr;
- *xrefline = yasm_exrefline;
- *xrefstr = yasm_exrefstr;
- yasm_eclass = YASM_ERROR_NONE;
- yasm_estr = NULL;
- yasm_exrefline = 0;
- yasm_exrefstr = NULL;
- }
- void yasm_warn_clear(void)
- {
- /* Delete all error/warnings */
- while (!STAILQ_EMPTY(&yasm_warns)) {
- warn *w = STAILQ_FIRST(&yasm_warns);
- if (w->wstr)
- yasm_xfree(w->wstr);
- STAILQ_REMOVE_HEAD(&yasm_warns, link);
- yasm_xfree(w);
- }
- }
- yasm_warn_class
- yasm_warn_occurred(void)
- {
- if (STAILQ_EMPTY(&yasm_warns))
- return YASM_WARN_NONE;
- return STAILQ_FIRST(&yasm_warns)->wclass;
- }
- void
- yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va)
- {
- warn *w;
- if (!(warn_class_enabled & (1UL<<wclass)))
- return; /* warning is part of disabled class */
- w = yasm_xmalloc(sizeof(warn));
- w->wclass = wclass;
- w->wstr = yasm_xmalloc(MSG_MAXSIZE+1);
- #ifdef HAVE_VSNPRINTF
- vsnprintf(w->wstr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
- #else
- vsprintf(w->wstr, yasm_gettext_hook(format), va);
- #endif
- STAILQ_INSERT_TAIL(&yasm_warns, w, link);
- }
- void
- yasm_warn_set(yasm_warn_class wclass, const char *format, ...)
- {
- va_list va;
- va_start(va, format);
- yasm_warn_set_va(wclass, format, va);
- va_end(va);
- }
- void
- yasm_warn_fetch(yasm_warn_class *wclass, char **str)
- {
- warn *w = STAILQ_FIRST(&yasm_warns);
- if (!w) {
- *wclass = YASM_WARN_NONE;
- *str = NULL;
- return;
- }
- *wclass = w->wclass;
- *str = w->wstr;
- STAILQ_REMOVE_HEAD(&yasm_warns, link);
- yasm_xfree(w);
- }
- void
- yasm_warn_enable(yasm_warn_class num)
- {
- warn_class_enabled |= (1UL<<num);
- }
- void
- yasm_warn_disable(yasm_warn_class num)
- {
- warn_class_enabled &= ~(1UL<<num);
- }
- void
- yasm_warn_disable_all(void)
- {
- warn_class_enabled = 0;
- }
- yasm_errwarns *
- yasm_errwarns_create(void)
- {
- yasm_errwarns *errwarns = yasm_xmalloc(sizeof(yasm_errwarns));
- SLIST_INIT(&errwarns->errwarns);
- errwarns->ecount = 0;
- errwarns->wcount = 0;
- errwarns->previous_we = NULL;
- return errwarns;
- }
- void
- yasm_errwarns_destroy(yasm_errwarns *errwarns)
- {
- errwarn_data *we;
- /* Delete all error/warnings */
- while (!SLIST_EMPTY(&errwarns->errwarns)) {
- we = SLIST_FIRST(&errwarns->errwarns);
- if (we->msg)
- yasm_xfree(we->msg);
- if (we->xrefmsg)
- yasm_xfree(we->xrefmsg);
- SLIST_REMOVE_HEAD(&errwarns->errwarns, link);
- yasm_xfree(we);
- }
- yasm_xfree(errwarns);
- }
- void
- yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line)
- {
- if (yasm_eclass != YASM_ERROR_NONE) {
- errwarn_data *we = errwarn_data_new(errwarns, line, 1);
- yasm_error_class eclass;
- yasm_error_fetch(&eclass, &we->msg, &we->xrefline, &we->xrefmsg);
- if (eclass != YASM_ERROR_GENERAL
- && (eclass & YASM_ERROR_PARSE) == YASM_ERROR_PARSE)
- we->type = WE_PARSERERROR;
- else
- we->type = WE_ERROR;
- errwarns->ecount++;
- }
- while (!STAILQ_EMPTY(&yasm_warns)) {
- errwarn_data *we = errwarn_data_new(errwarns, line, 0);
- yasm_warn_class wclass;
- yasm_warn_fetch(&wclass, &we->msg);
- we->type = WE_WARNING;
- errwarns->wcount++;
- }
- }
- unsigned int
- yasm_errwarns_num_errors(yasm_errwarns *errwarns, int warning_as_error)
- {
- if (warning_as_error)
- return errwarns->ecount+errwarns->wcount;
- else
- return errwarns->ecount;
- }
- void
- yasm_errwarns_output_all(yasm_errwarns *errwarns, yasm_linemap *lm,
- int warning_as_error,
- yasm_print_error_func print_error,
- yasm_print_warning_func print_warning)
- {
- errwarn_data *we;
- const char *filename, *xref_filename;
- unsigned long line, xref_line;
- /* If we're treating warnings as errors, tell the user about it. */
- if (warning_as_error && warning_as_error != 2) {
- print_error("", 0,
- yasm_gettext_hook(N_("warnings being treated as errors")),
- NULL, 0, NULL);
- warning_as_error = 2;
- }
- /* Output error/warnings. */
- SLIST_FOREACH(we, &errwarns->errwarns, link) {
- /* Output error/warning */
- yasm_linemap_lookup(lm, we->line, &filename, &line);
- if (we->xrefline)
- yasm_linemap_lookup(lm, we->xrefline, &xref_filename, &xref_line);
- else {
- xref_filename = NULL;
- xref_line = 0;
- }
- if (we->type == WE_ERROR || we->type == WE_PARSERERROR)
- print_error(filename, line, we->msg, xref_filename, xref_line,
- we->xrefmsg);
- else
- print_warning(filename, line, we->msg);
- }
- }
- void
- yasm__fatal(const char *message, ...)
- {
- va_list va;
- va_start(va, message);
- yasm_fatal(message, va);
- /*@notreached@*/
- va_end(va);
- }
- void
- yasm__fatal_missing_input_file(const char *message, const char *filename)
- {
- fprintf(stderr, "%s: %s %s (%s)\n", yasm_gettext_hook(N_("FATAL")), yasm_gettext_hook(message), strerror(errno), yasm_gettext_hook(filename));
- exit(EXIT_FAILURE);
- }
|