errwarn.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  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. #include <ctype.h>
  29. #include <errno.h>
  30. #include <stdarg.h>
  31. #include "coretype.h"
  32. #include "linemap.h"
  33. #include "errwarn.h"
  34. #define MSG_MAXSIZE 1024
  35. #if !defined(HAVE_TOASCII) || defined(lint)
  36. # define toascii(c) ((c) & 0x7F)
  37. #endif
  38. /* Default handlers for replacable functions */
  39. static /*@exits@*/ void def_internal_error_
  40. (const char *file, unsigned int line, const char *message);
  41. static /*@exits@*/ void def_fatal(const char *message, va_list va);
  42. static const char *def_gettext_hook(const char *msgid);
  43. /* Storage for errwarn's "extern" functions */
  44. /*@exits@*/ void (*yasm_internal_error_)
  45. (const char *file, unsigned int line, const char *message)
  46. = def_internal_error_;
  47. /*@exits@*/ void (*yasm_fatal) (const char *message, va_list va) = def_fatal;
  48. const char * (*yasm_gettext_hook) (const char *msgid) = def_gettext_hook;
  49. /* Error indicator */
  50. /* yasm_eclass is not static so that yasm_error_occurred macro can access it */
  51. yasm_error_class yasm_eclass;
  52. static /*@only@*/ /*@null@*/ char *yasm_estr;
  53. static unsigned long yasm_exrefline;
  54. static /*@only@*/ /*@null@*/ char *yasm_exrefstr;
  55. /* Warning indicator */
  56. typedef struct warn {
  57. /*@reldef@*/ STAILQ_ENTRY(warn) link;
  58. yasm_warn_class wclass;
  59. /*@owned@*/ /*@null@*/ char *wstr;
  60. } warn;
  61. static STAILQ_HEAD(warn_head, warn) yasm_warns;
  62. /* Enabled warnings. See errwarn.h for a list. */
  63. static unsigned long warn_class_enabled;
  64. typedef struct errwarn_data {
  65. /*@reldef@*/ SLIST_ENTRY(errwarn_data) link;
  66. enum { WE_UNKNOWN, WE_ERROR, WE_WARNING, WE_PARSERERROR } type;
  67. unsigned long line;
  68. unsigned long xrefline;
  69. /*@owned@*/ char *msg;
  70. /*@owned@*/ char *xrefmsg;
  71. } errwarn_data;
  72. struct yasm_errwarns {
  73. /*@reldef@*/ SLIST_HEAD(errwarn_head, errwarn_data) errwarns;
  74. /* Total error count */
  75. unsigned int ecount;
  76. /* Total warning count */
  77. unsigned int wcount;
  78. /* Last inserted error/warning. Used to speed up insertions. */
  79. /*@null@*/ errwarn_data *previous_we;
  80. };
  81. /* Static buffer for use by conv_unprint(). */
  82. static char unprint[5];
  83. static const char *
  84. def_gettext_hook(const char *msgid)
  85. {
  86. return msgid;
  87. }
  88. void
  89. yasm_errwarn_initialize(void)
  90. {
  91. /* Default enabled warnings. See errwarn.h for a list. */
  92. warn_class_enabled =
  93. (1UL<<YASM_WARN_GENERAL) | (1UL<<YASM_WARN_UNREC_CHAR) |
  94. (1UL<<YASM_WARN_PREPROC) | (0UL<<YASM_WARN_ORPHAN_LABEL) |
  95. (1UL<<YASM_WARN_UNINIT_CONTENTS) | (0UL<<YASM_WARN_SIZE_OVERRIDE) |
  96. (1UL<<YASM_WARN_IMPLICIT_SIZE_OVERRIDE);
  97. yasm_eclass = YASM_ERROR_NONE;
  98. yasm_estr = NULL;
  99. yasm_exrefline = 0;
  100. yasm_exrefstr = NULL;
  101. STAILQ_INIT(&yasm_warns);
  102. }
  103. void
  104. yasm_errwarn_cleanup(void)
  105. {
  106. yasm_error_clear();
  107. yasm_warn_clear();
  108. }
  109. /* Convert a possibly unprintable character into a printable string, using
  110. * standard cat(1) convention for unprintable characters.
  111. */
  112. char *
  113. yasm__conv_unprint(int ch)
  114. {
  115. int pos = 0;
  116. if (((ch & ~0x7F) != 0) /*!isascii(ch)*/ && !isprint(ch)) {
  117. unprint[pos++] = 'M';
  118. unprint[pos++] = '-';
  119. ch &= toascii(ch);
  120. }
  121. if (iscntrl(ch)) {
  122. unprint[pos++] = '^';
  123. unprint[pos++] = (ch == '\177') ? '?' : ch | 0100;
  124. } else
  125. unprint[pos++] = ch;
  126. unprint[pos] = '\0';
  127. return unprint;
  128. }
  129. /* Report an internal error. Essentially a fatal error with trace info.
  130. * Exit immediately because it's essentially an assert() trap.
  131. */
  132. static void
  133. def_internal_error_(const char *file, unsigned int line, const char *message)
  134. {
  135. fprintf(stderr,
  136. yasm_gettext_hook(N_("INTERNAL ERROR at %s, line %u: %s\n")),
  137. file, line, yasm_gettext_hook(message));
  138. #ifdef HAVE_ABORT
  139. abort();
  140. #else
  141. exit(EXIT_FAILURE);
  142. #endif
  143. }
  144. /* Report a fatal error. These are unrecoverable (such as running out of
  145. * memory), so just exit immediately.
  146. */
  147. static void
  148. def_fatal(const char *fmt, va_list va)
  149. {
  150. fprintf(stderr, "%s: ", yasm_gettext_hook(N_("FATAL")));
  151. vfprintf(stderr, yasm_gettext_hook(fmt), va);
  152. fputc('\n', stderr);
  153. exit(EXIT_FAILURE);
  154. }
  155. /* Create an errwarn structure in the correct linked list location.
  156. * If replace_parser_error is nonzero, overwrites the last error if its
  157. * type is WE_PARSERERROR.
  158. */
  159. static errwarn_data *
  160. errwarn_data_new(yasm_errwarns *errwarns, unsigned long line,
  161. int replace_parser_error)
  162. {
  163. errwarn_data *first, *next, *ins_we, *we;
  164. enum { INS_NONE, INS_HEAD, INS_AFTER } action = INS_NONE;
  165. /* Find the entry with either line=line or the last one with line<line.
  166. * Start with the last entry added to speed the search.
  167. */
  168. ins_we = errwarns->previous_we;
  169. first = SLIST_FIRST(&errwarns->errwarns);
  170. if (!ins_we || !first)
  171. action = INS_HEAD;
  172. while (action == INS_NONE) {
  173. next = SLIST_NEXT(ins_we, link);
  174. if (line < ins_we->line) {
  175. if (ins_we == first)
  176. action = INS_HEAD;
  177. else
  178. ins_we = first;
  179. } else if (!next)
  180. action = INS_AFTER;
  181. else if (line >= ins_we->line && line < next->line)
  182. action = INS_AFTER;
  183. else
  184. ins_we = next;
  185. }
  186. if (replace_parser_error && ins_we && ins_we->type == WE_PARSERERROR) {
  187. /* overwrite last error */
  188. we = ins_we;
  189. } else {
  190. /* add a new error */
  191. we = yasm_xmalloc(sizeof(errwarn_data));
  192. we->type = WE_UNKNOWN;
  193. we->line = line;
  194. we->xrefline = 0;
  195. we->msg = NULL;
  196. we->xrefmsg = NULL;
  197. if (action == INS_HEAD)
  198. SLIST_INSERT_HEAD(&errwarns->errwarns, we, link);
  199. else if (action == INS_AFTER) {
  200. assert(ins_we != NULL);
  201. SLIST_INSERT_AFTER(ins_we, we, link);
  202. } else
  203. yasm_internal_error(N_("Unexpected errwarn insert action"));
  204. }
  205. /* Remember previous err/warn */
  206. errwarns->previous_we = we;
  207. return we;
  208. }
  209. void
  210. yasm_error_clear(void)
  211. {
  212. if (yasm_estr)
  213. yasm_xfree(yasm_estr);
  214. if (yasm_exrefstr)
  215. yasm_xfree(yasm_exrefstr);
  216. yasm_eclass = YASM_ERROR_NONE;
  217. yasm_estr = NULL;
  218. yasm_exrefline = 0;
  219. yasm_exrefstr = NULL;
  220. }
  221. int
  222. yasm_error_matches(yasm_error_class eclass)
  223. {
  224. if (yasm_eclass == YASM_ERROR_NONE)
  225. return eclass == YASM_ERROR_NONE;
  226. if (yasm_eclass == YASM_ERROR_GENERAL)
  227. return eclass == YASM_ERROR_GENERAL;
  228. return (yasm_eclass & eclass) == eclass;
  229. }
  230. void
  231. yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va)
  232. {
  233. if (yasm_eclass != YASM_ERROR_NONE)
  234. return;
  235. yasm_eclass = eclass;
  236. yasm_estr = yasm_xmalloc(MSG_MAXSIZE+1);
  237. #ifdef HAVE_VSNPRINTF
  238. vsnprintf(yasm_estr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
  239. #else
  240. vsprintf(yasm_estr, yasm_gettext_hook(format), va);
  241. #endif
  242. }
  243. void
  244. yasm_error_set(yasm_error_class eclass, const char *format, ...)
  245. {
  246. va_list va;
  247. va_start(va, format);
  248. yasm_error_set_va(eclass, format, va);
  249. va_end(va);
  250. }
  251. void
  252. yasm_error_set_xref_va(unsigned long xrefline, const char *format, va_list va)
  253. {
  254. if (yasm_eclass != YASM_ERROR_NONE)
  255. return;
  256. yasm_exrefline = xrefline;
  257. yasm_exrefstr = yasm_xmalloc(MSG_MAXSIZE+1);
  258. #ifdef HAVE_VSNPRINTF
  259. vsnprintf(yasm_exrefstr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
  260. #else
  261. vsprintf(yasm_exrefstr, yasm_gettext_hook(format), va);
  262. #endif
  263. }
  264. void
  265. yasm_error_set_xref(unsigned long xrefline, const char *format, ...)
  266. {
  267. va_list va;
  268. va_start(va, format);
  269. yasm_error_set_xref_va(xrefline, format, va);
  270. va_end(va);
  271. }
  272. void
  273. yasm_error_fetch(yasm_error_class *eclass, char **str, unsigned long *xrefline,
  274. char **xrefstr)
  275. {
  276. *eclass = yasm_eclass;
  277. *str = yasm_estr;
  278. *xrefline = yasm_exrefline;
  279. *xrefstr = yasm_exrefstr;
  280. yasm_eclass = YASM_ERROR_NONE;
  281. yasm_estr = NULL;
  282. yasm_exrefline = 0;
  283. yasm_exrefstr = NULL;
  284. }
  285. void yasm_warn_clear(void)
  286. {
  287. /* Delete all error/warnings */
  288. while (!STAILQ_EMPTY(&yasm_warns)) {
  289. warn *w = STAILQ_FIRST(&yasm_warns);
  290. if (w->wstr)
  291. yasm_xfree(w->wstr);
  292. STAILQ_REMOVE_HEAD(&yasm_warns, link);
  293. yasm_xfree(w);
  294. }
  295. }
  296. yasm_warn_class
  297. yasm_warn_occurred(void)
  298. {
  299. if (STAILQ_EMPTY(&yasm_warns))
  300. return YASM_WARN_NONE;
  301. return STAILQ_FIRST(&yasm_warns)->wclass;
  302. }
  303. void
  304. yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va)
  305. {
  306. warn *w;
  307. if (!(warn_class_enabled & (1UL<<wclass)))
  308. return; /* warning is part of disabled class */
  309. w = yasm_xmalloc(sizeof(warn));
  310. w->wclass = wclass;
  311. w->wstr = yasm_xmalloc(MSG_MAXSIZE+1);
  312. #ifdef HAVE_VSNPRINTF
  313. vsnprintf(w->wstr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
  314. #else
  315. vsprintf(w->wstr, yasm_gettext_hook(format), va);
  316. #endif
  317. STAILQ_INSERT_TAIL(&yasm_warns, w, link);
  318. }
  319. void
  320. yasm_warn_set(yasm_warn_class wclass, const char *format, ...)
  321. {
  322. va_list va;
  323. va_start(va, format);
  324. yasm_warn_set_va(wclass, format, va);
  325. va_end(va);
  326. }
  327. void
  328. yasm_warn_fetch(yasm_warn_class *wclass, char **str)
  329. {
  330. warn *w = STAILQ_FIRST(&yasm_warns);
  331. if (!w) {
  332. *wclass = YASM_WARN_NONE;
  333. *str = NULL;
  334. return;
  335. }
  336. *wclass = w->wclass;
  337. *str = w->wstr;
  338. STAILQ_REMOVE_HEAD(&yasm_warns, link);
  339. yasm_xfree(w);
  340. }
  341. void
  342. yasm_warn_enable(yasm_warn_class num)
  343. {
  344. warn_class_enabled |= (1UL<<num);
  345. }
  346. void
  347. yasm_warn_disable(yasm_warn_class num)
  348. {
  349. warn_class_enabled &= ~(1UL<<num);
  350. }
  351. void
  352. yasm_warn_disable_all(void)
  353. {
  354. warn_class_enabled = 0;
  355. }
  356. yasm_errwarns *
  357. yasm_errwarns_create(void)
  358. {
  359. yasm_errwarns *errwarns = yasm_xmalloc(sizeof(yasm_errwarns));
  360. SLIST_INIT(&errwarns->errwarns);
  361. errwarns->ecount = 0;
  362. errwarns->wcount = 0;
  363. errwarns->previous_we = NULL;
  364. return errwarns;
  365. }
  366. void
  367. yasm_errwarns_destroy(yasm_errwarns *errwarns)
  368. {
  369. errwarn_data *we;
  370. /* Delete all error/warnings */
  371. while (!SLIST_EMPTY(&errwarns->errwarns)) {
  372. we = SLIST_FIRST(&errwarns->errwarns);
  373. if (we->msg)
  374. yasm_xfree(we->msg);
  375. if (we->xrefmsg)
  376. yasm_xfree(we->xrefmsg);
  377. SLIST_REMOVE_HEAD(&errwarns->errwarns, link);
  378. yasm_xfree(we);
  379. }
  380. yasm_xfree(errwarns);
  381. }
  382. void
  383. yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line)
  384. {
  385. if (yasm_eclass != YASM_ERROR_NONE) {
  386. errwarn_data *we = errwarn_data_new(errwarns, line, 1);
  387. yasm_error_class eclass;
  388. yasm_error_fetch(&eclass, &we->msg, &we->xrefline, &we->xrefmsg);
  389. if (eclass != YASM_ERROR_GENERAL
  390. && (eclass & YASM_ERROR_PARSE) == YASM_ERROR_PARSE)
  391. we->type = WE_PARSERERROR;
  392. else
  393. we->type = WE_ERROR;
  394. errwarns->ecount++;
  395. }
  396. while (!STAILQ_EMPTY(&yasm_warns)) {
  397. errwarn_data *we = errwarn_data_new(errwarns, line, 0);
  398. yasm_warn_class wclass;
  399. yasm_warn_fetch(&wclass, &we->msg);
  400. we->type = WE_WARNING;
  401. errwarns->wcount++;
  402. }
  403. }
  404. unsigned int
  405. yasm_errwarns_num_errors(yasm_errwarns *errwarns, int warning_as_error)
  406. {
  407. if (warning_as_error)
  408. return errwarns->ecount+errwarns->wcount;
  409. else
  410. return errwarns->ecount;
  411. }
  412. void
  413. yasm_errwarns_output_all(yasm_errwarns *errwarns, yasm_linemap *lm,
  414. int warning_as_error,
  415. yasm_print_error_func print_error,
  416. yasm_print_warning_func print_warning)
  417. {
  418. errwarn_data *we;
  419. const char *filename, *xref_filename;
  420. unsigned long line, xref_line;
  421. /* If we're treating warnings as errors, tell the user about it. */
  422. if (warning_as_error && warning_as_error != 2) {
  423. print_error("", 0,
  424. yasm_gettext_hook(N_("warnings being treated as errors")),
  425. NULL, 0, NULL);
  426. warning_as_error = 2;
  427. }
  428. /* Output error/warnings. */
  429. SLIST_FOREACH(we, &errwarns->errwarns, link) {
  430. /* Output error/warning */
  431. yasm_linemap_lookup(lm, we->line, &filename, &line);
  432. if (we->xrefline)
  433. yasm_linemap_lookup(lm, we->xrefline, &xref_filename, &xref_line);
  434. else {
  435. xref_filename = NULL;
  436. xref_line = 0;
  437. }
  438. if (we->type == WE_ERROR || we->type == WE_PARSERERROR)
  439. print_error(filename, line, we->msg, xref_filename, xref_line,
  440. we->xrefmsg);
  441. else
  442. print_warning(filename, line, we->msg);
  443. }
  444. }
  445. void
  446. yasm__fatal(const char *message, ...)
  447. {
  448. va_list va;
  449. va_start(va, message);
  450. yasm_fatal(message, va);
  451. /*@notreached@*/
  452. va_end(va);
  453. }
  454. void
  455. yasm__fatal_missing_input_file(const char *message, const char *filename)
  456. {
  457. fprintf(stderr, "%s: %s %s (%s)\n", yasm_gettext_hook(N_("FATAL")), yasm_gettext_hook(message), strerror(errno), yasm_gettext_hook(filename));
  458. exit(EXIT_FAILURE);
  459. }