diff --git a/Makefile.in b/Makefile.in index d3bae08c..7fac2af9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -149,7 +149,7 @@ ZLIBOBJ = \ # Common library objects LIBOBJ_COM = \ 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) \ diff --git a/asm/nasm.c b/asm/nasm.c index 128e5b72..947c76b9 100644 --- a/asm/nasm.c +++ b/asm/nasm.c @@ -886,7 +886,8 @@ enum text_options { OPT_DEBUG, OPT_INFO, OPT_REPRODUCIBLE, - OPT_BITS + OPT_BITS, + OPT_DEBUG_PREFIX_MAP }; enum need_arg { ARG_NO, @@ -925,6 +926,7 @@ static const struct textargs textopts[] = { {"debug", OPT_DEBUG, ARG_MAYBE, 0}, {"reproducible", OPT_REPRODUCIBLE, ARG_NO, 0}, {"bits", OPT_BITS, ARG_YES, 0}, + {"debug-prefix-map", OPT_DEBUG_PREFIX_MAP, ARG_YES, 0}, {NULL, OPT_BOGUS, ARG_NO, 0} }; @@ -1305,6 +1307,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: /* Allow --help topic without *requiring* topic */ if (!param) @@ -2031,6 +2053,8 @@ static void help(FILE *out, const char *what) " --lprefix str prepend the given string to local symbols\n" " --lpostfix str append the given string to local symbols\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" , out); } if (help_optor(with, HW_LIMIT)) { diff --git a/configure.ac b/configure.ac index acd7461b..3eb95f26 100644 --- a/configure.ac +++ b/configure.ac @@ -230,6 +230,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 stat], [AC_CHECK_FUNCS([stat fstat])]) @@ -247,6 +248,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_UINTMAX_T diff --git a/include/compiler.h b/include/compiler.h index df668800..97641874 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -181,6 +181,10 @@ size_t strlcpy(char *, const char *, size_t); char * pure_func strrchrnul(const char *, int); #endif +#if !defined(HAVE_STRLCAT) || !HAVE_DECL_STRLCAT +size_t strlcat(char *, const char *, size_t); +#endif + /* C++ and C23 have bool, false, and true as proper keywords */ #if !defined(__cplusplus) && (__STDC_VERSION__ < 202311L) # ifdef HAVE_STDBOOL_H diff --git a/include/nasmlib.h b/include/nasmlib.h index ed4222b1..aafbf00e 100644 --- a/include/nasmlib.h +++ b/include/nasmlib.h @@ -334,10 +334,19 @@ static inline const char *nasm_digit_chars(bool ucase) */ 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 950c361a..784618ca 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 2c29d386..a510fedd 100644 --- a/nasmlib/filename.c +++ b/nasmlib/filename.c @@ -9,6 +9,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 @@ -31,3 +33,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 0640af7d..9cad9145 100644 --- a/output/outas86.c +++ b/output/outas86.c @@ -71,6 +71,7 @@ static struct SAA *strs; static size_t strslen; static int as86_reloc_size; +static char filename[FILENAME_MAX]; static void as86_write(void); static void as86_write_section(struct Section *, int); @@ -101,7 +102,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 d38085d4..ac55c1f2 100644 --- a/output/outcoff.c +++ b/output/outcoff.c @@ -1239,10 +1239,10 @@ static void coff_write_symbols(void) */ coff_symbol(".file", 0L, 0L, -2, 0, 0x67, 1); if (reproducible) - memset(filename, 0, 18); + memset(filename, 0, sizeof(filename)); else - strncpy(filename, inname, 18); - nasm_write(filename, 18, ofile); + filename_debug_remap(filename, inname, sizeof(filename)); + nasm_write(filename, sizeof(filename), ofile); /* * The section records, with their auxiliaries. diff --git a/output/outelf.c b/output/outelf.c index e03c1623..a1ea648b 100644 --- a/output/outelf.c +++ b/output/outelf.c @@ -516,8 +516,8 @@ static void elf_init(void) const char * const *p; const char * cur_path = nasm_realpath(inname); - strlcpy(elf_module, inname, sizeof(elf_module)); - strlcpy(elf_dir, nasm_dirname(cur_path), sizeof(elf_dir)); + filename_debug_remap(elf_module, inname, sizeof(elf_module)); + filename_debug_remap(elf_dir, nasm_dirname(cur_path), sizeof(elf_dir)); 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 9e26cec9..3643eeb8 100644 --- a/output/outieee.c +++ b/output/outieee.c @@ -178,7 +178,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 685c5933..e3eb34a3 100644 --- a/output/outobj.c +++ b/output/outobj.c @@ -656,7 +656,7 @@ static const char *get_default_class(const char *segment) 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 00000000..ee93dea3 --- /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 00000000..a67ba29c --- /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 46b1bdfa..2426848f 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 b86f8479..7a156b8c 100755 --- a/travis/nasm-t.py +++ b/travis/nasm-t.py @@ -427,6 +427,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/efldebugprefix.json b/travis/test/efldebugprefix.json new file mode 100644 index 00000000..a90d46f0 --- /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 00000000..2dabae95 --- /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 00000000..635cdab1 Binary files /dev/null and b/travis/test/elfdebugprefix.o.t differ