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