]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lld / 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/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 /// 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 &reg,
45               StringRef path, bool logLoading)
46       : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
47         _registry(reg), _logLoading(logLoading) {}
48
49   /// 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   /// 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 &reg) 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