blob: f28cc4e7963b364f021273454f3f6c40ab9a318d [file] [log] [blame]
Nick Kledzike5552772013-12-19 21:58:00 +00001//===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===//
Rui Ueyama34efe772013-12-06 04:43:01 +00002//
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//
Nick Kledzike5552772013-12-19 21:58:00 +00008//===----------------------------------------------------------------------===//
Rui Ueyama34efe772013-12-06 04:43:01 +00009
Nick Kledzike5552772013-12-19 21:58:00 +000010#include "lld/Core/ArchiveLibraryFile.h"
11#include "lld/Core/LLVM.h"
Rui Ueyama34efe772013-12-06 04:43:01 +000012
13#include "llvm/ADT/Hashing.h"
Nick Kledzike5552772013-12-19 21:58:00 +000014#include "llvm/ADT/StringRef.h"
Rui Ueyama34efe772013-12-06 04:43:01 +000015#include "llvm/Object/Archive.h"
Nick Kledzike5552772013-12-19 21:58:00 +000016#include "llvm/Object/ObjectFile.h"
17#include "llvm/Support/Debug.h"
18#include "llvm/Support/Format.h"
Rui Ueyama34efe772013-12-06 04:43:01 +000019#include "llvm/Support/MemoryBuffer.h"
20
21#include <unordered_map>
Nick Kledzike5552772013-12-19 21:58:00 +000022#include <set>
23
24using llvm::object::Archive;
25using llvm::object::ObjectFile;
26using llvm::object::SymbolRef;
27using llvm::object::symbol_iterator;
28using llvm::object::object_error;
Rui Ueyama34efe772013-12-06 04:43:01 +000029
30namespace lld {
31
Nick Kledzike5552772013-12-19 21:58:00 +000032namespace {
Rui Ueyama34efe772013-12-06 04:43:01 +000033
Nick Kledzike5552772013-12-19 21:58:00 +000034/// \brief The FileArchive class represents an Archive Library file
35class FileArchive : public lld::ArchiveLibraryFile {
36public:
Rui Ueyama170a1a82013-12-20 07:48:29 +000037 virtual ~FileArchive() {}
Nick Kledzike5552772013-12-19 21:58:00 +000038
39 /// \brief Check if any member of the archive contains an Atom with the
40 /// specified name and return the File object for that member, or nullptr.
41 virtual const File *find(StringRef name, bool dataSymbolOnly) const {
42 auto member = _symbolMemberMap.find(name);
Rui Ueyama170a1a82013-12-20 07:48:29 +000043 if (member == _symbolMemberMap.end())
Rui Ueyama34efe772013-12-06 04:43:01 +000044 return nullptr;
Nick Kledzike5552772013-12-19 21:58:00 +000045 Archive::child_iterator ci = member->second;
46
Rui Ueyama170a1a82013-12-20 07:48:29 +000047 // Don't return a member already returned
Nick Kledzike5552772013-12-19 21:58:00 +000048 const char *memberStart = ci->getBuffer().data();
Rui Ueyama170a1a82013-12-20 07:48:29 +000049 if (_membersInstantiated.count(memberStart))
Rui Ueyama34efe772013-12-06 04:43:01 +000050 return nullptr;
Nick Kledzike5552772013-12-19 21:58:00 +000051
52 if (dataSymbolOnly) {
53 OwningPtr<MemoryBuffer> buff;
54 if (ci->getMemoryBuffer(buff, true))
55 return nullptr;
56 if (isDataSymbol(buff.take(), name))
57 return nullptr;
58 }
59
60 std::vector<std::unique_ptr<File>> result;
61 if (instantiateMember(ci, result))
62 return nullptr;
63 assert(result.size() == 1);
64
65 // give up the pointer so that this object no longer manages it
66 return result[0].release();
Rui Ueyama34efe772013-12-06 04:43:01 +000067 }
68
Nick Kledzike5552772013-12-19 21:58:00 +000069 /// \brief Load all members of the archive ?
70 virtual bool isWholeArchive() const { return _isWholeArchive; }
Rui Ueyama34efe772013-12-06 04:43:01 +000071
Nick Kledzike5552772013-12-19 21:58:00 +000072 /// \brief parse each member
73 virtual error_code
Rui Ueyama170a1a82013-12-20 07:48:29 +000074 parseAllMembers(std::vector<std::unique_ptr<File>> &result) const {
75 for (auto mf = _archive->begin_children(), me = _archive->end_children();
76 mf != me; ++mf) {
77 if (error_code ec = instantiateMember(mf, result))
Nick Kledzike5552772013-12-19 21:58:00 +000078 return ec;
79 }
80 return error_code::success();
81 }
Rui Ueyama34efe772013-12-06 04:43:01 +000082
Nick Kledzike5552772013-12-19 21:58:00 +000083 virtual const atom_collection<DefinedAtom> &defined() const {
84 return _definedAtoms;
85 }
Rui Ueyama34efe772013-12-06 04:43:01 +000086
Nick Kledzike5552772013-12-19 21:58:00 +000087 virtual const atom_collection<UndefinedAtom> &undefined() const {
88 return _undefinedAtoms;
89 }
Rui Ueyama34efe772013-12-06 04:43:01 +000090
Nick Kledzike5552772013-12-19 21:58:00 +000091 virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
92 return _sharedLibraryAtoms;
93 }
94
95 virtual const atom_collection<AbsoluteAtom> &absolute() const {
96 return _absoluteAtoms;
97 }
98
99protected:
Rui Ueyama170a1a82013-12-20 07:48:29 +0000100 error_code
101 instantiateMember(Archive::child_iterator member,
102 std::vector<std::unique_ptr<File>> &result) const {
Rui Ueyama34efe772013-12-06 04:43:01 +0000103 OwningPtr<MemoryBuffer> buff;
Rui Ueyama170a1a82013-12-20 07:48:29 +0000104 if (error_code ec = member->getMemoryBuffer(buff, true))
Rui Ueyama34efe772013-12-06 04:43:01 +0000105 return ec;
Nick Kledzike5552772013-12-19 21:58:00 +0000106 if (_logLoading)
Rui Ueyama34efe772013-12-06 04:43:01 +0000107 llvm::outs() << buff->getBufferIdentifier() << "\n";
Nick Kledzike5552772013-12-19 21:58:00 +0000108 std::unique_ptr<MemoryBuffer> mb(buff.take());
109 _registry.parseFile(mb, result);
110 const char *memberStart = member->getBuffer().data();
111 _membersInstantiated.insert(memberStart);
112 return error_code::success();
Rui Ueyama34efe772013-12-06 04:43:01 +0000113 }
Rui Ueyama34efe772013-12-06 04:43:01 +0000114
Nick Kledzike5552772013-12-19 21:58:00 +0000115 error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const {
Rui Ueyama170a1a82013-12-20 07:48:29 +0000116 std::unique_ptr<ObjectFile> obj(ObjectFile::createObjectFile(mb));
Nick Kledzike5552772013-12-19 21:58:00 +0000117 error_code ec;
118 SymbolRef::Type symtype;
119 uint32_t symflags;
120 symbol_iterator ibegin = obj->begin_symbols();
121 symbol_iterator iend = obj->end_symbols();
122 StringRef symbolname;
Rui Ueyama34efe772013-12-06 04:43:01 +0000123
Nick Kledzike5552772013-12-19 21:58:00 +0000124 for (symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
Rui Ueyama170a1a82013-12-20 07:48:29 +0000125 if (ec)
126 return ec;
Rui Ueyama34efe772013-12-06 04:43:01 +0000127
Nick Kledzike5552772013-12-19 21:58:00 +0000128 // Get symbol name
Rui Ueyama170a1a82013-12-20 07:48:29 +0000129 if ((ec = (i->getName(symbolname))))
130 return ec;
Rui Ueyama34efe772013-12-06 04:43:01 +0000131
Nick Kledzike5552772013-12-19 21:58:00 +0000132 if (symbolname != symbol)
Rui Ueyama170a1a82013-12-20 07:48:29 +0000133 continue;
Rui Ueyama34efe772013-12-06 04:43:01 +0000134
Nick Kledzike5552772013-12-19 21:58:00 +0000135 // Get symbol flags
Rui Ueyama170a1a82013-12-20 07:48:29 +0000136 if ((ec = (i->getFlags(symflags))))
137 return ec;
Nick Kledzike5552772013-12-19 21:58:00 +0000138
139 if (symflags <= SymbolRef::SF_Undefined)
Rui Ueyama170a1a82013-12-20 07:48:29 +0000140 continue;
Nick Kledzike5552772013-12-19 21:58:00 +0000141
142 // Get Symbol Type
Rui Ueyama170a1a82013-12-20 07:48:29 +0000143 if ((ec = (i->getType(symtype))))
144 return ec;
Nick Kledzike5552772013-12-19 21:58:00 +0000145
146 if (symtype == SymbolRef::ST_Data) {
147 return error_code::success();
148 }
149 }
150 return object_error::parse_failed;
151 }
152
153private:
Rui Ueyama170a1a82013-12-20 07:48:29 +0000154 typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap;
155 typedef std::set<const char *> InstantiatedSet;
Nick Kledzike5552772013-12-19 21:58:00 +0000156
Rui Ueyama170a1a82013-12-20 07:48:29 +0000157 const Registry &_registry;
158 std::unique_ptr<Archive> _archive;
159 mutable MemberMap _symbolMemberMap;
160 mutable InstantiatedSet _membersInstantiated;
161 atom_collection_vector<DefinedAtom> _definedAtoms;
162 atom_collection_vector<UndefinedAtom> _undefinedAtoms;
Nick Kledzike5552772013-12-19 21:58:00 +0000163 atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
Rui Ueyama170a1a82013-12-20 07:48:29 +0000164 atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
165 bool _isWholeArchive;
166 bool _logLoading;
Nick Kledzike5552772013-12-19 21:58:00 +0000167
168public:
169 /// only subclasses of ArchiveLibraryFile can be instantiated
Rui Ueyama170a1a82013-12-20 07:48:29 +0000170 FileArchive(const Registry &registry, Archive *archive, StringRef path,
171 bool isWholeArchive, bool logLoading)
172 : ArchiveLibraryFile(path), _registry(registry),
173 _archive(std::move(archive)), _isWholeArchive(isWholeArchive),
174 _logLoading(logLoading) {}
Nick Kledzike5552772013-12-19 21:58:00 +0000175
176 error_code buildTableOfContents() {
Rui Ueyama170a1a82013-12-20 07:48:29 +0000177 DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
178 << "Table of contents for archive '"
179 << _archive->getFileName() << "':\n");
Nick Kledzike5552772013-12-19 21:58:00 +0000180 for (auto i = _archive->begin_symbols(), e = _archive->end_symbols();
Rui Ueyama170a1a82013-12-20 07:48:29 +0000181 i != e; ++i) {
Nick Kledzike5552772013-12-19 21:58:00 +0000182 StringRef name;
183 error_code ec;
184 Archive::child_iterator member;
185 if ((ec = i->getName(name)))
186 return ec;
187 if ((ec = i->getMember(member)))
188 return ec;
Rui Ueyama170a1a82013-12-20 07:48:29 +0000189 DEBUG_WITH_TYPE(
190 "FileArchive",
191 llvm::dbgs() << llvm::format("0x%08llX ", member->getBuffer().data())
192 << "'" << name << "'\n");
Nick Kledzike5552772013-12-19 21:58:00 +0000193 _symbolMemberMap[name] = member;
194 }
Rui Ueyama170a1a82013-12-20 07:48:29 +0000195 return error_code::success();
Nick Kledzike5552772013-12-19 21:58:00 +0000196 }
197
198}; // class FileArchive
199
Nick Kledzike5552772013-12-19 21:58:00 +0000200class ArchiveReader : public Reader {
201public:
Rui Ueyama170a1a82013-12-20 07:48:29 +0000202 ArchiveReader(bool logLoading) : _logLoading(logLoading) {}
203
204 virtual bool canParse(file_magic magic, StringRef,
205 const MemoryBuffer &) const {
Nick Kledzike5552772013-12-19 21:58:00 +0000206 return (magic == llvm::sys::fs::file_magic::archive);
207 }
Rui Ueyama170a1a82013-12-20 07:48:29 +0000208
Nick Kledzike5552772013-12-19 21:58:00 +0000209 virtual error_code
210 parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry &reg,
211 std::vector<std::unique_ptr<File>> &result) const {
212 // Make Archive object which will be owned by FileArchive object.
213 error_code ec;
Rui Ueyama170a1a82013-12-20 07:48:29 +0000214 Archive *archive = new Archive(mb.get(), ec);
Rui Ueyama34efe772013-12-06 04:43:01 +0000215 if (ec)
216 return ec;
Nick Kledzike5552772013-12-19 21:58:00 +0000217 StringRef path = mb->getBufferIdentifier();
218 // Construct FileArchive object.
Rui Ueyama170a1a82013-12-20 07:48:29 +0000219 std::unique_ptr<FileArchive> file(
220 new FileArchive(reg, archive, path, false, _logLoading));
Nick Kledzike5552772013-12-19 21:58:00 +0000221 ec = file->buildTableOfContents();
222 if (ec)
Rui Ueyama34efe772013-12-06 04:43:01 +0000223 return ec;
Rui Ueyama170a1a82013-12-20 07:48:29 +0000224
Nick Kledzike5552772013-12-19 21:58:00 +0000225 // Transfer ownership of memory buffer to Archive object.
226 mb.release();
Rui Ueyama170a1a82013-12-20 07:48:29 +0000227
Nick Kledzike5552772013-12-19 21:58:00 +0000228 result.push_back(std::move(file));
Rui Ueyama170a1a82013-12-20 07:48:29 +0000229 return error_code::success();
Rui Ueyama34efe772013-12-06 04:43:01 +0000230 }
Rui Ueyama170a1a82013-12-20 07:48:29 +0000231
Nick Kledzike5552772013-12-19 21:58:00 +0000232private:
Rui Ueyama170a1a82013-12-20 07:48:29 +0000233 bool _logLoading;
Nick Kledzike5552772013-12-19 21:58:00 +0000234};
Rui Ueyama34efe772013-12-06 04:43:01 +0000235
Nick Kledzike5552772013-12-19 21:58:00 +0000236} // anonymous namespace
237
Nick Kledzike5552772013-12-19 21:58:00 +0000238void Registry::addSupportArchives(bool logLoading) {
239 add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
Rui Ueyama34efe772013-12-06 04:43:01 +0000240}
241
242} // end namespace lld
Nick Kledzike5552772013-12-19 21:58:00 +0000243
244