Add handleLoadedFile hook to the context.

This is called from the resolver on each file we decide we actually want to use.

Future commits will make use of this to extract useful information from the files and do
error checking against the context.  For example, ensure that files are the same arch as
each other.

Reviewed by Lang Hames.

Differential Revision: http://reviews.llvm.org/D16093

llvm-svn: 257814
This commit is contained in:
Pete Cooper 2016-01-14 21:53:13 +00:00
parent 43842b554c
commit 80c0974c6b
5 changed files with 82 additions and 27 deletions

View File

@ -307,6 +307,15 @@ public:
// Derived classes may use it to change the list of input files.
virtual void finalizeInputFiles() {}
/// Callback invoked for each file the Resolver decides we are going to load.
/// This can be used to update context state based on the file, and emit
/// errors for any differences between the context state and a loaded file.
/// For example, we can error if we try to load a file which is a different
/// arch from that being linked.
virtual std::error_code handleLoadedFile(File &file) {
return std::error_code();
}
TaskGroup &getTaskGroup() { return _taskGroup; }
/// @}

View File

@ -17,6 +17,7 @@
#include "lld/Core/SymbolTable.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/ErrorOr.h"
#include <set>
#include <unordered_map>
#include <unordered_set>
@ -43,13 +44,13 @@ public:
// Handle files, this adds atoms from the current file thats
// being processed by the resolver
bool handleFile(File &);
ErrorOr<bool> handleFile(File &);
// Handle an archive library file.
bool handleArchiveFile(File &);
ErrorOr<bool> handleArchiveFile(File &);
// Handle a shared library file.
void handleSharedLibrary(File &);
std::error_code handleSharedLibrary(File &);
/// @brief do work of merging and resolving and return list
bool resolve();
@ -57,7 +58,7 @@ public:
std::unique_ptr<SimpleFile> resultFile() { return std::move(_result); }
private:
typedef std::function<void(StringRef, bool)> UndefCallback;
typedef std::function<ErrorOr<bool>(StringRef, bool)> UndefCallback;
bool undefinesAdded(int begin, int end);
File *getFile(int &index);
@ -73,7 +74,8 @@ private:
bool checkUndefines();
void removeCoalescedAwayAtoms();
void checkDylibSymbolCollisions();
void forEachUndefines(File &file, bool searchForOverrides, UndefCallback callback);
ErrorOr<bool> forEachUndefines(File &file, bool searchForOverrides,
UndefCallback callback);
void markLive(const Atom *atom);
void addAtoms(const std::vector<const DefinedAtom *>&);

View File

@ -342,6 +342,8 @@ public:
void finalizeInputFiles() override;
std::error_code handleLoadedFile(File &file) override;
bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right,
bool &leftBeforeRight) const;

View File

@ -29,7 +29,9 @@
namespace lld {
bool Resolver::handleFile(File &file) {
ErrorOr<bool> Resolver::handleFile(File &file) {
if (auto ec = _ctx.handleLoadedFile(file))
return ec;
bool undefAdded = false;
for (const DefinedAtom *atom : file.defined())
doDefinedAtom(*atom);
@ -46,9 +48,10 @@ bool Resolver::handleFile(File &file) {
return undefAdded;
}
void Resolver::forEachUndefines(File &file, bool searchForOverrides,
UndefCallback callback) {
ErrorOr<bool> Resolver::forEachUndefines(File &file, bool searchForOverrides,
UndefCallback callback) {
size_t i = _undefineIndex[&file];
bool undefAdded = false;
do {
for (; i < _undefines.size(); ++i) {
StringRef undefName = _undefines[i];
@ -60,7 +63,10 @@ void Resolver::forEachUndefines(File &file, bool searchForOverrides,
_undefines[i] = "";
continue;
}
callback(undefName, false);
auto undefAddedOrError = callback(undefName, false);
if (undefAddedOrError.getError())
return undefAddedOrError;
undefAdded |= undefAddedOrError.get();
}
if (!searchForOverrides)
continue;
@ -69,43 +75,57 @@ void Resolver::forEachUndefines(File &file, bool searchForOverrides,
// something that overrode this tentative, so always check.
const Atom *curAtom = _symbolTable.findByName(tentDefName);
assert(curAtom != nullptr);
if (const DefinedAtom *curDefAtom = dyn_cast<DefinedAtom>(curAtom))
if (curDefAtom->merge() == DefinedAtom::mergeAsTentative)
callback(tentDefName, true);
if (const DefinedAtom *curDefAtom = dyn_cast<DefinedAtom>(curAtom)) {
if (curDefAtom->merge() == DefinedAtom::mergeAsTentative) {
auto undefAddedOrError = callback(tentDefName, true);
if (undefAddedOrError.getError())
return undefAddedOrError;
undefAdded |= undefAddedOrError.get();
}
}
}
} while (i < _undefines.size());
_undefineIndex[&file] = i;
return undefAdded;
}
bool Resolver::handleArchiveFile(File &file) {
ErrorOr<bool> Resolver::handleArchiveFile(File &file) {
ArchiveLibraryFile *archiveFile = cast<ArchiveLibraryFile>(&file);
bool searchForOverrides =
_ctx.searchArchivesToOverrideTentativeDefinitions();
bool undefAdded = false;
forEachUndefines(file, searchForOverrides,
[&](StringRef undefName, bool dataSymbolOnly) {
return forEachUndefines(file, searchForOverrides,
[&](StringRef undefName,
bool dataSymbolOnly)->ErrorOr<bool> {
if (File *member = archiveFile->find(undefName, dataSymbolOnly)) {
member->setOrdinal(_ctx.getNextOrdinalAndIncrement());
member->beforeLink();
updatePreloadArchiveMap();
undefAdded = handleFile(*member) || undefAdded;
return handleFile(*member);
}
return false;
});
return undefAdded;
}
void Resolver::handleSharedLibrary(File &file) {
std::error_code Resolver::handleSharedLibrary(File &file) {
// Add all the atoms from the shared library
SharedLibraryFile *sharedLibrary = cast<SharedLibraryFile>(&file);
handleFile(*sharedLibrary);
auto undefAddedOrError = handleFile(*sharedLibrary);
if (undefAddedOrError.getError())
return undefAddedOrError.getError();
bool searchForOverrides =
_ctx.searchSharedLibrariesToOverrideTentativeDefinitions();
forEachUndefines(file, searchForOverrides,
[&](StringRef undefName, bool dataSymbolOnly) {
undefAddedOrError = forEachUndefines(file, searchForOverrides,
[&](StringRef undefName,
bool dataSymbolOnly)->ErrorOr<bool> {
if (const SharedLibraryAtom *atom =
sharedLibrary->exports(undefName, dataSymbolOnly))
doSharedLibraryAtom(*atom);
return false;
});
if (undefAddedOrError.getError())
return undefAddedOrError.getError();
return std::error_code();
}
bool Resolver::doUndefinedAtom(const UndefinedAtom &atom) {
@ -318,7 +338,7 @@ bool Resolver::resolveUndefines() {
file->beforeLink();
updatePreloadArchiveMap();
switch (file->kind()) {
case File::kindObject:
case File::kindObject: {
// The same file may be visited more than once if the file is
// in --start-group and --end-group. Only library files should
// be processed more than once.
@ -327,17 +347,35 @@ bool Resolver::resolveUndefines() {
seen.insert(file);
assert(!file->hasOrdinal());
file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
undefAdded = handleFile(*file);
auto undefAddedOrError = handleFile(*file);
if (undefAddedOrError.getError()) {
llvm::errs() << "Error in " + file->path()
<< ": " << undefAddedOrError.getError().message() << "\n";
return false;
}
undefAdded = undefAddedOrError.get();
break;
case File::kindArchiveLibrary:
}
case File::kindArchiveLibrary: {
if (!file->hasOrdinal())
file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
undefAdded = handleArchiveFile(*file);
auto undefAddedOrError = handleArchiveFile(*file);
if (undefAddedOrError.getError()) {
llvm::errs() << "Error in " + file->path()
<< ": " << undefAddedOrError.getError().message() << "\n";
return false;
}
undefAdded = undefAddedOrError.get();
break;
}
case File::kindSharedLibrary:
if (!file->hasOrdinal())
file->setOrdinal(_ctx.getNextOrdinalAndIncrement());
handleSharedLibrary(*file);
if (auto EC = handleSharedLibrary(*file)) {
llvm::errs() << "Error in " + file->path()
<< ": " << EC.message() << "\n";
return false;
}
break;
}
_newUndefinesAdded[file] = undefAdded;

View File

@ -990,4 +990,8 @@ void MachOLinkingContext::finalizeInputFiles() {
elements.push_back(llvm::make_unique<GroupEnd>(numLibs));
}
std::error_code MachOLinkingContext::handleLoadedFile(File &file) {
return std::error_code();
}
} // end namespace lld