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