From 8496faea07de27b6d3435d02855db4bfebcc2781 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Mon, 17 Jun 2013 15:47:20 +0000 Subject: Move lib/Archive to tools/llvm-ar. llvm-ar is the only tool that needs to write archive files. Every other tool should be able to use the lib/Object interface. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@184083 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Bitcode/Archive.h | 524 ------------------------------------ lib/Archive/Archive.cpp | 254 ------------------ lib/Archive/ArchiveInternals.h | 87 ------ lib/Archive/ArchiveReader.cpp | 557 --------------------------------------- lib/Archive/ArchiveWriter.cpp | 429 ------------------------------ lib/Archive/CMakeLists.txt | 5 - lib/Archive/LLVMBuild.txt | 22 -- lib/Archive/Makefile | 17 -- lib/CMakeLists.txt | 1 - lib/LLVMBuild.txt | 2 +- lib/Makefile | 2 +- tools/llvm-ar/Archive.cpp | 254 ++++++++++++++++++ tools/llvm-ar/Archive.h | 524 ++++++++++++++++++++++++++++++++++++ tools/llvm-ar/ArchiveInternals.h | 87 ++++++ tools/llvm-ar/ArchiveReader.cpp | 557 +++++++++++++++++++++++++++++++++++++++ tools/llvm-ar/ArchiveWriter.cpp | 429 ++++++++++++++++++++++++++++++ tools/llvm-ar/CMakeLists.txt | 5 +- tools/llvm-ar/LLVMBuild.txt | 1 - tools/llvm-ar/Makefile | 2 +- tools/llvm-ar/llvm-ar.cpp | 2 +- 20 files changed, 1859 insertions(+), 1902 deletions(-) delete mode 100644 include/llvm/Bitcode/Archive.h delete mode 100644 lib/Archive/Archive.cpp delete mode 100644 lib/Archive/ArchiveInternals.h delete mode 100644 lib/Archive/ArchiveReader.cpp delete mode 100644 lib/Archive/ArchiveWriter.cpp delete mode 100644 lib/Archive/CMakeLists.txt delete mode 100644 lib/Archive/LLVMBuild.txt delete mode 100644 lib/Archive/Makefile create mode 100644 tools/llvm-ar/Archive.cpp create mode 100644 tools/llvm-ar/Archive.h create mode 100644 tools/llvm-ar/ArchiveInternals.h create mode 100644 tools/llvm-ar/ArchiveReader.cpp create mode 100644 tools/llvm-ar/ArchiveWriter.cpp diff --git a/include/llvm/Bitcode/Archive.h b/include/llvm/Bitcode/Archive.h deleted file mode 100644 index e576463c85..0000000000 --- a/include/llvm/Bitcode/Archive.h +++ /dev/null @@ -1,524 +0,0 @@ -//===-- llvm/Bitcode/Archive.h - LLVM Bitcode Archive -----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header file declares the Archive and ArchiveMember classes that provide -// manipulation of LLVM Archive files. The implementation is provided by the -// lib/Bitcode/Archive library. This library is used to read and write -// archive (*.a) files that contain LLVM bitcode files (or others). -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_BITCODE_ARCHIVE_H -#define LLVM_BITCODE_ARCHIVE_H - -#include "llvm/ADT/ilist.h" -#include "llvm/ADT/ilist_node.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/PathV1.h" -#include -#include - -namespace llvm { - class MemoryBuffer; - -// Forward declare classes -class Module; // From VMCore -class Archive; // Declared below -class ArchiveMemberHeader; // Internal implementation class -class LLVMContext; // Global data - -/// This class is the main class manipulated by users of the Archive class. It -/// holds information about one member of the Archive. It is also the element -/// stored by the Archive's ilist, the Archive's main abstraction. Because of -/// the special requirements of archive files, users are not permitted to -/// construct ArchiveMember instances. You should obtain them from the methods -/// of the Archive class instead. -/// @brief This class represents a single archive member. -class ArchiveMember : public ilist_node { - /// @name Types - /// @{ - public: - /// These flags are used internally by the archive member to specify various - /// characteristics of the member. The various "is" methods below provide - /// access to the flags. The flags are not user settable. - enum Flags { - SVR4SymbolTableFlag = 1, ///< Member is a SVR4 symbol table - BSD4SymbolTableFlag = 2, ///< Member is a BSD4 symbol table - BitcodeFlag = 4, ///< Member is bitcode - HasPathFlag = 8, ///< Member has a full or partial path - HasLongFilenameFlag = 16, ///< Member uses the long filename syntax - StringTableFlag = 32 ///< Member is an ar(1) format string table - }; - - /// @} - /// @name Accessors - /// @{ - public: - /// @returns the parent Archive instance - /// @brief Get the archive associated with this member - Archive* getArchive() const { return parent; } - - /// @returns the path to the Archive's file - /// @brief Get the path to the archive member - const sys::Path& getPath() const { return path; } - - /// The "user" is the owner of the file per Unix security. This may not - /// have any applicability on non-Unix systems but is a required component - /// of the "ar" file format. - /// @brief Get the user associated with this archive member. - unsigned getUser() const { return info.getUser(); } - - /// The "group" is the owning group of the file per Unix security. This - /// may not have any applicability on non-Unix systems but is a required - /// component of the "ar" file format. - /// @brief Get the group associated with this archive member. - unsigned getGroup() const { return info.getGroup(); } - - /// The "mode" specifies the access permissions for the file per Unix - /// security. This may not have any applicability on non-Unix systems but is - /// a required component of the "ar" file format. - /// @brief Get the permission mode associated with this archive member. - unsigned getMode() const { return info.getMode(); } - - /// This method returns the time at which the archive member was last - /// modified when it was not in the archive. - /// @brief Get the time of last modification of the archive member. - sys::TimeValue getModTime() const { return info.getTimestamp(); } - - /// @returns the size of the archive member in bytes. - /// @brief Get the size of the archive member. - uint64_t getSize() const { return info.getSize(); } - - /// This method returns the total size of the archive member as it - /// appears on disk. This includes the file content, the header, the - /// long file name if any, and the padding. - /// @brief Get total on-disk member size. - unsigned getMemberSize() const; - - /// This method will return a pointer to the in-memory content of the - /// archive member, if it is available. If the data has not been loaded - /// into memory, the return value will be null. - /// @returns a pointer to the member's data. - /// @brief Get the data content of the archive member - const char* getData() const { return data; } - - /// @returns true iff the member is a SVR4 (non-LLVM) symbol table - /// @brief Determine if this member is a SVR4 symbol table. - bool isSVR4SymbolTable() const { return flags&SVR4SymbolTableFlag; } - - /// @returns true iff the member is a BSD4.4 (non-LLVM) symbol table - /// @brief Determine if this member is a BSD4.4 symbol table. - bool isBSD4SymbolTable() const { return flags&BSD4SymbolTableFlag; } - - /// @returns true iff the archive member is the ar(1) string table - /// @brief Determine if this member is the ar(1) string table. - bool isStringTable() const { return flags&StringTableFlag; } - - /// @returns true iff the archive member is a bitcode file. - /// @brief Determine if this member is a bitcode file. - bool isBitcode() const { return flags&BitcodeFlag; } - - /// @returns true iff the file name contains a path (directory) component. - /// @brief Determine if the member has a path - bool hasPath() const { return flags&HasPathFlag; } - - /// Long filenames are an artifact of the ar(1) file format which allows - /// up to sixteen characters in its header and doesn't allow a path - /// separator character (/). To avoid this, a "long format" member name is - /// allowed that doesn't have this restriction. This method determines if - /// that "long format" is used for this member. - /// @returns true iff the file name uses the long form - /// @brief Determine if the member has a long file name - bool hasLongFilename() const { return flags&HasLongFilenameFlag; } - - /// This method returns the status info (like Unix stat(2)) for the archive - /// member. The status info provides the file's size, permissions, and - /// modification time. The contents of the Path::StatusInfo structure, other - /// than the size and modification time, may not have utility on non-Unix - /// systems. - /// @returns the status info for the archive member - /// @brief Obtain the status info for the archive member - const sys::FileStatus &getFileStatus() const { return info; } - - /// This method causes the archive member to be replaced with the contents - /// of the file specified by \p File. The contents of \p this will be - /// updated to reflect the new data from \p File. The \p File must exist and - /// be readable on entry to this method. - /// @returns true if an error occurred, false otherwise - /// @brief Replace contents of archive member with a new file. - bool replaceWith(const sys::Path &aFile, std::string* ErrMsg); - - /// @} - /// @name Data - /// @{ - private: - Archive* parent; ///< Pointer to parent archive - sys::PathWithStatus path; ///< Path of file containing the member - sys::FileStatus info; ///< Status info (size,mode,date) - unsigned flags; ///< Flags about the archive member - const char* data; ///< Data for the member - - /// @} - /// @name Constructors - /// @{ - public: - /// The default constructor is only used by the Archive's iplist when it - /// constructs the list's sentry node. - ArchiveMember(); - - private: - /// Used internally by the Archive class to construct an ArchiveMember. - /// The contents of the ArchiveMember are filled out by the Archive class. - explicit ArchiveMember(Archive *PAR); - - // So Archive can construct an ArchiveMember - friend class llvm::Archive; - /// @} -}; - -/// This class defines the interface to LLVM Archive files. The Archive class -/// presents the archive file as an ilist of ArchiveMember objects. The members -/// can be rearranged in any fashion either by directly editing the ilist or by -/// using editing methods on the Archive class (recommended). The Archive -/// class also provides several ways of accessing the archive file for various -/// purposes such as editing and linking. Full symbol table support is provided -/// for loading only those files that resolve symbols. Note that read -/// performance of this library is _crucial_ for performance of JIT type -/// applications and the linkers. Consequently, the implementation of the class -/// is optimized for reading. -class Archive { - - /// @name Types - /// @{ - public: - /// This is the ilist type over which users may iterate to examine - /// the contents of the archive - /// @brief The ilist type of ArchiveMembers that Archive contains. - typedef iplist MembersList; - - /// @brief Forward mutable iterator over ArchiveMember - typedef MembersList::iterator iterator; - - /// @brief Forward immutable iterator over ArchiveMember - typedef MembersList::const_iterator const_iterator; - - /// @brief Reverse mutable iterator over ArchiveMember - typedef std::reverse_iterator reverse_iterator; - - /// @brief Reverse immutable iterator over ArchiveMember - typedef std::reverse_iterator const_reverse_iterator; - - /// @brief The in-memory version of the symbol table - typedef std::map SymTabType; - - /// @} - /// @name ilist accessor methods - /// @{ - public: - inline iterator begin() { return members.begin(); } - inline const_iterator begin() const { return members.begin(); } - inline iterator end () { return members.end(); } - inline const_iterator end () const { return members.end(); } - - inline reverse_iterator rbegin() { return members.rbegin(); } - inline const_reverse_iterator rbegin() const { return members.rbegin(); } - inline reverse_iterator rend () { return members.rend(); } - inline const_reverse_iterator rend () const { return members.rend(); } - - inline size_t size() const { return members.size(); } - inline bool empty() const { return members.empty(); } - inline const ArchiveMember& front() const { return members.front(); } - inline ArchiveMember& front() { return members.front(); } - inline const ArchiveMember& back() const { return members.back(); } - inline ArchiveMember& back() { return members.back(); } - - /// @} - /// @name ilist mutator methods - /// @{ - public: - /// This method splices a \p src member from an archive (possibly \p this), - /// to a position just before the member given by \p dest in \p this. When - /// the archive is written, \p src will be written in its new location. - /// @brief Move a member to a new location - inline void splice(iterator dest, Archive& arch, iterator src) - { return members.splice(dest,arch.members,src); } - - /// This method erases a \p target member from the archive. When the - /// archive is written, it will no longer contain \p target. The associated - /// ArchiveMember is deleted. - /// @brief Erase a member. - inline iterator erase(iterator target) { return members.erase(target); } - - /// @} - /// @name Constructors - /// @{ - public: - /// Create an empty archive file and associate it with the \p Filename. This - /// method does not actually create the archive disk file. It creates an - /// empty Archive object. If the writeToDisk method is called, the archive - /// file \p Filename will be created at that point, with whatever content - /// the returned Archive object has at that time. - /// @returns An Archive* that represents the new archive file. - /// @brief Create an empty Archive. - static Archive* CreateEmpty( - const sys::Path& Filename,///< Name of the archive to (eventually) create. - LLVMContext& C ///< Context to use for global information - ); - - /// Open an existing archive and load its contents in preparation for - /// editing. After this call, the member ilist is completely populated based - /// on the contents of the archive file. You should use this form of open if - /// you intend to modify the archive or traverse its contents (e.g. for - /// printing). - /// @brief Open and load an archive file - static Archive* OpenAndLoad( - const sys::Path& filePath, ///< The file path to open and load - LLVMContext& C, ///< The context to use for global information - std::string* ErrorMessage ///< An optional error string - ); - - /// This method opens an existing archive file from \p Filename and reads in - /// its symbol table without reading in any of the archive's members. This - /// reduces both I/O and cpu time in opening the archive if it is to be used - /// solely for symbol lookup (e.g. during linking). The \p Filename must - /// exist and be an archive file or an error will be returned. This form - /// of opening the archive is intended for read-only operations that need to - /// locate members via the symbol table for link editing. Since the archve - /// members are not read by this method, the archive will appear empty upon - /// return. If editing operations are performed on the archive, they will - /// completely replace the contents of the archive! It is recommended that - /// if this form of opening the archive is used that only the symbol table - /// lookup methods (getSymbolTable, findModuleDefiningSymbol, and - /// findModulesDefiningSymbols) be used. - /// @returns an Archive* that represents the archive file, or null on error. - /// @brief Open an existing archive and load its symbols. - static Archive* OpenAndLoadSymbols( - const sys::Path& Filename, ///< Name of the archive file to open - LLVMContext& C, ///< The context to use for global info - std::string* ErrorMessage=0 ///< An optional error string - ); - - /// This destructor cleans up the Archive object, releases all memory, and - /// closes files. It does nothing with the archive file on disk. If you - /// haven't used the writeToDisk method by the time the destructor is - /// called, all changes to the archive will be lost. - /// @brief Destruct in-memory archive - ~Archive(); - - /// @} - /// @name Accessors - /// @{ - public: - /// @returns the path to the archive file. - /// @brief Get the archive path. - const sys::Path& getPath() { return archPath; } - - /// This method is provided so that editing methods can be invoked directly - /// on the Archive's iplist of ArchiveMember. However, it is recommended - /// that the usual STL style iterator interface be used instead. - /// @returns the iplist of ArchiveMember - /// @brief Get the iplist of the members - MembersList& getMembers() { return members; } - - /// This method allows direct query of the Archive's symbol table. The - /// symbol table is a std::map of std::string (the symbol) to unsigned (the - /// file offset). Note that for efficiency reasons, the offset stored in - /// the symbol table is not the actual offset. It is the offset from the - /// beginning of the first "real" file member (after the symbol table). Use - /// the getFirstFileOffset() to obtain that offset and add this value to the - /// offset in the symbol table to obtain the real file offset. Note that - /// there is purposefully no interface provided by Archive to look up - /// members by their offset. Use the findModulesDefiningSymbols and - /// findModuleDefiningSymbol methods instead. - /// @returns the Archive's symbol table. - /// @brief Get the archive's symbol table - const SymTabType& getSymbolTable() { return symTab; } - - /// This method returns the offset in the archive file to the first "real" - /// file member. Archive files, on disk, have a signature and might have a - /// symbol table that precedes the first actual file member. This method - /// allows you to determine what the size of those fields are. - /// @returns the offset to the first "real" file member in the archive. - /// @brief Get the offset to the first "real" file member in the archive. - unsigned getFirstFileOffset() { return firstFileOffset; } - - /// This method will scan the archive for bitcode modules, interpret them - /// and return a vector of the instantiated modules in \p Modules. If an - /// error occurs, this method will return true. If \p ErrMessage is not null - /// and an error occurs, \p *ErrMessage will be set to a string explaining - /// the error that occurred. - /// @returns true if an error occurred - /// @brief Instantiate all the bitcode modules located in the archive - bool getAllModules(std::vector& Modules, std::string* ErrMessage); - - /// This accessor looks up the \p symbol in the archive's symbol table and - /// returns the associated module that defines that symbol. This method can - /// be called as many times as necessary. This is handy for linking the - /// archive into another module based on unresolved symbols. Note that the - /// Module returned by this accessor should not be deleted by the caller. It - /// is managed internally by the Archive class. It is possible that multiple - /// calls to this accessor will return the same Module instance because the - /// associated module defines multiple symbols. - /// @returns The Module* found or null if the archive does not contain a - /// module that defines the \p symbol. - /// @brief Look up a module by symbol name. - Module* findModuleDefiningSymbol( - const std::string& symbol, ///< Symbol to be sought - std::string* ErrMessage ///< Error message storage, if non-zero - ); - - /// This method is similar to findModuleDefiningSymbol but allows lookup of - /// more than one symbol at a time. If \p symbols contains a list of - /// undefined symbols in some module, then calling this method is like - /// making one complete pass through the archive to resolve symbols but is - /// more efficient than looking at the individual members. Note that on - /// exit, the symbols resolved by this method will be removed from \p - /// symbols to ensure they are not re-searched on a subsequent call. If - /// you need to retain the list of symbols, make a copy. - /// @brief Look up multiple symbols in the archive. - bool findModulesDefiningSymbols( - std::set& symbols, ///< Symbols to be sought - SmallVectorImpl& modules, ///< The modules matching \p symbols - std::string* ErrMessage ///< Error msg storage, if non-zero - ); - - /// This method determines whether the archive is a properly formed llvm - /// bitcode archive. It first makes sure the symbol table has been loaded - /// and has a non-zero size. If it does, then it is an archive. If not, - /// then it tries to load all the bitcode modules of the archive. Finally, - /// it returns whether it was successful. - /// @returns true if the archive is a proper llvm bitcode archive - /// @brief Determine whether the archive is a proper llvm bitcode archive. - bool isBitcodeArchive(); - - /// @} - /// @name Mutators - /// @{ - public: - /// This method is the only way to get the archive written to disk. It - /// creates or overwrites the file specified when \p this was created - /// or opened. The arguments provide options for writing the archive. If - /// \p CreateSymbolTable is true, the archive is scanned for bitcode files - /// and a symbol table of the externally visible function and global - /// variable names is created. If \p TruncateNames is true, the names of the - /// archive members will have their path component stripped and the file - /// name will be truncated at 15 characters. If \p Compress is specified, - /// all archive members will be compressed before being written. If - /// \p PrintSymTab is true, the symbol table will be printed to std::cout. - /// @returns true if an error occurred, \p error set to error message; - /// returns false if the writing succeeded. - /// @brief Write (possibly modified) archive contents to disk - bool writeToDisk( - bool CreateSymbolTable=false, ///< Create Symbol table - bool TruncateNames=false, ///< Truncate the filename to 15 chars - std::string* ErrMessage=0 ///< If non-null, where error msg is set - ); - - /// This method adds a new file to the archive. The \p filename is examined - /// to determine just enough information to create an ArchiveMember object - /// which is then inserted into the Archive object's ilist at the location - /// given by \p where. - /// @returns true if an error occurred, false otherwise - /// @brief Add a file to the archive. - bool addFileBefore( - const sys::Path& filename, ///< The file to be added - iterator where, ///< Insertion point - std::string* ErrMsg ///< Optional error message location - ); - - /// @} - /// @name Implementation - /// @{ - protected: - /// @brief Construct an Archive for \p filename and optionally map it - /// into memory. - explicit Archive(const sys::Path& filename, LLVMContext& C); - - /// @returns A fully populated ArchiveMember or 0 if an error occurred. - /// @brief Parse the header of a member starting at \p At - ArchiveMember* parseMemberHeader( - const char*&At, ///< The pointer to the location we're parsing - const char*End, ///< The pointer to the end of the archive - std::string* error ///< Optional error message catcher - ); - - /// @param ErrMessage Set to address of a std::string to get error messages - /// @returns false on error - /// @brief Check that the archive signature is correct - bool checkSignature(std::string* ErrMessage); - - /// @param ErrMessage Set to address of a std::string to get error messages - /// @returns false on error - /// @brief Load the entire archive. - bool loadArchive(std::string* ErrMessage); - - /// @param ErrMessage Set to address of a std::string to get error messages - /// @returns false on error - /// @brief Load just the symbol table. - bool loadSymbolTable(std::string* ErrMessage); - - /// Writes one ArchiveMember to an ofstream. If an error occurs, returns - /// false, otherwise true. If an error occurs and error is non-null then - /// it will be set to an error message. - /// @returns false if writing member succeeded, - /// returns true if writing member failed, \p error set to error message. - bool writeMember( - const ArchiveMember& member, ///< The member to be written - std::ofstream& ARFile, ///< The file to write member onto - bool CreateSymbolTable, ///< Should symbol table be created? - bool TruncateNames, ///< Should names be truncated to 11 chars? - std::string* ErrMessage ///< If non-null, place were error msg is set - ); - - /// @brief Fill in an ArchiveMemberHeader from ArchiveMember. - bool fillHeader(const ArchiveMember&mbr, - ArchiveMemberHeader& hdr,int sz, bool TruncateNames) const; - - /// @brief Maps archive into memory - bool mapToMemory(std::string* ErrMsg); - - /// @brief Frees all the members and unmaps the archive file. - void cleanUpMemory(); - - /// This type is used to keep track of bitcode modules loaded from the - /// symbol table. It maps the file offset to a pair that consists of the - /// associated ArchiveMember and the Module. - /// @brief Module mapping type - typedef std::map > - ModuleMap; - - - /// @} - /// @name Data - /// @{ - protected: - sys::Path archPath; ///< Path to the archive file we read/write - MembersList members; ///< The ilist of ArchiveMember - MemoryBuffer *mapfile; ///< Raw Archive contents mapped into memory - const char* base; ///< Base of the memory mapped file data - SymTabType symTab; ///< The symbol table - std::string strtab; ///< The string table for long file names - unsigned symTabSize; ///< Size in bytes of symbol table - unsigned firstFileOffset; ///< Offset to first normal file. - ModuleMap modules; ///< The modules loaded via symbol lookup. - ArchiveMember* foreignST; ///< This holds the foreign symbol table. - LLVMContext& Context; ///< This holds global data. - /// @} - /// @name Hidden - /// @{ - private: - Archive() LLVM_DELETED_FUNCTION; - Archive(const Archive&) LLVM_DELETED_FUNCTION; - Archive& operator=(const Archive&) LLVM_DELETED_FUNCTION; - /// @} -}; - -} // End llvm namespace - -#endif diff --git a/lib/Archive/Archive.cpp b/lib/Archive/Archive.cpp deleted file mode 100644 index e6d4bae29d..0000000000 --- a/lib/Archive/Archive.cpp +++ /dev/null @@ -1,254 +0,0 @@ -//===-- Archive.cpp - Generic LLVM archive functions ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains the implementation of the Archive and ArchiveMember -// classes that is common to both reading and writing archives.. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Bitcode/Archive.h" -#include "ArchiveInternals.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/system_error.h" -#include -#include -using namespace llvm; - -// getMemberSize - compute the actual physical size of the file member as seen -// on disk. This isn't the size of member's payload. Use getSize() for that. -unsigned -ArchiveMember::getMemberSize() const { - // Basically its the file size plus the header size - unsigned result = info.fileSize + sizeof(ArchiveMemberHeader); - - // If it has a long filename, include the name length - if (hasLongFilename()) - result += path.str().length() + 1; - - // If its now odd lengthed, include the padding byte - if (result % 2 != 0 ) - result++; - - return result; -} - -// This default constructor is only use by the ilist when it creates its -// sentry node. We give it specific static values to make it stand out a bit. -ArchiveMember::ArchiveMember() - : parent(0), path("--invalid--"), flags(0), data(0) -{ - info.user = sys::Process::GetCurrentUserId(); - info.group = sys::Process::GetCurrentGroupId(); - info.mode = 0777; - info.fileSize = 0; - info.modTime = sys::TimeValue::now(); -} - -// This is the constructor that the Archive class uses when it is building or -// reading an archive. It just defaults a few things and ensures the parent is -// set for the iplist. The Archive class fills in the ArchiveMember's data. -// This is required because correctly setting the data may depend on other -// things in the Archive. -ArchiveMember::ArchiveMember(Archive* PAR) - : parent(PAR), path(), flags(0), data(0) -{ -} - -// This method allows an ArchiveMember to be replaced with the data for a -// different file, presumably as an update to the member. It also makes sure -// the flags are reset correctly. -bool ArchiveMember::replaceWith(const sys::Path& newFile, std::string* ErrMsg) { - bool Exists; - if (sys::fs::exists(newFile.str(), Exists) || !Exists) { - if (ErrMsg) - *ErrMsg = "Can not replace an archive member with a non-existent file"; - return true; - } - - data = 0; - path = newFile; - - // SVR4 symbol tables have an empty name - if (path.str() == ARFILE_SVR4_SYMTAB_NAME) - flags |= SVR4SymbolTableFlag; - else - flags &= ~SVR4SymbolTableFlag; - - // BSD4.4 symbol tables have a special name - if (path.str() == ARFILE_BSD4_SYMTAB_NAME) - flags |= BSD4SymbolTableFlag; - else - flags &= ~BSD4SymbolTableFlag; - - // String table name - if (path.str() == ARFILE_STRTAB_NAME) - flags |= StringTableFlag; - else - flags &= ~StringTableFlag; - - // If it has a slash then it has a path - bool hasSlash = path.str().find('/') != std::string::npos; - if (hasSlash) - flags |= HasPathFlag; - else - flags &= ~HasPathFlag; - - // If it has a slash or its over 15 chars then its a long filename format - if (hasSlash || path.str().length() > 15) - flags |= HasLongFilenameFlag; - else - flags &= ~HasLongFilenameFlag; - - // Get the signature and status info - const char* signature = (const char*) data; - SmallString<4> magic; - if (!signature) { - sys::fs::get_magic(path.str(), magic.capacity(), magic); - signature = magic.c_str(); - const sys::FileStatus *FSinfo = path.getFileStatus(false, ErrMsg); - if (FSinfo) - info = *FSinfo; - else - return true; - } - - // Determine what kind of file it is. - if (sys::fs::identify_magic(StringRef(signature, 4)) == - sys::fs::file_magic::bitcode) - flags |= BitcodeFlag; - else - flags &= ~BitcodeFlag; - - return false; -} - -// Archive constructor - this is the only constructor that gets used for the -// Archive class. Everything else (default,copy) is deprecated. This just -// initializes and maps the file into memory, if requested. -Archive::Archive(const sys::Path& filename, LLVMContext& C) - : archPath(filename), members(), mapfile(0), base(0), symTab(), strtab(), - symTabSize(0), firstFileOffset(0), modules(), foreignST(0), Context(C) { -} - -bool -Archive::mapToMemory(std::string* ErrMsg) { - OwningPtr File; - if (error_code ec = MemoryBuffer::getFile(archPath.c_str(), File)) { - if (ErrMsg) - *ErrMsg = ec.message(); - return true; - } - mapfile = File.take(); - base = mapfile->getBufferStart(); - return false; -} - -void Archive::cleanUpMemory() { - // Shutdown the file mapping - delete mapfile; - mapfile = 0; - base = 0; - - // Forget the entire symbol table - symTab.clear(); - symTabSize = 0; - - firstFileOffset = 0; - - // Free the foreign symbol table member - if (foreignST) { - delete foreignST; - foreignST = 0; - } - - // Delete any Modules and ArchiveMember's we've allocated as a result of - // symbol table searches. - for (ModuleMap::iterator I=modules.begin(), E=modules.end(); I != E; ++I ) { - delete I->second.first; - delete I->second.second; - } -} - -// Archive destructor - just clean up memory -Archive::~Archive() { - cleanUpMemory(); -} - - - -static void getSymbols(Module*M, std::vector& symbols) { - // Loop over global variables - for (Module::global_iterator GI = M->global_begin(), GE=M->global_end(); GI != GE; ++GI) - if (!GI->isDeclaration() && !GI->hasLocalLinkage()) - if (!GI->getName().empty()) - symbols.push_back(GI->getName()); - - // Loop over functions - for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI) - if (!FI->isDeclaration() && !FI->hasLocalLinkage()) - if (!FI->getName().empty()) - symbols.push_back(FI->getName()); - - // Loop over aliases - for (Module::alias_iterator AI = M->alias_begin(), AE = M->alias_end(); - AI != AE; ++AI) { - if (AI->hasName()) - symbols.push_back(AI->getName()); - } -} - -// Get just the externally visible defined symbols from the bitcode -bool llvm::GetBitcodeSymbols(const sys::Path& fName, - LLVMContext& Context, - std::vector& symbols, - std::string* ErrMsg) { - OwningPtr Buffer; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(fName.c_str(), Buffer)) { - if (ErrMsg) *ErrMsg = "Could not open file '" + fName.str() + "'" + ": " - + ec.message(); - return true; - } - - Module *M = ParseBitcodeFile(Buffer.get(), Context, ErrMsg); - if (!M) - return true; - - // Get the symbols - getSymbols(M, symbols); - - // Done with the module. - delete M; - return true; -} - -Module* -llvm::GetBitcodeSymbols(const char *BufPtr, unsigned Length, - const std::string& ModuleID, - LLVMContext& Context, - std::vector& symbols, - std::string* ErrMsg) { - // Get the module. - OwningPtr Buffer( - MemoryBuffer::getMemBufferCopy(StringRef(BufPtr, Length),ModuleID.c_str())); - - Module *M = ParseBitcodeFile(Buffer.get(), Context, ErrMsg); - if (!M) - return 0; - - // Get the symbols - getSymbols(M, symbols); - - // Done with the module. Note that it's the caller's responsibility to delete - // the Module. - return M; -} diff --git a/lib/Archive/ArchiveInternals.h b/lib/Archive/ArchiveInternals.h deleted file mode 100644 index bc5046de39..0000000000 --- a/lib/Archive/ArchiveInternals.h +++ /dev/null @@ -1,87 +0,0 @@ -//===-- lib/Archive/ArchiveInternals.h -------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Internal implementation header for LLVM Archive files. -// -//===----------------------------------------------------------------------===// - -#ifndef LIB_ARCHIVE_ARCHIVEINTERNALS_H -#define LIB_ARCHIVE_ARCHIVEINTERNALS_H - -#include "llvm/ADT/StringExtras.h" -#include "llvm/Bitcode/Archive.h" -#include "llvm/Support/TimeValue.h" -#include - -#define ARFILE_MAGIC "!\n" ///< magic string -#define ARFILE_MAGIC_LEN (sizeof(ARFILE_MAGIC)-1) ///< length of magic string -#define ARFILE_SVR4_SYMTAB_NAME "/ " ///< SVR4 symtab entry name -#define ARFILE_BSD4_SYMTAB_NAME "__.SYMDEF SORTED" ///< BSD4 symtab entry name -#define ARFILE_STRTAB_NAME "// " ///< Name of string table -#define ARFILE_PAD "\n" ///< inter-file align padding -#define ARFILE_MEMBER_MAGIC "`\n" ///< fmag field magic # - -namespace llvm { - - class LLVMContext; - - /// The ArchiveMemberHeader structure is used internally for bitcode - /// 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 { - /// @name Data - /// @{ - public: - char name[16]; ///< Name of the file member. - 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 - - /// @} - /// @name Methods - /// @{ - 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'; - } - - bool checkSignature() const { - return 0 == memcmp(fmag, ARFILE_MEMBER_MAGIC,2); - } - }; - - // Get just the externally visible defined symbols from the bitcode - bool GetBitcodeSymbols(const sys::Path& fName, - LLVMContext& Context, - std::vector& symbols, - std::string* ErrMsg); - - Module* GetBitcodeSymbols(const char *Buffer, unsigned Length, - const std::string& ModuleID, - LLVMContext& Context, - std::vector& symbols, - std::string* ErrMsg); -} - -#endif - -// vim: sw=2 ai diff --git a/lib/Archive/ArchiveReader.cpp b/lib/Archive/ArchiveReader.cpp deleted file mode 100644 index fc3a01f189..0000000000 --- a/lib/Archive/ArchiveReader.cpp +++ /dev/null @@ -1,557 +0,0 @@ -//===-- ArchiveReader.cpp - Read LLVM archive files -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Builds up standard unix archive files (.a) containing LLVM bitcode. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Bitcode/Archive.h" -#include "ArchiveInternals.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include -#include -using namespace llvm; - -/// Read a variable-bit-rate encoded unsigned integer -static inline unsigned readInteger(const char*&At, const char*End) { - unsigned Shift = 0; - unsigned Result = 0; - - do { - if (At == End) - return Result; - Result |= (unsigned)((*At++) & 0x7F) << Shift; - Shift += 7; - } while (At[-1] & 0x80); - return Result; -} - -// This member parses an ArchiveMemberHeader that is presumed to be pointed to -// by At. The At pointer is updated to the byte just after the header, which -// can be variable in size. -ArchiveMember* -Archive::parseMemberHeader(const char*& At, const char* End, std::string* error) -{ - if (At + sizeof(ArchiveMemberHeader) >= End) { - if (error) - *error = "Unexpected end of file"; - return 0; - } - - // Cast archive member header - const ArchiveMemberHeader* Hdr = (const ArchiveMemberHeader*)At; - At += sizeof(ArchiveMemberHeader); - - int flags = 0; - int MemberSize = atoi(Hdr->size); - assert(MemberSize >= 0); - - // Check the size of the member for sanity - if (At + MemberSize > End) { - if (error) - *error = "invalid member length in archive file"; - return 0; - } - - // Check the member signature - if (!Hdr->checkSignature()) { - if (error) - *error = "invalid file member signature"; - return 0; - } - - // Convert and check the member name - // The empty name ( '/' and 15 blanks) is for a foreign (non-LLVM) symbol - // table. The special name "//" and 14 blanks is for a string table, used - // for long file names. This library doesn't generate either of those but - // it will accept them. If the name starts with #1/ and the remainder is - // digits, then those digits specify the length of the name that is - // stored immediately following the header. Anything else is a regular, short - // filename that is terminated with a '/' and blanks. - - std::string pathname; - switch (Hdr->name[0]) { - case '#': - if (Hdr->name[1] == '1' && Hdr->name[2] == '/') { - if (isdigit(Hdr->name[3])) { - unsigned len = atoi(&Hdr->name[3]); - const char *nulp = (const char *)memchr(At, '\0', len); - pathname.assign(At, nulp != 0 ? (uintptr_t)(nulp - At) : len); - At += len; - MemberSize -= len; - flags |= ArchiveMember::HasLongFilenameFlag; - } else { - if (error) - *error = "invalid long filename"; - return 0; - } - } - break; - case '/': - if (Hdr->name[1]== '/') { - if (0 == memcmp(Hdr->name, ARFILE_STRTAB_NAME, 16)) { - pathname.assign(ARFILE_STRTAB_NAME); - flags |= ArchiveMember::StringTableFlag; - } else { - if (error) - *error = "invalid string table name"; - return 0; - } - } else if (Hdr->name[1] == ' ') { - if (0 == memcmp(Hdr->name, ARFILE_SVR4_SYMTAB_NAME, 16)) { - pathname.assign(ARFILE_SVR4_SYMTAB_NAME); - flags |= ArchiveMember::SVR4SymbolTableFlag; - } else { - if (error) - *error = "invalid SVR4 symbol table name"; - return 0; - } - } else if (isdigit(Hdr->name[1])) { - unsigned index = atoi(&Hdr->name[1]); - if (index < strtab.length()) { - const char* namep = strtab.c_str() + index; - const char* endp = strtab.c_str() + strtab.length(); - const char* p = namep; - const char* last_p = p; - while (p < endp) { - if (*p == '\n' && *last_p == '/') { - pathname.assign(namep, last_p - namep); - flags |= ArchiveMember::HasLongFilenameFlag; - break; - } - last_p = p; - p++; - } - if (p >= endp) { - if (error) - *error = "missing name terminator in string table"; - return 0; - } - } else { - if (error) - *error = "name index beyond string table"; - return 0; - } - } - break; - case '_': - if (Hdr->name[1] == '_' && - (0 == memcmp(Hdr->name, ARFILE_BSD4_SYMTAB_NAME, 16))) { - pathname.assign(ARFILE_BSD4_SYMTAB_NAME); - flags |= ArchiveMember::BSD4SymbolTableFlag; - break; - } - /* FALL THROUGH */ - - default: - const char* slash = (const char*) memchr(Hdr->name, '/', 16); - if (slash == 0) - slash = Hdr->name + 16; - pathname.assign(Hdr->name, slash - Hdr->name); - break; - } - - // Determine if this is a bitcode file - if (sys::fs::identify_magic(StringRef(At, 4)) == - sys::fs::file_magic::bitcode) - flags |= ArchiveMember::BitcodeFlag; - else - flags &= ~ArchiveMember::BitcodeFlag; - - // Instantiate the ArchiveMember to be filled - ArchiveMember* member = new ArchiveMember(this); - - // Fill in fields of the ArchiveMember - member->parent = this; - member->path.set(pathname); - member->info.fileSize = MemberSize; - member->info.modTime.fromEpochTime(atoi(Hdr->date)); - unsigned int mode; - sscanf(Hdr->mode, "%o", &mode); - member->info.mode = mode; - member->info.user = atoi(Hdr->uid); - member->info.group = atoi(Hdr->gid); - member->flags = flags; - member->data = At; - - return member; -} - -bool -Archive::checkSignature(std::string* error) { - // Check the magic string at file's header - if (mapfile->getBufferSize() < 8 || memcmp(base, ARFILE_MAGIC, 8)) { - if (error) - *error = "invalid signature for an archive file"; - return false; - } - return true; -} - -// 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 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 { - // 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; -} - -// Open and completely load the archive file. -Archive* -Archive::OpenAndLoad(const sys::Path& File, LLVMContext& C, - std::string* ErrorMessage) { - OwningPtr result ( new Archive(File, C)); - if (result->mapToMemory(ErrorMessage)) - return NULL; - if (!result->loadArchive(ErrorMessage)) - return NULL; - return result.take(); -} - -// Get all the bitcode modules from the archive -bool -Archive::getAllModules(std::vector& Modules, - std::string* ErrMessage) { - - for (iterator I=begin(), E=end(); I != E; ++I) { - if (I->isBitcode()) { - std::string FullMemberName = archPath.str() + - "(" + I->getPath().str() + ")"; - MemoryBuffer *Buffer = - MemoryBuffer::getMemBufferCopy(StringRef(I->getData(), I->getSize()), - FullMemberName.c_str()); - - Module *M = ParseBitcodeFile(Buffer, Context, ErrMessage); - delete Buffer; - if (!M) - return true; - - Modules.push_back(M); - } - } - return false; -} - -// Load just the symbol table from the archive file -bool -Archive::loadSymbolTable(std::string* ErrorMsg) { - - // Set up parsing - members.clear(); - symTab.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; -} - -// Open the archive and load just the symbol tables -Archive* Archive::OpenAndLoadSymbols(const sys::Path& File, - LLVMContext& C, - std::string* ErrorMessage) { - OwningPtr result ( new Archive(File, C) ); - if (result->mapToMemory(ErrorMessage)) - return NULL; - if (!result->loadSymbolTable(ErrorMessage)) - return NULL; - return result.take(); -} - -// 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; -} - -// Look up multiple symbols in the symbol table and return a set of -// Modules that define those symbols. -bool -Archive::findModulesDefiningSymbols(std::set& symbols, - SmallVectorImpl& 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 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::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 Added; - for (std::set::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; -} - -bool Archive::isBitcodeArchive() { - // Make sure the symTab has been loaded. In most cases this should have been - // done when the archive was constructed, but still, this is just in case. - if (symTab.empty()) - if (!loadSymbolTable(0)) - return false; - - // Now that we know it's been loaded, return true - // if it has a size - if (symTab.size()) return true; - - // We still can't be sure it isn't a bitcode archive - if (!loadArchive(0)) - return false; - - std::vector Modules; - std::string ErrorMessage; - - // Scan the archive, trying to load a bitcode member. We only load one to - // see if this works. - for (iterator I = begin(), E = end(); I != E; ++I) { - if (!I->isBitcode()) - continue; - - std::string FullMemberName = - archPath.str() + "(" + I->getPath().str() + ")"; - - MemoryBuffer *Buffer = - MemoryBuffer::getMemBufferCopy(StringRef(I->getData(), I->getSize()), - FullMemberName.c_str()); - Module *M = ParseBitcodeFile(Buffer, Context); - delete Buffer; - if (!M) - return false; // Couldn't parse bitcode, not a bitcode archive. - delete M; - return true; - } - - return false; -} diff --git a/lib/Archive/ArchiveWriter.cpp b/lib/Archive/ArchiveWriter.cpp deleted file mode 100644 index 97b34e616e..0000000000 --- a/lib/Archive/ArchiveWriter.cpp +++ /dev/null @@ -1,429 +0,0 @@ -//===-- ArchiveWriter.cpp - Write LLVM archive files ----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Builds up an LLVM archive file (.a) containing LLVM bitcode. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Bitcode/Archive.h" -#include "ArchiveInternals.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/system_error.h" -#include -#include -#include -using namespace llvm; - -// Write an integer using variable bit rate encoding. This saves a few bytes -// per entry in the symbol table. -static inline void writeInteger(unsigned num, std::ofstream& ARFile) { - while (1) { - if (num < 0x80) { // done? - ARFile << (unsigned char)num; - return; - } - - // Nope, we are bigger than a character, output the next 7 bits and set the - // high bit to say that there is more coming... - ARFile << (unsigned char)(0x80 | ((unsigned char)num & 0x7F)); - num >>= 7; // Shift out 7 bits now... - } -} - -// Compute how many bytes are taken by a given VBR encoded value. This is needed -// to pre-compute the size of the symbol table. -static inline unsigned numVbrBytes(unsigned num) { - - // Note that the following nested ifs are somewhat equivalent to a binary - // search. We split it in half by comparing against 2^14 first. This allows - // most reasonable values to be done in 2 comparisons instead of 1 for - // small ones and four for large ones. We expect this to access file offsets - // in the 2^10 to 2^24 range and symbol lengths in the 2^0 to 2^8 range, - // so this approach is reasonable. - if (num < 1<<14) { - if (num < 1<<7) - return 1; - else - return 2; - } - if (num < 1<<21) - return 3; - - if (num < 1<<28) - return 4; - return 5; // anything >= 2^28 takes 5 bytes -} - -// Create an empty archive. -Archive* Archive::CreateEmpty(const sys::Path& FilePath, LLVMContext& C) { - Archive* result = new Archive(FilePath, C); - return result; -} - -// 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 (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; -} - -// Insert a file into the archive before some other member. This also takes care -// of extracting the necessary flags and information from the file. -bool -Archive::addFileBefore(const sys::Path& filePath, iterator where, - std::string* ErrMsg) { - bool Exists; - if (sys::fs::exists(filePath.str(), Exists) || !Exists) { - if (ErrMsg) - *ErrMsg = "Can not add a non-existent file to archive"; - return true; - } - - ArchiveMember* mbr = new ArchiveMember(this); - - mbr->data = 0; - mbr->path = filePath; - const sys::FileStatus *FSInfo = mbr->path.getFileStatus(false, ErrMsg); - if (!FSInfo) { - delete mbr; - return true; - } - mbr->info = *FSInfo; - - unsigned flags = 0; - bool hasSlash = filePath.str().find('/') != std::string::npos; - if (hasSlash) - flags |= ArchiveMember::HasPathFlag; - if (hasSlash || filePath.str().length() > 15) - flags |= ArchiveMember::HasLongFilenameFlag; - - sys::fs::file_magic type; - if (sys::fs::identify_magic(mbr->path.str(), type)) - type = sys::fs::file_magic::unknown; - switch (type) { - case sys::fs::file_magic::bitcode: - flags |= ArchiveMember::BitcodeFlag; - break; - default: - break; - } - mbr->flags = flags; - members.insert(where,mbr); - return false; -} - -// Write one member out to the file. -bool -Archive::writeMember( - const ArchiveMember& member, - std::ofstream& ARFile, - bool CreateSymbolTable, - bool TruncateNames, - 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) { - OwningPtr File; - if (error_code ec = MemoryBuffer::getFile(member.getPath().c_str(), File)) { - if (ErrMsg) - *ErrMsg = ec.message(); - return true; - } - mFile = File.take(); - data = mFile->getBufferStart(); - fSize = mFile->getBufferSize(); - } - - // Now that we have the data in memory, update the - // symbol table if it's a bitcode file. - if (CreateSymbolTable && member.isBitcode()) { - std::vector symbols; - std::string FullMemberName = archPath.str() + "(" + member.getPath().str() - + ")"; - Module* M = - GetBitcodeSymbols(data, fSize, FullMemberName, Context, symbols, ErrMsg); - - // If the bitcode parsed successfully - if ( M ) { - for (std::vector::iterator SI = symbols.begin(), - SE = symbols.end(); SI != SE; ++SI) { - - std::pair 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; -} - -// Write the entire archive to the file specified when the archive was created. -// This writes to a temporary file first. Options are for creating a symbol -// table, flattening the file names (no directories, 15 chars max) and -// compressing each archive member. -bool -Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, - std::string* ErrMsg) -{ - // Make sure they haven't opened up the file, not loaded it, - // but are now trying to write it which would wipe out the file. - if (members.empty() && mapfile && mapfile->getBufferSize() > 8) { - if (ErrMsg) - *ErrMsg = "Can't write an archive not opened for writing"; - return true; - } - - // Create a temporary file to store the archive in - sys::Path TmpArchive = archPath; - if (TmpArchive.createTemporaryFileOnDisk(ErrMsg)) - return true; - - // Make sure the temporary gets removed if we crash - sys::RemoveFileOnSignal(TmpArchive.str()); - - // Create archive file for output. - std::ios::openmode io_mode = std::ios::out | std::ios::trunc | - std::ios::binary; - std::ofstream ArchiveFile(TmpArchive.c_str(), io_mode); - - // Check for errors opening or creating archive file. - if (!ArchiveFile.is_open() || ArchiveFile.bad()) { - TmpArchive.eraseFromDisk(); - if (ErrMsg) - *ErrMsg = "Error opening archive file: " + archPath.str(); - return true; - } - - // If we're creating a symbol table, reset it now - if (CreateSymbolTable) { - symTabSize = 0; - symTab.clear(); - } - - // Write magic string to archive. - ArchiveFile << ARFILE_MAGIC; - - // Loop over all member files, and write them out. Note that this also - // builds the symbol table, symTab. - for (MembersList::iterator I = begin(), E = end(); I != E; ++I) { - if (writeMember(*I, ArchiveFile, CreateSymbolTable, - TruncateNames, ErrMsg)) { - TmpArchive.eraseFromDisk(); - ArchiveFile.close(); - return true; - } - } - - // Close archive file. - ArchiveFile.close(); - - // Write the symbol table - if (CreateSymbolTable) { - // At this point we have written a file that is a legal archive but it - // doesn't have a symbol table in it. To aid in faster reading and to - // ensure compatibility with other archivers we need to put the symbol - // table first in the file. Unfortunately, this means mapping the file - // we just wrote back in and copying it to the destination file. - sys::Path FinalFilePath = archPath; - - // Map in the archive we just wrote. - { - OwningPtr arch; - if (error_code ec = MemoryBuffer::getFile(TmpArchive.c_str(), arch)) { - if (ErrMsg) - *ErrMsg = ec.message(); - return true; - } - const char* base = arch->getBufferStart(); - - // Open another temporary file in order to avoid invalidating the - // mmapped data - if (FinalFilePath.createTemporaryFileOnDisk(ErrMsg)) - return true; - sys::RemoveFileOnSignal(FinalFilePath.str()); - - std::ofstream FinalFile(FinalFilePath.c_str(), io_mode); - if (!FinalFile.is_open() || FinalFile.bad()) { - TmpArchive.eraseFromDisk(); - if (ErrMsg) - *ErrMsg = "Error opening archive file: " + FinalFilePath.str(); - return true; - } - - // Write the file magic number - FinalFile << ARFILE_MAGIC; - - // If there is a foreign symbol table, put it into the file now. Most - // ar(1) implementations require the symbol table to be first but llvm-ar - // can deal with it being after a foreign symbol table. This ensures - // compatibility with other ar(1) implementations as well as allowing the - // archive to store both native .o and LLVM .bc files, both indexed. - if (foreignST) { - if (writeMember(*foreignST, FinalFile, false, false, ErrMsg)) { - FinalFile.close(); - TmpArchive.eraseFromDisk(); - return true; - } - } - - // Copy the temporary file contents being sure to skip the file's magic - // number. - FinalFile.write(base + sizeof(ARFILE_MAGIC)-1, - arch->getBufferSize()-sizeof(ARFILE_MAGIC)+1); - - // Close up shop - FinalFile.close(); - } // free arch. - - // Move the final file over top of TmpArchive - if (FinalFilePath.renamePathOnDisk(TmpArchive, ErrMsg)) - return true; - } - - // Before we replace the actual archive, we need to forget all the - // members, since they point to data in that old archive. We need to do - // this because we cannot replace an open file on Windows. - cleanUpMemory(); - - if (TmpArchive.renamePathOnDisk(archPath, ErrMsg)) - return true; - - // Set correct read and write permissions after temporary file is moved - // to final destination path. - if (archPath.makeReadableOnDisk(ErrMsg)) - return true; - if (archPath.makeWriteableOnDisk(ErrMsg)) - return true; - - return false; -} diff --git a/lib/Archive/CMakeLists.txt b/lib/Archive/CMakeLists.txt deleted file mode 100644 index 7ff478a41a..0000000000 --- a/lib/Archive/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_llvm_library(LLVMArchive - Archive.cpp - ArchiveReader.cpp - ArchiveWriter.cpp - ) diff --git a/lib/Archive/LLVMBuild.txt b/lib/Archive/LLVMBuild.txt deleted file mode 100644 index d68550b45f..0000000000 --- a/lib/Archive/LLVMBuild.txt +++ /dev/null @@ -1,22 +0,0 @@ -;===- ./lib/Archive/LLVMBuild.txt ------------------------------*- Conf -*--===; -; -; The LLVM Compiler Infrastructure -; -; This file is distributed under the University of Illinois Open Source -; License. See LICENSE.TXT for details. -; -;===------------------------------------------------------------------------===; -; -; This is an LLVMBuild description file for the components in this subdirectory. -; -; For more information on the LLVMBuild system, please see: -; -; http://llvm.org/docs/LLVMBuild.html -; -;===------------------------------------------------------------------------===; - -[component_0] -type = Library -name = Archive -parent = Libraries -required_libraries = BitReader Core Support diff --git a/lib/Archive/Makefile b/lib/Archive/Makefile deleted file mode 100644 index da9780403a..0000000000 --- a/lib/Archive/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -##===- lib/Archive/Makefile --------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../.. -LIBRARYNAME = LLVMArchive - -# We only want an archive so only those modules actually used by a tool are -# included. -BUILD_ARCHIVE := 1 - -include $(LEVEL)/Makefile.common diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 76ebe9aca9..4d9aebcd0a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -14,4 +14,3 @@ add_subdirectory(DebugInfo) add_subdirectory(ExecutionEngine) add_subdirectory(Target) add_subdirectory(AsmParser) -add_subdirectory(Archive) diff --git a/lib/LLVMBuild.txt b/lib/LLVMBuild.txt index 0565443806..ff288bc78b 100644 --- a/lib/LLVMBuild.txt +++ b/lib/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = Analysis Archive AsmParser Bitcode CodeGen DebugInfo ExecutionEngine Linker IR IRReader MC Object Option Support TableGen Target Transforms +subdirectories = Analysis AsmParser Bitcode CodeGen DebugInfo ExecutionEngine Linker IR IRReader MC Object Option Support TableGen Target Transforms [component_0] type = Group diff --git a/lib/Makefile b/lib/Makefile index 57f016bc89..0a4435ef64 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -10,7 +10,7 @@ LEVEL = .. include $(LEVEL)/Makefile.config -PARALLEL_DIRS := IR AsmParser Bitcode Archive Analysis Transforms CodeGen \ +PARALLEL_DIRS := IR AsmParser Bitcode Analysis Transforms CodeGen \ Target ExecutionEngine Linker MC Object Option DebugInfo \ IRReader diff --git a/tools/llvm-ar/Archive.cpp b/tools/llvm-ar/Archive.cpp new file mode 100644 index 0000000000..3e9b9b2c25 --- /dev/null +++ b/tools/llvm-ar/Archive.cpp @@ -0,0 +1,254 @@ +//===-- Archive.cpp - Generic LLVM archive functions ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation of the Archive and ArchiveMember +// classes that is common to both reading and writing archives.. +// +//===----------------------------------------------------------------------===// + +#include "Archive.h" +#include "ArchiveInternals.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/system_error.h" +#include +#include +using namespace llvm; + +// getMemberSize - compute the actual physical size of the file member as seen +// on disk. This isn't the size of member's payload. Use getSize() for that. +unsigned +ArchiveMember::getMemberSize() const { + // Basically its the file size plus the header size + unsigned result = info.fileSize + sizeof(ArchiveMemberHeader); + + // If it has a long filename, include the name length + if (hasLongFilename()) + result += path.str().length() + 1; + + // If its now odd lengthed, include the padding byte + if (result % 2 != 0 ) + result++; + + return result; +} + +// This default constructor is only use by the ilist when it creates its +// sentry node. We give it specific static values to make it stand out a bit. +ArchiveMember::ArchiveMember() + : parent(0), path("--invalid--"), flags(0), data(0) +{ + info.user = sys::Process::GetCurrentUserId(); + info.group = sys::Process::GetCurrentGroupId(); + info.mode = 0777; + info.fileSize = 0; + info.modTime = sys::TimeValue::now(); +} + +// This is the constructor that the Archive class uses when it is building or +// reading an archive. It just defaults a few things and ensures the parent is +// set for the iplist. The Archive class fills in the ArchiveMember's data. +// This is required because correctly setting the data may depend on other +// things in the Archive. +ArchiveMember::ArchiveMember(Archive* PAR) + : parent(PAR), path(), flags(0), data(0) +{ +} + +// This method allows an ArchiveMember to be replaced with the data for a +// different file, presumably as an update to the member. It also makes sure +// the flags are reset correctly. +bool ArchiveMember::replaceWith(const sys::Path& newFile, std::string* ErrMsg) { + bool Exists; + if (sys::fs::exists(newFile.str(), Exists) || !Exists) { + if (ErrMsg) + *ErrMsg = "Can not replace an archive member with a non-existent file"; + return true; + } + + data = 0; + path = newFile; + + // SVR4 symbol tables have an empty name + if (path.str() == ARFILE_SVR4_SYMTAB_NAME) + flags |= SVR4SymbolTableFlag; + else + flags &= ~SVR4SymbolTableFlag; + + // BSD4.4 symbol tables have a special name + if (path.str() == ARFILE_BSD4_SYMTAB_NAME) + flags |= BSD4SymbolTableFlag; + else + flags &= ~BSD4SymbolTableFlag; + + // String table name + if (path.str() == ARFILE_STRTAB_NAME) + flags |= StringTableFlag; + else + flags &= ~StringTableFlag; + + // If it has a slash then it has a path + bool hasSlash = path.str().find('/') != std::string::npos; + if (hasSlash) + flags |= HasPathFlag; + else + flags &= ~HasPathFlag; + + // If it has a slash or its over 15 chars then its a long filename format + if (hasSlash || path.str().length() > 15) + flags |= HasLongFilenameFlag; + else + flags &= ~HasLongFilenameFlag; + + // Get the signature and status info + const char* signature = (const char*) data; + SmallString<4> magic; + if (!signature) { + sys::fs::get_magic(path.str(), magic.capacity(), magic); + signature = magic.c_str(); + const sys::FileStatus *FSinfo = path.getFileStatus(false, ErrMsg); + if (FSinfo) + info = *FSinfo; + else + return true; + } + + // Determine what kind of file it is. + if (sys::fs::identify_magic(StringRef(signature, 4)) == + sys::fs::file_magic::bitcode) + flags |= BitcodeFlag; + else + flags &= ~BitcodeFlag; + + return false; +} + +// Archive constructor - this is the only constructor that gets used for the +// Archive class. Everything else (default,copy) is deprecated. This just +// initializes and maps the file into memory, if requested. +Archive::Archive(const sys::Path& filename, LLVMContext& C) + : archPath(filename), members(), mapfile(0), base(0), symTab(), strtab(), + symTabSize(0), firstFileOffset(0), modules(), foreignST(0), Context(C) { +} + +bool +Archive::mapToMemory(std::string* ErrMsg) { + OwningPtr File; + if (error_code ec = MemoryBuffer::getFile(archPath.c_str(), File)) { + if (ErrMsg) + *ErrMsg = ec.message(); + return true; + } + mapfile = File.take(); + base = mapfile->getBufferStart(); + return false; +} + +void Archive::cleanUpMemory() { + // Shutdown the file mapping + delete mapfile; + mapfile = 0; + base = 0; + + // Forget the entire symbol table + symTab.clear(); + symTabSize = 0; + + firstFileOffset = 0; + + // Free the foreign symbol table member + if (foreignST) { + delete foreignST; + foreignST = 0; + } + + // Delete any Modules and ArchiveMember's we've allocated as a result of + // symbol table searches. + for (ModuleMap::iterator I=modules.begin(), E=modules.end(); I != E; ++I ) { + delete I->second.first; + delete I->second.second; + } +} + +// Archive destructor - just clean up memory +Archive::~Archive() { + cleanUpMemory(); +} + + + +static void getSymbols(Module*M, std::vector& symbols) { + // Loop over global variables + for (Module::global_iterator GI = M->global_begin(), GE=M->global_end(); GI != GE; ++GI) + if (!GI->isDeclaration() && !GI->hasLocalLinkage()) + if (!GI->getName().empty()) + symbols.push_back(GI->getName()); + + // Loop over functions + for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI) + if (!FI->isDeclaration() && !FI->hasLocalLinkage()) + if (!FI->getName().empty()) + symbols.push_back(FI->getName()); + + // Loop over aliases + for (Module::alias_iterator AI = M->alias_begin(), AE = M->alias_end(); + AI != AE; ++AI) { + if (AI->hasName()) + symbols.push_back(AI->getName()); + } +} + +// Get just the externally visible defined symbols from the bitcode +bool llvm::GetBitcodeSymbols(const sys::Path& fName, + LLVMContext& Context, + std::vector& symbols, + std::string* ErrMsg) { + OwningPtr Buffer; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(fName.c_str(), Buffer)) { + if (ErrMsg) *ErrMsg = "Could not open file '" + fName.str() + "'" + ": " + + ec.message(); + return true; + } + + Module *M = ParseBitcodeFile(Buffer.get(), Context, ErrMsg); + if (!M) + return true; + + // Get the symbols + getSymbols(M, symbols); + + // Done with the module. + delete M; + return true; +} + +Module* +llvm::GetBitcodeSymbols(const char *BufPtr, unsigned Length, + const std::string& ModuleID, + LLVMContext& Context, + std::vector& symbols, + std::string* ErrMsg) { + // Get the module. + OwningPtr Buffer( + MemoryBuffer::getMemBufferCopy(StringRef(BufPtr, Length),ModuleID.c_str())); + + Module *M = ParseBitcodeFile(Buffer.get(), Context, ErrMsg); + if (!M) + return 0; + + // Get the symbols + getSymbols(M, symbols); + + // Done with the module. Note that it's the caller's responsibility to delete + // the Module. + return M; +} diff --git a/tools/llvm-ar/Archive.h b/tools/llvm-ar/Archive.h new file mode 100644 index 0000000000..bd76298c42 --- /dev/null +++ b/tools/llvm-ar/Archive.h @@ -0,0 +1,524 @@ +//===-- llvm/Bitcode/Archive.h - LLVM Bitcode Archive -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file declares the Archive and ArchiveMember classes that provide +// manipulation of LLVM Archive files. The implementation is provided by the +// lib/Bitcode/Archive library. This library is used to read and write +// archive (*.a) files that contain LLVM bitcode files (or others). +// +//===----------------------------------------------------------------------===// + +#ifndef TOOLS_LLVM_AR_ARCHIVE_H +#define TOOLS_LLVM_AR_ARCHIVE_H + +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PathV1.h" +#include +#include + +namespace llvm { + class MemoryBuffer; + +// Forward declare classes +class Module; // From VMCore +class Archive; // Declared below +class ArchiveMemberHeader; // Internal implementation class +class LLVMContext; // Global data + +/// This class is the main class manipulated by users of the Archive class. It +/// holds information about one member of the Archive. It is also the element +/// stored by the Archive's ilist, the Archive's main abstraction. Because of +/// the special requirements of archive files, users are not permitted to +/// construct ArchiveMember instances. You should obtain them from the methods +/// of the Archive class instead. +/// @brief This class represents a single archive member. +class ArchiveMember : public ilist_node { + /// @name Types + /// @{ + public: + /// These flags are used internally by the archive member to specify various + /// characteristics of the member. The various "is" methods below provide + /// access to the flags. The flags are not user settable. + enum Flags { + SVR4SymbolTableFlag = 1, ///< Member is a SVR4 symbol table + BSD4SymbolTableFlag = 2, ///< Member is a BSD4 symbol table + BitcodeFlag = 4, ///< Member is bitcode + HasPathFlag = 8, ///< Member has a full or partial path + HasLongFilenameFlag = 16, ///< Member uses the long filename syntax + StringTableFlag = 32 ///< Member is an ar(1) format string table + }; + + /// @} + /// @name Accessors + /// @{ + public: + /// @returns the parent Archive instance + /// @brief Get the archive associated with this member + Archive* getArchive() const { return parent; } + + /// @returns the path to the Archive's file + /// @brief Get the path to the archive member + const sys::Path& getPath() const { return path; } + + /// The "user" is the owner of the file per Unix security. This may not + /// have any applicability on non-Unix systems but is a required component + /// of the "ar" file format. + /// @brief Get the user associated with this archive member. + unsigned getUser() const { return info.getUser(); } + + /// The "group" is the owning group of the file per Unix security. This + /// may not have any applicability on non-Unix systems but is a required + /// component of the "ar" file format. + /// @brief Get the group associated with this archive member. + unsigned getGroup() const { return info.getGroup(); } + + /// The "mode" specifies the access permissions for the file per Unix + /// security. This may not have any applicability on non-Unix systems but is + /// a required component of the "ar" file format. + /// @brief Get the permission mode associated with this archive member. + unsigned getMode() const { return info.getMode(); } + + /// This method returns the time at which the archive member was last + /// modified when it was not in the archive. + /// @brief Get the time of last modification of the archive member. + sys::TimeValue getModTime() const { return info.getTimestamp(); } + + /// @returns the size of the archive member in bytes. + /// @brief Get the size of the archive member. + uint64_t getSize() const { return info.getSize(); } + + /// This method returns the total size of the archive member as it + /// appears on disk. This includes the file content, the header, the + /// long file name if any, and the padding. + /// @brief Get total on-disk member size. + unsigned getMemberSize() const; + + /// This method will return a pointer to the in-memory content of the + /// archive member, if it is available. If the data has not been loaded + /// into memory, the return value will be null. + /// @returns a pointer to the member's data. + /// @brief Get the data content of the archive member + const char* getData() const { return data; } + + /// @returns true iff the member is a SVR4 (non-LLVM) symbol table + /// @brief Determine if this member is a SVR4 symbol table. + bool isSVR4SymbolTable() const { return flags&SVR4SymbolTableFlag; } + + /// @returns true iff the member is a BSD4.4 (non-LLVM) symbol table + /// @brief Determine if this member is a BSD4.4 symbol table. + bool isBSD4SymbolTable() const { return flags&BSD4SymbolTableFlag; } + + /// @returns true iff the archive member is the ar(1) string table + /// @brief Determine if this member is the ar(1) string table. + bool isStringTable() const { return flags&StringTableFlag; } + + /// @returns true iff the archive member is a bitcode file. + /// @brief Determine if this member is a bitcode file. + bool isBitcode() const { return flags&BitcodeFlag; } + + /// @returns true iff the file name contains a path (directory) component. + /// @brief Determine if the member has a path + bool hasPath() const { return flags&HasPathFlag; } + + /// Long filenames are an artifact of the ar(1) file format which allows + /// up to sixteen characters in its header and doesn't allow a path + /// separator character (/). To avoid this, a "long format" member name is + /// allowed that doesn't have this restriction. This method determines if + /// that "long format" is used for this member. + /// @returns true iff the file name uses the long form + /// @brief Determine if the member has a long file name + bool hasLongFilename() const { return flags&HasLongFilenameFlag; } + + /// This method returns the status info (like Unix stat(2)) for the archive + /// member. The status info provides the file's size, permissions, and + /// modification time. The contents of the Path::StatusInfo structure, other + /// than the size and modification time, may not have utility on non-Unix + /// systems. + /// @returns the status info for the archive member + /// @brief Obtain the status info for the archive member + const sys::FileStatus &getFileStatus() const { return info; } + + /// This method causes the archive member to be replaced with the contents + /// of the file specified by \p File. The contents of \p this will be + /// updated to reflect the new data from \p File. The \p File must exist and + /// be readable on entry to this method. + /// @returns true if an error occurred, false otherwise + /// @brief Replace contents of archive member with a new file. + bool replaceWith(const sys::Path &aFile, std::string* ErrMsg); + + /// @} + /// @name Data + /// @{ + private: + Archive* parent; ///< Pointer to parent archive + sys::PathWithStatus path; ///< Path of file containing the member + sys::FileStatus info; ///< Status info (size,mode,date) + unsigned flags; ///< Flags about the archive member + const char* data; ///< Data for the member + + /// @} + /// @name Constructors + /// @{ + public: + /// The default constructor is only used by the Archive's iplist when it + /// constructs the list's sentry node. + ArchiveMember(); + + private: + /// Used internally by the Archive class to construct an ArchiveMember. + /// The contents of the ArchiveMember are filled out by the Archive class. + explicit ArchiveMember(Archive *PAR); + + // So Archive can construct an ArchiveMember + friend class llvm::Archive; + /// @} +}; + +/// This class defines the interface to LLVM Archive files. The Archive class +/// presents the archive file as an ilist of ArchiveMember objects. The members +/// can be rearranged in any fashion either by directly editing the ilist or by +/// using editing methods on the Archive class (recommended). The Archive +/// class also provides several ways of accessing the archive file for various +/// purposes such as editing and linking. Full symbol table support is provided +/// for loading only those files that resolve symbols. Note that read +/// performance of this library is _crucial_ for performance of JIT type +/// applications and the linkers. Consequently, the implementation of the class +/// is optimized for reading. +class Archive { + + /// @name Types + /// @{ + public: + /// This is the ilist type over which users may iterate to examine + /// the contents of the archive + /// @brief The ilist type of ArchiveMembers that Archive contains. + typedef iplist MembersList; + + /// @brief Forward mutable iterator over ArchiveMember + typedef MembersList::iterator iterator; + + /// @brief Forward immutable iterator over ArchiveMember + typedef MembersList::const_iterator const_iterator; + + /// @brief Reverse mutable iterator over ArchiveMember + typedef std::reverse_iterator reverse_iterator; + + /// @brief Reverse immutable iterator over ArchiveMember + typedef std::reverse_iterator const_reverse_iterator; + + /// @brief The in-memory version of the symbol table + typedef std::map SymTabType; + + /// @} + /// @name ilist accessor methods + /// @{ + public: + inline iterator begin() { return members.begin(); } + inline const_iterator begin() const { return members.begin(); } + inline iterator end () { return members.end(); } + inline const_iterator end () const { return members.end(); } + + inline reverse_iterator rbegin() { return members.rbegin(); } + inline const_reverse_iterator rbegin() const { return members.rbegin(); } + inline reverse_iterator rend () { return members.rend(); } + inline const_reverse_iterator rend () const { return members.rend(); } + + inline size_t size() const { return members.size(); } + inline bool empty() const { return members.empty(); } + inline const ArchiveMember& front() const { return members.front(); } + inline ArchiveMember& front() { return members.front(); } + inline const ArchiveMember& back() const { return members.back(); } + inline ArchiveMember& back() { return members.back(); } + + /// @} + /// @name ilist mutator methods + /// @{ + public: + /// This method splices a \p src member from an archive (possibly \p this), + /// to a position just before the member given by \p dest in \p this. When + /// the archive is written, \p src will be written in its new location. + /// @brief Move a member to a new location + inline void splice(iterator dest, Archive& arch, iterator src) + { return members.splice(dest,arch.members,src); } + + /// This method erases a \p target member from the archive. When the + /// archive is written, it will no longer contain \p target. The associated + /// ArchiveMember is deleted. + /// @brief Erase a member. + inline iterator erase(iterator target) { return members.erase(target); } + + /// @} + /// @name Constructors + /// @{ + public: + /// Create an empty archive file and associate it with the \p Filename. This + /// method does not actually create the archive disk file. It creates an + /// empty Archive object. If the writeToDisk method is called, the archive + /// file \p Filename will be created at that point, with whatever content + /// the returned Archive object has at that time. + /// @returns An Archive* that represents the new archive file. + /// @brief Create an empty Archive. + static Archive* CreateEmpty( + const sys::Path& Filename,///< Name of the archive to (eventually) create. + LLVMContext& C ///< Context to use for global information + ); + + /// Open an existing archive and load its contents in preparation for + /// editing. After this call, the member ilist is completely populated based + /// on the contents of the archive file. You should use this form of open if + /// you intend to modify the archive or traverse its contents (e.g. for + /// printing). + /// @brief Open and load an archive file + static Archive* OpenAndLoad( + const sys::Path& filePath, ///< The file path to open and load + LLVMContext& C, ///< The context to use for global information + std::string* ErrorMessage ///< An optional error string + ); + + /// This method opens an existing archive file from \p Filename and reads in + /// its symbol table without reading in any of the archive's members. This + /// reduces both I/O and cpu time in opening the archive if it is to be used + /// solely for symbol lookup (e.g. during linking). The \p Filename must + /// exist and be an archive file or an error will be returned. This form + /// of opening the archive is intended for read-only operations that need to + /// locate members via the symbol table for link editing. Since the archve + /// members are not read by this method, the archive will appear empty upon + /// return. If editing operations are performed on the archive, they will + /// completely replace the contents of the archive! It is recommended that + /// if this form of opening the archive is used that only the symbol table + /// lookup methods (getSymbolTable, findModuleDefiningSymbol, and + /// findModulesDefiningSymbols) be used. + /// @returns an Archive* that represents the archive file, or null on error. + /// @brief Open an existing archive and load its symbols. + static Archive* OpenAndLoadSymbols( + const sys::Path& Filename, ///< Name of the archive file to open + LLVMContext& C, ///< The context to use for global info + std::string* ErrorMessage=0 ///< An optional error string + ); + + /// This destructor cleans up the Archive object, releases all memory, and + /// closes files. It does nothing with the archive file on disk. If you + /// haven't used the writeToDisk method by the time the destructor is + /// called, all changes to the archive will be lost. + /// @brief Destruct in-memory archive + ~Archive(); + + /// @} + /// @name Accessors + /// @{ + public: + /// @returns the path to the archive file. + /// @brief Get the archive path. + const sys::Path& getPath() { return archPath; } + + /// This method is provided so that editing methods can be invoked directly + /// on the Archive's iplist of ArchiveMember. However, it is recommended + /// that the usual STL style iterator interface be used instead. + /// @returns the iplist of ArchiveMember + /// @brief Get the iplist of the members + MembersList& getMembers() { return members; } + + /// This method allows direct query of the Archive's symbol table. The + /// symbol table is a std::map of std::string (the symbol) to unsigned (the + /// file offset). Note that for efficiency reasons, the offset stored in + /// the symbol table is not the actual offset. It is the offset from the + /// beginning of the first "real" file member (after the symbol table). Use + /// the getFirstFileOffset() to obtain that offset and add this value to the + /// offset in the symbol table to obtain the real file offset. Note that + /// there is purposefully no interface provided by Archive to look up + /// members by their offset. Use the findModulesDefiningSymbols and + /// findModuleDefiningSymbol methods instead. + /// @returns the Archive's symbol table. + /// @brief Get the archive's symbol table + const SymTabType& getSymbolTable() { return symTab; } + + /// This method returns the offset in the archive file to the first "real" + /// file member. Archive files, on disk, have a signature and might have a + /// symbol table that precedes the first actual file member. This method + /// allows you to determine what the size of those fields are. + /// @returns the offset to the first "real" file member in the archive. + /// @brief Get the offset to the first "real" file member in the archive. + unsigned getFirstFileOffset() { return firstFileOffset; } + + /// This method will scan the archive for bitcode modules, interpret them + /// and return a vector of the instantiated modules in \p Modules. If an + /// error occurs, this method will return true. If \p ErrMessage is not null + /// and an error occurs, \p *ErrMessage will be set to a string explaining + /// the error that occurred. + /// @returns true if an error occurred + /// @brief Instantiate all the bitcode modules located in the archive + bool getAllModules(std::vector& Modules, std::string* ErrMessage); + + /// This accessor looks up the \p symbol in the archive's symbol table and + /// returns the associated module that defines that symbol. This method can + /// be called as many times as necessary. This is handy for linking the + /// archive into another module based on unresolved symbols. Note that the + /// Module returned by this accessor should not be deleted by the caller. It + /// is managed internally by the Archive class. It is possible that multiple + /// calls to this accessor will return the same Module instance because the + /// associated module defines multiple symbols. + /// @returns The Module* found or null if the archive does not contain a + /// module that defines the \p symbol. + /// @brief Look up a module by symbol name. + Module* findModuleDefiningSymbol( + const std::string& symbol, ///< Symbol to be sought + std::string* ErrMessage ///< Error message storage, if non-zero + ); + + /// This method is similar to findModuleDefiningSymbol but allows lookup of + /// more than one symbol at a time. If \p symbols contains a list of + /// undefined symbols in some module, then calling this method is like + /// making one complete pass through the archive to resolve symbols but is + /// more efficient than looking at the individual members. Note that on + /// exit, the symbols resolved by this method will be removed from \p + /// symbols to ensure they are not re-searched on a subsequent call. If + /// you need to retain the list of symbols, make a copy. + /// @brief Look up multiple symbols in the archive. + bool findModulesDefiningSymbols( + std::set& symbols, ///< Symbols to be sought + SmallVectorImpl& modules, ///< The modules matching \p symbols + std::string* ErrMessage ///< Error msg storage, if non-zero + ); + + /// This method determines whether the archive is a properly formed llvm + /// bitcode archive. It first makes sure the symbol table has been loaded + /// and has a non-zero size. If it does, then it is an archive. If not, + /// then it tries to load all the bitcode modules of the archive. Finally, + /// it returns whether it was successful. + /// @returns true if the archive is a proper llvm bitcode archive + /// @brief Determine whether the archive is a proper llvm bitcode archive. + bool isBitcodeArchive(); + + /// @} + /// @name Mutators + /// @{ + public: + /// This method is the only way to get the archive written to disk. It + /// creates or overwrites the file specified when \p this was created + /// or opened. The arguments provide options for writing the archive. If + /// \p CreateSymbolTable is true, the archive is scanned for bitcode files + /// and a symbol table of the externally visible function and global + /// variable names is created. If \p TruncateNames is true, the names of the + /// archive members will have their path component stripped and the file + /// name will be truncated at 15 characters. If \p Compress is specified, + /// all archive members will be compressed before being written. If + /// \p PrintSymTab is true, the symbol table will be printed to std::cout. + /// @returns true if an error occurred, \p error set to error message; + /// returns false if the writing succeeded. + /// @brief Write (possibly modified) archive contents to disk + bool writeToDisk( + bool CreateSymbolTable=false, ///< Create Symbol table + bool TruncateNames=false, ///< Truncate the filename to 15 chars + std::string* ErrMessage=0 ///< If non-null, where error msg is set + ); + + /// This method adds a new file to the archive. The \p filename is examined + /// to determine just enough information to create an ArchiveMember object + /// which is then inserted into the Archive object's ilist at the location + /// given by \p where. + /// @returns true if an error occurred, false otherwise + /// @brief Add a file to the archive. + bool addFileBefore( + const sys::Path& filename, ///< The file to be added + iterator where, ///< Insertion point + std::string* ErrMsg ///< Optional error message location + ); + + /// @} + /// @name Implementation + /// @{ + protected: + /// @brief Construct an Archive for \p filename and optionally map it + /// into memory. + explicit Archive(const sys::Path& filename, LLVMContext& C); + + /// @returns A fully populated ArchiveMember or 0 if an error occurred. + /// @brief Parse the header of a member starting at \p At + ArchiveMember* parseMemberHeader( + const char*&At, ///< The pointer to the location we're parsing + const char*End, ///< The pointer to the end of the archive + std::string* error ///< Optional error message catcher + ); + + /// @param ErrMessage Set to address of a std::string to get error messages + /// @returns false on error + /// @brief Check that the archive signature is correct + bool checkSignature(std::string* ErrMessage); + + /// @param ErrMessage Set to address of a std::string to get error messages + /// @returns false on error + /// @brief Load the entire archive. + bool loadArchive(std::string* ErrMessage); + + /// @param ErrMessage Set to address of a std::string to get error messages + /// @returns false on error + /// @brief Load just the symbol table. + bool loadSymbolTable(std::string* ErrMessage); + + /// Writes one ArchiveMember to an ofstream. If an error occurs, returns + /// false, otherwise true. If an error occurs and error is non-null then + /// it will be set to an error message. + /// @returns false if writing member succeeded, + /// returns true if writing member failed, \p error set to error message. + bool writeMember( + const ArchiveMember& member, ///< The member to be written + std::ofstream& ARFile, ///< The file to write member onto + bool CreateSymbolTable, ///< Should symbol table be created? + bool TruncateNames, ///< Should names be truncated to 11 chars? + std::string* ErrMessage ///< If non-null, place were error msg is set + ); + + /// @brief Fill in an ArchiveMemberHeader from ArchiveMember. + bool fillHeader(const ArchiveMember&mbr, + ArchiveMemberHeader& hdr,int sz, bool TruncateNames) const; + + /// @brief Maps archive into memory + bool mapToMemory(std::string* ErrMsg); + + /// @brief Frees all the members and unmaps the archive file. + void cleanUpMemory(); + + /// This type is used to keep track of bitcode modules loaded from the + /// symbol table. It maps the file offset to a pair that consists of the + /// associated ArchiveMember and the Module. + /// @brief Module mapping type + typedef std::map > + ModuleMap; + + + /// @} + /// @name Data + /// @{ + protected: + sys::Path archPath; ///< Path to the archive file we read/write + MembersList members; ///< The ilist of ArchiveMember + MemoryBuffer *mapfile; ///< Raw Archive contents mapped into memory + const char* base; ///< Base of the memory mapped file data + SymTabType symTab; ///< The symbol table + std::string strtab; ///< The string table for long file names + unsigned symTabSize; ///< Size in bytes of symbol table + unsigned firstFileOffset; ///< Offset to first normal file. + ModuleMap modules; ///< The modules loaded via symbol lookup. + ArchiveMember* foreignST; ///< This holds the foreign symbol table. + LLVMContext& Context; ///< This holds global data. + /// @} + /// @name Hidden + /// @{ + private: + Archive() LLVM_DELETED_FUNCTION; + Archive(const Archive&) LLVM_DELETED_FUNCTION; + Archive& operator=(const Archive&) LLVM_DELETED_FUNCTION; + /// @} +}; + +} // End llvm namespace + +#endif diff --git a/tools/llvm-ar/ArchiveInternals.h b/tools/llvm-ar/ArchiveInternals.h new file mode 100644 index 0000000000..e906d7a059 --- /dev/null +++ b/tools/llvm-ar/ArchiveInternals.h @@ -0,0 +1,87 @@ +//===-- lib/Archive/ArchiveInternals.h -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Internal implementation header for LLVM Archive files. +// +//===----------------------------------------------------------------------===// + +#ifndef TOOLS_LLVM_AR_ARCHIVEINTERNALS_H +#define TOOLS_LLVM_AR_ARCHIVEINTERNALS_H + +#include "Archive.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/TimeValue.h" +#include + +#define ARFILE_MAGIC "!\n" ///< magic string +#define ARFILE_MAGIC_LEN (sizeof(ARFILE_MAGIC)-1) ///< length of magic string +#define ARFILE_SVR4_SYMTAB_NAME "/ " ///< SVR4 symtab entry name +#define ARFILE_BSD4_SYMTAB_NAME "__.SYMDEF SORTED" ///< BSD4 symtab entry name +#define ARFILE_STRTAB_NAME "// " ///< Name of string table +#define ARFILE_PAD "\n" ///< inter-file align padding +#define ARFILE_MEMBER_MAGIC "`\n" ///< fmag field magic # + +namespace llvm { + + class LLVMContext; + + /// The ArchiveMemberHeader structure is used internally for bitcode + /// 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 { + /// @name Data + /// @{ + public: + char name[16]; ///< Name of the file member. + 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 + + /// @} + /// @name Methods + /// @{ + 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'; + } + + bool checkSignature() const { + return 0 == memcmp(fmag, ARFILE_MEMBER_MAGIC,2); + } + }; + + // Get just the externally visible defined symbols from the bitcode + bool GetBitcodeSymbols(const sys::Path& fName, + LLVMContext& Context, + std::vector& symbols, + std::string* ErrMsg); + + Module* GetBitcodeSymbols(const char *Buffer, unsigned Length, + const std::string& ModuleID, + LLVMContext& Context, + std::vector& symbols, + std::string* ErrMsg); +} + +#endif + +// vim: sw=2 ai diff --git a/tools/llvm-ar/ArchiveReader.cpp b/tools/llvm-ar/ArchiveReader.cpp new file mode 100644 index 0000000000..8ad01dca0b --- /dev/null +++ b/tools/llvm-ar/ArchiveReader.cpp @@ -0,0 +1,557 @@ +//===-- ArchiveReader.cpp - Read LLVM archive files -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Builds up standard unix archive files (.a) containing LLVM bitcode. +// +//===----------------------------------------------------------------------===// + +#include "Archive.h" +#include "ArchiveInternals.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include +#include +using namespace llvm; + +/// Read a variable-bit-rate encoded unsigned integer +static inline unsigned readInteger(const char*&At, const char*End) { + unsigned Shift = 0; + unsigned Result = 0; + + do { + if (At == End) + return Result; + Result |= (unsigned)((*At++) & 0x7F) << Shift; + Shift += 7; + } while (At[-1] & 0x80); + return Result; +} + +// This member parses an ArchiveMemberHeader that is presumed to be pointed to +// by At. The At pointer is updated to the byte just after the header, which +// can be variable in size. +ArchiveMember* +Archive::parseMemberHeader(const char*& At, const char* End, std::string* error) +{ + if (At + sizeof(ArchiveMemberHeader) >= End) { + if (error) + *error = "Unexpected end of file"; + return 0; + } + + // Cast archive member header + const ArchiveMemberHeader* Hdr = (const ArchiveMemberHeader*)At; + At += sizeof(ArchiveMemberHeader); + + int flags = 0; + int MemberSize = atoi(Hdr->size); + assert(MemberSize >= 0); + + // Check the size of the member for sanity + if (At + MemberSize > End) { + if (error) + *error = "invalid member length in archive file"; + return 0; + } + + // Check the member signature + if (!Hdr->checkSignature()) { + if (error) + *error = "invalid file member signature"; + return 0; + } + + // Convert and check the member name + // The empty name ( '/' and 15 blanks) is for a foreign (non-LLVM) symbol + // table. The special name "//" and 14 blanks is for a string table, used + // for long file names. This library doesn't generate either of those but + // it will accept them. If the name starts with #1/ and the remainder is + // digits, then those digits specify the length of the name that is + // stored immediately following the header. Anything else is a regular, short + // filename that is terminated with a '/' and blanks. + + std::string pathname; + switch (Hdr->name[0]) { + case '#': + if (Hdr->name[1] == '1' && Hdr->name[2] == '/') { + if (isdigit(Hdr->name[3])) { + unsigned len = atoi(&Hdr->name[3]); + const char *nulp = (const char *)memchr(At, '\0', len); + pathname.assign(At, nulp != 0 ? (uintptr_t)(nulp - At) : len); + At += len; + MemberSize -= len; + flags |= ArchiveMember::HasLongFilenameFlag; + } else { + if (error) + *error = "invalid long filename"; + return 0; + } + } + break; + case '/': + if (Hdr->name[1]== '/') { + if (0 == memcmp(Hdr->name, ARFILE_STRTAB_NAME, 16)) { + pathname.assign(ARFILE_STRTAB_NAME); + flags |= ArchiveMember::StringTableFlag; + } else { + if (error) + *error = "invalid string table name"; + return 0; + } + } else if (Hdr->name[1] == ' ') { + if (0 == memcmp(Hdr->name, ARFILE_SVR4_SYMTAB_NAME, 16)) { + pathname.assign(ARFILE_SVR4_SYMTAB_NAME); + flags |= ArchiveMember::SVR4SymbolTableFlag; + } else { + if (error) + *error = "invalid SVR4 symbol table name"; + return 0; + } + } else if (isdigit(Hdr->name[1])) { + unsigned index = atoi(&Hdr->name[1]); + if (index < strtab.length()) { + const char* namep = strtab.c_str() + index; + const char* endp = strtab.c_str() + strtab.length(); + const char* p = namep; + const char* last_p = p; + while (p < endp) { + if (*p == '\n' && *last_p == '/') { + pathname.assign(namep, last_p - namep); + flags |= ArchiveMember::HasLongFilenameFlag; + break; + } + last_p = p; + p++; + } + if (p >= endp) { + if (error) + *error = "missing name terminator in string table"; + return 0; + } + } else { + if (error) + *error = "name index beyond string table"; + return 0; + } + } + break; + case '_': + if (Hdr->name[1] == '_' && + (0 == memcmp(Hdr->name, ARFILE_BSD4_SYMTAB_NAME, 16))) { + pathname.assign(ARFILE_BSD4_SYMTAB_NAME); + flags |= ArchiveMember::BSD4SymbolTableFlag; + break; + } + /* FALL THROUGH */ + + default: + const char* slash = (const char*) memchr(Hdr->name, '/', 16); + if (slash == 0) + slash = Hdr->name + 16; + pathname.assign(Hdr->name, slash - Hdr->name); + break; + } + + // Determine if this is a bitcode file + if (sys::fs::identify_magic(StringRef(At, 4)) == + sys::fs::file_magic::bitcode) + flags |= ArchiveMember::BitcodeFlag; + else + flags &= ~ArchiveMember::BitcodeFlag; + + // Instantiate the ArchiveMember to be filled + ArchiveMember* member = new ArchiveMember(this); + + // Fill in fields of the ArchiveMember + member->parent = this; + member->path.set(pathname); + member->info.fileSize = MemberSize; + member->info.modTime.fromEpochTime(atoi(Hdr->date)); + unsigned int mode; + sscanf(Hdr->mode, "%o", &mode); + member->info.mode = mode; + member->info.user = atoi(Hdr->uid); + member->info.group = atoi(Hdr->gid); + member->flags = flags; + member->data = At; + + return member; +} + +bool +Archive::checkSignature(std::string* error) { + // Check the magic string at file's header + if (mapfile->getBufferSize() < 8 || memcmp(base, ARFILE_MAGIC, 8)) { + if (error) + *error = "invalid signature for an archive file"; + return false; + } + return true; +} + +// 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 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 { + // 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; +} + +// Open and completely load the archive file. +Archive* +Archive::OpenAndLoad(const sys::Path& File, LLVMContext& C, + std::string* ErrorMessage) { + OwningPtr result ( new Archive(File, C)); + if (result->mapToMemory(ErrorMessage)) + return NULL; + if (!result->loadArchive(ErrorMessage)) + return NULL; + return result.take(); +} + +// Get all the bitcode modules from the archive +bool +Archive::getAllModules(std::vector& Modules, + std::string* ErrMessage) { + + for (iterator I=begin(), E=end(); I != E; ++I) { + if (I->isBitcode()) { + std::string FullMemberName = archPath.str() + + "(" + I->getPath().str() + ")"; + MemoryBuffer *Buffer = + MemoryBuffer::getMemBufferCopy(StringRef(I->getData(), I->getSize()), + FullMemberName.c_str()); + + Module *M = ParseBitcodeFile(Buffer, Context, ErrMessage); + delete Buffer; + if (!M) + return true; + + Modules.push_back(M); + } + } + return false; +} + +// Load just the symbol table from the archive file +bool +Archive::loadSymbolTable(std::string* ErrorMsg) { + + // Set up parsing + members.clear(); + symTab.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; +} + +// Open the archive and load just the symbol tables +Archive* Archive::OpenAndLoadSymbols(const sys::Path& File, + LLVMContext& C, + std::string* ErrorMessage) { + OwningPtr result ( new Archive(File, C) ); + if (result->mapToMemory(ErrorMessage)) + return NULL; + if (!result->loadSymbolTable(ErrorMessage)) + return NULL; + return result.take(); +} + +// 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; +} + +// Look up multiple symbols in the symbol table and return a set of +// Modules that define those symbols. +bool +Archive::findModulesDefiningSymbols(std::set& symbols, + SmallVectorImpl& 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 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::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 Added; + for (std::set::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; +} + +bool Archive::isBitcodeArchive() { + // Make sure the symTab has been loaded. In most cases this should have been + // done when the archive was constructed, but still, this is just in case. + if (symTab.empty()) + if (!loadSymbolTable(0)) + return false; + + // Now that we know it's been loaded, return true + // if it has a size + if (symTab.size()) return true; + + // We still can't be sure it isn't a bitcode archive + if (!loadArchive(0)) + return false; + + std::vector Modules; + std::string ErrorMessage; + + // Scan the archive, trying to load a bitcode member. We only load one to + // see if this works. + for (iterator I = begin(), E = end(); I != E; ++I) { + if (!I->isBitcode()) + continue; + + std::string FullMemberName = + archPath.str() + "(" + I->getPath().str() + ")"; + + MemoryBuffer *Buffer = + MemoryBuffer::getMemBufferCopy(StringRef(I->getData(), I->getSize()), + FullMemberName.c_str()); + Module *M = ParseBitcodeFile(Buffer, Context); + delete Buffer; + if (!M) + return false; // Couldn't parse bitcode, not a bitcode archive. + delete M; + return true; + } + + return false; +} diff --git a/tools/llvm-ar/ArchiveWriter.cpp b/tools/llvm-ar/ArchiveWriter.cpp new file mode 100644 index 0000000000..24f5dbc0dc --- /dev/null +++ b/tools/llvm-ar/ArchiveWriter.cpp @@ -0,0 +1,429 @@ +//===-- ArchiveWriter.cpp - Write LLVM archive files ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Builds up an LLVM archive file (.a) containing LLVM bitcode. +// +//===----------------------------------------------------------------------===// + +#include "Archive.h" +#include "ArchiveInternals.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.h" +#include +#include +#include +using namespace llvm; + +// Write an integer using variable bit rate encoding. This saves a few bytes +// per entry in the symbol table. +static inline void writeInteger(unsigned num, std::ofstream& ARFile) { + while (1) { + if (num < 0x80) { // done? + ARFile << (unsigned char)num; + return; + } + + // Nope, we are bigger than a character, output the next 7 bits and set the + // high bit to say that there is more coming... + ARFile << (unsigned char)(0x80 | ((unsigned char)num & 0x7F)); + num >>= 7; // Shift out 7 bits now... + } +} + +// Compute how many bytes are taken by a given VBR encoded value. This is needed +// to pre-compute the size of the symbol table. +static inline unsigned numVbrBytes(unsigned num) { + + // Note that the following nested ifs are somewhat equivalent to a binary + // search. We split it in half by comparing against 2^14 first. This allows + // most reasonable values to be done in 2 comparisons instead of 1 for + // small ones and four for large ones. We expect this to access file offsets + // in the 2^10 to 2^24 range and symbol lengths in the 2^0 to 2^8 range, + // so this approach is reasonable. + if (num < 1<<14) { + if (num < 1<<7) + return 1; + else + return 2; + } + if (num < 1<<21) + return 3; + + if (num < 1<<28) + return 4; + return 5; // anything >= 2^28 takes 5 bytes +} + +// Create an empty archive. +Archive* Archive::CreateEmpty(const sys::Path& FilePath, LLVMContext& C) { + Archive* result = new Archive(FilePath, C); + return result; +} + +// 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 (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; +} + +// Insert a file into the archive before some other member. This also takes care +// of extracting the necessary flags and information from the file. +bool +Archive::addFileBefore(const sys::Path& filePath, iterator where, + std::string* ErrMsg) { + bool Exists; + if (sys::fs::exists(filePath.str(), Exists) || !Exists) { + if (ErrMsg) + *ErrMsg = "Can not add a non-existent file to archive"; + return true; + } + + ArchiveMember* mbr = new ArchiveMember(this); + + mbr->data = 0; + mbr->path = filePath; + const sys::FileStatus *FSInfo = mbr->path.getFileStatus(false, ErrMsg); + if (!FSInfo) { + delete mbr; + return true; + } + mbr->info = *FSInfo; + + unsigned flags = 0; + bool hasSlash = filePath.str().find('/') != std::string::npos; + if (hasSlash) + flags |= ArchiveMember::HasPathFlag; + if (hasSlash || filePath.str().length() > 15) + flags |= ArchiveMember::HasLongFilenameFlag; + + sys::fs::file_magic type; + if (sys::fs::identify_magic(mbr->path.str(), type)) + type = sys::fs::file_magic::unknown; + switch (type) { + case sys::fs::file_magic::bitcode: + flags |= ArchiveMember::BitcodeFlag; + break; + default: + break; + } + mbr->flags = flags; + members.insert(where,mbr); + return false; +} + +// Write one member out to the file. +bool +Archive::writeMember( + const ArchiveMember& member, + std::ofstream& ARFile, + bool CreateSymbolTable, + bool TruncateNames, + 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) { + OwningPtr File; + if (error_code ec = MemoryBuffer::getFile(member.getPath().c_str(), File)) { + if (ErrMsg) + *ErrMsg = ec.message(); + return true; + } + mFile = File.take(); + data = mFile->getBufferStart(); + fSize = mFile->getBufferSize(); + } + + // Now that we have the data in memory, update the + // symbol table if it's a bitcode file. + if (CreateSymbolTable && member.isBitcode()) { + std::vector symbols; + std::string FullMemberName = archPath.str() + "(" + member.getPath().str() + + ")"; + Module* M = + GetBitcodeSymbols(data, fSize, FullMemberName, Context, symbols, ErrMsg); + + // If the bitcode parsed successfully + if ( M ) { + for (std::vector::iterator SI = symbols.begin(), + SE = symbols.end(); SI != SE; ++SI) { + + std::pair 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; +} + +// Write the entire archive to the file specified when the archive was created. +// This writes to a temporary file first. Options are for creating a symbol +// table, flattening the file names (no directories, 15 chars max) and +// compressing each archive member. +bool +Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, + std::string* ErrMsg) +{ + // Make sure they haven't opened up the file, not loaded it, + // but are now trying to write it which would wipe out the file. + if (members.empty() && mapfile && mapfile->getBufferSize() > 8) { + if (ErrMsg) + *ErrMsg = "Can't write an archive not opened for writing"; + return true; + } + + // Create a temporary file to store the archive in + sys::Path TmpArchive = archPath; + if (TmpArchive.createTemporaryFileOnDisk(ErrMsg)) + return true; + + // Make sure the temporary gets removed if we crash + sys::RemoveFileOnSignal(TmpArchive.str()); + + // Create archive file for output. + std::ios::openmode io_mode = std::ios::out | std::ios::trunc | + std::ios::binary; + std::ofstream ArchiveFile(TmpArchive.c_str(), io_mode); + + // Check for errors opening or creating archive file. + if (!ArchiveFile.is_open() || ArchiveFile.bad()) { + TmpArchive.eraseFromDisk(); + if (ErrMsg) + *ErrMsg = "Error opening archive file: " + archPath.str(); + return true; + } + + // If we're creating a symbol table, reset it now + if (CreateSymbolTable) { + symTabSize = 0; + symTab.clear(); + } + + // Write magic string to archive. + ArchiveFile << ARFILE_MAGIC; + + // Loop over all member files, and write them out. Note that this also + // builds the symbol table, symTab. + for (MembersList::iterator I = begin(), E = end(); I != E; ++I) { + if (writeMember(*I, ArchiveFile, CreateSymbolTable, + TruncateNames, ErrMsg)) { + TmpArchive.eraseFromDisk(); + ArchiveFile.close(); + return true; + } + } + + // Close archive file. + ArchiveFile.close(); + + // Write the symbol table + if (CreateSymbolTable) { + // At this point we have written a file that is a legal archive but it + // doesn't have a symbol table in it. To aid in faster reading and to + // ensure compatibility with other archivers we need to put the symbol + // table first in the file. Unfortunately, this means mapping the file + // we just wrote back in and copying it to the destination file. + sys::Path FinalFilePath = archPath; + + // Map in the archive we just wrote. + { + OwningPtr arch; + if (error_code ec = MemoryBuffer::getFile(TmpArchive.c_str(), arch)) { + if (ErrMsg) + *ErrMsg = ec.message(); + return true; + } + const char* base = arch->getBufferStart(); + + // Open another temporary file in order to avoid invalidating the + // mmapped data + if (FinalFilePath.createTemporaryFileOnDisk(ErrMsg)) + return true; + sys::RemoveFileOnSignal(FinalFilePath.str()); + + std::ofstream FinalFile(FinalFilePath.c_str(), io_mode); + if (!FinalFile.is_open() || FinalFile.bad()) { + TmpArchive.eraseFromDisk(); + if (ErrMsg) + *ErrMsg = "Error opening archive file: " + FinalFilePath.str(); + return true; + } + + // Write the file magic number + FinalFile << ARFILE_MAGIC; + + // If there is a foreign symbol table, put it into the file now. Most + // ar(1) implementations require the symbol table to be first but llvm-ar + // can deal with it being after a foreign symbol table. This ensures + // compatibility with other ar(1) implementations as well as allowing the + // archive to store both native .o and LLVM .bc files, both indexed. + if (foreignST) { + if (writeMember(*foreignST, FinalFile, false, false, ErrMsg)) { + FinalFile.close(); + TmpArchive.eraseFromDisk(); + return true; + } + } + + // Copy the temporary file contents being sure to skip the file's magic + // number. + FinalFile.write(base + sizeof(ARFILE_MAGIC)-1, + arch->getBufferSize()-sizeof(ARFILE_MAGIC)+1); + + // Close up shop + FinalFile.close(); + } // free arch. + + // Move the final file over top of TmpArchive + if (FinalFilePath.renamePathOnDisk(TmpArchive, ErrMsg)) + return true; + } + + // Before we replace the actual archive, we need to forget all the + // members, since they point to data in that old archive. We need to do + // this because we cannot replace an open file on Windows. + cleanUpMemory(); + + if (TmpArchive.renamePathOnDisk(archPath, ErrMsg)) + return true; + + // Set correct read and write permissions after temporary file is moved + // to final destination path. + if (archPath.makeReadableOnDisk(ErrMsg)) + return true; + if (archPath.makeWriteableOnDisk(ErrMsg)) + return true; + + return false; +} diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt index 70eb7603fd..68095df714 100644 --- a/tools/llvm-ar/CMakeLists.txt +++ b/tools/llvm-ar/CMakeLists.txt @@ -1,7 +1,10 @@ -set(LLVM_LINK_COMPONENTS archive) +set(LLVM_LINK_COMPONENTS support bitreader) add_llvm_tool(llvm-ar llvm-ar.cpp + ArchiveWriter.cpp + ArchiveReader.cpp + Archive.cpp ) # TODO: Support check-local. diff --git a/tools/llvm-ar/LLVMBuild.txt b/tools/llvm-ar/LLVMBuild.txt index 1f61a32014..236b4659f7 100644 --- a/tools/llvm-ar/LLVMBuild.txt +++ b/tools/llvm-ar/LLVMBuild.txt @@ -19,4 +19,3 @@ type = Tool name = llvm-ar parent = Tools -required_libraries = Archive diff --git a/tools/llvm-ar/Makefile b/tools/llvm-ar/Makefile index fafb14bc12..9e782cfca5 100644 --- a/tools/llvm-ar/Makefile +++ b/tools/llvm-ar/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-ar -LINK_COMPONENTS := archive +LINK_COMPONENTS := bitreader support # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 243a845e3c..2a4a3deecd 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// +#include "Archive.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/Bitcode/Archive.h" #include "llvm/IR/Module.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" -- cgit v1.2.3