0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-11-08 23:27:15 -05:00

error: factor out error functions into separate files

Tidy up a *lot* of code by moving error functions into separate source
files. This required breaking out some of the assembler-only files
into a separate library, as it conflicts with stubs in the
disassembler.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin (Intel)
2025-11-07 14:32:16 -08:00
parent c0e4def0fe
commit f4f7d18c06
15 changed files with 1024 additions and 918 deletions

View File

@@ -135,54 +135,22 @@ NDISASM = disasm/ndisasm.$(O)
PROGOBJ = $(NASM) $(NDISASM)
PROGS = nasm$(X) ndisasm$(X)
# Files dependent on warnings.dat
WARNOBJ = asm/warnings.$(O)
WARNFILES = asm/warnings_c.h include/warnings.h doc/warnings.src
# Objects for the local copy of zlib. The variable ZLIB is set to
# $(ZLIBOBJ) if the internal version of zlib should be used.
ZLIBOBJ = \
zlib/adler32.$(O) \
zlib/crc32.$(O) \
zlib/infback.$(O) \
zlib/inffast.$(O) \
zlib/inflate.$(O) \
zlib/inftrees.$(O) \
zlib/zutil.$(O)
OUTPUTOBJ = \
output/outform.$(O) output/outlib.$(O) \
output/nulldbg.$(O) output/nullout.$(O) \
output/outbin.$(O) output/outaout.$(O) output/outcoff.$(O) \
output/outelf.$(O) \
output/outobj.$(O) output/outas86.$(O) \
output/outdbg.$(O) output/outieee.$(O) output/outmacho.$(O) \
output/codeview.$(O)
# The source files for these objects are scanned for warnings
LIBOBJ_W = \
nasmlib/readnum.$(O) \
\
asm/error.$(O) \
asm/floats.$(O) \
asm/directiv.$(O) \
asm/pragma.$(O) \
asm/assemble.$(O) asm/labels.$(O) asm/parser.$(O) \
asm/preproc.$(O) asm/quote.$(O) \
asm/listing.$(O) asm/eval.$(O) asm/exprlib.$(O) asm/exprdump.$(O) \
asm/stdscan.$(O) \
asm/getbool.$(O) \
asm/strfunc.$(O) \
asm/segalloc.$(O) \
asm/rdstrnum.$(O) \
asm/srcfile.$(O) \
\
$(OUTPUTOBJ)
# The source files for these objects are NOT scanned for warnings;
# normally this will include all generated files.
# It is entirely possible that it may be necessary to move some of these
# files to LIBOBJ_W, notably $(OUTPUTOBJ)
LIBOBJ_NW = \
# Common library objects
LIBOBJ_COM = \
stdlib/snprintf.$(O) stdlib/vsnprintf.$(O) stdlib/strlcpy.$(O) \
stdlib/strnlen.$(O) stdlib/strrchrnul.$(O) \
\
asm/directbl.$(O) \
asm/pptok.$(O) \
asm/tokhash.$(O) \
asm/uncompress.$(O) \
\
macros/macros.$(O) \
\
nasmlib/ver.$(O) \
nasmlib/alloc.$(O) nasmlib/asprintf.$(O) \
nasmlib/crc32b.$(O) nasmlib/crc64.$(O) nasmlib/md5c.$(O) \
@@ -196,35 +164,63 @@ LIBOBJ_NW = \
nasmlib/raa.$(O) nasmlib/saa.$(O) \
nasmlib/strlist.$(O) \
nasmlib/perfhash.$(O) nasmlib/badenum.$(O) \
nasmlib/readnum.$(O) \
\
common/common.$(O) \
common/common.$(O) common/errstubs.$(O) \
\
x86/insnsa.$(O) x86/insnsb.$(O) x86/insnsn.$(O) \
x86/regs.$(O) x86/regvals.$(O) x86/regflags.$(O) \
x86/iflag.$(O) \
\
$(WARNOBJ)
$(ZLIB)
# Files dependent on warnings.dat
WARNOBJ = asm/warnings.$(O)
WARNFILES = asm/warnings_c.h include/warnings.h doc/warnings.src
OUTPUTOBJ = \
output/outform.$(O) output/outlib.$(O) \
output/nulldbg.$(O) output/nullout.$(O) \
output/outbin.$(O) output/outaout.$(O) output/outcoff.$(O) \
output/outelf.$(O) \
output/outobj.$(O) output/outas86.$(O) \
output/outdbg.$(O) output/outieee.$(O) output/outmacho.$(O) \
output/codeview.$(O)
# Assembler-only library objects
LIBOBJ_ASM = \
asm/error.$(O) \
asm/floats.$(O) \
asm/directiv.$(O) \
asm/pragma.$(O) \
asm/assemble.$(O) asm/labels.$(O) asm/parser.$(O) \
asm/preproc.$(O) asm/quote.$(O) \
asm/listing.$(O) asm/eval.$(O) asm/exprlib.$(O) asm/exprdump.$(O) \
asm/stdscan.$(O) \
asm/getbool.$(O) \
asm/strfunc.$(O) \
asm/segalloc.$(O) \
asm/rdstrnum.$(O) \
asm/srcfile.$(O) \
asm/directbl.$(O) \
asm/pptok.$(O) \
asm/tokhash.$(O) \
asm/uncompress.$(O) \
\
macros/macros.$(O) \
\
$(WARNOBJ) \
$(OUTPUTOBJ)
# Objects which are only used for the disassembler
LIBOBJ_DIS = \
disasm/disasm.$(O) disasm/sync.$(O) disasm/prefix.$(O) \
disasm/diserror.$(O) \
\
x86/insnsd.$(O) x86/regdis.$(O)
# Objects for the local copy of zlib. The variable ZLIB is set to
# $(ZLIBOBJ) if the internal version of zlib should be used.
ZLIBOBJ = \
zlib/adler32.$(O) \
zlib/crc32.$(O) \
zlib/infback.$(O) \
zlib/inffast.$(O) \
zlib/inflate.$(O) \
zlib/inftrees.$(O) \
zlib/zutil.$(O)
LIBOBJ = $(LIBOBJ_W) $(LIBOBJ_NW) $(ZLIB)
ALLOBJ_W = $(NASM) $(LIBOBJ_W)
ALLOBJ = $(PROGOBJ) $(LIBOBJ) $(LIBOBJ_DIS)
LIBOBJ = $(LIBOBJ_COM) $(LIBOBJ_ASM) $(LIBOBJ_DIS)
ALLOBJ = $(PROGOBJ) $(LIBOBJ)
SUBDIRS = stdlib nasmlib include config output asm disasm x86 \
common zlib macros misc
XSUBDIRS = nsis win test doc editors
@@ -241,21 +237,27 @@ $(DIRS):
@$(MKDIR_P) $(SUBDIRS) $(XSUBDIRS)
NASMLIB = libnasm.$(A)
DISLIB = libndis.$(A)
ASMLIB = libasm.$(A)
DISLIB = libdis.$(A)
$(NASMLIB): $(LIBOBJ)
$(NASMLIB): $(LIBOBJ_COM)
$(RM_F) $(NASMLIB)
$(AR) cq $(NASMLIB) $(LIBOBJ)
$(AR) cq $(NASMLIB) $(LIBOBJ_COM)
$(RANLIB) $(NASMLIB)
$(ASMLIB): $(LIBOBJ_ASM)
$(RM_F) $(ASMLIB)
$(AR) cq $(ASMLIB) $(LIBOBJ_ASM)
$(RANLIB) $(ASMLIB)
$(DISLIB): $(LIBOBJ_DIS)
$(RM_F) $(DISLIB)
$(AR) cq $(DISLIB) $(LIBOBJ_DIS)
$(RANLIB) $(DISLIB)
nasm$(X): $(NASM) $(MANIFEST) $(NASMLIB)
nasm$(X): $(NASM) $(MANIFEST) $(ASMLIB) $(NASMLIB)
$(CC) $(ALL_LDFLAGS) -o $@ $(NASM) $(MANIFEST) \
$(NASMLIB) $(LIBS)
$(ASMLIB) $(NASMLIB) $(LIBS)
ndisasm$(X): $(NDISASM) $(MANIFEST) $(DISLIB) $(NASMLIB)
$(CC) $(ALL_LDFLAGS) -o $@ $(NDISASM) $(MANIFEST) \

View File

@@ -86,54 +86,22 @@ NDISASM = disasm\ndisasm.obj
PROGOBJ = $(NASM) $(NDISASM)
PROGS = nasm$(X) ndisasm$(X)
# Files dependent on warnings.dat
WARNOBJ = asm\warnings.obj
WARNFILES = asm\warnings_c.h include\warnings.h doc\warnings.src
# Objects for the local copy of zlib. The variable ZLIB is set to
# $(ZLIBOBJ) if the internal version of zlib should be used.
ZLIBOBJ = \
zlib\adler32.obj \
zlib\crc32.obj \
zlib\infback.obj \
zlib\inffast.obj \
zlib\inflate.obj \
zlib\inftrees.obj \
zlib\zutil.obj
OUTPUTOBJ = \
output\outform.obj output\outlib.obj \
output\nulldbg.obj output\nullout.obj \
output\outbin.obj output\outaout.obj output\outcoff.obj \
output\outelf.obj \
output\outobj.obj output\outas86.obj \
output\outdbg.obj output\outieee.obj output\outmacho.obj \
output\codeview.obj
# The source files for these objects are scanned for warnings
LIBOBJ_W = \
nasmlib\readnum.obj \
\
asm\error.obj \
asm\floats.obj \
asm\directiv.obj \
asm\pragma.obj \
asm\assemble.obj asm\labels.obj asm\parser.obj \
asm\preproc.obj asm\quote.obj \
asm\listing.obj asm\eval.obj asm\exprlib.obj asm\exprdump.obj \
asm\stdscan.obj \
asm\getbool.obj \
asm\strfunc.obj \
asm\segalloc.obj \
asm\rdstrnum.obj \
asm\srcfile.obj \
\
$(OUTPUTOBJ)
# The source files for these objects are NOT scanned for warnings;
# normally this will include all generated files.
# It is entirely possible that it may be necessary to move some of these
# files to LIBOBJ_W, notably $(OUTPUTOBJ)
LIBOBJ_NW = \
# Common library objects
LIBOBJ_COM = \
stdlib\snprintf.obj stdlib\vsnprintf.obj stdlib\strlcpy.obj \
stdlib\strnlen.obj stdlib\strrchrnul.obj \
\
asm\directbl.obj \
asm\pptok.obj \
asm\tokhash.obj \
asm\uncompress.obj \
\
macros\macros.obj \
\
nasmlib\ver.obj \
nasmlib\alloc.obj nasmlib\asprintf.obj \
nasmlib\crc32b.obj nasmlib\crc64.obj nasmlib\md5c.obj \
@@ -147,35 +115,63 @@ LIBOBJ_NW = \
nasmlib\raa.obj nasmlib\saa.obj \
nasmlib\strlist.obj \
nasmlib\perfhash.obj nasmlib\badenum.obj \
nasmlib\readnum.obj \
\
common\common.obj \
common\common.obj common\errstubs.obj \
\
x86\insnsa.obj x86\insnsb.obj x86\insnsn.obj \
x86\regs.obj x86\regvals.obj x86\regflags.obj \
x86\iflag.obj \
\
$(WARNOBJ)
$(ZLIB)
# Files dependent on warnings.dat
WARNOBJ = asm\warnings.obj
WARNFILES = asm\warnings_c.h include\warnings.h doc\warnings.src
OUTPUTOBJ = \
output\outform.obj output\outlib.obj \
output\nulldbg.obj output\nullout.obj \
output\outbin.obj output\outaout.obj output\outcoff.obj \
output\outelf.obj \
output\outobj.obj output\outas86.obj \
output\outdbg.obj output\outieee.obj output\outmacho.obj \
output\codeview.obj
# Assembler-only library objects
LIBOBJ_ASM = \
asm\error.obj \
asm\floats.obj \
asm\directiv.obj \
asm\pragma.obj \
asm\assemble.obj asm\labels.obj asm\parser.obj \
asm\preproc.obj asm\quote.obj \
asm\listing.obj asm\eval.obj asm\exprlib.obj asm\exprdump.obj \
asm\stdscan.obj \
asm\getbool.obj \
asm\strfunc.obj \
asm\segalloc.obj \
asm\rdstrnum.obj \
asm\srcfile.obj \
asm\directbl.obj \
asm\pptok.obj \
asm\tokhash.obj \
asm\uncompress.obj \
\
macros\macros.obj \
\
$(WARNOBJ) \
$(OUTPUTOBJ)
# Objects which are only used for the disassembler
LIBOBJ_DIS = \
disasm\disasm.obj disasm\sync.obj disasm\prefix.obj \
disasm\diserror.obj \
\
x86\insnsd.obj x86\regdis.obj
# Objects for the local copy of zlib. The variable ZLIB is set to
# $(ZLIBOBJ) if the internal version of zlib should be used.
ZLIBOBJ = \
zlib\adler32.obj \
zlib\crc32.obj \
zlib\infback.obj \
zlib\inffast.obj \
zlib\inflate.obj \
zlib\inftrees.obj \
zlib\zutil.obj
LIBOBJ = $(LIBOBJ_W) $(LIBOBJ_NW) $(ZLIB)
ALLOBJ_W = $(NASM) $(LIBOBJ_W)
ALLOBJ = $(PROGOBJ) $(LIBOBJ) $(LIBOBJ_DIS)
LIBOBJ = $(LIBOBJ_COM) $(LIBOBJ_ASM) $(LIBOBJ_DIS)
ALLOBJ = $(PROGOBJ) $(LIBOBJ)
SUBDIRS = stdlib nasmlib include config output asm disasm x86 \
common zlib macros misc
XSUBDIRS = nsis win test doc editors
@@ -186,22 +182,26 @@ EDITORS = editors\nasmtok.el editors\nasmtok.json
#-- End File Lists --#
NASMLIB = libnasm.$(A)
NDISLIB = libndis.$(A)
ASMLIB = libasm.$(A)
DISLIB = libdis.$(A)
all: nasm$(X) ndisasm$(X)
nasm$(X): $(NASM) $(MANIFEST) $(NASMLIB)
$(CC) /Fe:$@ $(ALL_CFLAGS) $(NASM) $(NASMLIB) $(LIBS) \
nasm$(X): $(NASM) $(MANIFEST) $(ASMLIB) $(NASMLIB)
$(CC) /Fe:$@ $(ALL_CFLAGS) $(NASM) $(ASMLIB) $(NASMLIB) $(LIBS) \
$(ALL_LDFLAGS)
ndisasm$(X): $(NDISASM) $(MANIFEST) $(NDISLIB) $(NASMLIB)
$(CC) /Fe:$@ $(ALL_CFLAGS) $(NDISASM) $(NDISLIB) $(NASMLIB) $(LIBS) \
ndisasm$(X): $(NDISASM) $(MANIFEST) $(DISLIB) $(NASMLIB)
$(CC) /Fe:$@ $(ALL_CFLAGS) $(NDISASM) $(DISLIB) $(NASMLIB) $(LIBS) \
$(ALL_LDFLAGS)
$(NASMLIB): $(LIBOBJ)
$(NASMLIB): $(LIBOBJ_COM)
$(AR) $(ARFLAGS) /out:$@ $**
$(NDISLIB): $(LIBOBJ_DIS)
$(ASMLIB): $(LIBOBJ_ASM)
$(AR) $(ARFLAGS) /out:$@ $**
$(DISLIB): $(LIBOBJ_DIS)
$(AR) $(ARFLAGS) /out:$@ $**
# These are specific to certain Makefile syntaxes...

View File

@@ -72,54 +72,22 @@ NDISASM = disasm\ndisasm.obj
PROGOBJ = $(NASM) $(NDISASM)
PROGS = nasm$(X) ndisasm$(X)
# Files dependent on warnings.dat
WARNOBJ = asm\warnings.obj
WARNFILES = asm\warnings_c.h include\warnings.h doc\warnings.src
# Objects for the local copy of zlib. The variable ZLIB is set to
# $(ZLIBOBJ) if the internal version of zlib should be used.
ZLIBOBJ = &
zlib\adler32.obj &
zlib\crc32.obj &
zlib\infback.obj &
zlib\inffast.obj &
zlib\inflate.obj &
zlib\inftrees.obj &
zlib\zutil.obj
OUTPUTOBJ = &
output\outform.obj output\outlib.obj &
output\nulldbg.obj output\nullout.obj &
output\outbin.obj output\outaout.obj output\outcoff.obj &
output\outelf.obj &
output\outobj.obj output\outas86.obj &
output\outdbg.obj output\outieee.obj output\outmacho.obj &
output\codeview.obj
# The source files for these objects are scanned for warnings
LIBOBJ_W = &
nasmlib\readnum.obj &
&
asm\error.obj &
asm\floats.obj &
asm\directiv.obj &
asm\pragma.obj &
asm\assemble.obj asm\labels.obj asm\parser.obj &
asm\preproc.obj asm\quote.obj &
asm\listing.obj asm\eval.obj asm\exprlib.obj asm\exprdump.obj &
asm\stdscan.obj &
asm\getbool.obj &
asm\strfunc.obj &
asm\segalloc.obj &
asm\rdstrnum.obj &
asm\srcfile.obj &
&
$(OUTPUTOBJ)
# The source files for these objects are NOT scanned for warnings;
# normally this will include all generated files.
# It is entirely possible that it may be necessary to move some of these
# files to LIBOBJ_W, notably $(OUTPUTOBJ)
LIBOBJ_NW = &
# Common library objects
LIBOBJ_COM = &
stdlib\snprintf.obj stdlib\vsnprintf.obj stdlib\strlcpy.obj &
stdlib\strnlen.obj stdlib\strrchrnul.obj &
&
asm\directbl.obj &
asm\pptok.obj &
asm\tokhash.obj &
asm\uncompress.obj &
&
macros\macros.obj &
&
nasmlib\ver.obj &
nasmlib\alloc.obj nasmlib\asprintf.obj &
nasmlib\crc32b.obj nasmlib\crc64.obj nasmlib\md5c.obj &
@@ -133,35 +101,63 @@ LIBOBJ_NW = &
nasmlib\raa.obj nasmlib\saa.obj &
nasmlib\strlist.obj &
nasmlib\perfhash.obj nasmlib\badenum.obj &
nasmlib\readnum.obj &
&
common\common.obj &
common\common.obj common\errstubs.obj &
&
x86\insnsa.obj x86\insnsb.obj x86\insnsn.obj &
x86\regs.obj x86\regvals.obj x86\regflags.obj &
x86\iflag.obj &
&
$(WARNOBJ)
$(ZLIB)
# Files dependent on warnings.dat
WARNOBJ = asm\warnings.obj
WARNFILES = asm\warnings_c.h include\warnings.h doc\warnings.src
OUTPUTOBJ = &
output\outform.obj output\outlib.obj &
output\nulldbg.obj output\nullout.obj &
output\outbin.obj output\outaout.obj output\outcoff.obj &
output\outelf.obj &
output\outobj.obj output\outas86.obj &
output\outdbg.obj output\outieee.obj output\outmacho.obj &
output\codeview.obj
# Assembler-only library objects
LIBOBJ_ASM = &
asm\error.obj &
asm\floats.obj &
asm\directiv.obj &
asm\pragma.obj &
asm\assemble.obj asm\labels.obj asm\parser.obj &
asm\preproc.obj asm\quote.obj &
asm\listing.obj asm\eval.obj asm\exprlib.obj asm\exprdump.obj &
asm\stdscan.obj &
asm\getbool.obj &
asm\strfunc.obj &
asm\segalloc.obj &
asm\rdstrnum.obj &
asm\srcfile.obj &
asm\directbl.obj &
asm\pptok.obj &
asm\tokhash.obj &
asm\uncompress.obj &
&
macros\macros.obj &
&
$(WARNOBJ) &
$(OUTPUTOBJ)
# Objects which are only used for the disassembler
LIBOBJ_DIS = &
disasm\disasm.obj disasm\sync.obj disasm\prefix.obj &
disasm\diserror.obj &
&
x86\insnsd.obj x86\regdis.obj
# Objects for the local copy of zlib. The variable ZLIB is set to
# $(ZLIBOBJ) if the internal version of zlib should be used.
ZLIBOBJ = &
zlib\adler32.obj &
zlib\crc32.obj &
zlib\infback.obj &
zlib\inffast.obj &
zlib\inflate.obj &
zlib\inftrees.obj &
zlib\zutil.obj
LIBOBJ = $(LIBOBJ_W) $(LIBOBJ_NW) $(ZLIB)
ALLOBJ_W = $(NASM) $(LIBOBJ_W)
ALLOBJ = $(PROGOBJ) $(LIBOBJ) $(LIBOBJ_DIS)
LIBOBJ = $(LIBOBJ_COM) $(LIBOBJ_ASM) $(LIBOBJ_DIS)
ALLOBJ = $(PROGOBJ) $(LIBOBJ)
SUBDIRS = stdlib nasmlib include config output asm disasm x86 &
common zlib macros misc
XSUBDIRS = nsis win test doc editors
@@ -198,18 +194,22 @@ all: perlreq nasm$(X) ndisasm$(X) .SYMBOLIC
# cd rdoff && $(MAKE) all
NASMLIB = nasm.lib
NDISLIB = ndisasm.lib
ASMLIB = asm.lib
DISLIB = dis.lib
nasm$(X): $(NASM) $(NASMLIB)
$(LD) $(LDFLAGS) name nasm$(X) libr {$(NASMLIB) $(LIBS)} file {$(NASM)}
nasm$(X): $(NASM) $(ASMLIB) $(NASMLIB)
$(LD) $(LDFLAGS) name nasm$(X) libr {$(ASMLIB) $(NASMLIB) $(LIBS)} file {$(NASM)}
ndisasm$(X): $(NDISASM) $(NDISLIB) $(NASMLIB)
$(LD) $(LDFLAGS) name ndisasm$(X) libr {$(NDISLIB) $(NASMLIB) $(LIBS)} file {$(NDISASM)}
ndisasm$(X): $(NDISASM) $(DISLIB) $(NASMLIB)
$(LD) $(LDFLAGS) name ndisasm$(X) libr {$(DISLIB) $(NASMLIB) $(LIBS)} file {$(NDISASM)}
nasm.lib: $(LIBOBJ)
wlib -q -b -n $@ $(LIBOBJ)
nasm.lib: $(LIBOBJ_COM)
wlib -q -b -n $@ $(LIBOBJ_COM)
ndisasm.lib: $(LIBOBJ_DIS)
asm.lib: $(LIBOBJ_ASM)
wlib -q -b -n $@ $(LIBOBJ_ASM)
dis.lib: $(LIBOBJ_DIS)
wlib -q -b -n $@ $(LIBOBJ_DIS)
# These are specific to certain Makefile syntaxes (what are they

View File

@@ -8,108 +8,27 @@
#include "compiler.h"
#include "nasmlib.h"
#include "error.h"
#include "listing.h"
#include "srcfile.h"
#include "strlist.h"
unsigned int debug_nasm; /* Debugging messages? */
unsigned int opt_verbose_info; /* Informational messages? */
struct error_format {
const char *beforeline; /* Before line number, if present */
const char *afterline; /* After line number, if present */
const char *beforemsg; /* Before actual message */
};
/* Common function body */
#define nasm_do_error(_sev,_flags) \
do { \
const errflags nde_severity = (_sev); \
const errflags nde_flags = nde_severity | (_flags); \
va_list ap; \
va_start(ap, fmt); \
if (nde_severity >= ERR_CRITICAL) { \
nasm_verror_critical(nde_flags, fmt, ap); \
unreachable(); \
} else { \
nasm_verror(nde_flags, fmt, ap); \
if (nde_severity >= ERR_FATAL) \
unreachable(); \
} \
va_end(ap); \
} while (0)
/*
* This is the generic function to use when the error type is not
* known a priori. For ERR_DEBUG and ERR_INFO the level can be
* included by
*/
void nasm_error(errflags flags, const char *fmt, ...)
{
nasm_do_error(flags & ERR_MASK, flags);
}
#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, note, ERR_NOTE)
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.
*
* This is wrapped in a macro to be able to elide it if the warning is
* disabled, hence the extra underscore.
*/
void nasm_warn_(errflags flags, const char *fmt, ...)
{
nasm_do_error(ERR_WARNING, flags);
}
/*
* nasm_info() and nasm_debug() takes mandatory enabling levels.
*/
void nasm_info_(unsigned int level, const char *fmt, ...)
{
if (info_level(level))
nasm_do_error(ERR_INFO, LEVEL(level));
}
void nasm_debug_(unsigned int level, const char *fmt, ...)
{
if (debug_level(level))
nasm_do_error(ERR_DEBUG, LEVEL(level));
}
/*
* Convenience function for nasm_nonfatal(ERR_HOLD, ...)
*/
void nasm_holderr(const char *fmt, ...)
{
nasm_do_error(ERR_NONFATAL, ERR_NONFATAL|ERR_HOLD);
}
fatal_func nasm_panic_from_macro(const char *func, const char *file, int line)
{
if (!func)
func = "<unknown>";
nasm_panic("internal error in %s at %s:%d\n", func, file, line);
}
fatal_func nasm_assert_failed(const char *msg, const char *func,
const char *file, int line)
{
if (!func)
func = "<unknown>";
nasm_panic("assertion %s failed in %s at %s:%d", msg, func, file, line);
}
enum error_formats {
ERRFMT_GNU,
ERRFMT_MSVC
};
static const struct error_format errfmts[] = {
{ ":", "", ": " }, /* ERRFMT_GNU */
{ "(", ")", " : " } /* ERRFMT_MSVC */
};
static const struct error_format *errfmt = &errfmts[ERRFMT_GNU];
static void usage(void);
/*
* Warning stack management. Note that there is an implicit "push"
@@ -121,6 +40,7 @@ struct warning_stack {
uint8_t state[sizeof warning_state];
};
static struct warning_stack *warning_stack, *warning_state_init;
static struct strlist *warn_list;
/* Push the warning status onto the warning stack */
void push_warnings(void)
@@ -147,16 +67,33 @@ void pop_warnings(void)
}
}
/* Call after the command line is parsed, but before the first pass */
void init_warnings(void)
/* Called after the command line is parsed, but before the first pass */
static void init_warnings(void)
{
push_warnings();
warning_state_init = warning_stack;
}
void error_init(void)
{
erropt.worst = 0;
init_warnings();
}
/* Call after each pass */
void reset_warnings(void)
/* Called before each pass. Buffer warnings if "final" is false. */
void error_pass_start(bool final)
{
nasm_assert(!warn_list);
erropt.worst = 0;
if (!final)
warn_list = strlist_alloc(false);
}
/*
* Called after the completion of each pass. This MUST preserve erropt.worst!
*/
static void reset_warnings(void)
{
struct warning_stack *ws = warning_stack;
@@ -170,6 +107,12 @@ void reset_warnings(void)
memcpy(warning_state, ws->state, sizeof warning_state);
}
void error_pass_end(void)
{
strlist_free(&warn_list);
reset_warnings();
}
/*
* This is called when processing a -w or -W option, or a warning directive.
* Returns ok if the action was successful.
@@ -311,3 +254,500 @@ const char *error_pfx(errflags severity)
return "internal error: ";
}
}
static bool skip_this_pass(errflags severity)
{
errflags type = severity & ERR_MASK;
/*
* See if it's a pass-specific error or warning which should be skipped.
* We can never skip fatal errors as by definition they cannot be
* resumed from.
*/
if (type >= ERR_FATAL)
return false;
/*
* ERR_LISTMSG and ERR_NOTE messages are always skipped; the list
* file receives them anyway as this function is not consulted for
* sending to the list file.
*/
if (type <= ERR_NOTE)
return true;
/*
* This message is not applicable unless it is the last pass we
* are going to execute; this can be either the final
* code-generation pass or the single pass executed in
* preproc-only mode.
*/
return (severity & ERR_PASS2) && !pass_final_or_preproc();
}
/**
* check for suppressed message (usually warnings or notes)
*
* @param severity the severity of the warning or error
* @return true if we should abort error/warning printing
*/
static bool is_suppressed(errflags flags)
{
const errflags severity = flags & ERR_MASK;
const errflags level = WARN_IDX(flags);
if (severity >= ERR_FATAL) {
/* Fatal errors or higher can never be suppressed */
return false;
}
if (flags & erropt.never)
return true;
switch (severity) {
case ERR_WARNING:
if (!(warning_state[level] & WARN_ST_ENABLED))
return true;
break;
case ERR_INFO:
if (!info_level(level))
return true;
break;
case ERR_DEBUG:
if (!debug_level(level))
return true;
break;
default:
break;
}
/* Suppressed by the preprocessor? */
if (!(flags & ERR_PP_LISTMACRO))
return pp_suppress_error(flags);
return false;
}
/**
* Return the true error type (the ERR_MASK part) of the given
* severity, accounting for warnings that may need to be promoted to
* error.
*
* @param severity the severity of the warning or error
* @return true if we should error out
*/
static errflags pure_func true_error_type(errflags severity)
{
const uint8_t warn_is_err = WARN_ST_ENABLED|WARN_ST_ERROR;
int type;
type = severity & ERR_MASK;
if (type == ERR_WARNING) {
/* Promote warning to error? */
uint8_t state = warning_state[WARN_IDX(severity)];
if ((state & warn_is_err) == warn_is_err)
type = ERR_NONFATAL;
}
return type;
}
static const char no_file_name[] = "nasm"; /* What to print if no file name */
/*
* For fatal/critical/panic errors, kill this process.
*
* For FATAL errors doing cleanups, tidying up the list process,
* and so in is acceptable.
*
* For CRITICAL errors, minimize dependencies on memory allocation
* and/or having a system valid state.
*
* For PANIC, if abort_on_panic is set, abort without any other action.
*/
static_fatal_func die_hard(errflags true_type, errflags severity)
{
if (true_type < ERR_PANIC || !erropt.abort_on_panic) {
if (true_type < ERR_CRITICAL) {
/* FATAL shutdown, general cleanup actions are valid */
print_final_report(true);
lfmt->cleanup();
}
fflush(NULL);
close_output(true);
if (severity & ERR_USAGE)
usage();
/* Terminate immediately (exit closes any still open files) */
exit(true_type - ERR_FATAL + 1);
}
/*
* abort() shouldn't ever return, but be paranoid about this,
* plus it helps some compilers clue in to the fact that this
* function can never, ever return.
*/
while (1)
abort();
}
/*
* Returns the struct src_location appropriate for use, after some
* potential filename mangling.
*/
static struct src_location error_where(errflags severity)
{
struct src_location where;
if (severity & ERR_NOFILE) {
where.filename = NULL;
where.lineno = 0;
} else {
where = src_where_error();
if (!where.filename) {
where.filename =
inname && inname[0] ? inname :
outname && outname[0] ? outname :
NULL;
where.lineno = 0;
}
}
return where;
}
/*
* error reporting for critical and panic errors: minimize
* the amount of system dependencies for getting a message out,
* and in particular try to avoid memory allocations.
*/
fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list args)
{
struct src_location where;
errflags true_type = severity & ERR_MASK;
static bool been_here = false;
while (unlikely(been_here))
abort(); /* Recursive critical error... just die */
been_here = true;
erropt.worst = true_type;
where = error_where(severity);
if (!where.filename)
where.filename = no_file_name;
fputs(error_pfx(severity), erropt.file);
fputs(where.filename, erropt.file);
if (where.lineno) {
fprintf(erropt.file, "%s%"PRId32"%s",
errfmt->beforeline, where.lineno, errfmt->afterline);
}
fputs(errfmt->beforemsg, erropt.file);
vfprintf(erropt.file, fmt, args);
fputc('\n', erropt.file);
die_hard(true_type, severity);
unreachable();
}
/**
* Stack of tentative error hold lists.
*/
struct nasm_errtext {
struct nasm_errtext *next;
char *msg; /* Owned by this structure */
struct src_location where; /* Owned by the srcfile system */
errflags severity;
errflags true_type;
int c_errno; /* Saved errno (for ERR_PERROR) */
};
struct nasm_errhold {
struct nasm_errhold *up;
struct nasm_errtext *head, **tail;
};
static struct strlist *warn_list;
static struct nasm_errhold *errhold_stack;
static void nasm_free_error(struct nasm_errtext *et)
{
nasm_free(et->msg);
nasm_free(et);
}
static void nasm_issue_error(struct nasm_errtext *et);
struct nasm_errhold *nasm_error_hold_push(void)
{
struct nasm_errhold *eh;
nasm_new(eh);
eh->up = errhold_stack;
eh->tail = &eh->head;
errhold_stack = eh;
return eh;
}
/* Pop an error hold. Returns the highest severity issued or dropped. */
errflags nasm_error_hold_pop(struct nasm_errhold *eh, bool issue)
{
struct nasm_errtext *et, *etmp;
errflags worst = 0;
/*
* Allow calling with a null argument saying no hold in the first place.
*/
if (!eh)
return worst;
/* This *must* be the current top of the errhold stack */
nasm_assert(eh == errhold_stack);
if (eh->head) {
if (issue) {
if (eh->up) {
/* Commit the current hold list to the previous level */
*eh->up->tail = eh->head;
eh->up->tail = eh->tail;
} else {
/* Issue errors */
list_for_each_safe(et, etmp, eh->head) {
if (et->true_type > worst)
worst = et->true_type;
nasm_issue_error(et);
}
}
} else {
/* Free the list, drop errors */
list_for_each_safe(et, etmp, eh->head) {
if (et->true_type > worst)
worst = et->true_type;
nasm_free_error(et);
}
}
}
errhold_stack = eh->up;
nasm_free(eh);
return worst;
}
/**
* common error reporting
* This is the common back end of the error reporting schemes currently
* implemented. It prints the nature of the warning and then the
* specific error message to erropt.file and may or may not return. It
* doesn't return if the error severity is a "panic" or "debug" type.
*
* @param severity the severity of the warning or error
* @param fmt the printf style format string
*/
void nasm_verror(errflags severity, const char *fmt, va_list args)
{
struct nasm_errtext *et;
int c_errno = errno;
errflags true_type = true_error_type(severity);
if (true_type >= ERR_CRITICAL) {
nasm_verror_critical(severity, fmt, args);
abort();
}
if (is_suppressed(severity))
return;
nasm_new(et);
et->c_errno = c_errno;
et->severity = severity;
et->true_type = true_type;
et->msg = nasm_vasprintf(fmt, args);
et->where = error_where(severity);
if (errhold_stack && true_type <= ERR_NONFATAL) {
/* It is a tentative error */
*errhold_stack->tail = et;
errhold_stack->tail = &et->next;
} else {
nasm_issue_error(et);
}
/*
* Don't do this before then, if we do, we lose messages in the list
* file, as the list file is only generated in the last pass.
*/
if (skip_this_pass(severity))
return;
if (!(severity & (ERR_HERE|ERR_PP_LISTMACRO)))
pp_error_list_macros(severity);
}
/*
* Actually print, list and take action on an error
*/
static void nasm_issue_error(struct nasm_errtext *et)
{
const char *pfx;
char warnsuf[64]; /* Warning suffix */
char linestr[64]; /* Formatted line number if applicable */
const errflags severity = et->severity;
const errflags true_type = et->true_type;
const struct src_location where = et->where;
const char *cerrsep = "";
const char *cerrmsg = "";
bool buffer = true_type < ERR_NONFATAL || (severity & ERR_HOLD);
if (severity & ERR_NO_SEVERITY)
pfx = "";
else
pfx = error_pfx(true_type);
*warnsuf = 0;
if (!(severity & (ERR_HERE|ERR_PP_LISTMACRO))) {
switch (severity & ERR_MASK) {
case ERR_WARNING:
{
const unsigned int level = WARN_IDX(severity);
snprintf(warnsuf, sizeof warnsuf, " [-w+%s%s]",
(true_type >= ERR_NONFATAL) ? "error=" : "",
warning_name[level]);
break;
}
case ERR_DEBUG:
snprintf(warnsuf, sizeof warnsuf, " [--debug=%u]", erropt.debug_nasm);
break;
case ERR_INFO:
snprintf(warnsuf, sizeof warnsuf, " [--info=%u]", erropt.verbose_info);
break;
default:
/* Not WARNING, DEBUG or INFO, not suppressible */
break;
}
if (severity & ERR_PERROR) {
cerrsep = ":";
cerrmsg = strerror(et->c_errno);
}
}
*linestr = 0;
if (where.lineno) {
snprintf(linestr, sizeof linestr, "%s%"PRId32"%s",
errfmt->beforeline, where.lineno, errfmt->afterline);
}
if (!skip_this_pass(severity)) {
const char *file = where.filename ? where.filename : no_file_name;
const char *here = "";
if (severity & ERR_HERE) {
here = where.filename ? " here" : " in an unknown location";
}
if (!warn_list)
buffer = false;
if (buffer) {
/*
* Buffer up warnings and held errors until we either get
* an error or we are on the code-generation pass.
*/
strlist_printf(warn_list, "%s%s%s%s%s%s%s%s%s",
file, linestr, errfmt->beforemsg,
pfx, et->msg, cerrsep, cerrmsg,
here, warnsuf);
} else {
/*
* Actually output an error. If we have buffered
* warnings, and this is a non-warning, output them now.
*/
if (warn_list) {
strlist_write(warn_list, "\n", erropt.file);
strlist_free(&warn_list);
}
fprintf(erropt.file, "%s%s%s%s%s%s%s%s%s\n",
file, linestr, errfmt->beforemsg,
pfx, et->msg, cerrsep, cerrmsg,
here, warnsuf);
}
}
/* Are we recursing from error_list_macros? */
if (severity & ERR_PP_LISTMACRO)
goto done;
/*
* Don't suppress this with skip_this_pass(), or we don't get
* pass1 or preprocessor warnings in the list file
*/
if (severity & ERR_HERE) {
if (where.lineno)
lfmt->error(severity, "%s%s at %s:%"PRId32"%s",
pfx, et->msg, where.filename, where.lineno, warnsuf);
else if (where.filename)
lfmt->error(severity, "%s%s in file %s%s",
pfx, et->msg, where.filename, warnsuf);
else
lfmt->error(severity, "%s%s in an unknown location%s",
pfx, et->msg, warnsuf);
} else {
lfmt->error(severity, "%s%s%s", pfx, et->msg, warnsuf);
}
if (skip_this_pass(severity))
goto done;
if (true_type >= ERR_FATAL) {
die_hard(true_type, severity);
} else if (!buffer) {
if (true_type > erropt.worst)
erropt.worst = true_type;
if (true_type >= ERR_NONFATAL)
erropt.never |= ERR_UNDEAD;
}
done:
nasm_free_error(et);
}
int set_error_format(const char *fmt)
{
if (!nasm_stricmp("vc", fmt) ||
!nasm_stricmp("msvc", fmt) ||
!nasm_stricmp("ms", fmt))
errfmt = &errfmts[ERRFMT_MSVC];
else if (!nasm_stricmp("gnu", fmt) ||
!nasm_stricmp("gcc", fmt))
errfmt = &errfmts[ERRFMT_GNU];
else
return -1;
return 0;
}
static void usage(void)
{
fprintf(erropt.file,
"Usage: %s [-@ response_file] [options...] [--] filename\n"
" For additional help:\n"
" %s -h [run|topics|all|-option]\n",
_progname, _progname);
}
void warn_dollar_hex(void)
{
nasm_warn(WARN_NUMBER_DEPRECATED_HEX,
"$ prefix for hexadecimal is deprecated");
}

View File

@@ -27,6 +27,7 @@
#include "iflag.h"
#include "quote.h"
#include "ver.h"
#include "error.h"
/*
* This is the maximum number of optimization passes to do. If we ever
@@ -45,22 +46,8 @@ const char *_progname;
static void open_and_process_respfile(char *, int);
static void parse_cmdline(int, char **, int);
static void assemble_file(const char *, struct strlist *);
static bool skip_this_pass(errflags severity);
static void usage(void);
static void help(FILE *out, const char *what);
struct error_format {
const char *beforeline; /* Before line number, if present */
const char *afterline; /* After line number, if present */
const char *beforemsg; /* Before actual message */
};
static const struct error_format errfmt_gnu = { ":", "", ": " };
static const struct error_format errfmt_msvc = { "(", ")", " : " };
static const struct error_format *errfmt = &errfmt_gnu;
static struct strlist *warn_list;
static struct nasm_errhold *errhold_stack;
static bool using_debug_info;
static const char *debug_format;
@@ -91,7 +78,6 @@ const struct ofmt *ofmt = &OF_DEFAULT;
const struct ofmt_alias *ofmt_alias = NULL;
const struct dfmt *dfmt;
static FILE *error_file; /* Where to write error messages */
errflags errflags_never = 0; /* Error flags to unconditionally suppress */
FILE *ofile = NULL;
@@ -125,8 +111,10 @@ static const char *depend_target = NULL;
static const char *depend_file = NULL;
struct strlist *depend_list;
static bool want_usage;
static bool terminate_after_phase;
static inline bool terminate_after_phase(void)
{
return erropt.worst >= ERR_NONFATAL;
}
static char *quote_for_pmake(const char *str);
static char *quote_for_wmake(const char *str);
@@ -481,7 +469,7 @@ static void timestamp(void)
int main(int argc, char **argv)
{
/* Do these as early as possible */
error_file = stderr;
erropt.file = stderr;
_progname = argv[0];
if (!_progname || !_progname[0])
_progname = "nasm";
@@ -495,11 +483,10 @@ int main(int argc, char **argv)
include_path = strlist_alloc(true);
reset_global_defaults(0);
_pass_type = PASS_INIT;
_passn = 0;
want_usage = terminate_after_phase = false;
nasm_ctype_init();
src_init();
@@ -516,11 +503,8 @@ int main(int argc, char **argv)
operating_mode = OP_NORMAL;
parse_cmdline(argc, argv, 1);
if (terminate_after_phase) {
if (want_usage)
usage();
if (terminate_after_phase())
return 1;
}
/* At this point we have ofmt and the name of the desired debug format */
if (!using_debug_info) {
@@ -545,14 +529,11 @@ int main(int argc, char **argv)
preproc_init(include_path);
parse_cmdline(argc, argv, 2);
if (terminate_after_phase) {
if (want_usage)
usage();
if (terminate_after_phase())
return 1;
}
/* Save away the default state of warnings */
init_warnings();
error_init();
/* Dependency filename if we are also doing other things */
if (!depend_file && (operating_mode & ~OP_DEPEND)) {
@@ -580,9 +561,13 @@ int main(int argc, char **argv)
if (!depend_target)
depend_target = quote_for_make(outname);
reset_global_defaults(cmd_sb);
if (!(operating_mode & (OP_PREPROCESS|OP_NORMAL))) {
char *line;
error_pass_start(true);
if (depend_missing_ok)
pp_include_path(NULL); /* "assume generated" */
@@ -591,29 +576,28 @@ int main(int argc, char **argv)
while ((line = pp_getline()))
nasm_free(line);
pp_cleanup_pass();
reset_warnings();
error_pass_end();
} else if (operating_mode & OP_PREPROCESS) {
char *line;
const char *file_name = NULL;
char *quoted_file_name = nasm_quote_filename(file_name);
int32_t linnum = 0;
int32_t lineinc = 0;
FILE *out;
if (outname) {
ofile = nasm_open_write(outname, NF_TEXT);
if (!ofile)
nasm_fatal("unable to open output file `%s'", outname);
out = ofile;
nasm_fatalf(ERR_PERROR,
"unable to open output file `%s'", outname);
} else {
ofile = NULL;
out = stdout;
ofile = stdout;
}
location.known = false;
_pass_type = PASS_PREPROC;
pp_reset(inname, PP_PREPROC, depend_list);
error_pass_start(true);
while ((line = pp_getline())) {
/*
@@ -629,7 +613,7 @@ int main(int argc, char **argv)
} else if (lineinc) {
if (linnum + lineinc == where.lineno) {
/* Add one blank line to account for increment */
fputc('\n', out);
fputc('\n', ofile);
linnum += lineinc;
} else if (linnum - lineinc == where.lineno) {
/*
@@ -649,60 +633,49 @@ int main(int argc, char **argv)
continue;
if (linnum != where.lineno) {
fprintf(out, "%%line %"PRId32"%+"PRId32" %s\n",
fprintf(ofile, "%%line %"PRId32"%+"PRId32" %s\n",
where.lineno, lineinc, quoted_file_name);
}
linnum = where.lineno + lineinc;
fputs(line, out);
fputc('\n', out);
fputs(line, ofile);
fputc('\n', ofile);
}
nasm_free(quoted_file_name);
pp_cleanup_pass();
reset_warnings();
if (ofile)
fclose(ofile);
if (ofile && terminate_after_phase && !keep_all)
remove(outname);
ofile = NULL;
error_pass_end();
close_output(terminate_after_phase());
}
if (operating_mode & OP_NORMAL) {
ofile = nasm_open_write(outname, (ofmt->flags & OFMT_TEXT) ? NF_TEXT : NF_BINARY);
if (!ofile)
nasm_fatal("unable to open output file `%s'", outname);
nasm_fatalf(ERR_PERROR, "unable to open output file `%s'", outname);
ofmt->init();
dfmt->init();
assemble_file(inname, depend_list);
if (!terminate_after_phase) {
if (!terminate_after_phase()) {
ofmt->cleanup();
cleanup_labels();
fflush(ofile);
if (ferror(ofile))
nasm_nonfatal("write error on output file `%s'", outname);
nasm_nonfatalf(ERR_PERROR,
"write error on output file `%s'", outname);
}
if (ofile) {
fclose(ofile);
if (terminate_after_phase && !keep_all)
remove(outname);
ofile = NULL;
}
close_output(terminate_after_phase());
}
pp_cleanup_session();
if (depend_list && !terminate_after_phase)
if (depend_list && !terminate_after_phase())
emit_dependencies(depend_list);
if (want_usage)
usage();
raa_free(offsets);
saa_free(forwrefs);
eval_cleanup();
@@ -710,7 +683,7 @@ int main(int argc, char **argv)
src_free();
strlist_free(&include_path);
return terminate_after_phase;
return terminate_after_phase();
}
/*
@@ -984,7 +957,7 @@ static bool process_arg(char *p, char *q, int pass)
break;
case 's':
if (pass == 1)
error_file = stdout;
erropt.file = stdout;
break;
case 'o': /* output file */
@@ -1030,7 +1003,7 @@ static bool process_arg(char *p, char *q, int pass)
case 'v':
case '+':
param++;
opt_verbose_info++;
erropt.verbose_info++;
break;
case 'x':
@@ -1039,7 +1012,8 @@ static bool process_arg(char *p, char *q, int pass)
break;
default:
nasm_fatal("unknown optimization option -O%c\n",
nasm_fatalf(ERR_USAGE,
"unknown optimization option -O%c\n",
*param);
break;
}
@@ -1098,17 +1072,11 @@ static bool process_arg(char *p, char *q, int pass)
case 'X': /* specify error reporting format */
if (pass == 1) {
if (!nasm_stricmp("vc", param) ||
!nasm_stricmp("msvc", param) ||
!nasm_stricmp("ms", param))
errfmt = &errfmt_msvc;
else if (!nasm_stricmp("gnu", param) ||
!nasm_stricmp("gcc", param))
errfmt = &errfmt_gnu;
else
if (set_error_format(param)) {
nasm_fatalf(ERR_USAGE,
"unrecognized error reporting format `%s'",
param);
}
}
break;
@@ -1326,13 +1294,13 @@ static bool process_arg(char *p, char *q, int pass)
break;
case OPT_DEBUG:
if (pass == 1)
debug_nasm = param ?
strtoul(param, NULL, 10) : debug_nasm+1;
erropt.debug_nasm = param ?
strtoul(param, NULL, 10) : erropt.debug_nasm+1;
break;
case OPT_INFO:
if (pass == 1)
opt_verbose_info = param ?
strtoul(param, NULL, 10) : opt_verbose_info+1;
erropt.verbose_info = param ?
strtoul(param, NULL, 10) : erropt.verbose_info+1;
break;
case OPT_REPRODUCIBLE:
reproducible = true;
@@ -1476,7 +1444,7 @@ static void open_and_process_respfile(char *respfile, int pass)
process_respfile(rfile, pass);
fclose(rfile);
} else {
nasm_nonfatalf(ERR_USAGE, "unable to open response file `%s'", respfile);
nasm_fatalf(ERR_PERROR, "unable to open response file `%s'", respfile);
}
}
@@ -1536,13 +1504,15 @@ static void parse_cmdline(int argc, char **argv, int pass)
(outname && !strcmp(inname, outname)) ||
(listname && !strcmp(inname, listname)) ||
(depend_file && !strcmp(inname, depend_file)))
nasm_fatalf(ERR_USAGE, "will not overwrite input file");
nasm_fatal("will not overwrite input file");
if (errname) {
error_file = nasm_open_write(errname, NF_TEXT);
if (!error_file) {
error_file = stderr; /* Revert to default! */
nasm_fatalf(ERR_USAGE, "cannot open file `%s' for error messages", errname);
FILE *error_file = nasm_open_write(errname, NF_TEXT);
if (erropt.file) {
erropt.file = error_file;
} else {
nasm_fatalf(ERR_PERROR, "cannot open file `%s' for error messages",
errname);
}
}
}
@@ -1579,10 +1549,10 @@ static void forward_refs(insn *instruction)
}
}
static void print_pass_report(bool failure)
void print_final_report(bool failure)
{
/* This test is here to reduce the likelihood of a recursive failure */
if (unlikely(opt_verbose_info >= 1)) {
if (unlikely(erropt.verbose_info >= 1)) {
enum pass_type t = pass_type();
if (t >= PASS_FIRST) {
@@ -1624,7 +1594,7 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
remove(listname);
}
while (!terminate_after_phase && !pass_final()) {
while (!terminate_after_phase() && !pass_final()) {
_passn++;
switch (pass_type()) {
case PASS_INIT:
@@ -1639,30 +1609,15 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
break;
}
error_pass_start(pass_final());
global_offset_changed = 0;
/*
* Create a warning buffer list unless we are in
* pass 2 (everything will be emitted immediately in pass 2.)
*/
if (warn_list) {
if (warn_list->nstr || pass_final())
strlist_free(&warn_list);
}
if (!pass_final() && !warn_list)
warn_list = strlist_alloc(false);
/* Suppress ERR_PASS2 unless we are actually in the final pass */
errflags_never = 0;
erropt.never = 0;
if (!pass_final())
errflags_never |= ERR_PASS2;
erropt.never |= ERR_PASS2;
globl.bits = cmd_sb; /* set 'bits' to command line default */
globl.bnd = false;
globl.rel = 0;
globl.reldef = EAF_FS|EAF_GS; /* For now, don't warn on fs:/gs: absolute */
globl.dollarhex = true;
reset_global_defaults(cmd_sb);
cpu = cmd_cpu;
if (listname) {
@@ -1723,9 +1678,6 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
pp_cleanup_pass();
/* We better not be having an error hold still... */
nasm_assert(!errhold_stack);
if (global_offset_changed) {
switch (pass_type()) {
case PASS_OPT:
@@ -1770,473 +1722,27 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
}
}
reset_warnings();
error_pass_end();
}
if (terminate_after_phase || pass_final())
print_pass_report(terminate_after_phase);
print_final_report(terminate_after_phase());
lfmt->cleanup();
strlist_free(&warn_list);
}
static bool skip_this_pass(errflags severity)
void close_output(bool error)
{
errflags type = severity & ERR_MASK;
/*
* See if it's a pass-specific error or warning which should be skipped.
* We can never skip fatal errors as by definition they cannot be
* resumed from.
*/
if (type >= ERR_FATAL)
return false;
/*
* ERR_LISTMSG and ERR_NOTE messages are always skipped; the list
* file receives them anyway as this function is not consulted for
* sending to the list file.
*/
if (type <= ERR_NOTE)
return true;
/*
* This message is not applicable unless it is the last pass we
* are going to execute; this can be either the final
* code-generation pass or the single pass executed in
* preproc-only mode.
*/
return (severity & ERR_PASS2) && !pass_final_or_preproc();
}
/**
* check for suppressed message (usually warnings or notes)
*
* @param severity the severity of the warning or error
* @return true if we should abort error/warning printing
*/
static bool is_suppressed(errflags flags)
{
const errflags severity = flags & ERR_MASK;
const errflags level = WARN_IDX(flags);
if (severity >= ERR_FATAL) {
/* Fatal errors or higher can never be suppressed */
return false;
}
if (flags & errflags_never)
return true;
switch (severity) {
case ERR_WARNING:
if (!(warning_state[level] & WARN_ST_ENABLED))
return true;
break;
case ERR_INFO:
if (!info_level(level))
return true;
break;
case ERR_DEBUG:
if (!debug_level(level))
return true;
break;
default:
break;
}
/* Suppressed by the preprocessor? */
if (!(flags & ERR_PP_LISTMACRO))
return pp_suppress_error(flags);
return false;
}
/**
* Return the true error type (the ERR_MASK part) of the given
* severity, accounting for warnings that may need to be promoted to
* error.
*
* @param severity the severity of the warning or error
* @return true if we should error out
*/
static errflags pure_func true_error_type(errflags severity)
{
const uint8_t warn_is_err = WARN_ST_ENABLED|WARN_ST_ERROR;
int type;
type = severity & ERR_MASK;
if (type == ERR_WARNING) {
/* Promote warning to error? */
uint8_t state = warning_state[WARN_IDX(severity)];
if ((state & warn_is_err) == warn_is_err)
type = ERR_NONFATAL;
}
return type;
}
static const char no_file_name[] = "nasm"; /* What to print if no file name */
/*
* For fatal/critical/panic errors, kill this process.
*
* For FATAL errors doing cleanups, tidying up the list process,
* and so in is acceptable.
*
* For CRITICAL errors, minimize dependencies on memory allocation
* and/or having a system valid state.
*
* For PANIC, if abort_on_panic is set, abort without any other action.
*/
static_fatal_func die_hard(errflags true_type, errflags severity)
{
if (true_type < ERR_PANIC || !abort_on_panic) {
if (true_type < ERR_CRITICAL) {
/* FATAL shutdown, general cleanup actions are valid */
print_pass_report(true);
lfmt->cleanup();
}
fflush(NULL);
if (ofile) {
fclose(ofile);
if (!keep_all)
remove(outname);
ofile = NULL;
}
if (severity & ERR_USAGE)
usage();
/* Terminate immediately (exit closes any still open files) */
exit(true_type - ERR_FATAL + 1);
}
/*
* abort() shouldn't ever return, but be paranoid about this,
* plus it helps some compilers clue in to the fact that this
* function can never, ever return.
*/
while (1)
abort();
}
/*
* Returns the struct src_location appropriate for use, after some
* potential filename mangling.
*/
static struct src_location error_where(errflags severity)
{
struct src_location where;
if (severity & ERR_NOFILE) {
where.filename = NULL;
where.lineno = 0;
} else {
where = src_where_error();
if (!where.filename) {
where.filename =
inname && inname[0] ? inname :
outname && outname[0] ? outname :
NULL;
where.lineno = 0;
}
}
return where;
}
/*
* error reporting for critical and panic errors: minimize
* the amount of system dependencies for getting a message out,
* and in particular try to avoid memory allocations.
*/
fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list args)
{
struct src_location where;
errflags true_type = severity & ERR_MASK;
static bool been_here = false;
while (unlikely(been_here))
abort(); /* Recursive critical error... just die */
been_here = true;
where = error_where(severity);
if (!where.filename)
where.filename = no_file_name;
fputs(error_pfx(severity), error_file);
fputs(where.filename, error_file);
if (where.lineno) {
fprintf(error_file, "%s%"PRId32"%s",
errfmt->beforeline, where.lineno, errfmt->afterline);
}
fputs(errfmt->beforemsg, error_file);
vfprintf(error_file, fmt, args);
fputc('\n', error_file);
die_hard(true_type, severity);
unreachable();
}
/**
* Stack of tentative error hold lists.
*/
struct nasm_errtext {
struct nasm_errtext *next;
char *msg; /* Owned by this structure */
struct src_location where; /* Owned by the srcfile system */
errflags severity;
errflags true_type;
};
struct nasm_errhold {
struct nasm_errhold *up;
struct nasm_errtext *head, **tail;
};
static void nasm_free_error(struct nasm_errtext *et)
{
nasm_free(et->msg);
nasm_free(et);
}
static void nasm_issue_error(struct nasm_errtext *et);
struct nasm_errhold *nasm_error_hold_push(void)
{
struct nasm_errhold *eh;
nasm_new(eh);
eh->up = errhold_stack;
eh->tail = &eh->head;
errhold_stack = eh;
return eh;
}
/* Pop an error hold. Returns the highest severity issued or dropped. */
errflags nasm_error_hold_pop(struct nasm_errhold *eh, bool issue)
{
struct nasm_errtext *et, *etmp;
errflags worst = 0;
/*
* Allow calling with a null argument saying no hold in the first place.
*/
if (!eh)
return worst;
/* This *must* be the current top of the errhold stack */
nasm_assert(eh == errhold_stack);
if (eh->head) {
if (issue) {
if (eh->up) {
/* Commit the current hold list to the previous level */
*eh->up->tail = eh->head;
eh->up->tail = eh->tail;
} else {
/* Issue errors */
list_for_each_safe(et, etmp, eh->head) {
if (et->true_type > worst)
worst = et->true_type;
nasm_issue_error(et);
}
}
} else {
/* Free the list, drop errors */
list_for_each_safe(et, etmp, eh->head) {
if (et->true_type > worst)
worst = et->true_type;
nasm_free_error(et);
}
}
}
errhold_stack = eh->up;
nasm_free(eh);
return worst;
}
/**
* common error reporting
* This is the common back end of the error reporting schemes currently
* implemented. It prints the nature of the warning and then the
* specific error message to error_file and may or may not return. It
* doesn't return if the error severity is a "panic" or "debug" type.
*
* @param severity the severity of the warning or error
* @param fmt the printf style format string
*/
void nasm_verror(errflags severity, const char *fmt, va_list args)
{
struct nasm_errtext *et;
errflags true_type = true_error_type(severity);
if (true_type >= ERR_CRITICAL) {
nasm_verror_critical(severity, fmt, args);
abort();
}
if (is_suppressed(severity))
if (!ofile)
return;
nasm_new(et);
et->severity = severity;
et->true_type = true_type;
et->msg = nasm_vasprintf(fmt, args);
et->where = error_where(severity);
if (errhold_stack && true_type <= ERR_NONFATAL) {
/* It is a tentative error */
*errhold_stack->tail = et;
errhold_stack->tail = &et->next;
if (ofile == stdout || ofile == stdin) {
fflush(ofile);
} else {
nasm_issue_error(et);
fclose(ofile);
if (error && !keep_all)
remove(outname);
}
/*
* Don't do this before then, if we do, we lose messages in the list
* file, as the list file is only generated in the last pass.
*/
if (skip_this_pass(severity))
return;
if (!(severity & (ERR_HERE|ERR_PP_LISTMACRO)))
pp_error_list_macros(severity);
}
/*
* Actually print, list and take action on an error
*/
static void nasm_issue_error(struct nasm_errtext *et)
{
const char *pfx;
char warnsuf[64]; /* Warning suffix */
char linestr[64]; /* Formatted line number if applicable */
const errflags severity = et->severity;
const errflags true_type = et->true_type;
const struct src_location where = et->where;
bool buffer = true_type < ERR_NONFATAL || (severity & ERR_HOLD);
if (severity & ERR_NO_SEVERITY)
pfx = "";
else
pfx = error_pfx(true_type);
*warnsuf = 0;
if (!(severity & (ERR_HERE|ERR_PP_LISTMACRO))) {
const unsigned int level = WARN_IDX(severity);
switch (severity & ERR_MASK) {
case ERR_WARNING:
snprintf(warnsuf, sizeof warnsuf, " [-w+%s%s]",
(true_type >= ERR_NONFATAL) ? "error=" : "",
warning_name[level]);
break;
case ERR_DEBUG:
snprintf(warnsuf, sizeof warnsuf, " [--debug=%u]", debug_nasm);
break;
case ERR_INFO:
snprintf(warnsuf, sizeof warnsuf, " [--info=%u]", opt_verbose_info);
break;
default:
/* Not WARNING, DEBUG or INFO, not suppressible */
break;
}
}
*linestr = 0;
if (where.lineno) {
snprintf(linestr, sizeof linestr, "%s%"PRId32"%s",
errfmt->beforeline, where.lineno, errfmt->afterline);
}
if (!skip_this_pass(severity)) {
const char *file = where.filename ? where.filename : no_file_name;
const char *here = "";
if (severity & ERR_HERE) {
here = where.filename ? " here" : " in an unknown location";
}
if (!warn_list)
buffer = false;
if (buffer) {
/*
* Buffer up warnings and held errors until we either get
* an error or we are on the code-generation pass.
*/
strlist_printf(warn_list, "%s%s%s%s%s%s%s",
file, linestr, errfmt->beforemsg,
pfx, et->msg, here, warnsuf);
} else {
/*
* Actually output an error. If we have buffered
* warnings, and this is a non-warning, output them now.
*/
if (warn_list) {
strlist_write(warn_list, "\n", error_file);
strlist_free(&warn_list);
}
fprintf(error_file, "%s%s%s%s%s%s%s\n",
file, linestr, errfmt->beforemsg,
pfx, et->msg, here, warnsuf);
}
}
/* Are we recursing from error_list_macros? */
if (severity & ERR_PP_LISTMACRO)
goto done;
/*
* Don't suppress this with skip_this_pass(), or we don't get
* pass1 or preprocessor warnings in the list file
*/
if (severity & ERR_HERE) {
if (where.lineno)
lfmt->error(severity, "%s%s at %s:%"PRId32"%s",
pfx, et->msg, where.filename, where.lineno, warnsuf);
else if (where.filename)
lfmt->error(severity, "%s%s in file %s%s",
pfx, et->msg, where.filename, warnsuf);
else
lfmt->error(severity, "%s%s in an unknown location%s",
pfx, et->msg, warnsuf);
} else {
lfmt->error(severity, "%s%s%s", pfx, et->msg, warnsuf);
}
if (skip_this_pass(severity))
goto done;
if (true_type >= ERR_FATAL) {
die_hard(true_type, severity);
} else if (true_type >= ERR_NONFATAL && !buffer) {
terminate_after_phase = true;
errflags_never |= ERR_UNDEAD;
}
done:
nasm_free_error(et);
}
static void usage(void)
{
fprintf(error_file,
"Usage: %s [-@ response_file] [options...] [--] filename\n"
" For additional help:\n"
" %s -h [run|topics|all|-option]\n",
_progname, _progname);
ofile = NULL;
}
enum help_with {

View File

@@ -199,6 +199,7 @@ if ($what eq 'c') {
print $out " const char *name;\n";
print $out " enum warn_index warning;\n";
print $out "};\n\n";
printf $out "#define NUM_WARNINGS %d\n", $#warn_noall + 2;
printf $out "#define NUM_WARNING_ALIAS %d\n", scalar(keys %aliases);
printf $out "extern const char * const warning_name[%d];\n",
@@ -206,10 +207,8 @@ if ($what eq 'c') {
printf $out "extern const char * const warning_help[%d];\n",
$#warnings + 2;
print $out "extern const struct warning_alias warning_alias[NUM_WARNING_ALIAS];\n";
printf $out "extern const uint8_t warning_default[%d];\n",
$#warn_noall + 2;
printf $out "extern uint8_t warning_state[%d];\n",
$#warn_noall + 2;
printf $out "extern const uint8_t warning_default[NUM_WARNINGS];\n",
printf $out "extern uint8_t warning_state[NUM_WARNINGS];\n",
print $out "\n#endif /* $guard */\n";
} elsif ($what eq 'doc') {
my %wsec = ('on' => [], 'off' => [], 'err' => [],

View File

@@ -15,6 +15,15 @@
*/
struct globalopt globl;
void reset_global_defaults(int bits)
{
globl.bits = bits;
globl.bnd = false;
globl.rel = 0;
globl.reldef = EAF_FS|EAF_GS;
globl.dollarhex = true;
}
/*
* Name of a register token, if applicable; otherwise NULL
*/

109
common/errstubs.c Normal file
View File

@@ -0,0 +1,109 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2025 The NASM Authors - All Rights Reserved */
#include "compiler.h"
#include "nasmlib.h"
#include "error.h"
struct errinfo erropt;
/* Common function body */
#define nasm_do_error(_sev,_flags) \
do { \
const errflags nde_severity = (_sev); \
const errflags nde_flags = nde_severity | (_flags); \
va_list ap; \
va_start(ap, fmt); \
if (nde_severity >= ERR_CRITICAL) { \
nasm_verror_critical(nde_flags, fmt, ap); \
unreachable(); \
} else { \
nasm_verror(nde_flags, fmt, ap); \
if (nde_severity >= ERR_FATAL) \
unreachable(); \
} \
va_end(ap); \
} while (0)
/*
* This is the generic function to use when the error type is not
* known a priori. For ERR_DEBUG and ERR_INFO the level can be
* included by
*/
void nasm_error(errflags flags, const char *fmt, ...)
{
nasm_do_error(flags & ERR_MASK, flags);
}
#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, note, ERR_NOTE)
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.
*
* This is wrapped in a macro to be able to elide it if the warning is
* disabled, hence the extra underscore.
*/
void nasm_warn_(errflags flags, const char *fmt, ...)
{
nasm_do_error(ERR_WARNING, flags);
}
/*
* nasm_info() and nasm_debug() takes mandatory enabling levels.
*/
void nasm_info_(unsigned int level, const char *fmt, ...)
{
if (info_level(level))
nasm_do_error(ERR_INFO, LEVEL(level));
}
void nasm_debug_(unsigned int level, const char *fmt, ...)
{
if (debug_level(level))
nasm_do_error(ERR_DEBUG, LEVEL(level));
}
/*
* Convenience function for nasm_nonfatal(ERR_HOLD, ...)
*/
void nasm_holderr(const char *fmt, ...)
{
nasm_do_error(ERR_NONFATAL, ERR_NONFATAL|ERR_HOLD);
}
/*
* panic() and nasm_assert()
*/
fatal_func nasm_panic_from_macro(const char *func, const char *file, int line)
{
if (!func)
func = "<unknown>";
nasm_panic("internal error in %s at %s:%d\n", func, file, line);
}
fatal_func nasm_assert_failed(const char *msg, const char *func,
const char *file, int line)
{
if (!func)
func = "<unknown>";
nasm_panic("assertion %s failed in %s at %s:%d", msg, func, file, line);
}

View File

@@ -87,4 +87,8 @@ const uint8_t *parse_prefixes(struct prefix_info *pf, const uint8_t *data,
_op; \
} while (0)
/* Error module */
void usage(void);
#endif

46
disasm/diserror.c Normal file
View File

@@ -0,0 +1,46 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2025 The NASM Authors - All Rights Reserved */
/*
* diserror.c - stubs for the error functions for the disassembler
*/
#include "compiler.h"
#include "error.h"
#include "disasm.h"
void usage(void)
{
const char help[] =
"usage: ndisasm [-aihlruvw] [-b bits] [-o origin] [-s sync...]\n"
" [-e bytes] [-k start,bytes] [-p vendor] file\n"
" -a or -i activates auto (intelligent) sync\n"
" -b 16, -b 32 or -b 64 sets the processor mode\n"
" -u same as -b 32\n"
" -l same as -b 64\n"
" -w wide output (avoids continuation lines)\n"
" -h displays this text\n"
" -r or -v displays the version number\n"
" -e skips <bytes> bytes of header\n"
" -k avoids disassembling <bytes> bytes from position <start>\n"
" -p selects the preferred vendor instruction set (intel, amd, cyrix, idt)\n";
fputs(help, stderr);
}
void nasm_verror(errflags severity, const char *fmt, va_list val)
{
severity &= ERR_MASK;
vfprintf(stderr, fmt, val);
if (severity >= ERR_FATAL)
exit(severity - ERR_FATAL + 1);
}
fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list val)
{
nasm_verror(severity, fmt, val);
abort();
}
uint8_t warning_state[NUM_WARNINGS];

View File

@@ -18,42 +18,13 @@
#include "sync.h"
#include "disasm.h"
static int bpl = 8; /* bytes per line of hex dump */
const char *_progname;
static const char *help =
"usage: ndisasm [-aihlruvw] [-b bits] [-o origin] [-s sync...]\n"
" [-e bytes] [-k start,bytes] [-p vendor] file\n"
" -a or -i activates auto (intelligent) sync\n"
" -b 16, -b 32 or -b 64 sets the processor mode\n"
" -u same as -b 32\n"
" -l same as -b 64\n"
" -w wide output (avoids continuation lines)\n"
" -h displays this text\n"
" -r or -v displays the version number\n"
" -e skips <bytes> bytes of header\n"
" -k avoids disassembling <bytes> bytes from position <start>\n"
" -p selects the preferred vendor instruction set (intel, amd, cyrix, idt)\n";
static int bpl = 8; /* bytes per line of hex dump */
static void output_ins(uint64_t, const uint8_t *, int, const char *);
static void skip(uint32_t dist, FILE * fp);
void nasm_verror(errflags severity, const char *fmt, va_list val)
{
severity &= ERR_MASK;
vfprintf(stderr, fmt, val);
if (severity >= ERR_FATAL)
exit(severity - ERR_FATAL + 1);
}
fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list val)
{
nasm_verror(severity, fmt, val);
abort();
}
errflags errflags_never = 0;
int main(int argc, char **argv)
{
uint8_t buffer[INSN_MAX * 2], *p;
@@ -72,6 +43,9 @@ int main(int argc, char **argv)
int64_t offset;
FILE *fp;
_progname = argv[0];
reset_global_defaults(0);
nasm_ctype_init();
iflag_clear_all(&prefer);
@@ -90,7 +64,7 @@ int main(int argc, char **argv)
p++;
break;
case 'h':
fputs(help, stderr);
usage();
return 0;
case 'r':
case 'v':
@@ -253,8 +227,8 @@ int main(int argc, char **argv)
}
if (!filename) {
fprintf(stderr, help, pname);
return 0;
usage();
return 1;
}
if (strcmp(filename, "-")) {
@@ -269,6 +243,8 @@ int main(int argc, char **argv)
fp = stdin;
}
reset_global_defaults(bits);
if (initskip > 0)
skip(initskip, fp);

View File

@@ -477,4 +477,7 @@ static inline unsigned int watcom_switch_hack(uint64_t x)
# endif
#endif
/* This should be set from main() */
extern const char *_progname;
#endif /* NASM_COMPILER_H */

View File

@@ -90,6 +90,7 @@ const char *error_pfx(errflags severity);
#define ERR_PP_PRECOND 0x00000400 /* for preprocessor use */
#define ERR_PP_LISTMACRO 0x00000800 /* from pp_error_list_macros() */
#define ERR_HOLD 0x00001000 /* this error/warning can be held */
#define ERR_PERROR 0x00002000 /* append strerror(errno) */
/*
* These codes define specific types of suppressible warning.
@@ -114,14 +115,28 @@ const char *error_pfx(errflags severity);
#define WARN_INIT_ON WARN_ST_ENABLED
#define WARN_INIT_ERR (WARN_ST_ENABLED|WARN_ST_ERROR)
/* Options and status to/from the error module */
struct errinfo {
FILE *file; /* Error output file pointer */
errflags worst; /* Worst severity class encountered */
errflags never; /* Error flags to unconditionally suppress */
unsigned int debug_nasm; /* Debug message level */
unsigned int verbose_info; /* Info message level */
bool abort_on_panic; /* Call abort() on ERR_PANIC */
};
extern struct errinfo erropt;
int set_error_format(const char *fmt);
void error_init(void);
void error_pass_start(bool final);
void error_pass_end(void);
/* Process a warning option or directive */
bool set_warning_status(const char *value);
/* Warning stack management */
void push_warnings(void);
void pop_warnings(void);
void init_warnings(void);
void reset_warnings(void);
/*
* Tentative error hold for warnings/errors indicated with ERR_HOLD.
@@ -147,10 +162,9 @@ errflags nasm_error_hold_pop(errhold hold, bool issue);
#include "warnings.h"
/* True if a warning is enabled, either as a warning or an error */
extern errflags errflags_never;
static inline bool warn_active(errflags warn)
{
if (warn & errflags_never)
if (warn & erropt.never)
return false;
return !!(warning_state[WARN_IDX(warn)] & WARN_ST_ENABLED);
@@ -168,21 +182,19 @@ static inline bool warn_active(errflags warn)
#endif
/* Debug level checks */
extern unsigned int debug_nasm;
static inline bool debug_level(unsigned int level)
{
if (is_constant(level) && level > MAX_DEBUG)
return false;
return unlikely(level <= debug_nasm);
return unlikely(level <= erropt.debug_nasm);
}
/* Info level checks */
extern unsigned int opt_verbose_info;
static inline bool info_level(unsigned int level)
{
if (is_constant(level) && level > MAX_INFO)
return false;
return unlikely(level <= opt_verbose_info);
return unlikely(level <= erropt.verbose_info);
}
#ifdef HAVE_VARIADIC_MACROS
@@ -230,5 +242,11 @@ static inline bool info_level(unsigned int level)
#endif
/* Callbacks from the error module */
void print_final_report(bool failure);
void close_output(bool failure);
bool pp_suppress_error(errflags flags);
void pp_error_list_macros(errflags flags);
#endif /* NASM_ERROR_H */

View File

@@ -1569,6 +1569,7 @@ struct globalopt {
bool dollarhex; /* $-prefixed hexadecimal numbers? */
};
extern struct globalopt globl;
void reset_global_defaults(int bits);
extern const char *inname; /* primary input filename */
extern const char *outname; /* output filename */

View File

@@ -8,19 +8,12 @@
#include "compiler.h"
#include "nctype.h"
#include "nasmlib.h"
#include "nasm.h"
#include "error.h"
#include "nasm.h" /* For globl.dollarhex */
#define lib_isnumchar(c) (nasm_isalnum(c) || (c) == '$' || (c) == '_')
void warn_dollar_hex(void)
{
nasm_warn(WARN_NUMBER_DEPRECATED_HEX,
"$ prefix for hexadecimal is deprecated");
}
int64_t readnum(const char *str, bool *error)
{
const char *r = str, *q;