// Write one member out to the file. bool Archive::writeMember( const ArchiveMember& member, raw_fd_ostream& ARFile, std::string* ErrMsg ) { uint64_t filepos = ARFile.tell(); filepos -= 8; // Get the data and its size either from the // member's in-memory data or directly from the file. size_t fSize = member.getSize(); const char *data = (const char*)member.getData(); MemoryBuffer *mFile = 0; if (!data) { ErrorOr<std::unique_ptr<MemoryBuffer> > FileOrErr = MemoryBuffer::getFile(member.getPath()); if (!FileOrErr) { if (ErrMsg) *ErrMsg = FileOrErr.getError().message(); return true; } mFile = FileOrErr.get().release(); data = mFile->getBufferStart(); fSize = mFile->getBufferSize(); } int hdrSize = fSize; // Compute the fields of the header ArchiveMemberHeader Hdr; bool writeLongName = fillHeader(member,Hdr,hdrSize); // Write header to archive file ARFile.write((char*)&Hdr, sizeof(Hdr)); // Write the long filename if its long if (writeLongName) { StringRef Name = sys::path::filename(member.getPath()); ARFile.write(Name.data(), Name.size()); } // Write the (possibly compressed) member's content to the file. ARFile.write(data,fSize); // Make sure the member is an even length if ((ARFile.tell() & 1) == 1) ARFile << ARFILE_PAD; // Close the mapped file if it was opened delete mFile; return false; }
// Look up one symbol in the symbol table and return the module that defines // that symbol. Module* Archive::findModuleDefiningSymbol(const std::string& symbol, std::string* ErrMsg) { SymTabType::iterator SI = symTab.find(symbol); if (SI == symTab.end()) return 0; // The symbol table was previously constructed assuming that the members were // written without the symbol table header. Because VBR encoding is used, the // values could not be adjusted to account for the offset of the symbol table // because that could affect the size of the symbol table due to VBR encoding. // We now have to account for this by adjusting the offset by the size of the // symbol table and its header. unsigned fileOffset = SI->second + // offset in symbol-table-less file firstFileOffset; // add offset to first "real" file in archive // See if the module is already loaded ModuleMap::iterator MI = modules.find(fileOffset); if (MI != modules.end()) return MI->second.first; // Module hasn't been loaded yet, we need to load it const char* modptr = base + fileOffset; ArchiveMember* mbr = parseMemberHeader(modptr, mapfile->getBufferEnd(), ErrMsg); if (!mbr) return 0; // Now, load the bitcode module to get the Module. std::string FullMemberName = archPath.str() + "(" + mbr->getPath().str() + ")"; MemoryBuffer *Buffer = MemoryBuffer::getMemBufferCopy(StringRef(mbr->getData(), mbr->getSize()), FullMemberName.c_str()); Module *m = getLazyBitcodeModule(Buffer, Context, ErrMsg); if (!m) return 0; modules.insert(std::make_pair(fileOffset, std::make_pair(m, mbr))); return m; }
// Load just the symbol table from the archive file bool Archive::loadSymbolTable(std::string* ErrorMsg) { // Set up parsing members.clear(); const char *At = base; const char *End = mapfile->getBufferEnd(); // Make sure we're dealing with an archive if (!checkSignature(ErrorMsg)) return false; At += 8; // Skip signature // Parse the first file member header const char* FirstFile = At; ArchiveMember* mbr = parseMemberHeader(At, End, ErrorMsg); if (!mbr) return false; if (mbr->isSVR4SymbolTable() || mbr->isBSD4SymbolTable()) { // Skip the foreign symbol table, we don't do anything with it At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; delete mbr; // Read the next one FirstFile = At; mbr = parseMemberHeader(At, End, ErrorMsg); if (!mbr) { delete mbr; return false; } } if (mbr->isStringTable()) { // Process the string table entry strtab.assign((const char*)mbr->getData(), mbr->getSize()); At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; delete mbr; // Get the next one FirstFile = At; mbr = parseMemberHeader(At, End, ErrorMsg); if (!mbr) { delete mbr; return false; } } // There's no symbol table in the file. We have to rebuild it from scratch // because the intent of this method is to get the symbol table loaded so // it can be searched efficiently. // Add the member to the members list members.push_back(mbr); firstFileOffset = FirstFile - base; return true; }
// Write one member out to the file. bool Archive::writeMember( const ArchiveMember& member, std::ofstream& ARFile, bool CreateSymbolTable, bool TruncateNames, bool ShouldCompress, std::string* ErrMsg ) { unsigned filepos = ARFile.tellp(); filepos -= 8; // Get the data and its size either from the // member's in-memory data or directly from the file. size_t fSize = member.getSize(); const char *data = (const char*)member.getData(); MemoryBuffer *mFile = 0; if (!data) { mFile = MemoryBuffer::getFile(member.getPath().c_str(), ErrMsg); if (mFile == 0) return true; data = mFile->getBufferStart(); fSize = mFile->getBufferSize(); } // Now that we have the data in memory, update the // symbol table if its a bitcode file. if (CreateSymbolTable && member.isBitcode()) { std::vector<std::string> symbols; std::string FullMemberName = archPath.str() + "(" + member.getPath().str() + ")"; Module* M = GetBitcodeSymbols((const unsigned char*)data,fSize, FullMemberName, Context, symbols, ErrMsg); // If the bitcode parsed successfully if ( M ) { for (std::vector<std::string>::iterator SI = symbols.begin(), SE = symbols.end(); SI != SE; ++SI) { std::pair<SymTabType::iterator,bool> Res = symTab.insert(std::make_pair(*SI,filepos)); if (Res.second) { symTabSize += SI->length() + numVbrBytes(SI->length()) + numVbrBytes(filepos); } } // We don't need this module any more. delete M; } else { delete mFile; if (ErrMsg) *ErrMsg = "Can't parse bitcode member: " + member.getPath().str() + ": " + *ErrMsg; return true; } } int hdrSize = fSize; // Compute the fields of the header ArchiveMemberHeader Hdr; bool writeLongName = fillHeader(member,Hdr,hdrSize,TruncateNames); // Write header to archive file ARFile.write((char*)&Hdr, sizeof(Hdr)); // Write the long filename if its long if (writeLongName) { ARFile.write(member.getPath().str().data(), member.getPath().str().length()); } // Write the (possibly compressed) member's content to the file. ARFile.write(data,fSize); // Make sure the member is an even length if ((ARFile.tellp() & 1) == 1) ARFile << ARFILE_PAD; // Close the mapped file if it was opened delete mFile; return false; }
// This function loads the entire archive and fully populates its ilist with // the members of the archive file. This is typically used in preparation for // editing the contents of the archive. bool Archive::loadArchive(std::string* error) { // Set up parsing members.clear(); symTab.clear(); const char *At = base; const char *End = mapfile->getBufferEnd(); if (!checkSignature(error)) return false; At += 8; // Skip the magic string. bool seenSymbolTable = false; bool foundFirstFile = false; while (At < End) { // parse the member header const char* Save = At; ArchiveMember* mbr = parseMemberHeader(At, End, error); if (!mbr) return false; // check if this is the foreign symbol table if (mbr->isSVR4SymbolTable() || mbr->isBSD4SymbolTable()) { // We just save this but don't do anything special // with it. It doesn't count as the "first file". if (foreignST) { // What? Multiple foreign symbol tables? Just chuck it // and retain the last one found. delete foreignST; } foreignST = mbr; At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; } else if (mbr->isStringTable()) { // Simply suck the entire string table into a string // variable. This will be used to get the names of the // members that use the "/ddd" format for their names // (SVR4 style long names). strtab.assign(At, mbr->getSize()); At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; delete mbr; } else if (mbr->isLLVMSymbolTable()) { // This is the LLVM symbol table for the archive. If we've seen it // already, its an error. Otherwise, parse the symbol table and move on. if (seenSymbolTable) { if (error) *error = "invalid archive: multiple symbol tables"; return false; } if (!parseSymbolTable(mbr->getData(), mbr->getSize(), error)) return false; seenSymbolTable = true; At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; delete mbr; // We don't need this member in the list of members. } else { // This is just a regular file. If its the first one, save its offset. // Otherwise just push it on the list and move on to the next file. if (!foundFirstFile) { firstFileOffset = Save - base; foundFirstFile = true; } members.push_back(mbr); At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; } } return true; }