1 //===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lld/Core/ArchiveLibraryFile.h" 11 #include "lld/Core/File.h" 12 #include "lld/Core/LLVM.h" 13 #include "lld/Core/Reader.h" 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/Object/Archive.h" 16 #include "llvm/Support/Debug.h" 17 #include "llvm/Support/Format.h" 18 #include "llvm/Support/MemoryBuffer.h" 19 #include "llvm/ADT/STLExtras.h" 20 #include "llvm/Object/Error.h" 21 #include "llvm/Support/ErrorOr.h" 22 #include "llvm/Support/FileSystem.h" 23 #include "llvm/Support/raw_ostream.h" 24 #include <memory> 25 #include <set> 26 #include <string> 27 #include <system_error> 28 #include <unordered_map> 29 #include <utility> 30 #include <vector> 31 32 using llvm::object::Archive; 33 34 namespace lld { 35 36 namespace { 37 38 /// \brief The FileArchive class represents an Archive Library file 39 class FileArchive : public lld::ArchiveLibraryFile { 40 public: 41 FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry ®, 42 StringRef path, bool logLoading) 43 : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())), 44 _registry(reg), _logLoading(logLoading) {} 45 46 /// \brief Check if any member of the archive contains an Atom with the 47 /// specified name and return the File object for that member, or nullptr. 48 File *find(StringRef name) override { 49 auto member = _symbolMemberMap.find(name); 50 if (member == _symbolMemberMap.end()) 51 return nullptr; 52 Archive::Child c = member->second; 53 54 // Don't return a member already returned 55 ErrorOr<StringRef> buf = c.getBuffer(); 56 if (!buf) 57 return nullptr; 58 const char *memberStart = buf->data(); 59 if (_membersInstantiated.count(memberStart)) 60 return nullptr; 61 _membersInstantiated.insert(memberStart); 62 63 std::unique_ptr<File> result; 64 if (instantiateMember(c, result)) 65 return nullptr; 66 67 File *file = result.get(); 68 _filesReturned.push_back(std::move(result)); 69 70 // Give up the file pointer. It was stored and will be destroyed with destruction of FileArchive 71 return file; 72 } 73 74 /// \brief parse each member 75 std::error_code 76 parseAllMembers(std::vector<std::unique_ptr<File>> &result) override { 77 if (std::error_code ec = parse()) 78 return ec; 79 llvm::Error err; 80 for (auto mf = _archive->child_begin(err), me = _archive->child_end(); 81 mf != me; ++mf) { 82 std::unique_ptr<File> file; 83 if (std::error_code ec = instantiateMember(*mf, file)) { 84 // err is Success (or we wouldn't be in the loop body) but we can't 85 // return without testing or consuming it. 86 consumeError(std::move(err)); 87 return ec; 88 } 89 result.push_back(std::move(file)); 90 } 91 if (err) 92 return errorToErrorCode(std::move(err)); 93 return std::error_code(); 94 } 95 96 const AtomRange<DefinedAtom> defined() const override { 97 return _noDefinedAtoms; 98 } 99 100 const AtomRange<UndefinedAtom> undefined() const override { 101 return _noUndefinedAtoms; 102 } 103 104 const AtomRange<SharedLibraryAtom> sharedLibrary() const override { 105 return _noSharedLibraryAtoms; 106 } 107 108 const AtomRange<AbsoluteAtom> absolute() const override { 109 return _noAbsoluteAtoms; 110 } 111 112 void clearAtoms() override { 113 _noDefinedAtoms.clear(); 114 _noUndefinedAtoms.clear(); 115 _noSharedLibraryAtoms.clear(); 116 _noAbsoluteAtoms.clear(); 117 } 118 119 protected: 120 std::error_code doParse() override { 121 // Make Archive object which will be owned by FileArchive object. 122 llvm::Error Err; 123 _archive.reset(new Archive(_mb->getMemBufferRef(), Err)); 124 if (Err) 125 return errorToErrorCode(std::move(Err)); 126 std::error_code ec; 127 if ((ec = buildTableOfContents())) 128 return ec; 129 return std::error_code(); 130 } 131 132 private: 133 std::error_code instantiateMember(Archive::Child member, 134 std::unique_ptr<File> &result) const { 135 ErrorOr<llvm::MemoryBufferRef> mbOrErr = member.getMemoryBufferRef(); 136 if (std::error_code ec = mbOrErr.getError()) 137 return ec; 138 llvm::MemoryBufferRef mb = mbOrErr.get(); 139 std::string memberPath = (_archive->getFileName() + "(" 140 + mb.getBufferIdentifier() + ")").str(); 141 142 if (_logLoading) 143 llvm::errs() << memberPath << "\n"; 144 145 std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer( 146 mb.getBuffer(), mb.getBufferIdentifier(), false)); 147 148 ErrorOr<std::unique_ptr<File>> fileOrErr = 149 _registry.loadFile(std::move(memberMB)); 150 if (std::error_code ec = fileOrErr.getError()) 151 return ec; 152 result = std::move(fileOrErr.get()); 153 if (std::error_code ec = result->parse()) 154 return ec; 155 result->setArchivePath(_archive->getFileName()); 156 157 // The memory buffer is co-owned by the archive file and the children, 158 // so that the bufffer is deallocated when all the members are destructed. 159 result->setSharedMemoryBuffer(_mb); 160 return std::error_code(); 161 } 162 163 std::error_code buildTableOfContents() { 164 DEBUG_WITH_TYPE("FileArchive", llvm::dbgs() 165 << "Table of contents for archive '" 166 << _archive->getFileName() << "':\n"); 167 for (const Archive::Symbol &sym : _archive->symbols()) { 168 StringRef name = sym.getName(); 169 ErrorOr<Archive::Child> memberOrErr = sym.getMember(); 170 if (std::error_code ec = memberOrErr.getError()) 171 return ec; 172 Archive::Child member = memberOrErr.get(); 173 DEBUG_WITH_TYPE("FileArchive", 174 llvm::dbgs() 175 << llvm::format("0x%08llX ", 176 member.getBuffer()->data()) 177 << "'" << name << "'\n"); 178 _symbolMemberMap.insert(std::make_pair(name, member)); 179 } 180 return std::error_code(); 181 } 182 183 typedef std::unordered_map<StringRef, Archive::Child> MemberMap; 184 typedef std::set<const char *> InstantiatedSet; 185 186 std::shared_ptr<MemoryBuffer> _mb; 187 const Registry &_registry; 188 std::unique_ptr<Archive> _archive; 189 MemberMap _symbolMemberMap; 190 InstantiatedSet _membersInstantiated; 191 bool _logLoading; 192 std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers; 193 std::vector<std::unique_ptr<File>> _filesReturned; 194 }; 195 196 class ArchiveReader : public Reader { 197 public: 198 ArchiveReader(bool logLoading) : _logLoading(logLoading) {} 199 200 bool canParse(file_magic magic, MemoryBufferRef) const override { 201 return magic == llvm::sys::fs::file_magic::archive; 202 } 203 204 ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb, 205 const Registry ®) const override { 206 StringRef path = mb->getBufferIdentifier(); 207 std::unique_ptr<File> ret = 208 llvm::make_unique<FileArchive>(std::move(mb), reg, path, _logLoading); 209 return std::move(ret); 210 } 211 212 private: 213 bool _logLoading; 214 }; 215 216 } // anonymous namespace 217 218 void Registry::addSupportArchives(bool logLoading) { 219 add(std::unique_ptr<Reader>(new ArchiveReader(logLoading))); 220 } 221 222 } // namespace lld 223