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 Expected<StringRef> buf = c.getBuffer(); 56 if (!buf) { 57 // TODO: Actually report errors helpfully. 58 consumeError(buf.takeError()); 59 return nullptr; 60 } 61 const char *memberStart = buf->data(); 62 if (_membersInstantiated.count(memberStart)) 63 return nullptr; 64 _membersInstantiated.insert(memberStart); 65 66 std::unique_ptr<File> result; 67 if (instantiateMember(c, result)) 68 return nullptr; 69 70 File *file = result.get(); 71 _filesReturned.push_back(std::move(result)); 72 73 // Give up the file pointer. It was stored and will be destroyed with destruction of FileArchive 74 return file; 75 } 76 77 /// \brief parse each member 78 std::error_code 79 parseAllMembers(std::vector<std::unique_ptr<File>> &result) override { 80 if (std::error_code ec = parse()) 81 return ec; 82 llvm::Error err = llvm::Error::success(); 83 for (auto mf = _archive->child_begin(err), me = _archive->child_end(); 84 mf != me; ++mf) { 85 std::unique_ptr<File> file; 86 if (std::error_code ec = instantiateMember(*mf, file)) { 87 // err is Success (or we wouldn't be in the loop body) but we can't 88 // return without testing or consuming it. 89 consumeError(std::move(err)); 90 return ec; 91 } 92 result.push_back(std::move(file)); 93 } 94 if (err) 95 return errorToErrorCode(std::move(err)); 96 return std::error_code(); 97 } 98 99 const AtomRange<DefinedAtom> defined() const override { 100 return _noDefinedAtoms; 101 } 102 103 const AtomRange<UndefinedAtom> undefined() const override { 104 return _noUndefinedAtoms; 105 } 106 107 const AtomRange<SharedLibraryAtom> sharedLibrary() const override { 108 return _noSharedLibraryAtoms; 109 } 110 111 const AtomRange<AbsoluteAtom> absolute() const override { 112 return _noAbsoluteAtoms; 113 } 114 115 void clearAtoms() override { 116 _noDefinedAtoms.clear(); 117 _noUndefinedAtoms.clear(); 118 _noSharedLibraryAtoms.clear(); 119 _noAbsoluteAtoms.clear(); 120 } 121 122 protected: 123 std::error_code doParse() override { 124 // Make Archive object which will be owned by FileArchive object. 125 llvm::Error Err = llvm::Error::success(); 126 _archive.reset(new Archive(_mb->getMemBufferRef(), Err)); 127 if (Err) 128 return errorToErrorCode(std::move(Err)); 129 std::error_code ec; 130 if ((ec = buildTableOfContents())) 131 return ec; 132 return std::error_code(); 133 } 134 135 private: 136 std::error_code instantiateMember(Archive::Child member, 137 std::unique_ptr<File> &result) const { 138 Expected<llvm::MemoryBufferRef> mbOrErr = member.getMemoryBufferRef(); 139 if (!mbOrErr) 140 return errorToErrorCode(mbOrErr.takeError()); 141 llvm::MemoryBufferRef mb = mbOrErr.get(); 142 std::string memberPath = (_archive->getFileName() + "(" 143 + mb.getBufferIdentifier() + ")").str(); 144 145 if (_logLoading) 146 llvm::errs() << memberPath << "\n"; 147 148 std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer( 149 mb.getBuffer(), mb.getBufferIdentifier(), false)); 150 151 ErrorOr<std::unique_ptr<File>> fileOrErr = 152 _registry.loadFile(std::move(memberMB)); 153 if (std::error_code ec = fileOrErr.getError()) 154 return ec; 155 result = std::move(fileOrErr.get()); 156 if (std::error_code ec = result->parse()) 157 return ec; 158 result->setArchivePath(_archive->getFileName()); 159 160 // The memory buffer is co-owned by the archive file and the children, 161 // so that the bufffer is deallocated when all the members are destructed. 162 result->setSharedMemoryBuffer(_mb); 163 return std::error_code(); 164 } 165 166 std::error_code buildTableOfContents() { 167 DEBUG_WITH_TYPE("FileArchive", llvm::dbgs() 168 << "Table of contents for archive '" 169 << _archive->getFileName() << "':\n"); 170 for (const Archive::Symbol &sym : _archive->symbols()) { 171 StringRef name = sym.getName(); 172 Expected<Archive::Child> memberOrErr = sym.getMember(); 173 if (!memberOrErr) 174 return errorToErrorCode(memberOrErr.takeError()); 175 Archive::Child member = memberOrErr.get(); 176 DEBUG_WITH_TYPE("FileArchive", 177 llvm::dbgs() 178 << llvm::format("0x%08llX ", 179 member.getBuffer()->data()) 180 << "'" << name << "'\n"); 181 _symbolMemberMap.insert(std::make_pair(name, member)); 182 } 183 return std::error_code(); 184 } 185 186 typedef std::unordered_map<StringRef, Archive::Child> MemberMap; 187 typedef std::set<const char *> InstantiatedSet; 188 189 std::shared_ptr<MemoryBuffer> _mb; 190 const Registry &_registry; 191 std::unique_ptr<Archive> _archive; 192 MemberMap _symbolMemberMap; 193 InstantiatedSet _membersInstantiated; 194 bool _logLoading; 195 std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers; 196 std::vector<std::unique_ptr<File>> _filesReturned; 197 }; 198 199 class ArchiveReader : public Reader { 200 public: 201 ArchiveReader(bool logLoading) : _logLoading(logLoading) {} 202 203 bool canParse(file_magic magic, MemoryBufferRef) const override { 204 return magic == llvm::sys::fs::file_magic::archive; 205 } 206 207 ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb, 208 const Registry ®) const override { 209 StringRef path = mb->getBufferIdentifier(); 210 std::unique_ptr<File> ret = 211 llvm::make_unique<FileArchive>(std::move(mb), reg, path, _logLoading); 212 return std::move(ret); 213 } 214 215 private: 216 bool _logLoading; 217 }; 218 219 } // anonymous namespace 220 221 void Registry::addSupportArchives(bool logLoading) { 222 add(std::unique_ptr<Reader>(new ArchiveReader(logLoading))); 223 } 224 225 } // namespace lld 226