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
16namespace mcld {
17
18//===----------------------------------------------------------------------===//
19// Archive
20const char Archive::MAGIC[] = "!<arch>\n";
21const char Archive::THIN_MAGIC[] = "!<thin>\n";
22const size_t Archive::MAGIC_LEN = sizeof(Archive::MAGIC) - 1;
23const char Archive::SVR4_SYMTAB_NAME[] = "/               ";
24const char Archive::IRIX6_SYMTAB_NAME[] = "/SYM64/         ";
25const char Archive::STRTAB_NAME[] = "//              ";
26const char Archive::PAD[] = "\n";
27const char Archive::MEMBER_MAGIC[] = "`\n";
28
29Archive::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
38Archive::~Archive() {
39  delete m_pInputTree;
40}
41
42/// getARFile - get the Input& of the archive file
43Input& Archive::getARFile() {
44  return m_ArchiveFile;
45}
46
47/// getARFile - get the Input& of the archive file
48const Input& Archive::getARFile() const {
49  return m_ArchiveFile;
50}
51
52/// inputs - get the input tree built from this archive
53InputTree& Archive::inputs() {
54  return *m_pInputTree;
55}
56
57/// inputs - get the input tree built from this archive
58const InputTree& Archive::inputs() const {
59  return *m_pInputTree;
60}
61
62/// getObjectMemberMap - get the map that contains the included object files
63Archive::ObjectMemberMapType& Archive::getObjectMemberMap() {
64  return m_ObjectMemberMap;
65}
66
67/// getObjectMemberMap - get the map that contains the included object files
68const Archive::ObjectMemberMapType& Archive::getObjectMemberMap() const {
69  return m_ObjectMemberMap;
70}
71
72/// numOfObjectMember - return the number of included object files
73size_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
80bool 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
90bool 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
95Archive::ArchiveMemberMapType& Archive::getArchiveMemberMap() {
96  return m_ArchiveMemberMap;
97}
98
99/// getArchiveMemberMap - get the map that contains the included archive files
100const 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
110bool 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
128bool Archive::hasArchiveMember(const llvm::StringRef& pName) const {
129  return (m_ArchiveMemberMap.find(pName) != m_ArchiveMemberMap.end());
130}
131
132/// getArchiveMember - get a archive member
133Archive::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
142Archive::SymTabType& Archive::getSymbolTable() {
143  return m_SymTab;
144}
145
146/// getSymbolTable - get the symtab
147const Archive::SymTabType& Archive::getSymbolTable() const {
148  return m_SymTab;
149}
150
151/// setSymTabSize - set the memory size of symtab
152void Archive::setSymTabSize(size_t pSize) {
153  m_SymTabSize = pSize;
154}
155
156/// getSymTabSize - get the memory size of symtab
157size_t Archive::getSymTabSize() const {
158  return m_SymTabSize;
159}
160
161/// numOfSymbols - return the number of symbols in symtab
162size_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
169void 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
178const 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
184uint32_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
190enum 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
196void 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
203std::string& Archive::getStrTable() {
204  return m_StrTab;
205}
206
207/// getStrTable - get the extended name table
208const std::string& Archive::getStrTable() const {
209  return m_StrTab;
210}
211
212/// hasStrTable()
213bool 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
224Input* 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