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