[llvm-commits] CVS: llvm/lib/Bytecode/Archive/Archive.cpp ArchiveInternals.h ArchiveWriter.cpp

Reid Spencer reid at x10sys.com
Sat Nov 6 00:51:56 PST 2004



Changes in directory llvm/lib/Bytecode/Archive:

Archive.cpp added (r1.1)
ArchiveInternals.h added (r1.1)
ArchiveWriter.cpp added (r1.1)
---
Log message:

First kinda/sorta working version of the Archive library. Reading is not
yet supported but writing works. Way too early to review this. More to come


---
Diffs of the changes:  (+466 -0)

Index: llvm/lib/Bytecode/Archive/Archive.cpp
diff -c /dev/null llvm/lib/Bytecode/Archive/Archive.cpp:1.1
*** /dev/null	Sat Nov  6 02:51:55 2004
--- llvm/lib/Bytecode/Archive/Archive.cpp	Sat Nov  6 02:51:45 2004
***************
*** 0 ****
--- 1,24 ----
+ //===-- Archive.cpp - Generic LLVM archive functions ------------*- C++ -*-===//
+ // 
+ //                     The LLVM Compiler Infrastructure
+ //
+ // This file was developed by Reid Spencer and is distributed under the 
+ // University of Illinois Open Source License. See LICENSE.TXT for details.
+ // 
+ //===----------------------------------------------------------------------===//
+ //
+ // Builds up standard unix archive files (.a) containing LLVM bytecode.
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #include "ArchiveInternals.h"
+ 
+ using namespace llvm;
+ 
+ Archive::Archive() {
+ }
+ 
+ Archive::~Archive() {
+ }
+ 
+ // vim: sw=2 ai


Index: llvm/lib/Bytecode/Archive/ArchiveInternals.h
diff -c /dev/null llvm/lib/Bytecode/Archive/ArchiveInternals.h:1.1
*** /dev/null	Sat Nov  6 02:51:56 2004
--- llvm/lib/Bytecode/Archive/ArchiveInternals.h	Sat Nov  6 02:51:45 2004
***************
*** 0 ****
--- 1,158 ----
+ //===-- lib/Bytecode/ArchiveInternals.h -------------------------*- C++ -*-===//
+ // 
+ //                     The LLVM Compiler Infrastructure
+ //
+ // This file was developed by Reid Spencer and is distributed under the 
+ // University of Illinois Open Source License. See LICENSE.TXT for details.
+ // 
+ //===----------------------------------------------------------------------===//
+ //
+ // Internal implementation header for LLVM Archive files.
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #ifndef LIB_BYTECODE_ARCHIVEINTERNALS_H
+ #define LIB_BYTECODE_ARCHIVEINTERNALS_H
+ 
+ #include "llvm/Bytecode/Archive.h"
+ #include "llvm/System/TimeValue.h"
+ 
+ #define ARFILE_MAGIC "!<arch>\n"                   ///< magic string 
+ #define ARFILE_MAGIC_LEN (sizeof(ARFILE_MAGIC)-1)  ///< length of magic string 
+ #define ARFILE_SYMTAB_NAME "/"                     ///< name of symtab entry
+ #define ARFILE_STRTAB_NAME "//"                    ///< name of strtab entry
+ #define ARFILE_PAD '\n'                            ///< inter-file align padding
+ 
+ namespace llvm {
+ 
+   /// The ArchiveMemberHeader structure is used internally for bytecode archives. 
+   /// The header precedes each file member in the archive. This structure is 
+   /// defined using character arrays for direct and correct interpretation
+   /// regardless of the endianess of the machine that produced it.
+   /// @brief Archive File Member Header
+   class ArchiveMemberHeader {
+     public:
+     void init() {
+       memset(name,' ',16);
+       memset(date,' ',12);
+       memset(uid,' ',6);
+       memset(gid,' ',6);
+       memset(mode,' ',8);
+       memset(size,' ',10);
+       fmag[0] = '`';
+       fmag[1] = '\n';
+     }
+     void setDate( int secondsSinceEpoch = 0 ) {
+       if (secondsSinceEpoch == 0) {
+         sys::TimeValue tv = sys::TimeValue::now();
+         uint64_t secs; uint32_t nanos;
+         tv.GetTimespecTime(secs,nanos);
+         secondsSinceEpoch = (int) secs;
+       }
+       char buffer[20];
+       sprintf(buffer,"%d", secondsSinceEpoch);
+       memcpy(date,buffer,strlen(buffer));
+     }
+ 
+     void setSize(size_t sz) {
+       char buffer[20];
+       sprintf(buffer, "%u", (unsigned)sz);
+       memcpy(size,buffer,strlen(buffer));
+     }
+ 
+     void setMode(int m) {
+       char buffer[20];
+       sprintf(buffer, "%o", m);
+       memcpy(mode,buffer,strlen(buffer));
+     }
+ 
+     void setUid(unsigned u) {
+       char buffer[20];
+       sprintf(buffer, "%u", u);
+       memcpy(uid,buffer,strlen(buffer));
+     }
+ 
+     void setGid(unsigned g) {
+       char buffer[20];
+       sprintf(buffer, "%u", g);
+       memcpy(gid,buffer,strlen(buffer));
+     }
+ 
+     bool setName(const std::string& nm) {
+       if (nm.length() > 0 && nm.length() <= 16) {
+         memcpy(name,nm.c_str(),nm.length());
+         for (int i = nm.length()+1; i < 16; i++ ) name[i] = ' ';
+         return true;
+       }
+       return false;
+     }
+ 
+     private:
+     char name[16];  ///< Name of the file member. The filename is terminated with '/'
+                     ///< and blanks. The empty name (/ and 15 blanks) is for the 
+                     ///< symbol table. The special name "//" and 15 blanks is for
+                     ///< the string table, used for long file names. It must be
+                     ///< first in the archive.
+     char date[12];  ///< File date, decimal seconds since Epoch
+     char uid[6];    ///< user id in ASCII decimal
+     char gid[6];    ///< group id in ASCII decimal
+     char mode[8];   ///< file mode in ASCII octal
+     char size[10];  ///< file size in ASCII decimal
+     char fmag[2];   ///< Always contains ARFILE_MAGIC_TERMINATOR
+ 
+   };
+ 
+   /// The ArchiveInternals class is used to hold the content of the archive
+   /// while it is in memory. It also provides the bulk of the implementation for
+   /// the llvm:Archive class's interface.
+   class Archive::ArchiveInternals {
+     /// @name Types
+     /// @{
+     public:
+       typedef std::vector<std::string> StrTab;
+ 
+       /// This structure holds information for one member in the archive. It is
+       /// used temporarily while the contents of the archive are being
+       /// determined.
+       struct MemberInfo {
+         MemberInfo() {}
+         sys::Path path;
+         std::string name;
+         sys::Path::StatusInfo status;
+         StrTab symbols;
+         unsigned offset;
+       };
+ 
+     /// @}
+     /// @name Methods
+     /// @{
+     public:
+       /// @brief Add a file member to the archive.
+       void addFileMember(
+         const sys::Path& path,         ///< The path to the file to be added
+         const std::string& name,       ///< The name for the member
+         const StrTab* syms = 0         ///< The symbol table of the member
+       );
+ 
+       /// @brief Write the accumulated archive information to an archive file
+       void writeArchive();
+       void writeMember(const MemberInfo& member,std::ofstream& ARFile);
+       void writeSymbolTable(std::ofstream& ARFile);
+       void writeInteger(int num, std::ofstream& ARFile);
+ 
+     /// @}
+     /// @name  Data
+     /// @{
+     private:
+       friend class Archive;            ///< Parent class is a friend
+       sys::Path       fname;           ///< Path to the archive file
+       std::vector<MemberInfo> members; ///< Info about member files
+       Archive::SymTab* symtab;         ///< User's symbol table
+ 
+     /// @}
+   };
+ }
+ 
+ #endif
+ 
+ // vim: sw=2 ai


Index: llvm/lib/Bytecode/Archive/ArchiveWriter.cpp
diff -c /dev/null llvm/lib/Bytecode/Archive/ArchiveWriter.cpp:1.1
*** /dev/null	Sat Nov  6 02:51:56 2004
--- llvm/lib/Bytecode/Archive/ArchiveWriter.cpp	Sat Nov  6 02:51:45 2004
***************
*** 0 ****
--- 1,284 ----
+ //===-- ArchiveWriter.cpp - LLVM archive writing --------------------------===//
+ // 
+ //                     The LLVM Compiler Infrastructure
+ //
+ // This file was developed by Reid Spencerand is distributed under the 
+ // University of Illinois Open Source License. See LICENSE.TXT for details.
+ // 
+ //===----------------------------------------------------------------------===//
+ //
+ // Builds up standard unix archive files (.a) containing LLVM bytecode.
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #include "ArchiveInternals.h"
+ #include "llvm/Module.h"
+ #include "llvm/Bytecode/Reader.h"
+ #include "llvm/Support/FileUtilities.h"
+ #include "llvm/ADT/StringExtras.h"
+ #include "llvm/System/MappedFile.h"
+ #include <fstream>
+ #include <iostream>
+ 
+ using namespace llvm;
+ 
+ Archive* 
+ Archive::CreateEmpty(const sys::Path& Filename) {
+   Archive* result = new Archive;
+   Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
+   impl->fname = Filename;
+   return result;
+ }
+ 
+ Archive*
+ Archive::CreateFromFiles(
+   const sys::Path& Filename,
+   const PathList& Files,
+   const std::string& StripName
+ ) {
+   Archive* result = new Archive;
+   Archive::ArchiveInternals* impl = result->impl = new Archive::ArchiveInternals;
+   impl->fname = Filename;
+ 
+   try {
+     size_t strip_len = StripName.length();
+     for (PathList::const_iterator P = Files.begin(), E = Files.end(); P != E ;++P)
+     {
+       if (P->readable()) {
+         std::string name(P->get());
+         if (strip_len > 0 && StripName == name.substr(0,strip_len)) {
+           name.erase(0,strip_len);
+         }
+         if (P->isBytecodeFile()) {
+           std::vector<std::string> syms;
+           if (!GetBytecodeSymbols(*P, syms))
+             throw std::string("Can not get symbols from: ") + P->get();
+           impl->addFileMember(*P, name, &syms);
+         } else {
+           impl->addFileMember(*P, name);
+         }
+       }
+       else
+         throw std::string("Can not read: ") + P->get();
+     }
+ 
+     // Now that we've collected everything, write the archive
+     impl->writeArchive();
+ 
+   } catch(...) {
+     delete impl;
+     result->impl = 0;
+     delete result;
+     throw;
+   }
+ 
+   return result;
+ }
+ 
+ void
+ Archive::ArchiveInternals::addFileMember(
+   const sys::Path& filePath,
+   const std::string& memberName,
+   const StrTab* symbols
+ ) {
+   MemberInfo info;
+   info.path = filePath;
+   info.name = memberName;
+   filePath.getStatusInfo(info.status);
+   if (symbols)
+     info.symbols = *symbols;
+   info.offset = 0;
+   members.push_back(info);
+ }
+ 
+ void
+ Archive::ArchiveInternals::writeInteger(int num, std::ofstream& ARFile) {
+   char buff[4];
+   buff[0] = (num >> 24) & 255;
+   buff[1] = (num >> 16) & 255;
+   buff[2] = (num >> 8) & 255;
+   buff[3] = num & 255;
+   ARFile.write(buff, sizeof(buff));
+ }
+ 
+ void
+ Archive::ArchiveInternals::writeSymbolTable( std::ofstream& ARFile ) {
+  
+   // Compute the number of symbols in the symbol table and the
+   // total byte size of the string pool. While we're traversing,
+   // build the string pool for supporting long file names. Also,
+   // build the table of file offsets for the symbol table and 
+   // the 
+   typedef std::map<std::string,unsigned> SymbolMap;
+   StrTab stringPool;
+   SymbolMap symbolTable;
+   std::vector<unsigned> fileOffsets;
+   std::string symTabStrings;
+   unsigned fileOffset = 0;
+   unsigned spOffset = 0;
+   unsigned numSymbols = 0;
+   unsigned numSymBytes = 0;
+   for (unsigned i = 0; i < members.size(); i++ ) {
+     MemberInfo& mi = members[i];
+     StrTab& syms = mi.symbols;
+     size_t numSym = syms.size();
+     numSymbols += numSym;
+     for (unsigned j = 0; j < numSym; j++ ) {
+       numSymBytes += syms[j].size() + 1;
+       symbolTable[syms[i]] = i;
+     }
+     if (mi.name.length() > 15 || std::string::npos != mi.name.find('/')) {
+       stringPool.push_back(mi.name + "/\n");
+       mi.name = std::string("/") + utostr(spOffset);
+       spOffset += mi.name.length() + 2;
+     } else if (mi.name[mi.name.length()-1] != '/') {
+       mi.name += "/";
+     }
+     fileOffsets.push_back(fileOffset);
+     fileOffset += sizeof(ArchiveMemberHeader) + mi.status.fileSize;
+   }
+ 
+ 
+   // Compute the size of the symbol table file member
+   unsigned symTabSize = 0;
+   if (numSymbols != 0) 
+     symTabSize = 
+       sizeof(ArchiveMemberHeader) + // Size of the file header
+       4 +                           // Size of "number of entries"
+       (4 * numSymbols) +            // Size of member file indices
+       numSymBytes;                  // Size of the string table
+ 
+   // Compute the size of the string pool
+   unsigned strPoolSize = 0;
+   if (spOffset != 0 )
+     strPoolSize = 
+       sizeof(ArchiveMemberHeader) + // Size of the file header
+       spOffset;                     // Number of bytes in the string pool
+ 
+   // Compute the byte index offset created by symbol table and string pool
+   unsigned firstFileOffset = symTabSize + strPoolSize;
+ 
+   // Create header for symbol table. This must be first if there is
+   // a symbol table and must have a special name.
+   if ( symTabSize > 0 ) {
+     ArchiveMemberHeader Hdr;
+     Hdr.init();
+ 
+     // Name of symbol table is '/               ' but "" is passed in
+     // because the setName method always terminates with a /
+     Hdr.setName(ARFILE_SYMTAB_NAME);
+     Hdr.setDate();
+     Hdr.setSize(symTabSize - sizeof(ArchiveMemberHeader));
+     Hdr.setMode(0);
+     Hdr.setUid(0);
+     Hdr.setGid(0);
+     
+     // Write header to archive file
+     ARFile.write((char*)&Hdr, sizeof(Hdr));
+     
+     // Write the number of entries in the symbol table
+     this->writeInteger(numSymbols, ARFile);
+ 
+     // Write the file offset indices for each symbol and build the
+     // symbol table string pool
+     std::string symTabStrPool;
+     symTabStrPool.reserve(256 * 1024); // Reserve 256KBytes for symbols
+     for (SymbolMap::iterator I = symbolTable.begin(), E = symbolTable.end();
+          I != E; ++I ) {
+       this->writeInteger(firstFileOffset + fileOffsets[I->second], ARFile);
+       symTabStrPool += I->first;
+       symTabStrPool += "\0";
+     }
+ 
+     // Write the symbol table's string pool
+     ARFile.write(symTabStrPool.data(), symTabStrPool.size());
+   }
+ 
+   //============== DONE WITH SYMBOL TABLE 
+ 
+   if (strPoolSize > 0) {
+     // Initialize the header for the string pool
+     ArchiveMemberHeader Hdr;
+     Hdr.init();
+     Hdr.setName(ARFILE_STRTAB_NAME); 
+     Hdr.setDate();
+     Hdr.setSize(spOffset);
+     Hdr.setMode(0);
+     Hdr.setUid(0);
+     Hdr.setGid(0);
+ 
+     // Write the string pool header
+     ARFile.write((char*)&Hdr, sizeof(Hdr));
+ 
+     // Write the string pool
+     for (unsigned i = 0; i < stringPool.size(); i++) {
+       ARFile.write(stringPool[i].data(), stringPool[i].size());
+     }
+   }
+ }
+ 
+ void
+ Archive::ArchiveInternals::writeMember(
+   const MemberInfo& member,
+   std::ofstream& ARFile
+ ) {
+ 
+   // Map the file into memory. We do this early for two reasons. First,
+   // if there's any kind of error, we want to know about it. Second, we
+   // want to ensure we're using the most recent size for this file.
+   sys::MappedFile mFile(member.path);
+   mFile.map();
+ 
+   // Header for the archive member
+   ArchiveMemberHeader Hdr;
+   Hdr.init();
+ 
+   // Set the name. If its longer than 15 chars, it will have already
+   // been reduced by the writeSymbolTable.
+   Hdr.setName(member.name);
+ 
+   // Set the other header members
+   Hdr.setSize( mFile.size() );
+   Hdr.setMode( member.status.mode);
+   Hdr.setUid ( member.status.user);
+   Hdr.setGid ( member.status.group);
+   Hdr.setDate( member.status.modTime.ToPosixTime() );
+ 
+   // Write header to archive file
+   ARFile.write((char*)&Hdr, sizeof(Hdr));
+   
+   //write to archive file
+   ARFile.write(mFile.charBase(),mFile.size());
+ 
+   mFile.unmap();
+ }
+ 
+ void
+ Archive::ArchiveInternals::writeArchive() {
+   
+   // Create archive file for output.
+   std::ofstream ArchiveFile(fname.get().c_str());
+   
+   // Check for errors opening or creating archive file.
+   if ( !ArchiveFile.is_open() || ArchiveFile.bad() ) {
+     throw std::string("Error opening archive file: ") + fname.get();
+   }
+ 
+   // Write magic string to archive.
+   ArchiveFile << ARFILE_MAGIC;
+ 
+   // Write the symbol table and string pool
+   writeSymbolTable(ArchiveFile);
+ 
+   //Loop over all member files, and add to the archive.
+   for ( unsigned i = 0; i < members.size(); ++i) {
+     if(ArchiveFile.tellp() % 2 != 0)
+       ArchiveFile << ARFILE_PAD;
+     writeMember(members[i],ArchiveFile);
+   }
+ 
+   //Close archive file.
+   ArchiveFile.close();
+ }
+ 
+ // vim: sw=2 ai






More information about the llvm-commits mailing list