]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/ReaderWriter/FileArchive.cpp
Vendor import of lld trunk r233088:
[FreeBSD/FreeBSD.git] / lib / ReaderWriter / FileArchive.cpp
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/LLVM.h"
12 #include "lld/Core/LinkingContext.h"
13 #include "lld/Core/Parallel.h"
14 #include "llvm/ADT/Hashing.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Object/Archive.h"
17 #include "llvm/Object/ObjectFile.h"
18 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/Format.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include <memory>
22 #include <mutex>
23 #include <set>
24 #include <unordered_map>
25
26 using llvm::object::Archive;
27 using llvm::object::ObjectFile;
28 using llvm::object::SymbolRef;
29 using llvm::object::symbol_iterator;
30 using llvm::object::object_error;
31
32 namespace lld {
33
34 namespace {
35
36 /// \brief The FileArchive class represents an Archive Library file
37 class FileArchive : public lld::ArchiveLibraryFile {
38 public:
39   FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
40               StringRef path, bool logLoading)
41       : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
42         _registry(reg), _logLoading(logLoading) {}
43
44   /// \brief Check if any member of the archive contains an Atom with the
45   /// specified name and return the File object for that member, or nullptr.
46   File *find(StringRef name, bool dataSymbolOnly) override {
47     auto member = _symbolMemberMap.find(name);
48     if (member == _symbolMemberMap.end())
49       return nullptr;
50     Archive::child_iterator ci = member->second;
51
52     // Don't return a member already returned
53     const char *memberStart = ci->getBuffer().data();
54     if (_membersInstantiated.count(memberStart))
55       return nullptr;
56     if (dataSymbolOnly && !isDataSymbol(ci, name))
57       return nullptr;
58
59     _membersInstantiated.insert(memberStart);
60
61     // Check if a file is preloaded.
62     {
63       std::lock_guard<std::mutex> lock(_mutex);
64       auto it = _preloaded.find(memberStart);
65       if (it != _preloaded.end()) {
66         std::unique_ptr<Future<File *>> &p = it->second;
67         Future<File *> *future = p.get();
68         return future->get();
69       }
70     }
71
72     std::unique_ptr<File> result;
73     if (instantiateMember(ci, result))
74       return nullptr;
75
76     // give up the pointer so that this object no longer manages it
77     return result.release();
78   }
79
80   // Instantiate a member file containing a given symbol name.
81   void preload(TaskGroup &group, StringRef name) override {
82     auto member = _symbolMemberMap.find(name);
83     if (member == _symbolMemberMap.end())
84       return;
85     Archive::child_iterator ci = member->second;
86
87     // Do nothing if a member is already instantiated.
88     const char *memberStart = ci->getBuffer().data();
89     if (_membersInstantiated.count(memberStart))
90       return;
91
92     std::lock_guard<std::mutex> lock(_mutex);
93     if (_preloaded.find(memberStart) != _preloaded.end())
94       return;
95
96     // Instantiate the member
97     auto *future = new Future<File *>();
98     _preloaded[memberStart] = std::unique_ptr<Future<File *>>(future);
99
100     group.spawn([=] {
101       std::unique_ptr<File> result;
102       std::error_code ec = instantiateMember(ci, result);
103       future->set(ec ? nullptr : result.release());
104     });
105   }
106
107   /// \brief parse each member
108   std::error_code
109   parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
110     if (std::error_code ec = parse())
111       return ec;
112     for (auto mf = _archive->child_begin(), me = _archive->child_end();
113          mf != me; ++mf) {
114       std::unique_ptr<File> file;
115       if (std::error_code ec = instantiateMember(mf, file))
116         return ec;
117       result.push_back(std::move(file));
118     }
119     return std::error_code();
120   }
121
122   const atom_collection<DefinedAtom> &defined() const override {
123     return _definedAtoms;
124   }
125
126   const atom_collection<UndefinedAtom> &undefined() const override {
127     return _undefinedAtoms;
128   }
129
130   const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
131     return _sharedLibraryAtoms;
132   }
133
134   const atom_collection<AbsoluteAtom> &absolute() const override {
135     return _absoluteAtoms;
136   }
137
138   /// Returns a set of all defined symbols in the archive.
139   std::set<StringRef> getDefinedSymbols() override {
140     parse();
141     std::set<StringRef> ret;
142     for (const auto &e : _symbolMemberMap)
143       ret.insert(e.first);
144     return ret;
145   }
146
147 protected:
148   std::error_code doParse() override {
149     // Make Archive object which will be owned by FileArchive object.
150     std::error_code ec;
151     _archive.reset(new Archive(_mb->getMemBufferRef(), ec));
152     if (ec)
153       return ec;
154     if ((ec = buildTableOfContents()))
155       return ec;
156     return std::error_code();
157   }
158
159 private:
160   std::error_code
161   instantiateMember(Archive::child_iterator member,
162                     std::unique_ptr<File> &result) const {
163     ErrorOr<llvm::MemoryBufferRef> mbOrErr = member->getMemoryBufferRef();
164     if (std::error_code ec = mbOrErr.getError())
165       return ec;
166     llvm::MemoryBufferRef mb = mbOrErr.get();
167     std::string memberPath = (_archive->getFileName() + "("
168                            + mb.getBufferIdentifier() + ")").str();
169
170     if (_logLoading)
171       llvm::errs() << memberPath << "\n";
172
173     std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
174         mb.getBuffer(), mb.getBufferIdentifier(), false));
175
176     std::vector<std::unique_ptr<File>> files;
177     if (std::error_code ec = _registry.loadFile(std::move(memberMB), files))
178       return ec;
179     assert(files.size() == 1);
180     result = std::move(files[0]);
181     if (std::error_code ec = result->parse())
182       return ec;
183     result->setArchivePath(_archive->getFileName());
184
185     // The memory buffer is co-owned by the archive file and the children,
186     // so that the bufffer is deallocated when all the members are destructed.
187     result->setSharedMemoryBuffer(_mb);
188     return std::error_code();
189   }
190
191   // Parses the given memory buffer as an object file, and returns true
192   // code if the given symbol is a data symbol. If the symbol is not a data
193   // symbol or does not exist, returns false.
194   bool isDataSymbol(Archive::child_iterator member, StringRef symbol) const {
195     ErrorOr<llvm::MemoryBufferRef> buf = member->getMemoryBufferRef();
196     if (buf.getError())
197       return false;
198     std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(
199         buf.get().getBuffer(), buf.get().getBufferIdentifier(), false));
200
201     auto objOrErr(ObjectFile::createObjectFile(mb->getMemBufferRef()));
202     if (objOrErr.getError())
203       return false;
204     std::unique_ptr<ObjectFile> obj = std::move(objOrErr.get());
205
206     for (SymbolRef sym : obj->symbols()) {
207       // Skip until we find the symbol.
208       StringRef name;
209       if (sym.getName(name))
210         return false;
211       if (name != symbol)
212         continue;
213       uint32_t flags = sym.getFlags();
214       if (flags <= SymbolRef::SF_Undefined)
215         continue;
216
217       // Returns true if it's a data symbol.
218       SymbolRef::Type type;
219       if (sym.getType(type))
220         return false;
221       if (type == SymbolRef::ST_Data)
222         return true;
223     }
224     return false;
225   }
226
227   std::error_code buildTableOfContents() {
228     DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
229                                        << "Table of contents for archive '"
230                                        << _archive->getFileName() << "':\n");
231     for (const Archive::Symbol &sym : _archive->symbols()) {
232       StringRef name = sym.getName();
233       ErrorOr<Archive::child_iterator> memberOrErr = sym.getMember();
234       if (std::error_code ec = memberOrErr.getError())
235         return ec;
236       Archive::child_iterator member = memberOrErr.get();
237       DEBUG_WITH_TYPE(
238           "FileArchive",
239           llvm::dbgs() << llvm::format("0x%08llX ", member->getBuffer().data())
240                        << "'" << name << "'\n");
241       _symbolMemberMap[name] = member;
242     }
243     return std::error_code();
244   }
245
246   typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap;
247   typedef std::set<const char *> InstantiatedSet;
248
249   std::shared_ptr<MemoryBuffer> _mb;
250   const Registry &_registry;
251   std::unique_ptr<Archive> _archive;
252   MemberMap _symbolMemberMap;
253   InstantiatedSet _membersInstantiated;
254   atom_collection_vector<DefinedAtom> _definedAtoms;
255   atom_collection_vector<UndefinedAtom> _undefinedAtoms;
256   atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
257   atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
258   bool _logLoading;
259   std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
260   std::map<const char *, std::unique_ptr<Future<File *>>> _preloaded;
261   std::mutex _mutex;
262 };
263
264 class ArchiveReader : public Reader {
265 public:
266   ArchiveReader(bool logLoading) : _logLoading(logLoading) {}
267
268   bool canParse(file_magic magic, StringRef,
269                 const MemoryBuffer &) const override {
270     return (magic == llvm::sys::fs::file_magic::archive);
271   }
272
273   std::error_code
274   loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
275            std::vector<std::unique_ptr<File>> &result) const override {
276     StringRef path = mb->getBufferIdentifier();
277     std::unique_ptr<FileArchive> file(
278         new FileArchive(std::move(mb), reg, path, _logLoading));
279     result.push_back(std::move(file));
280     return std::error_code();
281   }
282
283 private:
284   bool _logLoading;
285 };
286
287 } // anonymous namespace
288
289 void Registry::addSupportArchives(bool logLoading) {
290   add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
291 }
292
293 } // end namespace lld