• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
def_gettext_hook(const char * msgid)105 def_gettext_hook(const char *msgid)
106 {
107     return msgid;
108 }
109 
110 void
yasm_errwarn_initialize(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
yasm_errwarn_cleanup(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 *
yasm__conv_unprint(int ch)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
def_internal_error_(const char * file,unsigned int line,const char * message)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
def_fatal(const char * fmt,va_list va)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 *
errwarn_data_new(yasm_errwarns * errwarns,unsigned long line,int replace_parser_error)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
yasm_error_clear(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
yasm_error_matches(yasm_error_class eclass)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
yasm_error_set_va(yasm_error_class eclass,const char * format,va_list va)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
yasm_error_set(yasm_error_class eclass,const char * format,...)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
yasm_error_set_xref_va(unsigned long xrefline,const char * format,va_list va)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
yasm_error_set_xref(unsigned long xrefline,const char * format,...)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
yasm_error_fetch(yasm_error_class * eclass,char ** str,unsigned long * xrefline,char ** xrefstr)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 
yasm_warn_clear(void)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
yasm_warn_occurred(void)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
yasm_warn_set_va(yasm_warn_class wclass,const char * format,va_list va)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
yasm_warn_set(yasm_warn_class wclass,const char * format,...)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
yasm_warn_fetch(yasm_warn_class * wclass,char ** str)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
yasm_warn_enable(yasm_warn_class num)402 yasm_warn_enable(yasm_warn_class num)
403 {
404     warn_class_enabled |= (1UL<<num);
405 }
406 
407 void
yasm_warn_disable(yasm_warn_class num)408 yasm_warn_disable(yasm_warn_class num)
409 {
410     warn_class_enabled &= ~(1UL<<num);
411 }
412 
413 void
yasm_warn_disable_all(void)414 yasm_warn_disable_all(void)
415 {
416     warn_class_enabled = 0;
417 }
418 
419 yasm_errwarns *
yasm_errwarns_create(void)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
yasm_errwarns_destroy(yasm_errwarns * errwarns)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
yasm_errwarn_propagate(yasm_errwarns * errwarns,unsigned long line)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
yasm_errwarns_num_errors(yasm_errwarns * errwarns,int warning_as_error)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
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)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
yasm__fatal(const char * message,...)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