c0e157e3b2
One must build yasm (included in the yasm directory) before building GMP, if building on an x86_64 machine. Note: make test and make tune do not currently build.
526 lines
14 KiB
C
526 lines
14 KiB
C
/*
|
|
* 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"
|
|
/*@unused@*/ RCSID("$Id: errwarn.c 1893 2007-07-14 03:11:32Z peter $");
|
|
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "coretype.h"
|
|
|
|
#include "linemap.h"
|
|
#include "errwarn.h"
|
|
|
|
|
|
#define MSG_MAXSIZE 1024
|
|
|
|
/* 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) 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_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);
|
|
|
|
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);
|
|
}
|