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 &reg,
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 &reg) 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