ELF: Do not use fatal in LinkerScript.cpp.

This patch adds "Error" field to LinkerScript class. That field
is false by default, and set to true if there is a syntax error
in an input file. The linker script parser is a recursive-descedent
parser. Each function returns if Error is true -- so that
eventually the whole parser returns to a caller.

http://reviews.llvm.org/D16667

llvm-svn: 259557
This commit is contained in:
Rui Ueyama 2016-02-02 20:27:59 +00:00
parent 015b0cc258
commit 025d59b16a
2 changed files with 101 additions and 22 deletions

View File

@ -33,11 +33,12 @@ public:
void run();
private:
void setError(const Twine &Msg);
static std::vector<StringRef> tokenize(StringRef S);
static StringRef skipSpace(StringRef S);
bool atEOF();
StringRef next();
bool skip(StringRef Tok);
bool atEOF() { return Tokens.size() == Pos; }
void expect(StringRef Expect);
void addFile(StringRef Path);
@ -57,6 +58,7 @@ private:
StringSaver Saver;
std::vector<StringRef> Tokens;
bool Error = false;
size_t Pos = 0;
bool IsUnderSysroot;
};
@ -86,11 +88,20 @@ void LinkerScript::run() {
} else if (Tok == "SECTIONS") {
readSections();
} else {
fatal("unknown directive: " + Tok);
setError("unknown directive: " + Tok);
return;
}
}
}
// We don't want to record cascading errors. Keep only the first one.
void LinkerScript::setError(const Twine &Msg) {
if (Error)
return;
error(Msg);
Error = true;
}
// Split S into linker script tokens.
std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
std::vector<StringRef> Ret;
@ -102,8 +113,10 @@ std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
// Quoted token
if (S.startswith("\"")) {
size_t E = S.find("\"", 1);
if (E == StringRef::npos)
fatal("unclosed quote");
if (E == StringRef::npos) {
error("unclosed quote");
return {};
}
Ret.push_back(S.substr(1, E - 1));
S = S.substr(E + 1);
continue;
@ -127,8 +140,10 @@ StringRef LinkerScript::skipSpace(StringRef S) {
for (;;) {
if (S.startswith("/*")) {
size_t E = S.find("*/", 2);
if (E == StringRef::npos)
fatal("unclosed comment in a linker script");
if (E == StringRef::npos) {
error("unclosed comment in a linker script");
return "";
}
S = S.substr(E + 2);
continue;
}
@ -139,15 +154,26 @@ StringRef LinkerScript::skipSpace(StringRef S) {
}
}
// An errneous token is handled as if it were the last token before EOF.
bool LinkerScript::atEOF() { return Error || Tokens.size() == Pos; }
StringRef LinkerScript::next() {
if (atEOF())
fatal("unexpected EOF");
if (Error)
return "";
if (atEOF()) {
setError("unexpected EOF");
return "";
}
return Tokens[Pos++];
}
bool LinkerScript::skip(StringRef Tok) {
if (atEOF())
fatal("unexpected EOF");
if (Error)
return false;
if (atEOF()) {
setError("unexpected EOF");
return false;
}
if (Tok != Tokens[Pos])
return false;
++Pos;
@ -155,9 +181,11 @@ bool LinkerScript::skip(StringRef Tok) {
}
void LinkerScript::expect(StringRef Expect) {
if (Error)
return;
StringRef Tok = next();
if (Tok != Expect)
fatal(Expect + " expected, but got " + Tok);
setError(Expect + " expected, but got " + Tok);
}
void LinkerScript::addFile(StringRef S) {
@ -184,8 +212,9 @@ void LinkerScript::addFile(StringRef S) {
} else {
std::string Path = findFromSearchPaths(S);
if (Path.empty())
fatal("Unable to find " + S);
Driver->addFile(Saver.save(Path));
setError("Unable to find " + S);
else
Driver->addFile(Saver.save(Path));
}
}
@ -193,7 +222,7 @@ void LinkerScript::readAsNeeded() {
expect("(");
bool Orig = Config->AsNeeded;
Config->AsNeeded = true;
for (;;) {
while (!Error) {
StringRef Tok = next();
if (Tok == ")")
break;
@ -213,7 +242,7 @@ void LinkerScript::readEntry() {
void LinkerScript::readExtern() {
expect("(");
for (;;) {
while (!Error) {
StringRef Tok = next();
if (Tok == ")")
return;
@ -223,7 +252,7 @@ void LinkerScript::readExtern() {
void LinkerScript::readGroup() {
expect("(");
for (;;) {
while (!Error) {
StringRef Tok = next();
if (Tok == ")")
return;
@ -238,7 +267,10 @@ void LinkerScript::readGroup() {
void LinkerScript::readInclude() {
StringRef Tok = next();
auto MBOrErr = MemoryBuffer::getFile(Tok);
fatal(MBOrErr, "cannot open " + Tok);
if (!MBOrErr) {
setError("cannot open " + Tok);
return;
}
std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
std::vector<StringRef> V = tokenize(S);
@ -268,8 +300,10 @@ void LinkerScript::readOutputFormat() {
StringRef Tok = next();
if (Tok == ")")
return;
if (Tok != ",")
fatal("unexpected token: " + Tok);
if (Tok != ",") {
setError("unexpected token: " + Tok);
return;
}
next();
expect(",");
next();
@ -284,7 +318,7 @@ void LinkerScript::readSearchDir() {
void LinkerScript::readSections() {
expect("{");
while (!skip("}"))
while (!Error && !skip("}"))
readOutputSectionDescription();
}
@ -294,10 +328,10 @@ void LinkerScript::readOutputSectionDescription() {
expect(":");
expect("{");
while (!skip("}")) {
while (!Error && !skip("}")) {
next(); // Skip input file name.
expect("(");
while (!skip(")"))
while (!Error && !skip(")"))
InputSections.push_back(next());
}
}

View File

@ -0,0 +1,45 @@
# RUN: mkdir -p %t.dir
## Note that we will see "no input files" error message after
## error messages from the linker script parser, because the
## linker keeps going when an error is found.
# RUN: echo foobar > %t1
# RUN: not ld.lld %t1 2>&1 | FileCheck -check-prefix=ERR1 %s
# ERR1: unknown directive: foobar
# ERR1: no input files
# RUN: echo "foo \"bar" > %t2
# RUN: not ld.lld %t2 2>&1 | FileCheck -check-prefix=ERR2 %s
# ERR2: unclosed quote
# ERR2: no input files
# RUN: echo "/*" > %t3
# RUN: not ld.lld %t3 2>&1 | FileCheck -check-prefix=ERR3 %s
# ERR3: unclosed comment
# ERR3: no input files
# RUN: echo "EXTERN (" > %t4
# RUN: not ld.lld %t4 2>&1 | FileCheck -check-prefix=ERR4 %s
# ERR4: unexpected EOF
# ERR4: no input files
# RUN: echo "EXTERN (" > %t5
# RUN: not ld.lld %t5 2>&1 | FileCheck -check-prefix=ERR5 %s
# ERR5: unexpected EOF
# ERR5: no input files
# RUN: echo "EXTERN xyz" > %t6
# RUN: not ld.lld %t6 2>&1 | FileCheck -check-prefix=ERR6 %s
# ERR6: ( expected, but got xyz
# ERR6: no input files
# RUN: echo "INCLUDE /no/such/file" > %t7
# RUN: not ld.lld %t7 2>&1 | FileCheck -check-prefix=ERR7 %s
# ERR7: cannot open /no/such/file
# ERR7: no input files
# RUN: echo "OUTPUT_FORMAT(x y z)" > %t8
# RUN: not ld.lld %t8 2>&1 | FileCheck -check-prefix=ERR8 %s
# ERR8: unexpected token: y
# ERR8: no input files