Home | History | Annotate | Download | only in libyasm
      1 /*
      2  * Error and warning reporting and related functions.
      3  *
      4  *  Copyright (C) 2001-2007  Peter Johnson
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
     16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
     19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  * POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 #include "util.h"
     28 
     29 #include <ctype.h>
     30 #include <stdarg.h>
     31 
     32 #include "coretype.h"
     33 
     34 #include "linemap.h"
     35 #include "errwarn.h"
     36 
     37 
     38 #define MSG_MAXSIZE     1024
     39 
     40 #if !defined(HAVE_TOASCII) || defined(lint)
     41 # define toascii(c) ((c) & 0x7F)
     42 #endif
     43 
     44 /* Default handlers for replacable functions */
     45 static /*@exits@*/ void def_internal_error_
     46     (const char *file, unsigned int line, const char *message);
     47 static /*@exits@*/ void def_fatal(const char *message, va_list va);
     48 static const char *def_gettext_hook(const char *msgid);
     49 
     50 /* Storage for errwarn's "extern" functions */
     51 /*@exits@*/ void (*yasm_internal_error_)
     52     (const char *file, unsigned int line, const char *message)
     53     = def_internal_error_;
     54 /*@exits@*/ void (*yasm_fatal) (const char *message, va_list va) = def_fatal;
     55 const char * (*yasm_gettext_hook) (const char *msgid) = def_gettext_hook;
     56 
     57 /* Error indicator */
     58 /* yasm_eclass is not static so that yasm_error_occurred macro can access it */
     59 yasm_error_class yasm_eclass;
     60 static /*@only@*/ /*@null@*/ char *yasm_estr;
     61 static unsigned long yasm_exrefline;
     62 static /*@only@*/ /*@null@*/ char *yasm_exrefstr;
     63 
     64 /* Warning indicator */
     65 typedef struct warn {
     66     /*@reldef@*/ STAILQ_ENTRY(warn) link;
     67 
     68     yasm_warn_class wclass;
     69     /*@owned@*/ /*@null@*/ char *wstr;
     70 } warn;
     71 static STAILQ_HEAD(warn_head, warn) yasm_warns;
     72 
     73 /* Enabled warnings.  See errwarn.h for a list. */
     74 static unsigned long warn_class_enabled;
     75 
     76 typedef struct errwarn_data {
     77     /*@reldef@*/ SLIST_ENTRY(errwarn_data) link;
     78 
     79     enum { WE_UNKNOWN, WE_ERROR, WE_WARNING, WE_PARSERERROR } type;
     80 
     81     unsigned long line;
     82     unsigned long xrefline;
     83     /*@owned@*/ char *msg;
     84     /*@owned@*/ char *xrefmsg;
     85 } errwarn_data;
     86 
     87 struct yasm_errwarns {
     88     /*@reldef@*/ SLIST_HEAD(errwarn_head, errwarn_data) errwarns;
     89 
     90     /* Total error count */
     91     unsigned int ecount;
     92 
     93     /* Total warning count */
     94     unsigned int wcount;
     95 
     96     /* Last inserted error/warning.  Used to speed up insertions. */
     97     /*@null@*/ errwarn_data *previous_we;
     98 };
     99 
    100 /* Static buffer for use by conv_unprint(). */
    101 static char unprint[5];
    102 
    103 
    104 static const char *
    105 def_gettext_hook(const char *msgid)
    106 {
    107     return msgid;
    108 }
    109 
    110 void
    111 yasm_errwarn_initialize(void)
    112 {
    113     /* Default enabled warnings.  See errwarn.h for a list. */
    114     warn_class_enabled =
    115         (1UL<<YASM_WARN_GENERAL) | (1UL<<YASM_WARN_UNREC_CHAR) |
    116         (1UL<<YASM_WARN_PREPROC) | (0UL<<YASM_WARN_ORPHAN_LABEL) |
    117         (1UL<<YASM_WARN_UNINIT_CONTENTS) | (0UL<<YASM_WARN_SIZE_OVERRIDE) |
    118         (1UL<<YASM_WARN_IMPLICIT_SIZE_OVERRIDE);
    119 
    120     yasm_eclass = YASM_ERROR_NONE;
    121     yasm_estr = NULL;
    122     yasm_exrefline = 0;
    123     yasm_exrefstr = NULL;
    124 
    125     STAILQ_INIT(&yasm_warns);
    126 }
    127 
    128 void
    129 yasm_errwarn_cleanup(void)
    130 {
    131     yasm_error_clear();
    132     yasm_warn_clear();
    133 }
    134 
    135 /* Convert a possibly unprintable character into a printable string, using
    136  * standard cat(1) convention for unprintable characters.
    137  */
    138 char *
    139 yasm__conv_unprint(int ch)
    140 {
    141     int pos = 0;
    142 
    143     if (((ch & ~0x7F) != 0) /*!isascii(ch)*/ && !isprint(ch)) {
    144         unprint[pos++] = 'M';
    145         unprint[pos++] = '-';
    146         ch &= toascii(ch);
    147     }
    148     if (iscntrl(ch)) {
    149         unprint[pos++] = '^';
    150         unprint[pos++] = (ch == '\177') ? '?' : ch | 0100;
    151     } else
    152         unprint[pos++] = ch;
    153     unprint[pos] = '\0';
    154 
    155     return unprint;
    156 }
    157 
    158 /* Report an internal error.  Essentially a fatal error with trace info.
    159  * Exit immediately because it's essentially an assert() trap.
    160  */
    161 static void
    162 def_internal_error_(const char *file, unsigned int line, const char *message)
    163 {
    164     fprintf(stderr,
    165             yasm_gettext_hook(N_("INTERNAL ERROR at %s, line %u: %s\n")),
    166             file, line, yasm_gettext_hook(message));
    167 #ifdef HAVE_ABORT
    168     abort();
    169 #else
    170     exit(EXIT_FAILURE);
    171 #endif
    172 }
    173 
    174 /* Report a fatal error.  These are unrecoverable (such as running out of
    175  * memory), so just exit immediately.
    176  */
    177 static void
    178 def_fatal(const char *fmt, va_list va)
    179 {
    180     fprintf(stderr, "%s: ", yasm_gettext_hook(N_("FATAL")));
    181     vfprintf(stderr, yasm_gettext_hook(fmt), va);
    182     fputc('\n', stderr);
    183     exit(EXIT_FAILURE);
    184 }
    185 
    186 /* Create an errwarn structure in the correct linked list location.
    187  * If replace_parser_error is nonzero, overwrites the last error if its
    188  * type is WE_PARSERERROR.
    189  */
    190 static errwarn_data *
    191 errwarn_data_new(yasm_errwarns *errwarns, unsigned long line,
    192                  int replace_parser_error)
    193 {
    194     errwarn_data *first, *next, *ins_we, *we;
    195     enum { INS_NONE, INS_HEAD, INS_AFTER } action = INS_NONE;
    196 
    197     /* Find the entry with either line=line or the last one with line<line.
    198      * Start with the last entry added to speed the search.
    199      */
    200     ins_we = errwarns->previous_we;
    201     first = SLIST_FIRST(&errwarns->errwarns);
    202     if (!ins_we || !first)
    203         action = INS_HEAD;
    204     while (action == INS_NONE) {
    205         next = SLIST_NEXT(ins_we, link);
    206         if (line < ins_we->line) {
    207             if (ins_we == first)
    208                 action = INS_HEAD;
    209             else
    210                 ins_we = first;
    211         } else if (!next)
    212             action = INS_AFTER;
    213         else if (line >= ins_we->line && line < next->line)
    214             action = INS_AFTER;
    215         else
    216             ins_we = next;
    217     }
    218 
    219     if (replace_parser_error && ins_we && ins_we->type == WE_PARSERERROR) {
    220         /* overwrite last error */
    221         we = ins_we;
    222     } else {
    223         /* add a new error */
    224         we = yasm_xmalloc(sizeof(errwarn_data));
    225 
    226         we->type = WE_UNKNOWN;
    227         we->line = line;
    228         we->xrefline = 0;
    229         we->msg = NULL;
    230         we->xrefmsg = NULL;
    231 
    232         if (action == INS_HEAD)
    233             SLIST_INSERT_HEAD(&errwarns->errwarns, we, link);
    234         else if (action == INS_AFTER) {
    235             assert(ins_we != NULL);
    236             SLIST_INSERT_AFTER(ins_we, we, link);
    237         } else
    238             yasm_internal_error(N_("Unexpected errwarn insert action"));
    239     }
    240 
    241     /* Remember previous err/warn */
    242     errwarns->previous_we = we;
    243 
    244     return we;
    245 }
    246 
    247 void
    248 yasm_error_clear(void)
    249 {
    250     if (yasm_estr)
    251         yasm_xfree(yasm_estr);
    252     if (yasm_exrefstr)
    253         yasm_xfree(yasm_exrefstr);
    254     yasm_eclass = YASM_ERROR_NONE;
    255     yasm_estr = NULL;
    256     yasm_exrefline = 0;
    257     yasm_exrefstr = NULL;
    258 }
    259 
    260 int
    261 yasm_error_matches(yasm_error_class eclass)
    262 {
    263     if (yasm_eclass == YASM_ERROR_NONE)
    264         return eclass == YASM_ERROR_NONE;
    265     if (yasm_eclass == YASM_ERROR_GENERAL)
    266         return eclass == YASM_ERROR_GENERAL;
    267     return (yasm_eclass & eclass) == eclass;
    268 }
    269 
    270 void
    271 yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va)
    272 {
    273     if (yasm_eclass != YASM_ERROR_NONE)
    274         return;
    275 
    276     yasm_eclass = eclass;
    277     yasm_estr = yasm_xmalloc(MSG_MAXSIZE+1);
    278 #ifdef HAVE_VSNPRINTF
    279     vsnprintf(yasm_estr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
    280 #else
    281     vsprintf(yasm_estr, yasm_gettext_hook(format), va);
    282 #endif
    283 }
    284 
    285 void
    286 yasm_error_set(yasm_error_class eclass, const char *format, ...)
    287 {
    288     va_list va;
    289     va_start(va, format);
    290     yasm_error_set_va(eclass, format, va);
    291     va_end(va);
    292 }
    293 
    294 void
    295 yasm_error_set_xref_va(unsigned long xrefline, const char *format, va_list va)
    296 {
    297     if (yasm_eclass != YASM_ERROR_NONE)
    298         return;
    299 
    300     yasm_exrefline = xrefline;
    301 
    302     yasm_exrefstr = yasm_xmalloc(MSG_MAXSIZE+1);
    303 #ifdef HAVE_VSNPRINTF
    304     vsnprintf(yasm_exrefstr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
    305 #else
    306     vsprintf(yasm_exrefstr, yasm_gettext_hook(format), va);
    307 #endif
    308 }
    309 
    310 void
    311 yasm_error_set_xref(unsigned long xrefline, const char *format, ...)
    312 {
    313     va_list va;
    314     va_start(va, format);
    315     yasm_error_set_xref_va(xrefline, format, va);
    316     va_end(va);
    317 }
    318 
    319 void
    320 yasm_error_fetch(yasm_error_class *eclass, char **str, unsigned long *xrefline,
    321                  char **xrefstr)
    322 {
    323     *eclass = yasm_eclass;
    324     *str = yasm_estr;
    325     *xrefline = yasm_exrefline;
    326     *xrefstr = yasm_exrefstr;
    327     yasm_eclass = YASM_ERROR_NONE;
    328     yasm_estr = NULL;
    329     yasm_exrefline = 0;
    330     yasm_exrefstr = NULL;
    331 }
    332 
    333 void yasm_warn_clear(void)
    334 {
    335     /* Delete all error/warnings */
    336     while (!STAILQ_EMPTY(&yasm_warns)) {
    337         warn *w = STAILQ_FIRST(&yasm_warns);
    338 
    339         if (w->wstr)
    340             yasm_xfree(w->wstr);
    341 
    342         STAILQ_REMOVE_HEAD(&yasm_warns, link);
    343         yasm_xfree(w);
    344     }
    345 }
    346 
    347 yasm_warn_class
    348 yasm_warn_occurred(void)
    349 {
    350     if (STAILQ_EMPTY(&yasm_warns))
    351         return YASM_WARN_NONE;
    352     return STAILQ_FIRST(&yasm_warns)->wclass;
    353 }
    354 
    355 void
    356 yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va)
    357 {
    358     warn *w;
    359 
    360     if (!(warn_class_enabled & (1UL<<wclass)))
    361         return;     /* warning is part of disabled class */
    362 
    363     w = yasm_xmalloc(sizeof(warn));
    364     w->wclass = wclass;
    365     w->wstr = yasm_xmalloc(MSG_MAXSIZE+1);
    366 #ifdef HAVE_VSNPRINTF
    367     vsnprintf(w->wstr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
    368 #else
    369     vsprintf(w->wstr, yasm_gettext_hook(format), va);
    370 #endif
    371     STAILQ_INSERT_TAIL(&yasm_warns, w, link);
    372 }
    373 
    374 void
    375 yasm_warn_set(yasm_warn_class wclass, const char *format, ...)
    376 {
    377     va_list va;
    378     va_start(va, format);
    379     yasm_warn_set_va(wclass, format, va);
    380     va_end(va);
    381 }
    382 
    383 void
    384 yasm_warn_fetch(yasm_warn_class *wclass, char **str)
    385 {
    386     warn *w = STAILQ_FIRST(&yasm_warns);
    387 
    388     if (!w) {
    389         *wclass = YASM_WARN_NONE;
    390         *str = NULL;
    391         return;
    392     }
    393 
    394     *wclass = w->wclass;
    395     *str = w->wstr;
    396 
    397     STAILQ_REMOVE_HEAD(&yasm_warns, link);
    398     yasm_xfree(w);
    399 }
    400 
    401 void
    402 yasm_warn_enable(yasm_warn_class num)
    403 {
    404     warn_class_enabled |= (1UL<<num);
    405 }
    406 
    407 void
    408 yasm_warn_disable(yasm_warn_class num)
    409 {
    410     warn_class_enabled &= ~(1UL<<num);
    411 }
    412 
    413 void
    414 yasm_warn_disable_all(void)
    415 {
    416     warn_class_enabled = 0;
    417 }
    418 
    419 yasm_errwarns *
    420 yasm_errwarns_create(void)
    421 {
    422     yasm_errwarns *errwarns = yasm_xmalloc(sizeof(yasm_errwarns));
    423     SLIST_INIT(&errwarns->errwarns);
    424     errwarns->ecount = 0;
    425     errwarns->wcount = 0;
    426     errwarns->previous_we = NULL;
    427     return errwarns;
    428 }
    429 
    430 void
    431 yasm_errwarns_destroy(yasm_errwarns *errwarns)
    432 {
    433     errwarn_data *we;
    434 
    435     /* Delete all error/warnings */
    436     while (!SLIST_EMPTY(&errwarns->errwarns)) {
    437         we = SLIST_FIRST(&errwarns->errwarns);
    438         if (we->msg)
    439             yasm_xfree(we->msg);
    440         if (we->xrefmsg)
    441             yasm_xfree(we->xrefmsg);
    442 
    443         SLIST_REMOVE_HEAD(&errwarns->errwarns, link);
    444         yasm_xfree(we);
    445     }
    446 
    447     yasm_xfree(errwarns);
    448 }
    449 
    450 void
    451 yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line)
    452 {
    453     if (yasm_eclass != YASM_ERROR_NONE) {
    454         errwarn_data *we = errwarn_data_new(errwarns, line, 1);
    455         yasm_error_class eclass;
    456 
    457         yasm_error_fetch(&eclass, &we->msg, &we->xrefline, &we->xrefmsg);
    458         if (eclass != YASM_ERROR_GENERAL
    459             && (eclass & YASM_ERROR_PARSE) == YASM_ERROR_PARSE)
    460             we->type = WE_PARSERERROR;
    461         else
    462             we->type = WE_ERROR;
    463         errwarns->ecount++;
    464     }
    465 
    466     while (!STAILQ_EMPTY(&yasm_warns)) {
    467         errwarn_data *we = errwarn_data_new(errwarns, line, 0);
    468         yasm_warn_class wclass;
    469 
    470         yasm_warn_fetch(&wclass, &we->msg);
    471         we->type = WE_WARNING;
    472         errwarns->wcount++;
    473     }
    474 }
    475 
    476 unsigned int
    477 yasm_errwarns_num_errors(yasm_errwarns *errwarns, int warning_as_error)
    478 {
    479     if (warning_as_error)
    480         return errwarns->ecount+errwarns->wcount;
    481     else
    482         return errwarns->ecount;
    483 }
    484 
    485 void
    486 yasm_errwarns_output_all(yasm_errwarns *errwarns, yasm_linemap *lm,
    487                          int warning_as_error,
    488                          yasm_print_error_func print_error,
    489                          yasm_print_warning_func print_warning)
    490 {
    491     errwarn_data *we;
    492     const char *filename, *xref_filename;
    493     unsigned long line, xref_line;
    494 
    495     /* If we're treating warnings as errors, tell the user about it. */
    496     if (warning_as_error && warning_as_error != 2) {
    497         print_error("", 0,
    498                     yasm_gettext_hook(N_("warnings being treated as errors")),
    499                     NULL, 0, NULL);
    500         warning_as_error = 2;
    501     }
    502 
    503     /* Output error/warnings. */
    504     SLIST_FOREACH(we, &errwarns->errwarns, link) {
    505         /* Output error/warning */
    506         yasm_linemap_lookup(lm, we->line, &filename, &line);
    507         if (we->xrefline)
    508             yasm_linemap_lookup(lm, we->xrefline, &xref_filename, &xref_line);
    509         else {
    510             xref_filename = NULL;
    511             xref_line = 0;
    512         }
    513         if (we->type == WE_ERROR || we->type == WE_PARSERERROR)
    514             print_error(filename, line, we->msg, xref_filename, xref_line,
    515                         we->xrefmsg);
    516         else
    517             print_warning(filename, line, we->msg);
    518     }
    519 }
    520 
    521 void
    522 yasm__fatal(const char *message, ...)
    523 {
    524     va_list va;
    525     va_start(va, message);
    526     yasm_fatal(message, va);
    527     /*@notreached@*/
    528     va_end(va);
    529 }
    530