#include "llvm/ADT/Optional.h"
#include "llvm/Support/ErrorHandling.h"
#include <functional>
+#include <memory>
#include <vector>
namespace lld {
return _lastError.getValue();
}
+ // Usually each file owns a std::unique_ptr<MemoryBuffer>.
+ // However, there's one special case. If a file is an archive file,
+ // the archive file and its children all shares the same memory buffer.
+ // This method is used by the ArchiveFile to give its children
+ // co-ownership of the buffer.
+ void setSharedMemoryBuffer(std::shared_ptr<MemoryBuffer> mb) {
+ _sharedMemoryBuffer = mb;
+ }
+
protected:
/// \brief only subclasses of File can be instantiated
File(StringRef p, Kind kind)
StringRef _path;
Kind _kind;
mutable uint64_t _ordinal;
+ std::shared_ptr<MemoryBuffer> _sharedMemoryBuffer;
};
/// \brief A mutable File.
bool getReplacements(InputGraph::InputElementVectorT &result) override;
protected:
- /// \brief Read the file into _buffer.
- std::error_code getBuffer(StringRef filePath);
-
StringRef _path; // The path of the Input file
InputGraph::FileVectorT _files; // A vector of lld File objects
- std::unique_ptr<MemoryBuffer> _buffer; // Memory buffer to actual contents
// The next file that would be processed by the resolver
uint32_t _nextFileIndex;
if (std::error_code ec = mb.getError())
return ec;
- _buffer = std::move(mb.get());
- return ctx.registry().parseFile(_buffer, _files);
+ return ctx.registry().parseFile(std::move(mb.get()), _files);
}
/// \brief Return the file that has to be processed by the resolver
}
private:
- void narrowFatBuffer(StringRef filePath);
+ void narrowFatBuffer(std::unique_ptr<MemoryBuffer> &mb, StringRef filePath);
MachOLinkingContext &_context;
std::unique_ptr<const ArchiveLibraryFile> _archiveFile;
/// \brief Parse a supplied buffer (already filled with the contents of a
/// file) and create a File object.
- ///
- /// The resulting File object may take ownership of the MemoryBuffer.
+ /// The resulting File object takes ownership of the MemoryBuffer.
virtual std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const = 0;
};
/// Walk the list of registered Readers and find one that can parse the
/// supplied file and parse it.
- std::error_code parseFile(std::unique_ptr<MemoryBuffer> &mb,
+ std::error_code parseFile(std::unique_ptr<MemoryBuffer> mb,
std::vector<std::unique_ptr<File>> &result) const;
/// Walk the list of registered kind tables to convert a Reference Kind
_nextElementIndex++;
}
-/// \brief Read the file into _buffer.
-std::error_code FileNode::getBuffer(StringRef filePath) {
- // Create a memory buffer
- ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
- MemoryBuffer::getFileOrSTDIN(filePath);
- if (std::error_code ec = mb.getError())
- return ec;
- _buffer = std::move(mb.get());
- return std::error_code();
-}
-
bool FileNode::getReplacements(InputGraph::InputElementVectorT &result) {
if (_files.size() < 2)
return false;
ErrorOr<StringRef> filePath = getPath(ctx);
if (std::error_code ec = filePath.getError())
return ec;
-
- if (std::error_code ec = getBuffer(*filePath))
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr =
+ MemoryBuffer::getFileOrSTDIN(*filePath);
+ if (std::error_code ec = mbOrErr.getError())
return ec;
+ std::unique_ptr<MemoryBuffer> mb = std::move(mbOrErr.get());
_context.addInputFileDependency(*filePath);
if (ctx.logInputFiles())
diagnostics << *filePath << "\n";
- narrowFatBuffer(*filePath);
+ narrowFatBuffer(mb, *filePath);
std::vector<std::unique_ptr<File>> parsedFiles;
- if (std::error_code ec = ctx.registry().parseFile(_buffer, parsedFiles))
+ if (std::error_code ec = ctx.registry().parseFile(std::move(mb), parsedFiles))
return ec;
for (std::unique_ptr<File> &pf : parsedFiles) {
// If file is a dylib, inform LinkingContext about it.
/// If buffer contains a fat file, find required arch in fat buffer and
/// switch buffer to point to just that required slice.
-void MachOFileNode::narrowFatBuffer(StringRef filePath) {
+void MachOFileNode::narrowFatBuffer(std::unique_ptr<MemoryBuffer> &mb,
+ StringRef filePath) {
// Check if buffer is a "fat" file that contains needed arch.
uint32_t offset;
uint32_t size;
- if (!_context.sliceFromFatFile(*_buffer, offset, size)) {
+ if (!_context.sliceFromFatFile(*mb, offset, size)) {
return;
}
// Create new buffer containing just the needed slice.
auto subuf = MemoryBuffer::getFileSlice(filePath, size, offset);
if (subuf.getError())
return;
- // The assignment to _buffer will release previous buffer.
- _buffer = std::move(subuf.get());
+ // The assignment to mb will release previous buffer.
+ mb = std::move(subuf.get());
}
ErrorOr<StringRef> filePath = getPath(ctx);
if (std::error_code ec = filePath.getError())
return ec;
- if (std::error_code ec = getBuffer(*filePath))
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(*filePath);
+ if (std::error_code ec = mb.getError())
return ec;
if (ctx.logInputFiles())
diagnostics << *filePath << "\n";
if (_attributes._isWholeArchive) {
std::vector<std::unique_ptr<File>> parsedFiles;
- if (std::error_code ec = ctx.registry().parseFile(_buffer, parsedFiles))
+ if (std::error_code ec = ctx.registry().parseFile(
+ std::move(mb.get()), parsedFiles))
return ec;
assert(parsedFiles.size() == 1);
std::unique_ptr<File> f(parsedFiles[0].release());
_files.push_back(std::move(f));
return std::error_code();
}
- return ctx.registry().parseFile(_buffer, _files);
+ return ctx.registry().parseFile(std::move(mb.get()), _files);
}
/// \brief Parse the GnuLD Script
ErrorOr<StringRef> filePath = getPath(ctx);
if (std::error_code ec = filePath.getError())
return ec;
- if (std::error_code ec = getBuffer(*filePath))
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(*filePath);
+ if (std::error_code ec = mb.getError())
return ec;
if (ctx.logInputFiles())
diagnostics << *filePath << "\n";
- _lexer.reset(new script::Lexer(std::move(_buffer)));
+ _lexer.reset(new script::Lexer(std::move(mb.get())));
_parser.reset(new script::Parser(*_lexer.get()));
_linkerScript = _parser->parse();
return ec;
}
- if (std::error_code ec = getBuffer(*filePath)) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
+ MemoryBuffer::getFileOrSTDIN(*filePath);
+ if (std::error_code ec = mb.getError()) {
diagnostics << "Cannot open file: " << *filePath << "\n";
return ec;
}
if (ctx.logInputFiles())
diagnostics << *filePath << "\n";
- return ctx.registry().parseFile(_buffer, _files);
+ return ctx.registry().parseFile(std::move(mb.get()), _files);
}
ErrorOr<File &> PECOFFFileNode::getNextFile() {
if (!mb)
return;
- std::error_code ec = _context.registry().parseFile(mb.get(), _nativeFile);
+ std::error_code ec = _context.registry().parseFile(
+ std::move(mb.get()), _nativeFile);
if (ec) {
// Note: we need a way for Passes to report errors.
llvm_unreachable("native reader not registered or read error");
if (!mb)
return;
- std::error_code ec = _context.registry().parseFile(mb.get(), _yamlFile);
+ std::error_code ec = _context.registry().parseFile(
+ std::move(mb.get()), _yamlFile);
if (ec) {
// Note: we need a way for Passes to report errors.
llvm_unreachable("yaml reader not registered or read error");
}
std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const override {
std::size_t maxAlignment =
1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));
}
std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const override {
std::size_t maxAlignment =
1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));
_flagMerger(flagMerger) {}
std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry ®istry,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
std::vector<std::unique_ptr<File>> &result) const override {
auto &hdr = *elfHeader(*mb);
if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
return ec;
- return BaseReaderType::parseFile(mb, registry, result);
+ return BaseReaderType::parseFile(std::move(mb), registry, result);
}
private:
_flagMerger(flagMerger) {}
std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry ®istry,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
std::vector<std::unique_ptr<File>> &result) const override {
auto &hdr = *elfHeader(*mb);
if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
return ec;
- return BaseReaderType::parseFile(mb, registry, result);
+ return BaseReaderType::parseFile(std::move(mb), registry, result);
}
private:
/// \brief The FileArchive class represents an Archive Library file
class FileArchive : public lld::ArchiveLibraryFile {
public:
- FileArchive(std::unique_ptr<MemoryBuffer> &mb, const Registry ®,
+ FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry ®,
StringRef path, bool logLoading)
- : ArchiveLibraryFile(path), _mb(mb), _registry(reg),
- _logLoading(logLoading) {}
+ : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
+ _registry(reg), _logLoading(logLoading) {}
std::error_code doParse() override {
// Make Archive object which will be owned by FileArchive object.
mb.getBuffer(), memberPath, false));
std::vector<std::unique_ptr<File>> files;
- _registry.parseFile(memberMB, files);
+ _registry.parseFile(std::move(memberMB), files);
assert(files.size() == 1);
result = std::move(files[0]);
- // Note: The object file parsers use getBufferIdentifier() from memberMB
- // for the file path. And MemoryBuffer makes its own copy of the path.
- // That means when if memberMB is destroyed, the lld:File objects will
- // have a dangling reference for their path. To fix that, all the
- // MemoryBuffers for the archive members are owned by _memberBuffers.
- _memberBuffers.push_back(std::move(memberMB));
-
+ // The memory buffer is co-owned by the archive file and the children,
+ // so that the bufffer is deallocated when all the members are destructed.
+ result->setSharedMemoryBuffer(_mb);
return std::error_code();
}
typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap;
typedef std::set<const char *> InstantiatedSet;
- std::unique_ptr<MemoryBuffer> &_mb;
+ std::shared_ptr<MemoryBuffer> _mb;
const Registry &_registry;
std::unique_ptr<Archive> _archive;
mutable MemberMap _symbolMemberMap;
}
std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry ®,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®,
std::vector<std::unique_ptr<File>> &result) const override {
+ StringRef path = mb->getBufferIdentifier();
std::unique_ptr<FileArchive> file(
- new FileArchive(mb, reg, mb->getBufferIdentifier(), _logLoading));
+ new FileArchive(std::move(mb), reg, path, _logLoading));
result.push_back(std::move(file));
return std::error_code();
}
class MachOFile : public SimpleFile {
public:
- MachOFile(MemoryBuffer *mb, MachOLinkingContext *ctx)
- : SimpleFile(mb->getBufferIdentifier()), _mb(mb), _ctx(ctx) {}
+ MachOFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx)
+ : SimpleFile(mb->getBufferIdentifier()), _mb(std::move(mb)), _ctx(ctx) {}
MachOFile(StringRef path) : SimpleFile(path) {}
std::error_code doParse() override {
// Convert binary file to normalized mach-o.
- std::unique_ptr<MemoryBuffer>mb(_mb);
- auto normFile = normalized::readBinary(mb, _ctx->arch());
- mb.release();
+ auto normFile = normalized::readBinary(_mb, _ctx->arch());
if (std::error_code ec = normFile.getError())
return ec;
// Convert normalized mach-o to atoms.
std::vector<SectionOffsetAndAtom>> SectionToAtoms;
typedef llvm::StringMap<const lld::Atom *> NameToAtom;
- MemoryBuffer *_mb;
- MachOLinkingContext *_ctx;
- SectionToAtoms _sectionAtoms;
- NameToAtom _undefAtoms;
+ std::unique_ptr<MemoryBuffer> _mb;
+ MachOLinkingContext *_ctx;
+ SectionToAtoms _sectionAtoms;
+ NameToAtom _undefAtoms;
};
class MachODylibFile : public SharedLibraryFile {
public:
- MachODylibFile(MemoryBuffer *mb, MachOLinkingContext *ctx)
- : SharedLibraryFile(mb->getBufferIdentifier()), _mb(mb), _ctx(ctx) {}
+ MachODylibFile(std::unique_ptr<MemoryBuffer> mb, MachOLinkingContext *ctx)
+ : SharedLibraryFile(mb->getBufferIdentifier()),
+ _mb(std::move(mb)), _ctx(ctx) {}
MachODylibFile(StringRef path) : SharedLibraryFile(path) {}
std::error_code doParse() override {
// Convert binary file to normalized mach-o.
- std::unique_ptr<MemoryBuffer>mb(_mb);
- auto normFile = normalized::readBinary(mb, _ctx->arch());
- mb.release();
+ auto normFile = normalized::readBinary(_mb, _ctx->arch());
if (std::error_code ec = normFile.getError())
return ec;
// Convert normalized mach-o to atoms.
bool weakDef;
};
- MemoryBuffer *_mb;
+ std::unique_ptr<MemoryBuffer> _mb;
MachOLinkingContext *_ctx;
StringRef _installName;
uint32_t _currentVersion;
}
std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry ®istry,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
std::vector<std::unique_ptr<File>> &result) const override {
- auto *file = new MachOFile(mb.get(), &_ctx);
+ auto *file = new MachOFile(std::move(mb), &_ctx);
result.push_back(std::unique_ptr<MachOFile>(file));
return std::error_code();
}
}
std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry ®istry,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
std::vector<std::unique_ptr<File>> &result) const override {
- auto *file = new MachODylibFile(mb.get(), &_ctx);
+ auto *file = new MachODylibFile(std::move(mb), &_ctx);
result.push_back(std::unique_ptr<MachODylibFile>(file));
return std::error_code();
}
}
virtual std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const override {
auto *file = new lld::native::File(std::move(mb));
result.push_back(std::unique_ptr<File>(file));
}
std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry &,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry &,
std::vector<std::unique_ptr<File>> &result) const override {
// Parse the memory buffer as PECOFF file.
auto *file = new FileCOFF(std::move(mb), _ctx);
}
std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File> > &result) const override {
auto *file = new FileImportLibrary(std::move(mb), _machine);
result.push_back(std::unique_ptr<File>(file));
}
std::error_code
-Registry::parseFile(std::unique_ptr<MemoryBuffer> &mb,
+Registry::parseFile(std::unique_ptr<MemoryBuffer> mb,
std::vector<std::unique_ptr<File>> &result) const {
// Get file type.
StringRef content(mb->getBufferStart(), mb->getBufferSize());
for (const std::unique_ptr<Reader> &reader : _readers) {
if (!reader->canParse(fileType, extension, *mb))
continue;
- if (std::error_code ec = reader->parseFile(mb, *this, result))
+ if (std::error_code ec = reader->parseFile(std::move(mb), *this, result))
return ec;
for (std::unique_ptr<File> &file : result)
if (std::error_code ec = file->parse())
}
std::error_code
- parseFile(std::unique_ptr<MemoryBuffer> &mb, const class Registry &,
+ parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const override {
- // Note: we do not take ownership of the MemoryBuffer. That is
- // because yaml may produce multiple File objects, so there is no
- // *one* File to take ownership. Therefore, the yaml File objects
- // produced must make copies of all strings that come from YAML I/O.
- // Otherwise the strings will become invalid when this MemoryBuffer
- // is deallocated.
+ // Note: we do not store the unique pointer to the MemoryBuffer,
+ // so the buffer will be deallocated at end of this function.
+ // That's OK since the YAML file contents are parsed and consumed
+ // in this function.
// Create YAML Input Reader.
YamlContext yamlContext;