shithub: rgbds

Download patch

ref: 82e0e4ffaf93f9d577fc21a1d6502d3093b6dca5
parent: ffb199a26a0837829f96077aa58a1faa331d5637
author: ISSOtm <[email protected]>
date: Sun Apr 5 20:45:22 EDT 2020

Make some RGBLINK errors non-fatal

--- a/include/link/main.h
+++ b/include/link/main.h
@@ -14,6 +14,8 @@
 #include <stdbool.h>
 #include <stdio.h>
 
+#include "helpers.h"
+
 /* Variables related to CLI options */
 extern bool isDmgMode;
 extern char const *linkerScriptName;
@@ -31,6 +33,10 @@
 					if (beVerbose) \
 						fprintf(stderr, __VA_ARGS__); \
 				} while (0)
+
+void error(char const *fmt, ...);
+
+noreturn_ void fatal(char const *fmt, ...);
 
 /**
  * Opens a file if specified, and aborts on error.
--- a/src/link/assign.c
+++ b/src/link/assign.c
@@ -80,15 +80,15 @@
 
 		/* Check if this doesn't conflict with what the code says */
 		if (section->isBankFixed && placement->bank != section->bank)
-			errx(1, "Linker script contradicts \"%s\"'s bank placement",
-			     section->name);
+			error("Linker script contradicts \"%s\"'s bank placement",
+			      section->name);
 		if (section->isAddressFixed && placement->org != section->org)
-			errx(1, "Linker script contradicts \"%s\"'s address placement",
-			     section->name);
+			error("Linker script contradicts \"%s\"'s address placement",
+			      section->name);
 		if (section->isAlignFixed
 		 && (placement->org & section->alignMask) != 0)
-			errx(1, "Linker script contradicts \"%s\"'s alignment",
-			     section->name);
+			error("Linker script contradicts \"%s\"'s alignment",
+			      section->name);
 
 		section->isAddressFixed = true;
 		section->org = placement->org;
--- a/src/link/main.c
+++ b/src/link/main.c
@@ -35,6 +35,40 @@
 bool beVerbose;               /* -v */
 bool isWRA0Mode;              /* -w */
 
+static uint32_t nbErrors = 0;
+
+void error(char const *fmt, ...)
+{
+	va_list ap;
+
+	fprintf(stderr, "error: ");
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	putc('\n', stderr);
+
+	if (nbErrors != UINT32_MAX)
+		nbErrors++;
+}
+
+noreturn_ void fatal(char const *fmt, ...)
+{
+	va_list ap;
+
+	fprintf(stderr, "fatal: ");
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	putc('\n', stderr);
+
+	if (nbErrors != UINT32_MAX)
+		nbErrors++;
+
+	fprintf(stderr, "Linking aborted after %u error%s\n", nbErrors,
+		nbErrors != 1 ? "s" : "");
+	exit(1);
+}
+
 FILE *openFile(char const *fileName, char const *mode)
 {
 	if (!fileName)
@@ -138,10 +172,14 @@
 			break;
 		case 'p':
 			value = strtoul(optarg, &endptr, 0);
-			if (optarg[0] == '\0' || *endptr != '\0')
-				errx(1, "Invalid argument for option 'p'");
-			if (value > 0xFF)
-				errx(1, "Argument for 'p' must be a byte (between 0 and 0xFF)");
+			if (optarg[0] == '\0' || *endptr != '\0') {
+				error("Invalid argument for option 'p'");
+				value = 0xFF;
+			}
+			if (value > 0xFF) {
+				error("Argument for 'p' must be a byte (between 0 and 0xFF)");
+				value = 0xFF;
+			}
 			padValue = value;
 			break;
 		case 's':
@@ -171,7 +209,7 @@
 
 	/* If no input files were specified, the user must have screwed up */
 	if (curArgIndex == argc) {
-		fputs("FATAL: no input files\n", stderr);
+		fputs("fatal: no input files\n", stderr);
 		printUsage();
 		exit(1);
 	}
@@ -198,6 +236,11 @@
 
 	/* and finally output the result. */
 	patch_ApplyPatches();
+	if (nbErrors) {
+		fprintf(stderr, "Linking failed with %u error%s\n", nbErrors,
+			nbErrors != 1 ? "s" : "");
+		exit(1);
+	}
 	out_WriteFiles();
 
 	/* Do cleanup before quitting, though. */
--- a/src/link/patch.c
+++ b/src/link/patch.c
@@ -118,19 +118,13 @@
 }
 
 static struct Symbol const *getSymbol(struct Symbol const * const *symbolList,
-				      uint32_t index, char const *fileName)
+				      uint32_t index)
 {
 	struct Symbol const *symbol = symbolList[index];
 
 	/* If the symbol is defined elsewhere... */
-	if (symbol->type == SYMTYPE_IMPORT) {
-		struct Symbol const *symbolDefinition =
-						sym_GetSymbol(symbol->name);
-		if (!symbolDefinition)
-			errx(1, "%s: Unknown symbol \"%s\"", fileName,
-			     symbol->name);
-		symbol = symbolDefinition;
-	}
+	if (symbol->type == SYMTYPE_IMPORT)
+		return sym_GetSymbol(symbol->name);
 
 	return symbol;
 }
@@ -182,9 +176,13 @@
 			break;
 		case RPN_DIV:
 			value = popRPN();
-			if (value == 0)
-				errx(1, "%s: Division by 0", patch->fileName);
-			value = popRPN() / value;
+			if (value == 0) {
+				error("%s: Division by 0", patch->fileName);
+				popRPN();
+				value = INT32_MAX;
+			} else {
+				value = popRPN() / value;
+			}
 			break;
 		case RPN_MOD:
 			value = popRPN();
@@ -256,9 +254,16 @@
 			for (uint8_t shift = 0; shift < 32; shift += 8)
 				value |= getRPNByte(&expression, &size,
 						    patch->fileName) << shift;
+			symbol = getSymbol(fileSymbols, value);
 
-			value = getSymbol(fileSymbols, value,
-					  patch->fileName)->section->bank;
+			if (!symbol) {
+				error("%s: Requested BANK() of symbol \"%s\", which was not found",
+				      patch->fileName,
+				      fileSymbols[value]->name);
+				value = 1;
+			} else {
+				value = symbol->section->bank;
+			}
 			break;
 
 		case RPN_BANK_SECT:
@@ -268,11 +273,13 @@
 
 			sect = sect_GetSection(name);
 
-			if (!sect)
-				errx(1, "%s: Requested BANK() of section \"%s\", which was not found",
-				     patch->fileName, name);
-
-			value = sect->bank;
+			if (!sect) {
+				error("%s: Requested BANK() of section \"%s\", which was not found",
+				      patch->fileName, name);
+				value = 1;
+			} else {
+				value = sect->bank;
+			}
 			break;
 
 		case RPN_BANK_SELF:
@@ -284,8 +291,8 @@
 			if (value < 0
 			 || (value > 0xFF && value < 0xFF00)
 			 || value > 0xFFFF)
-				errx(1, "%s: Value %d is not in HRAM range",
-				     patch->fileName, value);
+				error("%s: Value %d is not in HRAM range",
+				      patch->fileName, value);
 			value &= 0xFF;
 			break;
 
@@ -295,8 +302,8 @@
 			 * They can be easily checked with a bitmask
 			 */
 			if (value & ~0x38)
-				errx(1, "%s: Value %d is not a RST vector",
-				     patch->fileName, value);
+				error("%s: Value %d is not a RST vector",
+				      patch->fileName, value);
 			value |= 0xC7;
 			break;
 
@@ -313,7 +320,7 @@
 				value |= getRPNByte(&expression, &size,
 						    patch->fileName) << shift;
 
-			symbol = getSymbol(fileSymbols, value, patch->fileName);
+			symbol = getSymbol(fileSymbols, value);
 
 			if (!strcmp(symbol->name, "@")) {
 				value = section->org + patch->offset;
@@ -330,7 +337,7 @@
 	}
 
 	if (stack.size > 1)
-		warnx("%s: RPN stack has %lu entries on exit, not 1",
+		error("%s: RPN stack has %lu entries on exit, not 1",
 		      patch->fileName, stack.size);
 
 	return popRPN();
@@ -343,8 +350,6 @@
 	verbosePrint("Checking assertions...");
 	initRPNStack();
 
-	uint8_t failures = 0;
-
 	while (assert) {
 		if (!computeRPNExpr(&assert->patch, assert->section,
 				    (struct Symbol const * const *)
@@ -351,17 +356,15 @@
 				    			assert->fileSymbols)) {
 			switch ((enum AssertionType)assert->patch.type) {
 			case ASSERT_FATAL:
-				errx(1, "%s: %s", assert->patch.fileName,
-				     assert->message[0] ? assert->message
-							: "assert failure");
+				fatal("%s: %s", assert->patch.fileName,
+				      assert->message[0] ? assert->message
+							 : "assert failure");
 				/* Not reached */
 				break; /* Here so checkpatch doesn't complain */
 			case ASSERT_ERROR:
-				fprintf(stderr, "%s: %s\n",
-					assert->patch.fileName,
-					assert->message[0] ? assert->message
-							   : "assert failure");
-				failures++;
+				error("%s: %s", assert->patch.fileName,
+				      assert->message[0] ? assert->message
+							 : "assert failure");
 				break;
 			case ASSERT_WARN:
 				warnx("%s: %s", assert->patch.fileName,
@@ -377,9 +380,6 @@
 	}
 
 	freeRPNStack();
-
-	if (failures)
-		errx(1, "%u assertions failed!", failures);
 }
 
 /**
@@ -406,8 +406,8 @@
 			int16_t offset = value - address;
 
 			if (offset < -128 || offset > 127)
-				errx(1, "%s: jr target out of reach (expected -129 < %d < 128)",
-				     patch->fileName, offset);
+				error("%s: jr target out of reach (expected -129 < %d < 128)",
+				      patch->fileName, offset);
 			section->data[patch->offset] = offset & 0xFF;
 		} else {
 			/* Patch a certain number of bytes */
@@ -423,10 +423,10 @@
 
 			if (value < types[patch->type].min
 			 || value > types[patch->type].max)
-				errx(1, "%s: Value %#x%s is not %u-bit",
-				     patch->fileName, value,
-				     value < 0 ? " (maybe negative?)" : "",
-				     types[patch->type].size * 8);
+				error("%s: Value %#x%s is not %u-bit",
+				      patch->fileName, value,
+				      value < 0 ? " (maybe negative?)" : "",
+				      types[patch->type].size * 8);
 			for (uint8_t i = 0; i < types[patch->type].size; i++) {
 				section->data[patch->offset + i] = value & 0xFF;
 				value >>= 8;
--- a/test/link/assert.out
+++ b/test/link/assert.out
@@ -1,3 +1,4 @@
 warning: assert.asm(7): Worry about me, but not too much.
-assert.asm(8): Okay, this is getting serious!
-error: assert.asm(9): It all ends now.
+error: assert.asm(8): Okay, this is getting serious!
+fatal: assert.asm(9): It all ends now.
+Linking aborted after 2 errors
--- a/test/link/rst-bad.out
+++ b/test/link/rst-bad.out
@@ -1,1 +1,2 @@
 error: rst-bad.asm(2): Value 1 is not a RST vector
+Linking failed with 1 error
--- a/test/link/section-attributes-mismatch.out
+++ b/test/link/section-attributes-mismatch.out
@@ -1,1 +1,2 @@
 error: Linker script contradicts "sec"'s alignment
+Linking failed with 1 error
--- a/test/link/section-union/assert.out
+++ b/test/link/section-union/assert.out
@@ -1,5 +1,5 @@
-section-union/assert.asm(11): Force failing the build
-error: 1 assertions failed!
+error: section-union/assert.asm(11): Force failing the build
+Linking failed with 1 error
 ---
 ERROR: -(30):
     Assertion failed: Force failing the build