diff --git a/Makefile.in b/Makefile.in index 3b4b595cf..96e4363c9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -104,7 +104,7 @@ PROGOBJ = $(NASM) $(NDISASM) PROGS = nasm$(X) ndisasm$(X) LIBOBJ_NW = stdlib/snprintf.$(O) stdlib/vsnprintf.$(O) stdlib/strlcpy.$(O) \ - stdlib/strnlen.$(O) stdlib/strrchrnul.$(O) \ + stdlib/strnlen.$(O) stdlib/strrchrnul.$(O) stdlib/strlcat.$(O) \ \ nasmlib/ver.$(O) \ nasmlib/alloc.$(O) nasmlib/asprintf.$(O) nasmlib/errfile.$(O) \ diff --git a/asm/nasm.c b/asm/nasm.c index 6af927547..aacceacbf 100644 --- a/asm/nasm.c +++ b/asm/nasm.c @@ -942,7 +942,8 @@ enum text_options { OPT_KEEP_ALL, OPT_NO_LINE, OPT_DEBUG, - OPT_REPRODUCIBLE + OPT_REPRODUCIBLE, + OPT_DEBUG_PREFIX_MAP }; enum need_arg { ARG_NO, @@ -975,6 +976,7 @@ static const struct textargs textopts[] = { {"no-line", OPT_NO_LINE, ARG_NO, 0}, {"debug", OPT_DEBUG, ARG_MAYBE, 0}, {"reproducible", OPT_REPRODUCIBLE, ARG_NO, 0}, + {"debug-prefix-map", OPT_DEBUG_PREFIX_MAP, ARG_YES, 0}, {NULL, OPT_BOGUS, ARG_NO, 0} }; @@ -1338,6 +1340,26 @@ static bool process_arg(char *p, char *q, int pass) case OPT_REPRODUCIBLE: reproducible = true; break; + case OPT_DEBUG_PREFIX_MAP: { + struct debug_prefix_list *d; + char *c; + c = strchr(param, '='); + + if (!c) { + nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "option `--%s' must be of the form `BASE=DEST'", p); + break; + } + + *c = '\0'; + d = nasm_malloc(sizeof(*d)); + d->next = debug_prefixes; + d->base = nasm_strdup(param); + d->dest = nasm_strdup(c + 1); + debug_prefixes = d; + *c = '='; + } + break; case OPT_HELP: help(stdout); exit(0); @@ -2296,6 +2318,8 @@ static void help(FILE *out) " --lpostfix str append the given string to local symbols\n" "\n" " --reproducible attempt to produce run-to-run identical output\n" + " --debug-prefix-map base=dest\n" + " remap paths starting with 'base' to 'dest' in output files\n" "\n" " -w+x enable warning x (also -Wx)\n" " -w-x disable warning x (also -Wno-x)\n" diff --git a/configure.ac b/configure.ac index 17132af90..39680b145 100644 --- a/configure.ac +++ b/configure.ac @@ -234,6 +234,7 @@ PA_FUNC_SNPRINTF PA_FUNC_VSNPRINTF AC_CHECK_FUNCS([strlcpy]) AC_CHECK_FUNCS([strrchrnul]) +AC_CHECK_FUNCS([strlcat]) dnl These types are POSIX-specific, and Windows does it differently... AC_CHECK_TYPES([struct _stati64]) @@ -253,6 +254,7 @@ AC_CHECK_DECLS(strsep) AC_CHECK_DECLS(strlcpy) AC_CHECK_DECLS(strnlen) AC_CHECK_DECLS(strrchrnul) +AC_CHECK_DECLS(strlcat) dnl Check for missing types AC_TYPE_UINTPTR_T diff --git a/include/compiler.h b/include/compiler.h index c5bac6e57..db3d6d630 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -169,6 +169,10 @@ size_t strlcpy(char *, const char *, size_t); char *strrchrnul(const char *, int); #endif +#if !defined(HAVE_STRLCAT) || !HAVE_DECL_STRLCAT +size_t strlcat(char *, const char *, size_t); +#endif + #ifndef __cplusplus /* C++ has false, true, bool as keywords */ # ifdef HAVE_STDBOOL_H # include diff --git a/include/nasmlib.h b/include/nasmlib.h index 87a7fc6f0..a3e5144b0 100644 --- a/include/nasmlib.h +++ b/include/nasmlib.h @@ -250,10 +250,19 @@ int64_t readstrnum(char *str, int length, bool *warn); */ int32_t seg_alloc(void); +struct debug_prefix_list { + struct debug_prefix_list *next; + char *base; + char *dest; +}; + +extern struct debug_prefix_list *debug_prefixes; + /* * Add/replace or remove an extension to the end of a filename */ const char *filename_set_extension(const char *inname, const char *extension); +char *filename_debug_remap(char *dest, char const *inname, size_t len); /* * Utility macros... diff --git a/nasm.txt b/nasm.txt index cc7fa27b2..d3485c99f 100644 --- a/nasm.txt +++ b/nasm.txt @@ -147,6 +147,10 @@ OPTIONS Prepend or append (respectively) the given argument to all global or extern variables. +--debug-prefix-map 'BASE=DEST':: + Map file names beginning with 'BASE' to 'DEST' when encoding them in + output object files. + SYNTAX ------ This man page does not fully describe the syntax of *nasm*'s assembly language, diff --git a/nasmlib/filename.c b/nasmlib/filename.c index 172ae0bc0..fda2be415 100644 --- a/nasmlib/filename.c +++ b/nasmlib/filename.c @@ -39,6 +39,8 @@ #include "nasmlib.h" #include "error.h" +struct debug_prefix_list *debug_prefixes = NULL; + /* * Add/modify a filename extension, assumed to be a period-delimited * field at the very end of the filename. Returns a newly allocated @@ -61,3 +63,21 @@ const char *filename_set_extension(const char *inname, const char *extension) return p; } + +char *filename_debug_remap(char *dest, char const *in, size_t len) +{ + struct debug_prefix_list *d; + size_t n; + + for (d = debug_prefixes; d != NULL; d = d->next) { + n = strlen(d->base); + if (strncmp(in, d->base, n) == 0) { + strlcpy(dest, d->dest, len); + strlcat(dest, &in[n], len); + return dest; + } + } + + strlcpy(dest, in, len); + return dest; +} diff --git a/output/outas86.c b/output/outas86.c index 54b22f878..c4a412c18 100644 --- a/output/outas86.c +++ b/output/outas86.c @@ -110,6 +110,8 @@ static void as86_sect_write(struct Section *, const uint8_t *, static void as86_init(void) { + char filename[FILENAME_MAX]; + stext.data = saa_init(1L); stext.datalen = 0L; stext.head = stext.last = NULL; @@ -131,7 +133,7 @@ static void as86_init(void) strslen = 0; /* as86 module name = input file minus extension */ - as86_add_string(filename_set_extension(inname, "")); + as86_add_string(filename_debug_remap(filename, filename_set_extension(inname, ""), sizeof(filename))); } static void as86_cleanup(void) diff --git a/output/outcoff.c b/output/outcoff.c index 58fa0249b..14baf7b6c 100644 --- a/output/outcoff.c +++ b/output/outcoff.c @@ -1072,14 +1072,14 @@ static void coff_symbol(char *name, int32_t strpos, int32_t value, static void coff_write_symbols(void) { - char filename[18]; + char filename[19]; uint32_t i; /* * The `.file' record, and the file name auxiliary record. */ coff_symbol(".file", 0L, 0L, -2, 0, 0x67, 1); - strncpy(filename, inname, 18); + filename_debug_remap(filename, inname, 19); nasm_write(filename, 18, ofile); /* diff --git a/output/outelf.c b/output/outelf.c index bb2acbb48..380e2b3ef 100644 --- a/output/outelf.c +++ b/output/outelf.c @@ -553,7 +553,7 @@ static void elf_init(void) }; const char * const *p; - strlcpy(elf_module, inname, sizeof(elf_module)); + filename_debug_remap(elf_module, inname, sizeof(elf_module)); sects = NULL; nsects = sectlen = 0; syms = saa_init((int32_t)sizeof(struct elf_symbol)); diff --git a/output/outieee.c b/output/outieee.c index b3ccc5f64..837b53050 100644 --- a/output/outieee.c +++ b/output/outieee.c @@ -207,7 +207,7 @@ static void ieee_unqualified_name(char *, char *); */ static void ieee_init(void) { - strlcpy(ieee_infile, inname, sizeof(ieee_infile)); + filename_debug_remap(ieee_infile, inname, sizeof(ieee_infile)); any_segs = false; fpubhead = NULL; fpubtail = &fpubhead; diff --git a/output/outobj.c b/output/outobj.c index 1ba650d1f..830911d5d 100644 --- a/output/outobj.c +++ b/output/outobj.c @@ -644,7 +644,7 @@ static enum directive_result obj_directive(enum directive, char *); static void obj_init(void) { - strlcpy(obj_infile, inname, sizeof(obj_infile)); + filename_debug_remap(obj_infile, inname, sizeof(obj_infile)); first_seg = seg_alloc(); any_segs = false; fpubhead = NULL; diff --git a/stdlib/strlcat.c b/stdlib/strlcat.c new file mode 100644 index 000000000..ee93dea35 --- /dev/null +++ b/stdlib/strlcat.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 Garmin Ltd. or its subsidiaries + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "compiler.h" + +/* + * Concatenate src string to dest of size size. The destination buffer will + * have no more than size-1 character when the operation finishes. Always NUL + * terminates, unless size == 0 or dest has no NUL terminator. Returns + * strlen(initial dest) + strlen(src); if retval >= size, truncation occurred. + */ +#ifndef HAVE_STRLCAT + +size_t strlcat(char *dest, const char *src, size_t size) +{ + size_t n; + + /* find the NULL terminator in dest */ + for (n = 0; n < size && dest[n] != '\0'; n++) + ; + + /* destination was not NULL terminated. Return the initial size */ + if (n == size) + return size; + + return strlcpy(&dest[n], src, size - n) + n; +} + +#endif + diff --git a/test/elfdebugprefix.asm b/test/elfdebugprefix.asm new file mode 100644 index 000000000..a67ba29c8 --- /dev/null +++ b/test/elfdebugprefix.asm @@ -0,0 +1,6 @@ +;Testname=unoptimized; Arguments=-O0 --debug-prefix-map elf=ELF -felf -oelfdebugprefix.o; Files=stdout stderr elfdebugprefix.o; Validate=readelf --wide --symbols elfdebugprefix.o | grep 'FILE.*ELFdebugprefix.asm' + + SECTION .text +test: ; [1] + ret + diff --git a/test/performtest.pl b/test/performtest.pl index f7865b39f..096f96048 100755 --- a/test/performtest.pl +++ b/test/performtest.pl @@ -42,14 +42,22 @@ sub perform { TEST: while() { #See if there is a test case - last unless /Testname=(.*);\s*Arguments=(.*);\s*Files=(.*)/; - my ($subname, $arguments, $files) = ($1, $2, $3); + last unless /Testname=(.*);\s*Arguments=(.*);\s*Files=([^;]*)(?:;\s*Validate=(.*))?/; + my ($subname, $arguments, $files, $validate) = ($1, $2, $3, $4); + chomp $files; debugprint("$subname | $arguments | $files"); #Call nasm with this test case system("$nasm $arguments $testpath > $stdoutfile 2> $stderrfile"); debugprint("$nasm $arguments $testpath > $stdoutfile 2> $stderrfile ----> $?"); + if($validate) { + if(system("$validate >> $stdoutfile 2>> $stderrfile") != 0) { + print "Test $testname/$subname validation failed\n"; + $globalresult = 1; + } + } + #Move the output to the test dir mkpath("$outputdir/$testname/$subname"); foreach(split / /,$files) { diff --git a/travis/nasm-t.py b/travis/nasm-t.py index b22249ed9..a984be5f6 100755 --- a/travis/nasm-t.py +++ b/travis/nasm-t.py @@ -402,6 +402,12 @@ def test_run(desc): if filecmp.cmp(match, output) == False: show_diff(desc['_test-name'], match, output) return test_fail(desc['_test-name'], match + " and " + output + " files are different") + if 'validate' in t: + pvalidate = subprocess.run(t['validate'].format(output=output), shell=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if pvalidate.returncode != 0: + return test_fail(desc['_test-name'], "Validation failed with %d:\nSTDOUT: %s\nSTDERR: %s" % (pvalidate.returncode, pvalidate.stdout, pvalidate.stderr)) + elif 'stdout' in t: print("\tComparing stdout") match = desc['_base-dir'] + os.sep + t['stdout'] diff --git a/travis/test/_version.stdout b/travis/test/_version.stdout index c20ee8046..95f65b010 100644 --- a/travis/test/_version.stdout +++ b/travis/test/_version.stdout @@ -1 +1 @@ -NASM version 2.16rc0 compiled on Jul 3 2020 +NASM version 2.16rc0 compiled on Apr 29 2021 diff --git a/travis/test/efldebugprefix.json b/travis/test/efldebugprefix.json new file mode 100644 index 000000000..a90d46f08 --- /dev/null +++ b/travis/test/efldebugprefix.json @@ -0,0 +1,16 @@ +[ + { + "description": "Test debug-prefix-map on ELF files", + "id": "elfdebugprefix", + "format": "elf", + "source": "elfdebugprefix.asm", + "option": "-O0 --debug-prefix-map ./travis/test/elf=ELF", + "target": [ + { + "output": "elfdebugprefix.o", + "validate": "readelf --wide --symbols {output} | grep 'FILE.*ELFdebugprefix.asm'" + } + ] + } +] + diff --git a/travis/test/elfdebugprefix.asm b/travis/test/elfdebugprefix.asm new file mode 100644 index 000000000..2dabae95b --- /dev/null +++ b/travis/test/elfdebugprefix.asm @@ -0,0 +1,4 @@ + SECTION .text +test: ; [1] + ret + diff --git a/travis/test/elfdebugprefix.o.t b/travis/test/elfdebugprefix.o.t new file mode 100644 index 000000000..635cdab1c Binary files /dev/null and b/travis/test/elfdebugprefix.o.t differ