Archive.cpp revision 6f75755c9204b1d8817ae5a65a2f7e5af0ec3f70
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
18using namespace mcld;
19
20//===----------------------------------------------------------------------===//
21// Archive
22const char   Archive::MAGIC[]            = "!<arch>\n";
23const char   Archive::THIN_MAGIC[]       = "!<thin>\n";
24const size_t Archive::MAGIC_LEN          = sizeof(Archive::MAGIC) - 1;
25const char   Archive::SVR4_SYMTAB_NAME[] = "/               ";
26const char   Archive::STRTAB_NAME[]      = "//              ";
27const char   Archive::PAD[]              = "\n";
28const char   Archive::MEMBER_MAGIC[]     = "`\n";
29
30Archive::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
40Archive::~Archive()
41{
42  delete m_pInputTree;
43}
44
45/// getARFile - get the Input& of the archive file
46Input& Archive::getARFile()
47{
48  return m_ArchiveFile;
49}
50
51/// getARFile - get the Input& of the archive file
52const Input& Archive::getARFile() const
53{
54  return m_ArchiveFile;
55}
56
57/// inputs - get the input tree built from this archive
58InputTree& Archive::inputs()
59{
60  return *m_pInputTree;
61}
62
63/// inputs - get the input tree built from this archive
64const InputTree& Archive::inputs() const
65{
66  return *m_pInputTree;
67}
68
69/// getObjectMemberMap - get the map that contains the included object files
70Archive::ObjectMemberMapType& Archive::getObjectMemberMap()
71{
72  return m_ObjectMemberMap;
73}
74
75/// getObjectMemberMap - get the map that contains the included object files
76const Archive::ObjectMemberMapType& Archive::getObjectMemberMap() const
77{
78  return m_ObjectMemberMap;
79}
80
81/// numOfObjectMember - return the number of included object files
82size_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
90bool 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
101bool 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
107Archive::ArchiveMemberMapType& Archive::getArchiveMemberMap()
108{
109  return m_ArchiveMemberMap;
110}
111
112/// getArchiveMemberMap - get the map that contains the included archive files
113const 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
124bool 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
143bool 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
149Archive::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
158Archive::SymTabType& Archive::getSymbolTable()
159{
160  return m_SymTab;
161}
162
163/// getSymbolTable - get the symtab
164const Archive::SymTabType& Archive::getSymbolTable() const
165{
166  return m_SymTab;
167}
168
169/// setSymTabSize - set the memory size of symtab
170void Archive::setSymTabSize(size_t pSize)
171{
172  m_SymTabSize = pSize;
173}
174
175/// getSymTabSize - get the memory size of symtab
176size_t Archive::getSymTabSize() const
177{
178  return m_SymTabSize;
179}
180
181/// numOfSymbols - return the number of symbols in symtab
182size_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
190void 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
200const 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
207uint32_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
214enum 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
221void 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
229std::string& Archive::getStrTable()
230{
231  return m_StrTab;
232}
233
234/// getStrTable - get the extended name table
235const std::string& Archive::getStrTable() const
236{
237  return m_StrTab;
238}
239
240/// hasStrTable()
241bool 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
253Input* 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