| /* ----------------------------------------------------------------------- * |
| * |
| * Copyright 1996-2019 The NASM Authors - All Rights Reserved |
| * See the file AUTHORS included with the NASM distribution for |
| * the specific copyright holders. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following |
| * conditions are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * 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 COPYRIGHT HOLDERS AND |
| * 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 COPYRIGHT OWNER OR |
| * 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. |
| * |
| * ----------------------------------------------------------------------- */ |
| |
| /* |
| * error.c - error message handling routines for the assembler |
| */ |
| |
| #include "compiler.h" |
| |
| |
| #include "nasmlib.h" |
| #include "error.h" |
| |
| /* Common function body */ |
| #define nasm_do_error(_sev,_flags) \ |
| va_list ap; \ |
| va_start(ap, fmt); \ |
| if ((_sev) >= ERR_CRITICAL) \ |
| nasm_verror_critical((_sev)|(_flags), fmt, ap); \ |
| else \ |
| nasm_verror((_sev)|(_flags), fmt, ap); \ |
| va_end(ap); \ |
| if ((_sev) >= ERR_FATAL) \ |
| abort(); |
| |
| |
| void nasm_error(errflags severity, const char *fmt, ...) |
| { |
| nasm_do_error(severity & ERR_MASK, severity & ~ERR_MASK); |
| } |
| |
| #define nasm_err_helpers(_type, _name, _sev) \ |
| _type nasm_ ## _name ## f (errflags flags, const char *fmt, ...) \ |
| { \ |
| nasm_do_error(_sev, flags); \ |
| } \ |
| _type nasm_ ## _name (const char *fmt, ...) \ |
| { \ |
| nasm_do_error(_sev, 0); \ |
| } |
| |
| nasm_err_helpers(void, listmsg, ERR_LISTMSG) |
| nasm_err_helpers(void, debug, ERR_DEBUG) |
| nasm_err_helpers(void, info, ERR_INFO) |
| nasm_err_helpers(void, nonfatal, ERR_NONFATAL) |
| nasm_err_helpers(fatal_func, fatal, ERR_FATAL) |
| nasm_err_helpers(fatal_func, critical, ERR_CRITICAL) |
| nasm_err_helpers(fatal_func, panic, ERR_PANIC) |
| |
| /* |
| * Strongly discourage warnings without level by require flags on warnings. |
| * This means nasm_warn() is the equivalent of the -f variants of the |
| * other ones. |
| */ |
| void nasm_warn(errflags flags, const char *fmt, ...) |
| { |
| nasm_do_error(ERR_WARNING, flags); |
| } |
| |
| fatal_func nasm_panic_from_macro(const char *file, int line) |
| { |
| nasm_panic("internal error at %s:%d\n", file, line); |
| } |
| |
| fatal_func nasm_assert_failed(const char *file, int line, const char *msg) |
| { |
| nasm_panic("assertion %s failed at %s:%d", msg, file, line); |
| } |
| |
| |
| /* |
| * Warning stack management. Note that there is an implicit "push" |
| * after the command line has been parsed, but this particular push |
| * cannot be popped. |
| */ |
| struct warning_stack { |
| struct warning_stack *next; |
| uint8_t state[sizeof warning_state]; |
| }; |
| static struct warning_stack *warning_stack, *warning_state_init; |
| |
| /* Push the warning status onto the warning stack */ |
| void push_warnings(void) |
| { |
| struct warning_stack *ws; |
| |
| ws = nasm_malloc(sizeof *ws); |
| memcpy(ws->state, warning_state, sizeof warning_state); |
| ws->next = warning_stack; |
| warning_stack = ws; |
| } |
| |
| /* Pop the warning status off the warning stack */ |
| void pop_warnings(void) |
| { |
| struct warning_stack *ws = warning_stack; |
| |
| memcpy(warning_state, ws->state, sizeof warning_state); |
| if (!ws->next) { |
| /*! |
| *!warn-stack-empty [on] warning stack empty |
| *! a [WARNING POP] directive was executed when |
| *! the warning stack is empty. This is treated |
| *! as a [WARNING *all] directive. |
| */ |
| nasm_warn(WARN_WARN_STACK_EMPTY, "warning stack empty"); |
| } else { |
| warning_stack = ws->next; |
| nasm_free(ws); |
| } |
| } |
| |
| /* Call after the command line is parsed, but before the first pass */ |
| void init_warnings(void) |
| { |
| push_warnings(); |
| warning_state_init = warning_stack; |
| } |
| |
| |
| /* Call after each pass */ |
| void reset_warnings(void) |
| { |
| struct warning_stack *ws = warning_stack; |
| |
| /* Unwind the warning stack. We do NOT delete the last entry! */ |
| while (ws->next) { |
| struct warning_stack *wst = ws; |
| ws = ws->next; |
| nasm_free(wst); |
| } |
| warning_stack = ws; |
| memcpy(warning_state, ws->state, sizeof warning_state); |
| } |
| |
| /* |
| * This is called when processing a -w or -W option, or a warning directive. |
| * Returns on if if the action was successful. |
| * |
| * Special pseudo-warnings: |
| * |
| *!other [on] any warning not specifially mentioned above |
| *! specifies any warning not included in any specific warning class. |
| * |
| *!all [all] all possible warnings |
| *! is an group alias for \e{all} warning classes. Thus, \c{-w+all} |
| *! enables all available warnings, and \c{-w-all} disables warnings |
| *! entirely (since NASM 2.13). |
| */ |
| bool set_warning_status(const char *value) |
| { |
| enum warn_action { WID_OFF, WID_ON, WID_RESET }; |
| enum warn_action action; |
| const struct warning_alias *wa; |
| size_t vlen; |
| bool ok = false; |
| uint8_t mask; |
| |
| value = nasm_skip_spaces(value); |
| |
| switch (*value) { |
| case '-': |
| action = WID_OFF; |
| value++; |
| break; |
| case '+': |
| action = WID_ON; |
| value++; |
| break; |
| case '*': |
| action = WID_RESET; |
| value++; |
| break; |
| case 'N': |
| case 'n': |
| if (!nasm_strnicmp(value, "no-", 3)) { |
| action = WID_OFF; |
| value += 3; |
| break; |
| } else if (!nasm_stricmp(value, "none")) { |
| action = WID_OFF; |
| value = NULL; |
| break; |
| } |
| /* else fall through */ |
| default: |
| action = WID_ON; |
| break; |
| } |
| |
| mask = WARN_ST_ENABLED; |
| |
| if (value && !nasm_strnicmp(value, "error", 5)) { |
| switch (value[5]) { |
| case '=': |
| mask = WARN_ST_ERROR; |
| value += 6; |
| break; |
| case '\0': |
| mask = WARN_ST_ERROR; |
| value = NULL; |
| break; |
| default: |
| /* Just an accidental prefix? */ |
| break; |
| } |
| } |
| |
| if (value && !nasm_stricmp(value, "all")) |
| value = NULL; |
| |
| vlen = value ? strlen(value) : 0; |
| |
| /* |
| * This is inefficient, but it shouldn't matter. |
| * Note: warning_alias[0] is "all". |
| */ |
| for (wa = warning_alias+1; |
| wa < &warning_alias[NUM_WARNING_ALIAS]; wa++) { |
| enum warn_index i = wa->warning; |
| |
| if (value) { |
| char sep; |
| |
| if (nasm_strnicmp(value, wa->name, vlen)) |
| continue; /* Not a prefix */ |
| |
| sep = wa->name[vlen]; |
| if (sep != '\0' && sep != '-') |
| continue; /* Not a valid prefix */ |
| } |
| |
| ok = true; /* At least one action taken */ |
| switch (action) { |
| case WID_OFF: |
| warning_state[i] &= ~mask; |
| break; |
| case WID_ON: |
| warning_state[i] |= mask; |
| break; |
| case WID_RESET: |
| warning_state[i] &= ~mask; |
| warning_state[i] |= warning_state_init->state[i] & mask; |
| break; |
| } |
| } |
| |
| if (!ok && value) { |
| /*! |
| *!unknown-warning [off] unknown warning in -W/-w or warning directive |
| *! warns about a \c{-w} or \c{-W} option or a \c{[WARNING]} directive |
| *! that contains an unknown warning name or is otherwise not possible to process. |
| */ |
| nasm_warn(WARN_UNKNOWN_WARNING, "unknown warning name: %s", value); |
| } |
| |
| return ok; |
| } |