blob: 1928e2fa0f78a536c159be6c9d1356ece1af033b [file] [log] [blame]
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +00001//===- lib/ReaderWriter/ReaderArchive.cpp - Archive Library Reader--------===//
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//===---------------------------------------------------------------------===//
Michael J. Spencera5d22812012-11-13 19:58:58 +00009
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000010#include "lld/ReaderWriter/ReaderArchive.h"
11
Michael J. Spencer64afcb42013-01-23 01:18:43 +000012#include "lld/Core/ArchiveLibraryFile.h"
Michael J. Spencer64afcb42013-01-23 01:18:43 +000013
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000014#include "llvm/ADT/Hashing.h"
Michael J. Spencer64afcb42013-01-23 01:18:43 +000015#include "llvm/Object/ObjectFile.h"
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000016
17#include <unordered_map>
18
Michael J. Spencera5d22812012-11-13 19:58:58 +000019namespace lld {
20/// \brief The FileArchive class represents an Archive Library file
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000021class FileArchive : public ArchiveLibraryFile {
22public:
23
24 virtual ~FileArchive() { }
25
Michael J. Spencera5d22812012-11-13 19:58:58 +000026 /// \brief Check if any member of the archive contains an Atom with the
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000027 /// specified name and return the File object for that member, or nullptr.
28 virtual const File *find(StringRef name, bool dataSymbolOnly) const {
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000029 auto member = _symbolMemberMap.find(name);
30 if (member == _symbolMemberMap.end())
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000031 return nullptr;
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000032
Michael J. Spencerad5f00e2013-01-10 01:27:45 +000033 llvm::object::Archive::child_iterator ci = member->second;
Shankar Easwaran8962feb2013-03-14 16:09:49 +000034
Michael J. Spencer4673da22013-02-03 10:49:26 +000035 if (dataSymbolOnly) {
36 OwningPtr<MemoryBuffer> buff;
37 if (ci->getMemoryBuffer(buff, true))
38 return nullptr;
39 if (isDataSymbol(buff.take(), name))
40 return nullptr;
41 }
Shankar Easwaran8962feb2013-03-14 16:09:49 +000042
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000043 std::vector<std::unique_ptr<File>> result;
44
Michael J. Spencer4673da22013-02-03 10:49:26 +000045 OwningPtr<MemoryBuffer> buff;
46 if (ci->getMemoryBuffer(buff, true))
47 return nullptr;
Nick Kledzikc314b462013-04-04 18:59:24 +000048 if (_targetInfo.logInputFiles())
49 llvm::outs() << buff->getBufferIdentifier() << "\n";
Shankar Easwarana4323a52013-04-05 03:50:15 +000050 std::unique_ptr<MemoryBuffer> mb(buff.take());
Michael J. Spencere6d56092013-04-05 22:04:44 +000051 if (_targetInfo.parseFile(mb, result))
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000052 return nullptr;
53
54 assert(result.size() == 1);
55
Michael J. Spencer6580d1f2013-03-20 18:56:57 +000056 result[0]->setOrdinalAndIncrement(_curChildOrd);
Shankar Easwaran8962feb2013-03-14 16:09:49 +000057
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000058 // give up the pointer so that this object no longer manages it
Shankar Easwaran85bb0452012-11-13 20:34:55 +000059 return result[0].release();
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000060 }
61
Nick Kledzik36293f62013-01-23 22:32:56 +000062 virtual void setOrdinalAndIncrement(uint64_t &ordinal) const {
63 _ordinal = ordinal++;
Michael J. Spencer6580d1f2013-03-20 18:56:57 +000064 _curChildOrd = _ordinal;
Nick Kledzik36293f62013-01-23 22:32:56 +000065 // Leave space in ordinal range for all children
Shankar Easwaran8962feb2013-03-14 16:09:49 +000066 for (auto mf = _archive->begin_children(),
Nick Kledzik36293f62013-01-23 22:32:56 +000067 me = _archive->end_children(); mf != me; ++mf) {
68 ordinal++;
69 }
70 }
71
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000072 virtual const atom_collection<DefinedAtom> &defined() const {
73 return _definedAtoms;
74 }
75
76 virtual const atom_collection<UndefinedAtom> &undefined() const {
77 return _undefinedAtoms;
78 }
79
80 virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
81 return _sharedLibraryAtoms;
82 }
83
84 virtual const atom_collection<AbsoluteAtom> &absolute() const {
85 return _absoluteAtoms;
86 }
87
88protected:
Michael J. Spencera5d22812012-11-13 19:58:58 +000089 error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const {
Shankar Easwaran8962feb2013-03-14 16:09:49 +000090 std::unique_ptr<llvm::object::ObjectFile>
Shankar Easwaran85bb0452012-11-13 20:34:55 +000091 obj(llvm::object::ObjectFile::createObjectFile(mb));
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +000092 error_code ec;
93 llvm::object::SymbolRef::Type symtype;
94 uint32_t symflags;
95 llvm::object::symbol_iterator ibegin = obj->begin_symbols();
96 llvm::object::symbol_iterator iend = obj->end_symbols();
97 StringRef symbolname;
98
99 for (llvm::object::symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
100 if (ec) return ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000101
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000102 // Get symbol name
103 if ((ec = (i->getName(symbolname)))) return ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000104
105 if (symbolname != symbol)
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000106 continue;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000107
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000108 // Get symbol flags
109 if ((ec = (i->getFlags(symflags)))) return ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000110
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000111 if (symflags <= llvm::object::SymbolRef::SF_Undefined)
112 continue;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000113
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000114 // Get Symbol Type
115 if ((ec = (i->getType(symtype)))) return ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000116
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000117 if (symtype == llvm::object::SymbolRef::ST_Data) {
118 return error_code::success();
119 }
120 }
121 return llvm::object::object_error::parse_failed;
122 }
123
124private:
Nick Kledzikc314b462013-04-04 18:59:24 +0000125 std::unique_ptr<llvm::object::Archive> _archive;
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000126 atom_collection_vector<DefinedAtom> _definedAtoms;
127 atom_collection_vector<UndefinedAtom> _undefinedAtoms;
128 atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
129 atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
Michael J. Spencer6580d1f2013-03-20 18:56:57 +0000130 mutable uint64_t _curChildOrd;
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000131
132public:
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000133 /// only subclasses of ArchiveLibraryFile can be instantiated
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000134 FileArchive(const TargetInfo &ti,
Shankar Easwaran3256d4f2013-01-25 07:39:18 +0000135 std::unique_ptr<llvm::MemoryBuffer> mb, error_code &ec)
Nick Kledzikc314b462013-04-04 18:59:24 +0000136 : ArchiveLibraryFile(ti, mb->getBufferIdentifier()) {
Michael J. Spencera5d22812012-11-13 19:58:58 +0000137 std::unique_ptr<llvm::object::Archive> archive_obj(
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000138 new llvm::object::Archive(mb.release(), ec));
Michael J. Spencera5d22812012-11-13 19:58:58 +0000139 if (ec)
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000140 return;
Michael J. Spencera5d22812012-11-13 19:58:58 +0000141 _archive.swap(archive_obj);
Michael J. Spencerad5f00e2013-01-10 01:27:45 +0000142
143 // Cache symbols.
144 for (auto i = _archive->begin_symbols(), e = _archive->end_symbols();
145 i != e; ++i) {
146 StringRef name;
147 llvm::object::Archive::child_iterator member;
148 if ((ec = i->getName(name)))
149 return;
150 if ((ec = i->getMember(member)))
151 return;
152 _symbolMemberMap[name] = member;
153 }
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000154 }
Michael J. Spencerad5f00e2013-01-10 01:27:45 +0000155
Shankar Easwarana4323a52013-04-05 03:50:15 +0000156 std::unordered_map<StringRef,
Nick Kledzikc314b462013-04-04 18:59:24 +0000157 llvm::object::Archive::child_iterator> _symbolMemberMap;
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000158}; // class FileArchive
159
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000160// Returns a vector of Files that are contained in the archive file
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000161// pointed to by the MemoryBuffer
Michael J. Spencere6d56092013-04-05 22:04:44 +0000162error_code ReaderArchive::parseFile(std::unique_ptr<llvm::MemoryBuffer> &mb,
163 std::vector<std::unique_ptr<File>> &result) const {
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000164 error_code ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000165
Nick Kledzikc314b462013-04-04 18:59:24 +0000166 if (_targetInfo.forceLoadAllArchives()) {
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000167 _archive.reset(new llvm::object::Archive(mb.release(), ec));
168 if (ec)
169 return ec;
Shankar Easwaran8962feb2013-03-14 16:09:49 +0000170
171 for (auto mf = _archive->begin_children(),
Michael J. Spencera5d22812012-11-13 19:58:58 +0000172 me = _archive->end_children(); mf != me; ++mf) {
Michael J. Spencer4673da22013-02-03 10:49:26 +0000173 OwningPtr<MemoryBuffer> buff;
174 if ((ec = mf->getMemoryBuffer(buff, true)))
175 return ec;
Nick Kledzikc314b462013-04-04 18:59:24 +0000176 std::unique_ptr<MemoryBuffer> mbc(buff.take());
177 if (_targetInfo.logInputFiles())
178 llvm::outs() << buff->getBufferIdentifier() << "\n";
Michael J. Spencere6d56092013-04-05 22:04:44 +0000179 if ((ec = _targetInfo.parseFile(mbc, result)))
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000180 return ec;
181 }
182 } else {
183 std::unique_ptr<File> f;
Nick Kledzikc314b462013-04-04 18:59:24 +0000184 f.reset(new FileArchive(_targetInfo, std::move(mb), ec));
Shankar Easwaran70b4dcf2012-11-13 18:39:10 +0000185 if (ec)
186 return ec;
187
188 result.push_back(std::move(f));
189 }
190 return llvm::error_code::success();
191}
Michael J. Spencer64afcb42013-01-23 01:18:43 +0000192} // end namespace lld