1From 81d6519499dcfebe7d21e65e002a8885a4e8d852 Mon Sep 17 00:00:00 2001 2From: Joshua Watt <JPEWhacker@gmail.com> 3Date: Tue, 19 Nov 2019 13:12:17 -0600 4Subject: [PATCH] Add --debug-prefix-map option 5 6Adds an option to remap file prefixes in output object files. This is 7analogous to the "-fdebug-prefix-map" option in GCC, and allows files to 8be built in a reproducible manner regardless of the build directory. 9 10Upstream-Status: Submitted [https://bugzilla.nasm.us/show_bug.cgi?id=3392635] 11Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> 12 13--- 14 asm/nasm.c | 24 ++++++++++++++++++++++++ 15 include/nasmlib.h | 9 +++++++++ 16 nasm.txt | 4 ++++ 17 nasmlib/filename.c | 20 ++++++++++++++++++++ 18 output/outas86.c | 4 +++- 19 output/outcoff.c | 4 ++-- 20 output/outelf.c | 2 +- 21 output/outieee.c | 2 +- 22 output/outobj.c | 2 +- 23 stdlib/strlcat.c | 2 +- 24 test/elfdebugprefix.asm | 6 ++++++ 25 test/performtest.pl | 12 ++++++++++-- 26 12 files changed, 82 insertions(+), 9 deletions(-) 27 create mode 100644 test/elfdebugprefix.asm 28 29diff --git a/asm/nasm.c b/asm/nasm.c 30index e5ae89a..7a7f8b4 100644 31--- a/asm/nasm.c 32+++ b/asm/nasm.c 33@@ -939,6 +939,7 @@ enum text_options { 34 OPT_KEEP_ALL, 35 OPT_NO_LINE, 36 OPT_DEBUG, 37+ OPT_DEBUG_PREFIX_MAP, 38 OPT_REPRODUCIBLE 39 }; 40 enum need_arg { 41@@ -971,6 +972,7 @@ static const struct textargs textopts[] = { 42 {"keep-all", OPT_KEEP_ALL, ARG_NO, 0}, 43 {"no-line", OPT_NO_LINE, ARG_NO, 0}, 44 {"debug", OPT_DEBUG, ARG_MAYBE, 0}, 45+ {"debug-prefix-map", OPT_DEBUG_PREFIX_MAP, true, 0}, 46 {"reproducible", OPT_REPRODUCIBLE, ARG_NO, 0}, 47 {NULL, OPT_BOGUS, ARG_NO, 0} 48 }; 49@@ -1337,6 +1339,26 @@ static bool process_arg(char *p, char *q, int pass) 50 case OPT_REPRODUCIBLE: 51 reproducible = true; 52 break; 53+ case OPT_DEBUG_PREFIX_MAP: { 54+ struct debug_prefix_list *d; 55+ char *c; 56+ c = strchr(param, '='); 57+ 58+ if (!c) { 59+ nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, 60+ "option `--%s' must be of the form `BASE=DEST'", p); 61+ break; 62+ } 63+ 64+ *c = '\0'; 65+ d = nasm_malloc(sizeof(*d)); 66+ d->next = debug_prefixes; 67+ d->base = nasm_strdup(param); 68+ d->dest = nasm_strdup(c + 1); 69+ debug_prefixes = d; 70+ *c = '='; 71+ } 72+ break; 73 case OPT_HELP: 74 help(stdout); 75 exit(0); 76@@ -2304,6 +2326,8 @@ static void help(FILE *out) 77 " -w-x disable warning x (also -Wno-x)\n" 78 " -w[+-]error promote all warnings to errors (also -Werror)\n" 79 " -w[+-]error=x promote warning x to errors (also -Werror=x)\n" 80+ " --debug-prefix-map base=dest\n" 81+ " remap paths starting with 'base' to 'dest' in output files\n" 82 , out); 83 84 fprintf(out, " %-20s %s\n", 85diff --git a/include/nasmlib.h b/include/nasmlib.h 86index 438178d..4c3e90d 100644 87--- a/include/nasmlib.h 88+++ b/include/nasmlib.h 89@@ -250,10 +250,19 @@ int64_t readstrnum(char *str, int length, bool *warn); 90 */ 91 int32_t seg_alloc(void); 92 93+struct debug_prefix_list { 94+ struct debug_prefix_list *next; 95+ char *base; 96+ char *dest; 97+}; 98+ 99+extern struct debug_prefix_list *debug_prefixes; 100+ 101 /* 102 * Add/replace or remove an extension to the end of a filename 103 */ 104 const char *filename_set_extension(const char *inname, const char *extension); 105+char *filename_debug_remap(char *dest, char const *inname, size_t len); 106 107 /* 108 * Utility macros... 109diff --git a/nasm.txt b/nasm.txt 110index cc7fa27..d3485c9 100644 111--- a/nasm.txt 112+++ b/nasm.txt 113@@ -147,6 +147,10 @@ OPTIONS 114 Prepend or append (respectively) the given argument to all global or 115 extern variables. 116 117+--debug-prefix-map 'BASE=DEST':: 118+ Map file names beginning with 'BASE' to 'DEST' when encoding them in 119+ output object files. 120+ 121 SYNTAX 122 ------ 123 This man page does not fully describe the syntax of *nasm*'s assembly language, 124diff --git a/nasmlib/filename.c b/nasmlib/filename.c 125index 172ae0b..fda2be4 100644 126--- a/nasmlib/filename.c 127+++ b/nasmlib/filename.c 128@@ -39,6 +39,8 @@ 129 #include "nasmlib.h" 130 #include "error.h" 131 132+struct debug_prefix_list *debug_prefixes = NULL; 133+ 134 /* 135 * Add/modify a filename extension, assumed to be a period-delimited 136 * field at the very end of the filename. Returns a newly allocated 137@@ -61,3 +63,21 @@ const char *filename_set_extension(const char *inname, const char *extension) 138 139 return p; 140 } 141+ 142+char *filename_debug_remap(char *dest, char const *in, size_t len) 143+{ 144+ struct debug_prefix_list *d; 145+ size_t n; 146+ 147+ for (d = debug_prefixes; d != NULL; d = d->next) { 148+ n = strlen(d->base); 149+ if (strncmp(in, d->base, n) == 0) { 150+ strlcpy(dest, d->dest, len); 151+ strlcat(dest, &in[n], len); 152+ return dest; 153+ } 154+ } 155+ 156+ strlcpy(dest, in, len); 157+ return dest; 158+} 159diff --git a/output/outas86.c b/output/outas86.c 160index 54b22f8..c4a412c 100644 161--- a/output/outas86.c 162+++ b/output/outas86.c 163@@ -110,6 +110,8 @@ static void as86_sect_write(struct Section *, const uint8_t *, 164 165 static void as86_init(void) 166 { 167+ char filename[FILENAME_MAX]; 168+ 169 stext.data = saa_init(1L); 170 stext.datalen = 0L; 171 stext.head = stext.last = NULL; 172@@ -131,7 +133,7 @@ static void as86_init(void) 173 strslen = 0; 174 175 /* as86 module name = input file minus extension */ 176- as86_add_string(filename_set_extension(inname, "")); 177+ as86_add_string(filename_debug_remap(filename, filename_set_extension(inname, ""), sizeof(filename))); 178 } 179 180 static void as86_cleanup(void) 181diff --git a/output/outcoff.c b/output/outcoff.c 182index 58fa024..14baf7b 100644 183--- a/output/outcoff.c 184+++ b/output/outcoff.c 185@@ -1072,14 +1072,14 @@ static void coff_symbol(char *name, int32_t strpos, int32_t value, 186 187 static void coff_write_symbols(void) 188 { 189- char filename[18]; 190+ char filename[19]; 191 uint32_t i; 192 193 /* 194 * The `.file' record, and the file name auxiliary record. 195 */ 196 coff_symbol(".file", 0L, 0L, -2, 0, 0x67, 1); 197- strncpy(filename, inname, 18); 198+ filename_debug_remap(filename, inname, 19); 199 nasm_write(filename, 18, ofile); 200 201 /* 202diff --git a/output/outelf.c b/output/outelf.c 203index 61af020..1292958 100644 204--- a/output/outelf.c 205+++ b/output/outelf.c 206@@ -553,7 +553,7 @@ static void elf_init(void) 207 }; 208 const char * const *p; 209 210- strlcpy(elf_module, inname, sizeof(elf_module)); 211+ filename_debug_remap(elf_module, inname, sizeof(elf_module)); 212 sects = NULL; 213 nsects = sectlen = 0; 214 syms = saa_init((int32_t)sizeof(struct elf_symbol)); 215diff --git a/output/outieee.c b/output/outieee.c 216index 6d6d4b2..cdb8333 100644 217--- a/output/outieee.c 218+++ b/output/outieee.c 219@@ -207,7 +207,7 @@ static void ieee_unqualified_name(char *, char *); 220 */ 221 static void ieee_init(void) 222 { 223- strlcpy(ieee_infile, inname, sizeof(ieee_infile)); 224+ filename_debug_remap(ieee_infile, inname, sizeof(ieee_infile)); 225 any_segs = false; 226 fpubhead = NULL; 227 fpubtail = &fpubhead; 228diff --git a/output/outobj.c b/output/outobj.c 229index 56b43f9..fefea94 100644 230--- a/output/outobj.c 231+++ b/output/outobj.c 232@@ -644,7 +644,7 @@ static enum directive_result obj_directive(enum directive, char *); 233 234 static void obj_init(void) 235 { 236- strlcpy(obj_infile, inname, sizeof(obj_infile)); 237+ filename_debug_remap(obj_infile, inname, sizeof(obj_infile)); 238 first_seg = seg_alloc(); 239 any_segs = false; 240 fpubhead = NULL; 241diff --git a/stdlib/strlcat.c b/stdlib/strlcat.c 242index 7084d46..ee93dea 100644 243--- a/stdlib/strlcat.c 244+++ b/stdlib/strlcat.c 245@@ -29,7 +29,7 @@ size_t strlcat(char *dest, const char *src, size_t size) 246 size_t n; 247 248 /* find the NULL terminator in dest */ 249- for (n = 0; i < size && dest[n] != '\0'; n++) 250+ for (n = 0; n < size && dest[n] != '\0'; n++) 251 ; 252 253 /* destination was not NULL terminated. Return the initial size */ 254diff --git a/test/elfdebugprefix.asm b/test/elfdebugprefix.asm 255new file mode 100644 256index 0000000..a67ba29 257--- /dev/null 258+++ b/test/elfdebugprefix.asm 259@@ -0,0 +1,6 @@ 260+;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' 261+ 262+ SECTION .text 263+test: ; [1] 264+ ret 265+ 266diff --git a/test/performtest.pl b/test/performtest.pl 267index f7865b3..096f960 100755 268--- a/test/performtest.pl 269+++ b/test/performtest.pl 270@@ -42,14 +42,22 @@ sub perform { 271 TEST: 272 while(<TESTFILE>) { 273 #See if there is a test case 274- last unless /Testname=(.*);\s*Arguments=(.*);\s*Files=(.*)/; 275- my ($subname, $arguments, $files) = ($1, $2, $3); 276+ last unless /Testname=(.*);\s*Arguments=(.*);\s*Files=([^;]*)(?:;\s*Validate=(.*))?/; 277+ my ($subname, $arguments, $files, $validate) = ($1, $2, $3, $4); 278+ chomp $files; 279 debugprint("$subname | $arguments | $files"); 280 281 #Call nasm with this test case 282 system("$nasm $arguments $testpath > $stdoutfile 2> $stderrfile"); 283 debugprint("$nasm $arguments $testpath > $stdoutfile 2> $stderrfile ----> $?"); 284 285+ if($validate) { 286+ if(system("$validate >> $stdoutfile 2>> $stderrfile") != 0) { 287+ print "Test $testname/$subname validation failed\n"; 288+ $globalresult = 1; 289+ } 290+ } 291+ 292 #Move the output to the test dir 293 mkpath("$outputdir/$testname/$subname"); 294 foreach(split / /,$files) { 295