forked from OSchip/llvm-project
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:
parent
015b0cc258
commit
025d59b16a
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue