1 //===- Archive.cpp --------------------------------------------------------===//
2 //
3 // The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include <mcld/LD/Archive.h>
10 #include <mcld/MC/InputBuilder.h>
11 #include <mcld/MC/MCLDInput.h>
12 #include <mcld/MC/AttributeSet.h>
13 #include <mcld/MC/ContextFactory.h>
14 #include <llvm/ADT/StringRef.h>
15 #include <mcld/Support/MemoryAreaFactory.h>
16 #include <mcld/Support/MsgHandling.h>
17
18 using namespace mcld;
19
20 //===----------------------------------------------------------------------===//
21 // Archive
22 const char Archive::MAGIC[] = "!<arch>\n";
23 const char Archive::THIN_MAGIC[] = "!<thin>\n";
24 const size_t Archive::MAGIC_LEN = sizeof(Archive::MAGIC) - 1;
25 const char Archive::SVR4_SYMTAB_NAME[] = "/ ";
26 const char Archive::STRTAB_NAME[] = "// ";
27 const char Archive::PAD[] = "\n";
28 const char Archive::MEMBER_MAGIC[] = "`\n";
29
Archive(Input & pInputFile,InputBuilder & pBuilder)30 Archive::Archive(Input& pInputFile, InputBuilder& pBuilder)
31 : m_ArchiveFile(pInputFile),
32 m_pInputTree(NULL),
33 m_SymbolFactory(32),
34 m_Builder(pBuilder)
35 {
36 // FIXME: move creation of input tree out of Archive.
37 m_pInputTree = new InputTree();
38 }
39
~Archive()40 Archive::~Archive()
41 {
42 delete m_pInputTree;
43 }
44
45 /// getARFile - get the Input& of the archive file
getARFile()46 Input& Archive::getARFile()
47 {
48 return m_ArchiveFile;
49 }
50
51 /// getARFile - get the Input& of the archive file
getARFile() const52 const Input& Archive::getARFile() const
53 {
54 return m_ArchiveFile;
55 }
56
57 /// inputs - get the input tree built from this archive
inputs()58 InputTree& Archive::inputs()
59 {
60 return *m_pInputTree;
61 }
62
63 /// inputs - get the input tree built from this archive
inputs() const64 const InputTree& Archive::inputs() const
65 {
66 return *m_pInputTree;
67 }
68
69 /// getObjectMemberMap - get the map that contains the included object files
getObjectMemberMap()70 Archive::ObjectMemberMapType& Archive::getObjectMemberMap()
71 {
72 return m_ObjectMemberMap;
73 }
74
75 /// getObjectMemberMap - get the map that contains the included object files
getObjectMemberMap() const76 const Archive::ObjectMemberMapType& Archive::getObjectMemberMap() const
77 {
78 return m_ObjectMemberMap;
79 }
80
81 /// numOfObjectMember - return the number of included object files
numOfObjectMember() const82 size_t Archive::numOfObjectMember() const
83 {
84 return m_ObjectMemberMap.numOfEntries();
85 }
86
87 /// addObjectMember - add a object in the object member map
88 /// @param pFileOffset - file offset in symtab represents a object file
89 /// @param pIter - the iterator in the input tree built from this archive
addObjectMember(uint32_t pFileOffset,InputTree::iterator pIter)90 bool Archive::addObjectMember(uint32_t pFileOffset, InputTree::iterator pIter)
91 {
92 bool exist;
93 ObjectMemberEntryType* entry = m_ObjectMemberMap.insert(pFileOffset, exist);
94 if (!exist)
95 entry->setValue(pIter);
96 return !exist;
97 }
98
99 /// hasObjectMember - check if a object file is included or not
100 /// @param pFileOffset - file offset in symtab represents a object file
hasObjectMember(uint32_t pFileOffset) const101 bool Archive::hasObjectMember(uint32_t pFileOffset) const
102 {
103 return (m_ObjectMemberMap.find(pFileOffset) != m_ObjectMemberMap.end());
104 }
105
106 /// getArchiveMemberMap - get the map that contains the included archive files
getArchiveMemberMap()107 Archive::ArchiveMemberMapType& Archive::getArchiveMemberMap()
108 {
109 return m_ArchiveMemberMap;
110 }
111
112 /// getArchiveMemberMap - get the map that contains the included archive files
getArchiveMemberMap() const113 const Archive::ArchiveMemberMapType& Archive::getArchiveMemberMap() const
114 {
115 return m_ArchiveMemberMap;
116 }
117
118 /// addArchiveMember - add an archive in the archive member map
119 /// @param pName - the name of the new archive member
120 /// @param pLastPos - this records the point to insert the next node in the
121 /// subtree of this archive member
122 /// @param pMove - this records the direction to insert the next node in the
123 /// subtree of this archive member
addArchiveMember(const llvm::StringRef & pName,InputTree::iterator pLastPos,InputTree::Mover * pMove)124 bool Archive::addArchiveMember(const llvm::StringRef& pName,
125 InputTree::iterator pLastPos,
126 InputTree::Mover* pMove)
127 {
128 bool exist;
129 ArchiveMemberEntryType* entry = m_ArchiveMemberMap.insert(pName, exist);
130 if (!exist) {
131 ArchiveMember& ar = entry->value();
132 if (pLastPos == m_pInputTree->root())
133 ar.file = &m_ArchiveFile;
134 else
135 ar.file = *pLastPos;
136 ar.lastPos = pLastPos;
137 ar.move = pMove;
138 }
139 return !exist;
140 }
141
142 /// hasArchiveMember - check if an archive file is included or not
hasArchiveMember(const llvm::StringRef & pName) const143 bool Archive::hasArchiveMember(const llvm::StringRef& pName) const
144 {
145 return (m_ArchiveMemberMap.find(pName) != m_ArchiveMemberMap.end());
146 }
147
148 /// getArchiveMember - get a archive member
getArchiveMember(const llvm::StringRef & pName)149 Archive::ArchiveMember* Archive::getArchiveMember(const llvm::StringRef& pName)
150 {
151 ArchiveMemberMapType::iterator it = m_ArchiveMemberMap.find(pName);
152 if (it != m_ArchiveMemberMap.end())
153 return &(it.getEntry()->value());
154 return NULL;
155 }
156
157 /// getSymbolTable - get the symtab
getSymbolTable()158 Archive::SymTabType& Archive::getSymbolTable()
159 {
160 return m_SymTab;
161 }
162
163 /// getSymbolTable - get the symtab
getSymbolTable() const164 const Archive::SymTabType& Archive::getSymbolTable() const
165 {
166 return m_SymTab;
167 }
168
169 /// setSymTabSize - set the memory size of symtab
setSymTabSize(size_t pSize)170 void Archive::setSymTabSize(size_t pSize)
171 {
172 m_SymTabSize = pSize;
173 }
174
175 /// getSymTabSize - get the memory size of symtab
getSymTabSize() const176 size_t Archive::getSymTabSize() const
177 {
178 return m_SymTabSize;
179 }
180
181 /// numOfSymbols - return the number of symbols in symtab
numOfSymbols() const182 size_t Archive::numOfSymbols() const
183 {
184 return m_SymTab.size();
185 }
186
187 /// addSymbol - add a symtab entry to symtab
188 /// @param pName - symbol name
189 /// @param pFileOffset - file offset in symtab represents a object file
addSymbol(const char * pName,uint32_t pFileOffset,enum Archive::Symbol::Status pStatus)190 void Archive::addSymbol(const char* pName,
191 uint32_t pFileOffset,
192 enum Archive::Symbol::Status pStatus)
193 {
194 Symbol* entry = m_SymbolFactory.allocate();
195 new (entry) Symbol(pName, pFileOffset, pStatus);
196 m_SymTab.push_back(entry);
197 }
198
199 /// getSymbolName - get the symbol name with the given index
getSymbolName(size_t pSymIdx) const200 const std::string& Archive::getSymbolName(size_t pSymIdx) const
201 {
202 assert(pSymIdx < numOfSymbols());
203 return m_SymTab[pSymIdx]->name;
204 }
205
206 /// getObjFileOffset - get the file offset that represent a object file
getObjFileOffset(size_t pSymIdx) const207 uint32_t Archive::getObjFileOffset(size_t pSymIdx) const
208 {
209 assert(pSymIdx < numOfSymbols());
210 return m_SymTab[pSymIdx]->fileOffset;
211 }
212
213 /// getSymbolStatus - get the status of a symbol
getSymbolStatus(size_t pSymIdx) const214 enum Archive::Symbol::Status Archive::getSymbolStatus(size_t pSymIdx) const
215 {
216 assert(pSymIdx < numOfSymbols());
217 return m_SymTab[pSymIdx]->status;
218 }
219
220 /// setSymbolStatus - set the status of a symbol
setSymbolStatus(size_t pSymIdx,enum Archive::Symbol::Status pStatus)221 void Archive::setSymbolStatus(size_t pSymIdx,
222 enum Archive::Symbol::Status pStatus)
223 {
224 assert(pSymIdx < numOfSymbols());
225 m_SymTab[pSymIdx]->status = pStatus;
226 }
227
228 /// getStrTable - get the extended name table
getStrTable()229 std::string& Archive::getStrTable()
230 {
231 return m_StrTab;
232 }
233
234 /// getStrTable - get the extended name table
getStrTable() const235 const std::string& Archive::getStrTable() const
236 {
237 return m_StrTab;
238 }
239
240 /// hasStrTable()
hasStrTable() const241 bool Archive::hasStrTable() const
242 {
243 return (m_StrTab.size() > 0);
244 }
245
246 /// getMemberFile - get the member file in an archive member
247 /// @param pArchiveFile - Input reference of the archive member
248 /// @param pIsThinAR - denote the archive menber is a Thin Archive or not
249 /// @param pName - the name of the member file we want to get
250 /// @param pPath - the path of the member file
251 /// @param pFileOffset - the file offset of the member file in a regular AR
252 /// FIXME: maybe we should not construct input file here
getMemberFile(Input & pArchiveFile,bool isThinAR,const std::string & pName,const sys::fs::Path & pPath,off_t pFileOffset)253 Input* Archive::getMemberFile(Input& pArchiveFile,
254 bool isThinAR,
255 const std::string& pName,
256 const sys::fs::Path& pPath,
257 off_t pFileOffset)
258 {
259 Input* member = NULL;
260 if (!isThinAR) {
261 member = m_Builder.createInput(pName, pPath, Input::Unknown, pFileOffset);
262 assert(member != NULL);
263 member->setMemArea(pArchiveFile.memArea());
264 m_Builder.setContext(*member);
265 }
266 else {
267 member = m_Builder.createInput(pName, pPath, Input::Unknown);
268 assert(member != NULL);
269 if (!m_Builder.setMemory(*member, FileHandle::ReadOnly)) {
270 error(diag::err_cannot_open_input) << member->name() << member->path();
271 return NULL;
272 }
273 m_Builder.setContext(*member);
274 }
275 return member;
276 }
277
278