blob: 471916d0ff82b95f32e38ce9105685eee59a7a7b [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 Ueyama34efe772013-12-06 04:43:01 +000037
Nick Kledzike5552772013-12-19 21:58:00 +000038 virtual ~FileArchive() { }
39
40 /// \brief Check if any member of the archive contains an Atom with the
41 /// specified name and return the File object for that member, or nullptr.
42 virtual const File *find(StringRef name, bool dataSymbolOnly) const {
43 auto member = _symbolMemberMap.find(name);
44 if (member == _symbolMemberMap.end())
Rui Ueyama34efe772013-12-06 04:43:01 +000045 return nullptr;
Nick Kledzike5552772013-12-19 21:58:00 +000046 Archive::child_iterator ci = member->second;
47
48 // Don't return a member already returned
49 const char *memberStart = ci->getBuffer().data();
50 if (_membersInstantiated.count(memberStart))
Rui Ueyama34efe772013-12-06 04:43:01 +000051 return nullptr;
Nick Kledzike5552772013-12-19 21:58:00 +000052
53 if (dataSymbolOnly) {
54 OwningPtr<MemoryBuffer> buff;
55 if (ci->getMemoryBuffer(buff, true))
56 return nullptr;
57 if (isDataSymbol(buff.take(), name))
58 return nullptr;
59 }
60
61 std::vector<std::unique_ptr<File>> result;
62 if (instantiateMember(ci, result))
63 return nullptr;
64 assert(result.size() == 1);
65
66 // give up the pointer so that this object no longer manages it
67 return result[0].release();
Rui Ueyama34efe772013-12-06 04:43:01 +000068 }
69
Nick Kledzike5552772013-12-19 21:58:00 +000070 /// \brief Load all members of the archive ?
71 virtual bool isWholeArchive() const { return _isWholeArchive; }
Rui Ueyama34efe772013-12-06 04:43:01 +000072
Nick Kledzike5552772013-12-19 21:58:00 +000073 /// \brief parse each member
74 virtual error_code
75 parseAllMembers(std::vector<std::unique_ptr<File>> &result) const {
76 for (auto mf = _archive->begin_children(),
77 me = _archive->end_children(); mf != me; ++mf) {
78 if (error_code ec=instantiateMember(mf, result))
79 return ec;
80 }
81 return error_code::success();
82 }
Rui Ueyama34efe772013-12-06 04:43:01 +000083
Nick Kledzike5552772013-12-19 21:58:00 +000084 virtual const atom_collection<DefinedAtom> &defined() const {
85 return _definedAtoms;
86 }
Rui Ueyama34efe772013-12-06 04:43:01 +000087
Nick Kledzike5552772013-12-19 21:58:00 +000088 virtual const atom_collection<UndefinedAtom> &undefined() const {
89 return _undefinedAtoms;
90 }
Rui Ueyama34efe772013-12-06 04:43:01 +000091
Nick Kledzike5552772013-12-19 21:58:00 +000092 virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
93 return _sharedLibraryAtoms;
94 }
95
96 virtual const atom_collection<AbsoluteAtom> &absolute() const {
97 return _absoluteAtoms;
98 }
99
100protected:
101 error_code 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;
Nick Kledzike5552772013-12-19 21:58:00 +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
Rui Ueyama34efe772013-12-06 04:43:01 +0000115
Nick Kledzike5552772013-12-19 21:58:00 +0000116 error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const {
117 std::unique_ptr<ObjectFile>
118 obj(ObjectFile::createObjectFile(mb));
119 error_code ec;
120 SymbolRef::Type symtype;
121 uint32_t symflags;
122 symbol_iterator ibegin = obj->begin_symbols();
123 symbol_iterator iend = obj->end_symbols();
124 StringRef symbolname;
Rui Ueyama34efe772013-12-06 04:43:01 +0000125
Nick Kledzike5552772013-12-19 21:58:00 +0000126 for (symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
127 if (ec) return ec;
Rui Ueyama34efe772013-12-06 04:43:01 +0000128
Nick Kledzike5552772013-12-19 21:58:00 +0000129 // Get symbol name
130 if ((ec = (i->getName(symbolname)))) return ec;
Rui Ueyama34efe772013-12-06 04:43:01 +0000131
Nick Kledzike5552772013-12-19 21:58:00 +0000132 if (symbolname != symbol)
133 continue;
Rui Ueyama34efe772013-12-06 04:43:01 +0000134
Nick Kledzike5552772013-12-19 21:58:00 +0000135 // Get symbol flags
136 if ((ec = (i->getFlags(symflags)))) return ec;
137
138 if (symflags <= SymbolRef::SF_Undefined)
139 continue;
140
141 // Get Symbol Type
142 if ((ec = (i->getType(symtype)))) return ec;
143
144 if (symtype == SymbolRef::ST_Data) {
145 return error_code::success();
146 }
147 }
148 return object_error::parse_failed;
149 }
150
151private:
152 typedef std::unordered_map<StringRef,Archive::child_iterator> MemberMap;
153 typedef std::set<const char*> InstantiatedSet;
154
155 const Registry &_registry;
156 std::unique_ptr<Archive> _archive;
157 mutable MemberMap _symbolMemberMap;
158 mutable InstantiatedSet _membersInstantiated;
159 atom_collection_vector<DefinedAtom> _definedAtoms;
160 atom_collection_vector<UndefinedAtom> _undefinedAtoms;
161 atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
162 atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
163 bool _isWholeArchive;
164 bool _logLoading;
165
166public:
167 /// only subclasses of ArchiveLibraryFile can be instantiated
168 FileArchive(const Registry &registry,
169 Archive* archive,
170 StringRef path,
171 bool isWholeArchive,
172 bool logLoading)
173 : ArchiveLibraryFile(path),
174 _registry(registry),
175 _archive(std::move(archive)),
176 _isWholeArchive(isWholeArchive),
177 _logLoading(logLoading) {
178 }
179
180 error_code buildTableOfContents() {
181 DEBUG_WITH_TYPE("FileArchive",
182 llvm::dbgs() << "Table of contents for archive '"
183 << _archive->getFileName() << "':\n");
184 for (auto i = _archive->begin_symbols(), e = _archive->end_symbols();
185 i != e; ++i) {
186 StringRef name;
187 error_code ec;
188 Archive::child_iterator member;
189 if ((ec = i->getName(name)))
190 return ec;
191 if ((ec = i->getMember(member)))
192 return ec;
193 DEBUG_WITH_TYPE("FileArchive",
194 llvm::dbgs() << llvm::format("0x%08llX ", member->getBuffer().data())
195 << "'" << name << "'\n");
196 _symbolMemberMap[name] = member;
197 }
198 return error_code::success();
199 }
200
201}; // class FileArchive
202
203
204
205class ArchiveReader : public Reader {
206public:
207 ArchiveReader(bool logLoading) : _logLoading(logLoading) { }
208
209 virtual bool canParse(file_magic magic, StringRef, const MemoryBuffer&) const{
210 return (magic == llvm::sys::fs::file_magic::archive);
211 }
212
213 virtual error_code
214 parseFile(std::unique_ptr<MemoryBuffer> &mb, const Registry &reg,
215 std::vector<std::unique_ptr<File>> &result) const {
216 // Make Archive object which will be owned by FileArchive object.
217 error_code ec;
218 Archive* archive = new Archive(mb.get(), ec);
Rui Ueyama34efe772013-12-06 04:43:01 +0000219 if (ec)
220 return ec;
Nick Kledzike5552772013-12-19 21:58:00 +0000221 StringRef path = mb->getBufferIdentifier();
222 // Construct FileArchive object.
223 std::unique_ptr<FileArchive> file(new FileArchive(reg, archive,
224 path, false, _logLoading));
225 ec = file->buildTableOfContents();
226 if (ec)
Rui Ueyama34efe772013-12-06 04:43:01 +0000227 return ec;
Nick Kledzike5552772013-12-19 21:58:00 +0000228
229 // Transfer ownership of memory buffer to Archive object.
230 mb.release();
231
232 result.push_back(std::move(file));
233 return error_code::success();
Rui Ueyama34efe772013-12-06 04:43:01 +0000234 }
Nick Kledzike5552772013-12-19 21:58:00 +0000235private:
236 bool _logLoading;
237};
Rui Ueyama34efe772013-12-06 04:43:01 +0000238
Rui Ueyama34efe772013-12-06 04:43:01 +0000239
Nick Kledzike5552772013-12-19 21:58:00 +0000240} // anonymous namespace
241
242
243void Registry::addSupportArchives(bool logLoading) {
244 add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
Rui Ueyama34efe772013-12-06 04:43:01 +0000245}
246
247} // end namespace lld
Nick Kledzike5552772013-12-19 21:58:00 +0000248
249