//===- Archive.cpp --------------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include <mcld/LD/Archive.h> #include <mcld/MC/InputBuilder.h> #include <mcld/MC/MCLDInput.h> #include <mcld/MC/AttributeSet.h> #include <mcld/MC/ContextFactory.h> #include <llvm/ADT/StringRef.h> #include <mcld/Support/MemoryAreaFactory.h> #include <mcld/Support/MsgHandling.h> using namespace mcld; //===----------------------------------------------------------------------===// // Archive const char Archive::MAGIC[] = "!<arch>\n"; const char Archive::THIN_MAGIC[] = "!<thin>\n"; const size_t Archive::MAGIC_LEN = sizeof(Archive::MAGIC) - 1; const char Archive::SVR4_SYMTAB_NAME[] = "/ "; const char Archive::STRTAB_NAME[] = "// "; const char Archive::PAD[] = "\n"; const char Archive::MEMBER_MAGIC[] = "`\n"; Archive::Archive(Input& pInputFile, InputBuilder& pBuilder) : m_ArchiveFile(pInputFile), m_pInputTree(NULL), m_SymbolFactory(32), m_Builder(pBuilder) { // FIXME: move creation of input tree out of Archive. m_pInputTree = new InputTree(); } Archive::~Archive() { delete m_pInputTree; } /// getARFile - get the Input& of the archive file Input& Archive::getARFile() { return m_ArchiveFile; } /// getARFile - get the Input& of the archive file const Input& Archive::getARFile() const { return m_ArchiveFile; } /// inputs - get the input tree built from this archive InputTree& Archive::inputs() { return *m_pInputTree; } /// inputs - get the input tree built from this archive const InputTree& Archive::inputs() const { return *m_pInputTree; } /// getObjectMemberMap - get the map that contains the included object files Archive::ObjectMemberMapType& Archive::getObjectMemberMap() { return m_ObjectMemberMap; } /// getObjectMemberMap - get the map that contains the included object files const Archive::ObjectMemberMapType& Archive::getObjectMemberMap() const { return m_ObjectMemberMap; } /// numOfObjectMember - return the number of included object files size_t Archive::numOfObjectMember() const { return m_ObjectMemberMap.numOfEntries(); } /// addObjectMember - add a object in the object member map /// @param pFileOffset - file offset in symtab represents a object file /// @param pIter - the iterator in the input tree built from this archive bool Archive::addObjectMember(uint32_t pFileOffset, InputTree::iterator pIter) { bool exist; ObjectMemberEntryType* entry = m_ObjectMemberMap.insert(pFileOffset, exist); if (!exist) entry->setValue(pIter); return !exist; } /// hasObjectMember - check if a object file is included or not /// @param pFileOffset - file offset in symtab represents a object file bool Archive::hasObjectMember(uint32_t pFileOffset) const { return (m_ObjectMemberMap.find(pFileOffset) != m_ObjectMemberMap.end()); } /// getArchiveMemberMap - get the map that contains the included archive files Archive::ArchiveMemberMapType& Archive::getArchiveMemberMap() { return m_ArchiveMemberMap; } /// getArchiveMemberMap - get the map that contains the included archive files const Archive::ArchiveMemberMapType& Archive::getArchiveMemberMap() const { return m_ArchiveMemberMap; } /// addArchiveMember - add an archive in the archive member map /// @param pName - the name of the new archive member /// @param pLastPos - this records the point to insert the next node in the /// subtree of this archive member /// @param pMove - this records the direction to insert the next node in the /// subtree of this archive member bool Archive::addArchiveMember(const llvm::StringRef& pName, InputTree::iterator pLastPos, InputTree::Mover* pMove) { bool exist; ArchiveMemberEntryType* entry = m_ArchiveMemberMap.insert(pName, exist); if (!exist) { ArchiveMember& ar = entry->value(); if (pLastPos == m_pInputTree->root()) ar.file = &m_ArchiveFile; else ar.file = *pLastPos; ar.lastPos = pLastPos; ar.move = pMove; } return !exist; } /// hasArchiveMember - check if an archive file is included or not bool Archive::hasArchiveMember(const llvm::StringRef& pName) const { return (m_ArchiveMemberMap.find(pName) != m_ArchiveMemberMap.end()); } /// getArchiveMember - get a archive member Archive::ArchiveMember* Archive::getArchiveMember(const llvm::StringRef& pName) { ArchiveMemberMapType::iterator it = m_ArchiveMemberMap.find(pName); if (it != m_ArchiveMemberMap.end()) return &(it.getEntry()->value()); return NULL; } /// getSymbolTable - get the symtab Archive::SymTabType& Archive::getSymbolTable() { return m_SymTab; } /// getSymbolTable - get the symtab const Archive::SymTabType& Archive::getSymbolTable() const { return m_SymTab; } /// setSymTabSize - set the memory size of symtab void Archive::setSymTabSize(size_t pSize) { m_SymTabSize = pSize; } /// getSymTabSize - get the memory size of symtab size_t Archive::getSymTabSize() const { return m_SymTabSize; } /// numOfSymbols - return the number of symbols in symtab size_t Archive::numOfSymbols() const { return m_SymTab.size(); } /// addSymbol - add a symtab entry to symtab /// @param pName - symbol name /// @param pFileOffset - file offset in symtab represents a object file void Archive::addSymbol(const char* pName, uint32_t pFileOffset, enum Archive::Symbol::Status pStatus) { Symbol* entry = m_SymbolFactory.allocate(); new (entry) Symbol(pName, pFileOffset, pStatus); m_SymTab.push_back(entry); } /// getSymbolName - get the symbol name with the given index const std::string& Archive::getSymbolName(size_t pSymIdx) const { assert(pSymIdx < numOfSymbols()); return m_SymTab[pSymIdx]->name; } /// getObjFileOffset - get the file offset that represent a object file uint32_t Archive::getObjFileOffset(size_t pSymIdx) const { assert(pSymIdx < numOfSymbols()); return m_SymTab[pSymIdx]->fileOffset; } /// getSymbolStatus - get the status of a symbol enum Archive::Symbol::Status Archive::getSymbolStatus(size_t pSymIdx) const { assert(pSymIdx < numOfSymbols()); return m_SymTab[pSymIdx]->status; } /// setSymbolStatus - set the status of a symbol void Archive::setSymbolStatus(size_t pSymIdx, enum Archive::Symbol::Status pStatus) { assert(pSymIdx < numOfSymbols()); m_SymTab[pSymIdx]->status = pStatus; } /// getStrTable - get the extended name table std::string& Archive::getStrTable() { return m_StrTab; } /// getStrTable - get the extended name table const std::string& Archive::getStrTable() const { return m_StrTab; } /// hasStrTable() bool Archive::hasStrTable() const { return (m_StrTab.size() > 0); } /// getMemberFile - get the member file in an archive member /// @param pArchiveFile - Input reference of the archive member /// @param pIsThinAR - denote the archive menber is a Thin Archive or not /// @param pName - the name of the member file we want to get /// @param pPath - the path of the member file /// @param pFileOffset - the file offset of the member file in a regular AR /// FIXME: maybe we should not construct input file here Input* Archive::getMemberFile(Input& pArchiveFile, bool isThinAR, const std::string& pName, const sys::fs::Path& pPath, off_t pFileOffset) { Input* member = NULL; if (!isThinAR) { member = m_Builder.createInput(pName, pPath, Input::Unknown, pFileOffset); assert(member != NULL); member->setMemArea(pArchiveFile.memArea()); m_Builder.setContext(*member); } else { member = m_Builder.createInput(pName, pPath, Input::Unknown); assert(member != NULL); if (!m_Builder.setMemory(*member, FileHandle::ReadOnly)) { error(diag::err_cannot_open_input) << member->name() << member->path(); return NULL; } m_Builder.setContext(*member); } return member; }