mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Format linker script error backtraces the same way as others (#1792)
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
#include "helpers.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include "link/lexer.hpp" // lexer_Error
|
||||
#include "link/section.hpp"
|
||||
#include "link/warning.hpp"
|
||||
|
||||
@@ -47,7 +46,7 @@ void layout_SetFloatingSectionType(SectionType type) {
|
||||
|
||||
void layout_SetSectionType(SectionType type) {
|
||||
if (nbbanks(type) != 1) {
|
||||
lexer_Error("A bank number must be specified for %s", sectionTypeInfo[type].name.c_str());
|
||||
scriptError("A bank number must be specified for %s", sectionTypeInfo[type].name.c_str());
|
||||
// Keep going with a default value for the bank index.
|
||||
}
|
||||
|
||||
@@ -58,7 +57,7 @@ void layout_SetSectionType(SectionType type, uint32_t bank) {
|
||||
SectionTypeInfo const &typeInfo = sectionTypeInfo[type];
|
||||
|
||||
if (bank < typeInfo.firstBank) {
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"%s bank %" PRIu32 " does not exist (the minimum is %" PRIu32 ")",
|
||||
typeInfo.name.c_str(),
|
||||
bank,
|
||||
@@ -66,7 +65,7 @@ void layout_SetSectionType(SectionType type, uint32_t bank) {
|
||||
);
|
||||
bank = typeInfo.firstBank;
|
||||
} else if (bank > typeInfo.lastBank) {
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"%s bank %" PRIu32 " does not exist (the maximum is %" PRIu32 ")",
|
||||
typeInfo.name.c_str(),
|
||||
bank,
|
||||
@@ -79,11 +78,11 @@ void layout_SetSectionType(SectionType type, uint32_t bank) {
|
||||
|
||||
void layout_SetAddr(uint32_t addr) {
|
||||
if (activeType == SECTTYPE_INVALID) {
|
||||
lexer_Error("Cannot set the current address: no memory region is active");
|
||||
scriptError("Cannot set the current address: no memory region is active");
|
||||
return;
|
||||
}
|
||||
if (activeBankIdx == UINT32_MAX) {
|
||||
lexer_Error("Cannot set the current address: the bank is floating");
|
||||
scriptError("Cannot set the current address: the bank is floating");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,9 +90,9 @@ void layout_SetAddr(uint32_t addr) {
|
||||
SectionTypeInfo const &typeInfo = sectionTypeInfo[activeType];
|
||||
|
||||
if (addr < pc) {
|
||||
lexer_Error("Cannot decrease the current address (from $%04x to $%04x)", pc, addr);
|
||||
scriptError("Cannot decrease the current address (from $%04x to $%04x)", pc, addr);
|
||||
} else if (addr > endaddr(activeType)) { // Allow "one past the end" sections.
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"Cannot set the current address to $%04" PRIx32 ": %s ends at $%04" PRIx16,
|
||||
addr,
|
||||
typeInfo.name.c_str(),
|
||||
@@ -108,7 +107,7 @@ void layout_SetAddr(uint32_t addr) {
|
||||
|
||||
void layout_MakeAddrFloating() {
|
||||
if (activeType == SECTTYPE_INVALID) {
|
||||
lexer_Error("Cannot make the current address floating: no memory region is active");
|
||||
scriptError("Cannot make the current address floating: no memory region is active");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -119,7 +118,7 @@ void layout_MakeAddrFloating() {
|
||||
|
||||
void layout_AlignTo(uint32_t alignment, uint32_t alignOfs) {
|
||||
if (activeType == SECTTYPE_INVALID) {
|
||||
lexer_Error("Cannot align: no memory region is active");
|
||||
scriptError("Cannot align: no memory region is active");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -130,7 +129,7 @@ void layout_AlignTo(uint32_t alignment, uint32_t alignOfs) {
|
||||
uint32_t alignSize = 1u << alignment;
|
||||
|
||||
if (alignOfs >= alignSize) {
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"Cannot align: The alignment offset (%" PRIu32
|
||||
") must be less than alignment size (%" PRIu32 ")",
|
||||
alignOfs,
|
||||
@@ -149,7 +148,7 @@ void layout_AlignTo(uint32_t alignment, uint32_t alignOfs) {
|
||||
uint16_t &pc = curAddr[activeType][activeBankIdx];
|
||||
|
||||
if (alignment > 16) {
|
||||
lexer_Error("Cannot align: The alignment (%" PRIu32 ") must be less than 16", alignment);
|
||||
scriptError("Cannot align: The alignment (%" PRIu32 ") must be less than 16", alignment);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -160,7 +159,7 @@ void layout_AlignTo(uint32_t alignment, uint32_t alignOfs) {
|
||||
uint32_t alignSize = 1u << alignment;
|
||||
|
||||
if (alignOfs >= alignSize) {
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"Cannot align: The alignment offset (%" PRIu32
|
||||
") must be less than alignment size (%" PRIu32 ")",
|
||||
alignOfs,
|
||||
@@ -174,7 +173,7 @@ void layout_AlignTo(uint32_t alignment, uint32_t alignOfs) {
|
||||
}
|
||||
|
||||
if (uint16_t offset = pc - typeInfo.startAddr; length > typeInfo.size - offset) {
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"Cannot align: the next suitable address after $%04" PRIx16 " is $%04" PRIx16
|
||||
", past $%04" PRIx16,
|
||||
pc,
|
||||
@@ -189,7 +188,7 @@ void layout_AlignTo(uint32_t alignment, uint32_t alignOfs) {
|
||||
|
||||
void layout_Pad(uint32_t length) {
|
||||
if (activeType == SECTTYPE_INVALID) {
|
||||
lexer_Error("Cannot increase the current address: no memory region is active");
|
||||
scriptError("Cannot increase the current address: no memory region is active");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -203,7 +202,7 @@ void layout_Pad(uint32_t length) {
|
||||
|
||||
assume(pc >= typeInfo.startAddr);
|
||||
if (uint16_t offset = pc - typeInfo.startAddr; length + offset > typeInfo.size) {
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"Cannot increase the current address by %u bytes: only %u bytes to $%04" PRIx16,
|
||||
length,
|
||||
typeInfo.size - offset,
|
||||
@@ -216,14 +215,14 @@ void layout_Pad(uint32_t length) {
|
||||
|
||||
void layout_PlaceSection(std::string const &name, bool isOptional) {
|
||||
if (activeType == SECTTYPE_INVALID) {
|
||||
lexer_Error("No memory region has been specified to place section \"%s\" in", name.c_str());
|
||||
scriptError("No memory region has been specified to place section \"%s\" in", name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
Section *section = sect_GetSection(name.c_str());
|
||||
if (!section) {
|
||||
if (!isOptional) {
|
||||
lexer_Error("Undefined section \"%s\"", name.c_str());
|
||||
scriptError("Undefined section \"%s\"", name.c_str());
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -234,7 +233,7 @@ void layout_PlaceSection(std::string const &name, bool isOptional) {
|
||||
if (section->type == SECTTYPE_INVALID) {
|
||||
// A section that has data must get assigned a type that requires data.
|
||||
if (!sect_HasData(activeType) && !section->data.empty()) {
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"\"%s\" is specified to be a %s section, but it contains data",
|
||||
name.c_str(),
|
||||
typeInfo.name.c_str()
|
||||
@@ -242,7 +241,7 @@ void layout_PlaceSection(std::string const &name, bool isOptional) {
|
||||
} else if (sect_HasData(activeType) && section->data.empty() && section->size != 0) {
|
||||
// A section that lacks data can only be assigned to a type that requires data
|
||||
// if it's empty.
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"\"%s\" is specified to be a %s section, but it does not contain data",
|
||||
name.c_str(),
|
||||
typeInfo.name.c_str()
|
||||
@@ -255,7 +254,7 @@ void layout_PlaceSection(std::string const &name, bool isOptional) {
|
||||
}
|
||||
}
|
||||
} else if (section->type != activeType) {
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"\"%s\" is specified to be a %s section, but it is already a %s section",
|
||||
name.c_str(),
|
||||
typeInfo.name.c_str(),
|
||||
@@ -268,7 +267,7 @@ void layout_PlaceSection(std::string const &name, bool isOptional) {
|
||||
} else {
|
||||
uint32_t bank = activeBankIdx + typeInfo.firstBank;
|
||||
if (section->isBankFixed && bank != section->bank) {
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"The linker script places section \"%s\" in %s bank %" PRIu32
|
||||
", but it was already defined in bank %" PRIu32,
|
||||
name.c_str(),
|
||||
@@ -284,7 +283,7 @@ void layout_PlaceSection(std::string const &name, bool isOptional) {
|
||||
if (!isPcFloating) {
|
||||
uint16_t &org = curAddr[activeType][activeBankIdx];
|
||||
if (section->isAddressFixed && org != section->org) {
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"The linker script assigns section \"%s\" to address $%04" PRIx16
|
||||
", but it was already at $%04" PRIx16,
|
||||
name.c_str(),
|
||||
@@ -293,7 +292,7 @@ void layout_PlaceSection(std::string const &name, bool isOptional) {
|
||||
);
|
||||
} else if (section->isAlignFixed && (org & section->alignMask) != section->alignOfs) {
|
||||
uint8_t alignment = std::countr_one(section->alignMask);
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"The linker script assigns section \"%s\" to address $%04" PRIx16
|
||||
", but that would be ALIGN[%" PRIu8 ", %" PRIu16
|
||||
"] instead of the requested ALIGN[%" PRIu8 ", %" PRIu16 "]",
|
||||
@@ -312,7 +311,7 @@ void layout_PlaceSection(std::string const &name, bool isOptional) {
|
||||
uint16_t curOfs = org - typeInfo.startAddr;
|
||||
if (section->size > typeInfo.size - curOfs) {
|
||||
uint16_t overflowSize = section->size - (typeInfo.size - curOfs);
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"The linker script assigns section \"%s\" to address $%04" PRIx16
|
||||
", but then it would overflow %s by %" PRIu16 " byte%s",
|
||||
name.c_str(),
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "itertools.hpp"
|
||||
#include "style.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include "link/warning.hpp"
|
||||
@@ -27,12 +28,52 @@ struct LexerStackEntry {
|
||||
|
||||
static std::vector<LexerStackEntry> lexerStack;
|
||||
|
||||
void lexer_Error(char const *fmt, ...) {
|
||||
LexerStackEntry &context = lexerStack.back();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
scriptError(context.path.c_str(), context.lineNo, fmt, args);
|
||||
va_end(args);
|
||||
static void printStackEntry(LexerStackEntry const &context) {
|
||||
style_Set(stderr, STYLE_CYAN, true);
|
||||
fputs(context.path.c_str(), stderr);
|
||||
style_Set(stderr, STYLE_CYAN, false);
|
||||
fprintf(stderr, "(%" PRIu32 ")", context.lineNo);
|
||||
}
|
||||
|
||||
void lexer_TraceCurrent() {
|
||||
size_t n = lexerStack.size();
|
||||
|
||||
if (warnings.traceDepth == TRACE_COLLAPSE) {
|
||||
fputs(" ", stderr); // Just three spaces; the fourth will be handled by the loop
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
style_Reset(stderr);
|
||||
fprintf(stderr, " %s ", i == 0 ? "at" : "<-");
|
||||
printStackEntry(lexerStack[n - i - 1]);
|
||||
}
|
||||
putc('\n', stderr);
|
||||
} else if (warnings.traceDepth == 0 || static_cast<size_t>(warnings.traceDepth) >= n) {
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
style_Reset(stderr);
|
||||
fprintf(stderr, " %s ", i == 0 ? "at" : "<-");
|
||||
printStackEntry(lexerStack[n - i - 1]);
|
||||
putc('\n', stderr);
|
||||
}
|
||||
} else {
|
||||
size_t last = warnings.traceDepth / 2;
|
||||
size_t first = warnings.traceDepth - last;
|
||||
size_t skipped = n - warnings.traceDepth;
|
||||
for (size_t i = 0; i < first; ++i) {
|
||||
style_Reset(stderr);
|
||||
fprintf(stderr, " %s ", i == 0 ? "at" : "<-");
|
||||
printStackEntry(lexerStack[n - i - 1]);
|
||||
putc('\n', stderr);
|
||||
}
|
||||
style_Reset(stderr);
|
||||
fprintf(stderr, " ...%zu more%s\n", skipped, last ? "..." : "");
|
||||
for (size_t i = n - last; i < n; ++i) {
|
||||
style_Reset(stderr);
|
||||
fputs(" <- ", stderr);
|
||||
printStackEntry(lexerStack[n - i - 1]);
|
||||
putc('\n', stderr);
|
||||
}
|
||||
}
|
||||
|
||||
style_Reset(stderr);
|
||||
}
|
||||
|
||||
void lexer_IncludeFile(std::string &&path) {
|
||||
@@ -46,7 +87,7 @@ void lexer_IncludeFile(std::string &&path) {
|
||||
std::string badPath = std::move(newContext.path);
|
||||
lexerStack.pop_back();
|
||||
// This error will occur in `prevContext`, *before* incrementing the line number!
|
||||
lexer_Error(
|
||||
scriptError(
|
||||
"Failed to open included linker script \"%s\": %s", badPath.c_str(), strerror(errno)
|
||||
);
|
||||
}
|
||||
@@ -119,7 +160,7 @@ static yy::parser::symbol_type parseBinNumber(char const *prefix) {
|
||||
LexerStackEntry &context = lexerStack.back();
|
||||
int c = context.file.sgetc();
|
||||
if (!isBinDigit(c)) {
|
||||
lexer_Error("No binary digits found after %s", prefix);
|
||||
scriptError("No binary digits found after %s", prefix);
|
||||
return yy::parser::make_number(0);
|
||||
}
|
||||
|
||||
@@ -142,7 +183,7 @@ static yy::parser::symbol_type parseOctNumber(char const *prefix) {
|
||||
LexerStackEntry &context = lexerStack.back();
|
||||
int c = context.file.sgetc();
|
||||
if (!isOctDigit(c)) {
|
||||
lexer_Error("No octal digits found after %s", prefix);
|
||||
scriptError("No octal digits found after %s", prefix);
|
||||
return yy::parser::make_number(0);
|
||||
}
|
||||
|
||||
@@ -177,7 +218,7 @@ static yy::parser::symbol_type parseHexNumber(char const *prefix) {
|
||||
LexerStackEntry &context = lexerStack.back();
|
||||
int c = context.file.sgetc();
|
||||
if (!isHexDigit(c)) {
|
||||
lexer_Error("No hexadecimal digits found after %s", prefix);
|
||||
scriptError("No hexadecimal digits found after %s", prefix);
|
||||
return yy::parser::make_number(0);
|
||||
}
|
||||
|
||||
@@ -225,14 +266,14 @@ static yy::parser::symbol_type parseString() {
|
||||
std::string str;
|
||||
for (; c != '"'; c = context.file.sgetc()) {
|
||||
if (c == EOF || isNewline(c)) {
|
||||
lexer_Error("Unterminated string");
|
||||
scriptError("Unterminated string");
|
||||
break;
|
||||
}
|
||||
context.file.sbumpc();
|
||||
if (c == '\\') {
|
||||
c = context.file.sgetc();
|
||||
if (c == EOF || isNewline(c)) {
|
||||
lexer_Error("Unterminated string");
|
||||
scriptError("Unterminated string");
|
||||
break;
|
||||
} else if (c == 'n') {
|
||||
c = '\n';
|
||||
@@ -243,7 +284,7 @@ static yy::parser::symbol_type parseString() {
|
||||
} else if (c == '0') {
|
||||
c = '\0';
|
||||
} else if (c != '\\' && c != '"' && c != '\'') {
|
||||
lexer_Error("Cannot escape character %s", printChar(c));
|
||||
scriptError("Cannot escape character %s", printChar(c));
|
||||
}
|
||||
context.file.sbumpc();
|
||||
}
|
||||
@@ -320,10 +361,10 @@ yy::parser::symbol_type yylex() {
|
||||
return search->second();
|
||||
}
|
||||
|
||||
lexer_Error("Unknown keyword `%s`", ident.c_str());
|
||||
scriptError("Unknown keyword `%s`", ident.c_str());
|
||||
return yylex();
|
||||
} else {
|
||||
lexer_Error("Unexpected character %s", printChar(c));
|
||||
scriptError("Unexpected character %s", printChar(c));
|
||||
// Keep reading characters until the EOL, to avoid reporting too many errors.
|
||||
for (c = context.file.sgetc(); !isNewline(c); c = context.file.sgetc()) {
|
||||
if (c == EOF) {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
%code {
|
||||
#include "link/lexer.hpp"
|
||||
#include "link/layout.hpp"
|
||||
#include "link/warning.hpp"
|
||||
|
||||
yy::parser::symbol_type yylex(); // Provided by layout.cpp
|
||||
}
|
||||
@@ -110,5 +111,5 @@ optional:
|
||||
/******************** Error handler ********************/
|
||||
|
||||
void yy::parser::error(std::string const &msg) {
|
||||
lexer_Error("%s", msg.c_str());
|
||||
scriptError("%s", msg.c_str());
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "style.hpp"
|
||||
|
||||
#include "link/fstack.hpp"
|
||||
#include "link/lexer.hpp"
|
||||
|
||||
// clang-format off: nested initializers
|
||||
Diagnostics<WarningLevel, WarningID> warnings = {
|
||||
@@ -102,17 +103,13 @@ void error(char const *fmt, ...) {
|
||||
warnings.incrementErrors();
|
||||
}
|
||||
|
||||
void scriptError(char const *name, uint32_t lineNo, char const *fmt, va_list args) {
|
||||
style_Set(stderr, STYLE_RED, true);
|
||||
fputs("error: ", stderr);
|
||||
style_Set(stderr, STYLE_CYAN, true);
|
||||
fputs(name, stderr);
|
||||
style_Set(stderr, STYLE_CYAN, false);
|
||||
fprintf(stderr, "(%" PRIu32 ")", lineNo);
|
||||
style_Reset(stderr);
|
||||
fputs(": ", stderr);
|
||||
vfprintf(stderr, fmt, args);
|
||||
putc('\n', stderr);
|
||||
void scriptError(char const *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printDiag(nullptr, 0, fmt, args, "error", STYLE_RED, nullptr, nullptr);
|
||||
va_end(args);
|
||||
|
||||
lexer_TraceCurrent();
|
||||
|
||||
warnings.incrementErrors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user