LLVM API Documentation
00001 //===-- ArchiveWriter.cpp - Write LLVM archive files ----------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // Builds up an LLVM archive file (.a) containing LLVM bitcode. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "ArchiveInternals.h" 00015 #include "llvm/Bitcode/ReaderWriter.h" 00016 #include "llvm/ADT/OwningPtr.h" 00017 #include "llvm/Support/MemoryBuffer.h" 00018 #include "llvm/System/Signals.h" 00019 #include "llvm/System/Process.h" 00020 #include "llvm/ModuleProvider.h" 00021 #include <fstream> 00022 #include <ostream> 00023 #include <iomanip> 00024 using namespace llvm; 00025 00026 // Write an integer using variable bit rate encoding. This saves a few bytes 00027 // per entry in the symbol table. 00028 static inline void writeInteger(unsigned num, std::ofstream& ARFile) { 00029 while (1) { 00030 if (num < 0x80) { // done? 00031 ARFile << (unsigned char)num; 00032 return; 00033 } 00034 00035 // Nope, we are bigger than a character, output the next 7 bits and set the 00036 // high bit to say that there is more coming... 00037 ARFile << (unsigned char)(0x80 | ((unsigned char)num & 0x7F)); 00038 num >>= 7; // Shift out 7 bits now... 00039 } 00040 } 00041 00042 // Compute how many bytes are taken by a given VBR encoded value. This is needed 00043 // to pre-compute the size of the symbol table. 00044 static inline unsigned numVbrBytes(unsigned num) { 00045 00046 // Note that the following nested ifs are somewhat equivalent to a binary 00047 // search. We split it in half by comparing against 2^14 first. This allows 00048 // most reasonable values to be done in 2 comparisons instead of 1 for 00049 // small ones and four for large ones. We expect this to access file offsets 00050 // in the 2^10 to 2^24 range and symbol lengths in the 2^0 to 2^8 range, 00051 // so this approach is reasonable. 00052 if (num < 1<<14) { 00053 if (num < 1<<7) 00054 return 1; 00055 else 00056 return 2; 00057 } 00058 if (num < 1<<21) 00059 return 3; 00060 00061 if (num < 1<<28) 00062 return 4; 00063 return 5; // anything >= 2^28 takes 5 bytes 00064 } 00065 00066 // Create an empty archive. 00067 Archive* 00068 Archive::CreateEmpty(const sys::Path& FilePath ) { 00069 Archive* result = new Archive(FilePath); 00070 return result; 00071 } 00072 00073 // Fill the ArchiveMemberHeader with the information from a member. If 00074 // TruncateNames is true, names are flattened to 15 chars or less. The sz field 00075 // is provided here instead of coming from the mbr because the member might be 00076 // stored compressed and the compressed size is not the ArchiveMember's size. 00077 // Furthermore compressed files have negative size fields to identify them as 00078 // compressed. 00079 bool 00080 Archive::fillHeader(const ArchiveMember &mbr, ArchiveMemberHeader& hdr, 00081 int sz, bool TruncateNames) const { 00082 00083 // Set the permissions mode, uid and gid 00084 hdr.init(); 00085 char buffer[32]; 00086 sprintf(buffer, "%-8o", mbr.getMode()); 00087 memcpy(hdr.mode,buffer,8); 00088 sprintf(buffer, "%-6u", mbr.getUser()); 00089 memcpy(hdr.uid,buffer,6); 00090 sprintf(buffer, "%-6u", mbr.getGroup()); 00091 memcpy(hdr.gid,buffer,6); 00092 00093 // Set the last modification date 00094 uint64_t secondsSinceEpoch = mbr.getModTime().toEpochTime(); 00095 sprintf(buffer,"%-12u", unsigned(secondsSinceEpoch)); 00096 memcpy(hdr.date,buffer,12); 00097 00098 // Get rid of trailing blanks in the name 00099 std::string mbrPath = mbr.getPath().toString(); 00100 size_t mbrLen = mbrPath.length(); 00101 while (mbrLen > 0 && mbrPath[mbrLen-1] == ' ') { 00102 mbrPath.erase(mbrLen-1,1); 00103 mbrLen--; 00104 } 00105 00106 // Set the name field in one of its various flavors. 00107 bool writeLongName = false; 00108 if (mbr.isStringTable()) { 00109 memcpy(hdr.name,ARFILE_STRTAB_NAME,16); 00110 } else if (mbr.isSVR4SymbolTable()) { 00111 memcpy(hdr.name,ARFILE_SVR4_SYMTAB_NAME,16); 00112 } else if (mbr.isBSD4SymbolTable()) { 00113 memcpy(hdr.name,ARFILE_BSD4_SYMTAB_NAME,16); 00114 } else if (mbr.isLLVMSymbolTable()) { 00115 memcpy(hdr.name,ARFILE_LLVM_SYMTAB_NAME,16); 00116 } else if (TruncateNames) { 00117 const char* nm = mbrPath.c_str(); 00118 unsigned len = mbrPath.length(); 00119 size_t slashpos = mbrPath.rfind('/'); 00120 if (slashpos != std::string::npos) { 00121 nm += slashpos + 1; 00122 len -= slashpos +1; 00123 } 00124 if (len > 15) 00125 len = 15; 00126 memcpy(hdr.name,nm,len); 00127 hdr.name[len] = '/'; 00128 } else if (mbrPath.length() < 16 && mbrPath.find('/') == std::string::npos) { 00129 memcpy(hdr.name,mbrPath.c_str(),mbrPath.length()); 00130 hdr.name[mbrPath.length()] = '/'; 00131 } else { 00132 std::string nm = "#1/"; 00133 nm += utostr(mbrPath.length()); 00134 memcpy(hdr.name,nm.data(),nm.length()); 00135 if (sz < 0) 00136 sz -= mbrPath.length(); 00137 else 00138 sz += mbrPath.length(); 00139 writeLongName = true; 00140 } 00141 00142 // Set the size field 00143 if (sz < 0) { 00144 buffer[0] = '-'; 00145 sprintf(&buffer[1],"%-9u",(unsigned)-sz); 00146 } else { 00147 sprintf(buffer, "%-10u", (unsigned)sz); 00148 } 00149 memcpy(hdr.size,buffer,10); 00150 00151 return writeLongName; 00152 } 00153 00154 // Insert a file into the archive before some other member. This also takes care 00155 // of extracting the necessary flags and information from the file. 00156 bool 00157 Archive::addFileBefore(const sys::Path& filePath, iterator where, 00158 std::string* ErrMsg) { 00159 if (!filePath.exists()) { 00160 if (ErrMsg) 00161 *ErrMsg = "Can not add a non-existent file to archive"; 00162 return true; 00163 } 00164 00165 ArchiveMember* mbr = new ArchiveMember(this); 00166 00167 mbr->data = 0; 00168 mbr->path = filePath; 00169 const sys::FileStatus *FSInfo = mbr->path.getFileStatus(false, ErrMsg); 00170 if (FSInfo) 00171 mbr->info = *FSInfo; 00172 else 00173 return true; 00174 00175 unsigned flags = 0; 00176 bool hasSlash = filePath.toString().find('/') != std::string::npos; 00177 if (hasSlash) 00178 flags |= ArchiveMember::HasPathFlag; 00179 if (hasSlash || filePath.toString().length() > 15) 00180 flags |= ArchiveMember::HasLongFilenameFlag; 00181 std::string magic; 00182 mbr->path.getMagicNumber(magic,4); 00183 switch (sys::IdentifyFileType(magic.c_str(),4)) { 00184 case sys::Bitcode_FileType: 00185 flags |= ArchiveMember::BitcodeFlag; 00186 break; 00187 default: 00188 break; 00189 } 00190 mbr->flags = flags; 00191 members.insert(where,mbr); 00192 return false; 00193 } 00194 00195 // Write one member out to the file. 00196 bool 00197 Archive::writeMember( 00198 const ArchiveMember& member, 00199 std::ofstream& ARFile, 00200 bool CreateSymbolTable, 00201 bool TruncateNames, 00202 bool ShouldCompress, 00203 std::string* ErrMsg 00204 ) { 00205 00206 unsigned filepos = ARFile.tellp(); 00207 filepos -= 8; 00208 00209 // Get the data and its size either from the 00210 // member's in-memory data or directly from the file. 00211 size_t fSize = member.getSize(); 00212 const char *data = (const char*)member.getData(); 00213 MemoryBuffer *mFile = 0; 00214 if (!data) { 00215 mFile = MemoryBuffer::getFile(member.getPath().c_str(), ErrMsg); 00216 if (mFile == 0) 00217 return true; 00218 data = mFile->getBufferStart(); 00219 fSize = mFile->getBufferSize(); 00220 } 00221 00222 // Now that we have the data in memory, update the 00223 // symbol table if its a bitcode file. 00224 if (CreateSymbolTable && member.isBitcode()) { 00225 std::vector<std::string> symbols; 00226 std::string FullMemberName = archPath.toString() + "(" + 00227 member.getPath().toString() 00228 + ")"; 00229 ModuleProvider* MP = 00230 GetBitcodeSymbols((const unsigned char*)data,fSize, 00231 FullMemberName, symbols, ErrMsg); 00232 00233 // If the bitcode parsed successfully 00234 if ( MP ) { 00235 for (std::vector<std::string>::iterator SI = symbols.begin(), 00236 SE = symbols.end(); SI != SE; ++SI) { 00237 00238 std::pair<SymTabType::iterator,bool> Res = 00239 symTab.insert(std::make_pair(*SI,filepos)); 00240 00241 if (Res.second) { 00242 symTabSize += SI->length() + 00243 numVbrBytes(SI->length()) + 00244 numVbrBytes(filepos); 00245 } 00246 } 00247 // We don't need this module any more. 00248 delete MP; 00249 } else { 00250 delete mFile; 00251 if (ErrMsg) 00252 *ErrMsg = "Can't parse bitcode member: " + member.getPath().toString() 00253 + ": " + *ErrMsg; 00254 return true; 00255 } 00256 } 00257 00258 int hdrSize = fSize; 00259 00260 // Compute the fields of the header 00261 ArchiveMemberHeader Hdr; 00262 bool writeLongName = fillHeader(member,Hdr,hdrSize,TruncateNames); 00263 00264 // Write header to archive file 00265 ARFile.write((char*)&Hdr, sizeof(Hdr)); 00266 00267 // Write the long filename if its long 00268 if (writeLongName) { 00269 ARFile.write(member.getPath().toString().data(), 00270 member.getPath().toString().length()); 00271 } 00272 00273 // Write the (possibly compressed) member's content to the file. 00274 ARFile.write(data,fSize); 00275 00276 // Make sure the member is an even length 00277 if ((ARFile.tellp() & 1) == 1) 00278 ARFile << ARFILE_PAD; 00279 00280 // Close the mapped file if it was opened 00281 delete mFile; 00282 return false; 00283 } 00284 00285 // Write out the LLVM symbol table as an archive member to the file. 00286 void 00287 Archive::writeSymbolTable(std::ofstream& ARFile) { 00288 00289 // Construct the symbol table's header 00290 ArchiveMemberHeader Hdr; 00291 Hdr.init(); 00292 memcpy(Hdr.name,ARFILE_LLVM_SYMTAB_NAME,16); 00293 uint64_t secondsSinceEpoch = sys::TimeValue::now().toEpochTime(); 00294 char buffer[32]; 00295 sprintf(buffer, "%-8o", 0644); 00296 memcpy(Hdr.mode,buffer,8); 00297 sprintf(buffer, "%-6u", sys::Process::GetCurrentUserId()); 00298 memcpy(Hdr.uid,buffer,6); 00299 sprintf(buffer, "%-6u", sys::Process::GetCurrentGroupId()); 00300 memcpy(Hdr.gid,buffer,6); 00301 sprintf(buffer,"%-12u", unsigned(secondsSinceEpoch)); 00302 memcpy(Hdr.date,buffer,12); 00303 sprintf(buffer,"%-10u",symTabSize); 00304 memcpy(Hdr.size,buffer,10); 00305 00306 // Write the header 00307 ARFile.write((char*)&Hdr, sizeof(Hdr)); 00308 00309 #ifndef NDEBUG 00310 // Save the starting position of the symbol tables data content. 00311 unsigned startpos = ARFile.tellp(); 00312 #endif 00313 00314 // Write out the symbols sequentially 00315 for ( Archive::SymTabType::iterator I = symTab.begin(), E = symTab.end(); 00316 I != E; ++I) 00317 { 00318 // Write out the file index 00319 writeInteger(I->second, ARFile); 00320 // Write out the length of the symbol 00321 writeInteger(I->first.length(), ARFile); 00322 // Write out the symbol 00323 ARFile.write(I->first.data(), I->first.length()); 00324 } 00325 00326 #ifndef NDEBUG 00327 // Now that we're done with the symbol table, get the ending file position 00328 unsigned endpos = ARFile.tellp(); 00329 #endif 00330 00331 // Make sure that the amount we wrote is what we pre-computed. This is 00332 // critical for file integrity purposes. 00333 assert(endpos - startpos == symTabSize && "Invalid symTabSize computation"); 00334 00335 // Make sure the symbol table is even sized 00336 if (symTabSize % 2 != 0 ) 00337 ARFile << ARFILE_PAD; 00338 } 00339 00340 // Write the entire archive to the file specified when the archive was created. 00341 // This writes to a temporary file first. Options are for creating a symbol 00342 // table, flattening the file names (no directories, 15 chars max) and 00343 // compressing each archive member. 00344 bool 00345 Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, 00346 std::string* ErrMsg) 00347 { 00348 // Make sure they haven't opened up the file, not loaded it, 00349 // but are now trying to write it which would wipe out the file. 00350 if (members.empty() && mapfile && mapfile->getBufferSize() > 8) { 00351 if (ErrMsg) 00352 *ErrMsg = "Can't write an archive not opened for writing"; 00353 return true; 00354 } 00355 00356 // Create a temporary file to store the archive in 00357 sys::Path TmpArchive = archPath; 00358 if (TmpArchive.createTemporaryFileOnDisk(ErrMsg)) 00359 return true; 00360 00361 // Make sure the temporary gets removed if we crash 00362 sys::RemoveFileOnSignal(TmpArchive); 00363 00364 // Create archive file for output. 00365 std::ios::openmode io_mode = std::ios::out | std::ios::trunc | 00366 std::ios::binary; 00367 std::ofstream ArchiveFile(TmpArchive.c_str(), io_mode); 00368 00369 // Check for errors opening or creating archive file. 00370 if (!ArchiveFile.is_open() || ArchiveFile.bad()) { 00371 if (TmpArchive.exists()) 00372 TmpArchive.eraseFromDisk(); 00373 if (ErrMsg) 00374 *ErrMsg = "Error opening archive file: " + archPath.toString(); 00375 return true; 00376 } 00377 00378 // If we're creating a symbol table, reset it now 00379 if (CreateSymbolTable) { 00380 symTabSize = 0; 00381 symTab.clear(); 00382 } 00383 00384 // Write magic string to archive. 00385 ArchiveFile << ARFILE_MAGIC; 00386 00387 // Loop over all member files, and write them out. Note that this also 00388 // builds the symbol table, symTab. 00389 for (MembersList::iterator I = begin(), E = end(); I != E; ++I) { 00390 if (writeMember(*I, ArchiveFile, CreateSymbolTable, 00391 TruncateNames, Compress, ErrMsg)) { 00392 if (TmpArchive.exists()) 00393 TmpArchive.eraseFromDisk(); 00394 ArchiveFile.close(); 00395 return true; 00396 } 00397 } 00398 00399 // Close archive file. 00400 ArchiveFile.close(); 00401 00402 // Write the symbol table 00403 if (CreateSymbolTable) { 00404 // At this point we have written a file that is a legal archive but it 00405 // doesn't have a symbol table in it. To aid in faster reading and to 00406 // ensure compatibility with other archivers we need to put the symbol 00407 // table first in the file. Unfortunately, this means mapping the file 00408 // we just wrote back in and copying it to the destination file. 00409 sys::Path FinalFilePath = archPath; 00410 00411 // Map in the archive we just wrote. 00412 { 00413 OwningPtr<MemoryBuffer> arch(MemoryBuffer::getFile(TmpArchive.c_str())); 00414 if (arch == 0) return true; 00415 const char* base = arch->getBufferStart(); 00416 00417 // Open another temporary file in order to avoid invalidating the 00418 // mmapped data 00419 if (FinalFilePath.createTemporaryFileOnDisk(ErrMsg)) 00420 return true; 00421 sys::RemoveFileOnSignal(FinalFilePath); 00422 00423 std::ofstream FinalFile(FinalFilePath.c_str(), io_mode); 00424 if (!FinalFile.is_open() || FinalFile.bad()) { 00425 if (TmpArchive.exists()) 00426 TmpArchive.eraseFromDisk(); 00427 if (ErrMsg) 00428 *ErrMsg = "Error opening archive file: " + FinalFilePath.toString(); 00429 return true; 00430 } 00431 00432 // Write the file magic number 00433 FinalFile << ARFILE_MAGIC; 00434 00435 // If there is a foreign symbol table, put it into the file now. Most 00436 // ar(1) implementations require the symbol table to be first but llvm-ar 00437 // can deal with it being after a foreign symbol table. This ensures 00438 // compatibility with other ar(1) implementations as well as allowing the 00439 // archive to store both native .o and LLVM .bc files, both indexed. 00440 if (foreignST) { 00441 if (writeMember(*foreignST, FinalFile, false, false, false, ErrMsg)) { 00442 FinalFile.close(); 00443 if (TmpArchive.exists()) 00444 TmpArchive.eraseFromDisk(); 00445 return true; 00446 } 00447 } 00448 00449 // Put out the LLVM symbol table now. 00450 writeSymbolTable(FinalFile); 00451 00452 // Copy the temporary file contents being sure to skip the file's magic 00453 // number. 00454 FinalFile.write(base + sizeof(ARFILE_MAGIC)-1, 00455 arch->getBufferSize()-sizeof(ARFILE_MAGIC)+1); 00456 00457 // Close up shop 00458 FinalFile.close(); 00459 } // free arch. 00460 00461 // Move the final file over top of TmpArchive 00462 if (FinalFilePath.renamePathOnDisk(TmpArchive, ErrMsg)) 00463 return true; 00464 } 00465 00466 // Before we replace the actual archive, we need to forget all the 00467 // members, since they point to data in that old archive. We need to do 00468 // this because we cannot replace an open file on Windows. 00469 cleanUpMemory(); 00470 00471 if (TmpArchive.renamePathOnDisk(archPath, ErrMsg)) 00472 return true; 00473 00474 // Set correct read and write permissions after temporary file is moved 00475 // to final destination path. 00476 if (archPath.makeReadableOnDisk(ErrMsg)) 00477 return true; 00478 if (archPath.makeWriteableOnDisk(ErrMsg)) 00479 return true; 00480 00481 return false; 00482 }
This web site is hosted by the Computer Science Department at the University of Illinois at Urbana-Champaign.