// 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; }
// Fill the ArchiveMemberHeader with the information from a member. If // TruncateNames is true, names are flattened to 15 chars or less. The sz field // is provided here instead of coming from the mbr because the member might be // stored compressed and the compressed size is not the ArchiveMember's size. // Furthermore compressed files have negative size fields to identify them as // compressed. bool Archive::fillHeader(const ArchiveMember &mbr, ArchiveMemberHeader& hdr, int sz) const { // Set the permissions mode, uid and gid hdr.init(); char buffer[32]; sprintf(buffer, "%-8o", mbr.getMode()); memcpy(hdr.mode,buffer,8); sprintf(buffer, "%-6u", mbr.getUser()); memcpy(hdr.uid,buffer,6); sprintf(buffer, "%-6u", mbr.getGroup()); memcpy(hdr.gid,buffer,6); // Set the last modification date uint64_t secondsSinceEpoch = mbr.getModTime().toEpochTime(); sprintf(buffer,"%-12u", unsigned(secondsSinceEpoch)); memcpy(hdr.date,buffer,12); std::string mbrPath = sys::path::filename(mbr.getPath()); // Set the name field in one of its various flavors. bool writeLongName = false; if (mbr.isStringTable()) { memcpy(hdr.name,ARFILE_STRTAB_NAME,16); } else if (mbr.isSVR4SymbolTable()) { memcpy(hdr.name,ARFILE_SVR4_SYMTAB_NAME,16); } else if (mbr.isBSD4SymbolTable()) { memcpy(hdr.name,ARFILE_BSD4_SYMTAB_NAME,16); } else if (mbrPath.length() < 16 && mbrPath.find('/') == std::string::npos) { memcpy(hdr.name,mbrPath.c_str(),mbrPath.length()); hdr.name[mbrPath.length()] = '/'; } else { std::string nm = "#1/"; nm += utostr(mbrPath.length()); memcpy(hdr.name,nm.data(),nm.length()); if (sz < 0) sz -= mbrPath.length(); else sz += mbrPath.length(); writeLongName = true; } // Set the size field if (sz < 0) { buffer[0] = '-'; sprintf(&buffer[1],"%-9u",(unsigned)-sz); } else { sprintf(buffer, "%-10u", (unsigned)sz); } memcpy(hdr.size,buffer,10); return writeLongName; }
// 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; }
// Fill the ArchiveMemberHeader with the information from a member. If // TruncateNames is true, names are flattened to 15 chars or less. The sz field // is provided here instead of coming from the mbr because the member might be // stored compressed and the compressed size is not the ArchiveMember's size. // Furthermore compressed files have negative size fields to identify them as // compressed. bool Archive::fillHeader(const ArchiveMember &mbr, ArchiveMemberHeader& hdr, int sz, bool TruncateNames) const { // Set the permissions mode, uid and gid hdr.init(); char buffer[32]; sprintf(buffer, "%-8o", mbr.getMode()); memcpy(hdr.mode,buffer,8); sprintf(buffer, "%-6u", mbr.getUser()); memcpy(hdr.uid,buffer,6); sprintf(buffer, "%-6u", mbr.getGroup()); memcpy(hdr.gid,buffer,6); // Set the last modification date uint64_t secondsSinceEpoch = mbr.getModTime().toEpochTime(); sprintf(buffer,"%-12u", unsigned(secondsSinceEpoch)); memcpy(hdr.date,buffer,12); // Get rid of trailing blanks in the name std::string mbrPath = mbr.getPath().str(); size_t mbrLen = mbrPath.length(); while (mbrLen > 0 && mbrPath[mbrLen-1] == ' ') { mbrPath.erase(mbrLen-1,1); mbrLen--; } // Set the name field in one of its various flavors. bool writeLongName = false; if (mbr.isStringTable()) { memcpy(hdr.name,ARFILE_STRTAB_NAME,16); } else if (mbr.isSVR4SymbolTable()) { memcpy(hdr.name,ARFILE_SVR4_SYMTAB_NAME,16); } else if (mbr.isBSD4SymbolTable()) { memcpy(hdr.name,ARFILE_BSD4_SYMTAB_NAME,16); } else if (mbr.isLLVMSymbolTable()) { memcpy(hdr.name,ARFILE_LLVM_SYMTAB_NAME,16); } else if (TruncateNames) { const char* nm = mbrPath.c_str(); unsigned len = mbrPath.length(); size_t slashpos = mbrPath.rfind('/'); if (slashpos != std::string::npos) { nm += slashpos + 1; len -= slashpos +1; } if (len > 15) len = 15; memcpy(hdr.name,nm,len); hdr.name[len] = '/'; } else if (mbrPath.length() < 16 && mbrPath.find('/') == std::string::npos) { memcpy(hdr.name,mbrPath.c_str(),mbrPath.length()); hdr.name[mbrPath.length()] = '/'; } else { std::string nm = "#1/"; nm += utostr(mbrPath.length()); memcpy(hdr.name,nm.data(),nm.length()); if (sz < 0) sz -= mbrPath.length(); else sz += mbrPath.length(); writeLongName = true; } // Set the size field if (sz < 0) { buffer[0] = '-'; sprintf(&buffer[1],"%-9u",(unsigned)-sz); } else { sprintf(buffer, "%-10u", (unsigned)sz); } memcpy(hdr.size,buffer,10); return writeLongName; }
// 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; }
// Look up multiple symbols in the symbol table and return a set of // Modules that define those symbols. bool Archive::findModulesDefiningSymbols(std::set<std::string>& symbols, SmallVectorImpl<Module*>& result, std::string* error) { if (!mapfile || !base) { if (error) *error = "Empty archive invalid for finding modules defining symbols"; return false; } if (symTab.empty()) { // We don't have a symbol table, so we must build it now but lets also // make sure that we populate the modules table as we do this to ensure // that we don't load them twice when findModuleDefiningSymbol is called // below. // Get a pointer to the first file const char* At = base + firstFileOffset; const char* End = mapfile->getBufferEnd(); while ( At < End) { // Compute the offset to be put in the symbol table unsigned offset = At - base - firstFileOffset; // Parse the file's header ArchiveMember* mbr = parseMemberHeader(At, End, error); if (!mbr) return false; // If it contains symbols if (mbr->isBitcode()) { // Get the symbols std::vector<std::string> symbols; std::string FullMemberName = archPath.str() + "(" + mbr->getPath().str() + ")"; Module* M = GetBitcodeSymbols(At, mbr->getSize(), FullMemberName, Context, symbols, error); if (M) { // Insert the module's symbols into the symbol table for (std::vector<std::string>::iterator I = symbols.begin(), E=symbols.end(); I != E; ++I ) { symTab.insert(std::make_pair(*I, offset)); } // Insert the Module and the ArchiveMember into the table of // modules. modules.insert(std::make_pair(offset, std::make_pair(M, mbr))); } else { if (error) *error = "Can't parse bitcode member: " + mbr->getPath().str() + ": " + *error; delete mbr; return false; } } // Go to the next file location At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; } } // At this point we have a valid symbol table (one way or another) so we // just use it to quickly find the symbols requested. SmallPtrSet<Module*, 16> Added; for (std::set<std::string>::iterator I=symbols.begin(), Next = I, E=symbols.end(); I != E; I = Next) { // Increment Next before we invalidate it. ++Next; // See if this symbol exists Module* m = findModuleDefiningSymbol(*I,error); if (!m) continue; bool NewMember = Added.insert(m); if (!NewMember) continue; // The symbol exists, insert the Module into our result. result.push_back(m); // Remove the symbol now that its been resolved. symbols.erase(I); } return true; }
// Look up multiple symbols in the symbol table and return a set of // ModuleProviders that define those symbols. bool Archive::findModulesDefiningSymbols(std::set<std::string>& symbols, std::set<ModuleProvider*>& result, std::string* error) { if (!mapfile || !base) { if (error) *error = "Empty archive invalid for finding modules defining symbols"; return false; } if (symTab.empty()) { // We don't have a symbol table, so we must build it now but lets also // make sure that we populate the modules table as we do this to ensure // that we don't load them twice when findModuleDefiningSymbol is called // below. // Get a pointer to the first file const char* At = base + firstFileOffset; const char* End = mapfile->getBufferEnd(); while ( At < End) { // Compute the offset to be put in the symbol table unsigned offset = At - base - firstFileOffset; // Parse the file's header ArchiveMember* mbr = parseMemberHeader(At, End, error); if (!mbr) return false; // If it contains symbols if (mbr->isBitcode()) { // Get the symbols std::vector<std::string> symbols; std::string FullMemberName = archPath.toString() + "(" + mbr->getPath().toString() + ")"; ModuleProvider* MP = GetBitcodeSymbols((const unsigned char*)At, mbr->getSize(), FullMemberName, symbols, error); if (MP) { // Insert the module's symbols into the symbol table for (std::vector<std::string>::iterator I = symbols.begin(), E=symbols.end(); I != E; ++I ) { symTab.insert(std::make_pair(*I, offset)); } // Insert the ModuleProvider and the ArchiveMember into the table of // modules. modules.insert(std::make_pair(offset, std::make_pair(MP, mbr))); } else { if (error) *error = "Can't parse bitcode member: " + mbr->getPath().toString() + ": " + *error; delete mbr; return false; } } // Go to the next file location At += mbr->getSize(); if ((intptr_t(At) & 1) == 1) At++; } } // At this point we have a valid symbol table (one way or another) so we // just use it to quickly find the symbols requested. for (std::set<std::string>::iterator I=symbols.begin(), E=symbols.end(); I != E;) { // See if this symbol exists ModuleProvider* mp = findModuleDefiningSymbol(*I,error); if (mp) { // The symbol exists, insert the ModuleProvider into our result, // duplicates wil be ignored result.insert(mp); // Remove the symbol now that its been resolved, being careful to // post-increment the iterator. symbols.erase(I++); } else { ++I; } } return true; }