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/Input.h"
11 #include "mcld/MC/InputBuilder.h"
12 #include "mcld/Support/MsgHandling.h"
13 
14 #include <llvm/ADT/StringRef.h>
15 
16 namespace mcld {
17 
18 //===----------------------------------------------------------------------===//
19 // Archive
20 const char Archive::MAGIC[] = "!<arch>\n";
21 const char Archive::THIN_MAGIC[] = "!<thin>\n";
22 const size_t Archive::MAGIC_LEN = sizeof(Archive::MAGIC) - 1;
23 const char Archive::SVR4_SYMTAB_NAME[] = "/               ";
24 const char Archive::IRIX6_SYMTAB_NAME[] = "/SYM64/         ";
25 const char Archive::STRTAB_NAME[] = "//              ";
26 const char Archive::PAD[] = "\n";
27 const char Archive::MEMBER_MAGIC[] = "`\n";
28 
Archive(Input & pInputFile,InputBuilder & pBuilder)29 Archive::Archive(Input& pInputFile, InputBuilder& pBuilder)
30     : m_ArchiveFile(pInputFile),
31       m_pInputTree(NULL),
32       m_SymbolFactory(32),
33       m_Builder(pBuilder) {
34   // FIXME: move creation of input tree out of Archive.
35   m_pInputTree = new InputTree();
36 }
37 
~Archive()38 Archive::~Archive() {
39   delete m_pInputTree;
40 }
41 
42 /// getARFile - get the Input& of the archive file
getARFile()43 Input& Archive::getARFile() {
44   return m_ArchiveFile;
45 }
46 
47 /// getARFile - get the Input& of the archive file
getARFile() const48 const Input& Archive::getARFile() const {
49   return m_ArchiveFile;
50 }
51 
52 /// inputs - get the input tree built from this archive
inputs()53 InputTree& Archive::inputs() {
54   return *m_pInputTree;
55 }
56 
57 /// inputs - get the input tree built from this archive
inputs() const58 const InputTree& Archive::inputs() const {
59   return *m_pInputTree;
60 }
61 
62 /// getObjectMemberMap - get the map that contains the included object files
getObjectMemberMap()63 Archive::ObjectMemberMapType& Archive::getObjectMemberMap() {
64   return m_ObjectMemberMap;
65 }
66 
67 /// getObjectMemberMap - get the map that contains the included object files
getObjectMemberMap() const68 const Archive::ObjectMemberMapType& Archive::getObjectMemberMap() const {
69   return m_ObjectMemberMap;
70 }
71 
72 /// numOfObjectMember - return the number of included object files
numOfObjectMember() const73 size_t Archive::numOfObjectMember() const {
74   return m_ObjectMemberMap.numOfEntries();
75 }
76 
77 /// addObjectMember - add a object in the object member map
78 /// @param pFileOffset - file offset in symtab represents a object file
79 /// @param pIter - the iterator in the input tree built from this archive
addObjectMember(uint32_t pFileOffset,InputTree::iterator pIter)80 bool Archive::addObjectMember(uint32_t pFileOffset, InputTree::iterator pIter) {
81   bool exist;
82   ObjectMemberEntryType* entry = m_ObjectMemberMap.insert(pFileOffset, exist);
83   if (!exist)
84     entry->setValue(pIter);
85   return !exist;
86 }
87 
88 /// hasObjectMember - check if a object file is included or not
89 /// @param pFileOffset - file offset in symtab represents a object file
hasObjectMember(uint32_t pFileOffset) const90 bool Archive::hasObjectMember(uint32_t pFileOffset) const {
91   return (m_ObjectMemberMap.find(pFileOffset) != m_ObjectMemberMap.end());
92 }
93 
94 /// getArchiveMemberMap - get the map that contains the included archive files
getArchiveMemberMap()95 Archive::ArchiveMemberMapType& Archive::getArchiveMemberMap() {
96   return m_ArchiveMemberMap;
97 }
98 
99 /// getArchiveMemberMap - get the map that contains the included archive files
getArchiveMemberMap() const100 const Archive::ArchiveMemberMapType& Archive::getArchiveMemberMap() const {
101   return m_ArchiveMemberMap;
102 }
103 
104 /// addArchiveMember - add an archive in the archive member map
105 /// @param pName    - the name of the new archive member
106 /// @param pLastPos - this records the point to insert the next node in the
107 ///                   subtree of this archive member
108 /// @param pMove    - this records the direction to insert the next node in the
109 ///                   subtree of this archive member
addArchiveMember(const llvm::StringRef & pName,InputTree::iterator pLastPos,InputTree::Mover * pMove)110 bool Archive::addArchiveMember(const llvm::StringRef& pName,
111                                InputTree::iterator pLastPos,
112                                InputTree::Mover* pMove) {
113   bool exist;
114   ArchiveMemberEntryType* entry = m_ArchiveMemberMap.insert(pName, exist);
115   if (!exist) {
116     ArchiveMember& ar = entry->value();
117     if (pLastPos == m_pInputTree->root())
118       ar.file = &m_ArchiveFile;
119     else
120       ar.file = *pLastPos;
121     ar.lastPos = pLastPos;
122     ar.move = pMove;
123   }
124   return !exist;
125 }
126 
127 /// hasArchiveMember - check if an archive file is included or not
hasArchiveMember(const llvm::StringRef & pName) const128 bool Archive::hasArchiveMember(const llvm::StringRef& pName) const {
129   return (m_ArchiveMemberMap.find(pName) != m_ArchiveMemberMap.end());
130 }
131 
132 /// getArchiveMember - get a archive member
getArchiveMember(const llvm::StringRef & pName)133 Archive::ArchiveMember* Archive::getArchiveMember(
134     const llvm::StringRef& pName) {
135   ArchiveMemberMapType::iterator it = m_ArchiveMemberMap.find(pName);
136   if (it != m_ArchiveMemberMap.end())
137     return &(it.getEntry()->value());
138   return NULL;
139 }
140 
141 /// getSymbolTable - get the symtab
getSymbolTable()142 Archive::SymTabType& Archive::getSymbolTable() {
143   return m_SymTab;
144 }
145 
146 /// getSymbolTable - get the symtab
getSymbolTable() const147 const Archive::SymTabType& Archive::getSymbolTable() const {
148   return m_SymTab;
149 }
150 
151 /// setSymTabSize - set the memory size of symtab
setSymTabSize(size_t pSize)152 void Archive::setSymTabSize(size_t pSize) {
153   m_SymTabSize = pSize;
154 }
155 
156 /// getSymTabSize - get the memory size of symtab
getSymTabSize() const157 size_t Archive::getSymTabSize() const {
158   return m_SymTabSize;
159 }
160 
161 /// numOfSymbols - return the number of symbols in symtab
numOfSymbols() const162 size_t Archive::numOfSymbols() const {
163   return m_SymTab.size();
164 }
165 
166 /// addSymbol - add a symtab entry to symtab
167 /// @param pName - symbol name
168 /// @param pFileOffset - file offset in symtab represents a object file
addSymbol(const char * pName,uint32_t pFileOffset,enum Archive::Symbol::Status pStatus)169 void Archive::addSymbol(const char* pName,
170                         uint32_t pFileOffset,
171                         enum Archive::Symbol::Status pStatus) {
172   Symbol* entry = m_SymbolFactory.allocate();
173   new (entry) Symbol(pName, pFileOffset, pStatus);
174   m_SymTab.push_back(entry);
175 }
176 
177 /// getSymbolName - get the symbol name with the given index
getSymbolName(size_t pSymIdx) const178 const std::string& Archive::getSymbolName(size_t pSymIdx) const {
179   assert(pSymIdx < numOfSymbols());
180   return m_SymTab[pSymIdx]->name;
181 }
182 
183 /// getObjFileOffset - get the file offset that represent a object file
getObjFileOffset(size_t pSymIdx) const184 uint32_t Archive::getObjFileOffset(size_t pSymIdx) const {
185   assert(pSymIdx < numOfSymbols());
186   return m_SymTab[pSymIdx]->fileOffset;
187 }
188 
189 /// getSymbolStatus - get the status of a symbol
getSymbolStatus(size_t pSymIdx) const190 enum Archive::Symbol::Status Archive::getSymbolStatus(size_t pSymIdx) const {
191   assert(pSymIdx < numOfSymbols());
192   return m_SymTab[pSymIdx]->status;
193 }
194 
195 /// setSymbolStatus - set the status of a symbol
setSymbolStatus(size_t pSymIdx,enum Archive::Symbol::Status pStatus)196 void Archive::setSymbolStatus(size_t pSymIdx,
197                               enum Archive::Symbol::Status pStatus) {
198   assert(pSymIdx < numOfSymbols());
199   m_SymTab[pSymIdx]->status = pStatus;
200 }
201 
202 /// getStrTable - get the extended name table
getStrTable()203 std::string& Archive::getStrTable() {
204   return m_StrTab;
205 }
206 
207 /// getStrTable - get the extended name table
getStrTable() const208 const std::string& Archive::getStrTable() const {
209   return m_StrTab;
210 }
211 
212 /// hasStrTable()
hasStrTable() const213 bool Archive::hasStrTable() const {
214   return (m_StrTab.size() > 0);
215 }
216 
217 /// getMemberFile - get the member file in an archive member
218 /// @param pArchiveFile - Input reference of the archive member
219 /// @param pIsThinAR    - denote the archive menber is a Thin Archive or not
220 /// @param pName        - the name of the member file we want to get
221 /// @param pPath        - the path of the member file
222 /// @param pFileOffset  - the file offset of the member file in a regular AR
223 /// 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)224 Input* Archive::getMemberFile(Input& pArchiveFile,
225                               bool isThinAR,
226                               const std::string& pName,
227                               const sys::fs::Path& pPath,
228                               off_t pFileOffset) {
229   Input* member = NULL;
230   if (!isThinAR) {
231     member = m_Builder.createInput(pName, pPath, Input::Unknown, pFileOffset);
232     assert(member != NULL);
233     member->setMemArea(pArchiveFile.memArea());
234     m_Builder.setContext(*member);
235   } else {
236     member = m_Builder.createInput(pName, pPath, Input::Unknown);
237     assert(member != NULL);
238     if (!m_Builder.setMemory(*member,
239                              FileHandle::OpenMode(FileHandle::ReadOnly),
240                              FileHandle::Permission(FileHandle::System))) {
241       error(diag::err_cannot_open_input) << member->name() << member->path();
242       return NULL;
243     }
244     m_Builder.setContext(*member);
245   }
246   return member;
247 }
248 
249 }  // namespace mcld
250