Home | History | Annotate | Download | only in Object
      1 //===- Archive.h - ar archive file format -----------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file declares the ar archive file format class.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_OBJECT_ARCHIVE_H
     15 #define LLVM_OBJECT_ARCHIVE_H
     16 
     17 #include "llvm/ADT/StringRef.h"
     18 #include "llvm/ADT/iterator_range.h"
     19 #include "llvm/Object/Binary.h"
     20 #include "llvm/Support/ErrorHandling.h"
     21 #include "llvm/Support/ErrorOr.h"
     22 #include "llvm/Support/FileSystem.h"
     23 #include "llvm/Support/MemoryBuffer.h"
     24 
     25 namespace llvm {
     26 namespace object {
     27 struct ArchiveMemberHeader {
     28   char Name[16];
     29   char LastModified[12];
     30   char UID[6];
     31   char GID[6];
     32   char AccessMode[8];
     33   char Size[10]; ///< Size of data, not including header or padding.
     34   char Terminator[2];
     35 
     36   /// Get the name without looking up long names.
     37   llvm::StringRef getName() const;
     38 
     39   /// Members are not larger than 4GB.
     40   uint32_t getSize() const;
     41 
     42   sys::fs::perms getAccessMode() const;
     43   sys::TimeValue getLastModified() const;
     44   llvm::StringRef getRawLastModified() const {
     45     return StringRef(LastModified, sizeof(LastModified)).rtrim(" ");
     46   }
     47   unsigned getUID() const;
     48   unsigned getGID() const;
     49 };
     50 
     51 class Archive : public Binary {
     52   virtual void anchor();
     53 public:
     54   class Child {
     55     const Archive *Parent;
     56     /// \brief Includes header but not padding byte.
     57     StringRef Data;
     58     /// \brief Offset from Data to the start of the file.
     59     uint16_t StartOfFile;
     60 
     61     const ArchiveMemberHeader *getHeader() const {
     62       return reinterpret_cast<const ArchiveMemberHeader *>(Data.data());
     63     }
     64 
     65   public:
     66     Child(const Archive *Parent, const char *Start);
     67 
     68     bool operator ==(const Child &other) const {
     69       assert(Parent == other.Parent);
     70       return Data.begin() == other.Data.begin();
     71     }
     72 
     73     bool operator <(const Child &other) const {
     74       return Data.begin() < other.Data.begin();
     75     }
     76 
     77     Child getNext() const;
     78 
     79     ErrorOr<StringRef> getName() const;
     80     StringRef getRawName() const { return getHeader()->getName(); }
     81     sys::TimeValue getLastModified() const {
     82       return getHeader()->getLastModified();
     83     }
     84     StringRef getRawLastModified() const {
     85       return getHeader()->getRawLastModified();
     86     }
     87     unsigned getUID() const { return getHeader()->getUID(); }
     88     unsigned getGID() const { return getHeader()->getGID(); }
     89     sys::fs::perms getAccessMode() const {
     90       return getHeader()->getAccessMode();
     91     }
     92     /// \return the size of the archive member without the header or padding.
     93     uint64_t getSize() const;
     94     /// \return the size in the archive header for this member.
     95     uint64_t getRawSize() const;
     96 
     97     StringRef getBuffer() const {
     98       return StringRef(Data.data() + StartOfFile, getSize());
     99     }
    100     uint64_t getChildOffset() const;
    101 
    102     ErrorOr<MemoryBufferRef> getMemoryBufferRef() const;
    103 
    104     ErrorOr<std::unique_ptr<Binary>>
    105     getAsBinary(LLVMContext *Context = nullptr) const;
    106   };
    107 
    108   class child_iterator {
    109     Child child;
    110 
    111   public:
    112     child_iterator() : child(Child(nullptr, nullptr)) {}
    113     child_iterator(const Child &c) : child(c) {}
    114     const Child *operator->() const { return &child; }
    115     const Child &operator*() const { return child; }
    116 
    117     bool operator==(const child_iterator &other) const {
    118       return child == other.child;
    119     }
    120 
    121     bool operator!=(const child_iterator &other) const {
    122       return !(*this == other);
    123     }
    124 
    125     bool operator<(const child_iterator &other) const {
    126       return child < other.child;
    127     }
    128 
    129     child_iterator &operator++() { // Preincrement
    130       child = child.getNext();
    131       return *this;
    132     }
    133   };
    134 
    135   class Symbol {
    136     const Archive *Parent;
    137     uint32_t SymbolIndex;
    138     uint32_t StringIndex; // Extra index to the string.
    139 
    140   public:
    141     bool operator ==(const Symbol &other) const {
    142       return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex);
    143     }
    144 
    145     Symbol(const Archive *p, uint32_t symi, uint32_t stri)
    146       : Parent(p)
    147       , SymbolIndex(symi)
    148       , StringIndex(stri) {}
    149     StringRef getName() const;
    150     ErrorOr<child_iterator> getMember() const;
    151     Symbol getNext() const;
    152   };
    153 
    154   class symbol_iterator {
    155     Symbol symbol;
    156   public:
    157     symbol_iterator(const Symbol &s) : symbol(s) {}
    158     const Symbol *operator->() const { return &symbol; }
    159     const Symbol &operator*() const { return symbol; }
    160 
    161     bool operator==(const symbol_iterator &other) const {
    162       return symbol == other.symbol;
    163     }
    164 
    165     bool operator!=(const symbol_iterator &other) const {
    166       return !(*this == other);
    167     }
    168 
    169     symbol_iterator& operator++() {  // Preincrement
    170       symbol = symbol.getNext();
    171       return *this;
    172     }
    173   };
    174 
    175   Archive(MemoryBufferRef Source, std::error_code &EC);
    176   static ErrorOr<std::unique_ptr<Archive>> create(MemoryBufferRef Source);
    177 
    178   enum Kind {
    179     K_GNU,
    180     K_MIPS64,
    181     K_BSD,
    182     K_COFF
    183   };
    184 
    185   Kind kind() const { return (Kind)Format; }
    186 
    187   child_iterator child_begin(bool SkipInternal = true) const;
    188   child_iterator child_end() const;
    189   iterator_range<child_iterator> children(bool SkipInternal = true) const {
    190     return iterator_range<child_iterator>(child_begin(SkipInternal),
    191                                           child_end());
    192   }
    193 
    194   symbol_iterator symbol_begin() const;
    195   symbol_iterator symbol_end() const;
    196   iterator_range<symbol_iterator> symbols() const {
    197     return iterator_range<symbol_iterator>(symbol_begin(), symbol_end());
    198   }
    199 
    200   // Cast methods.
    201   static inline bool classof(Binary const *v) {
    202     return v->isArchive();
    203   }
    204 
    205   // check if a symbol is in the archive
    206   child_iterator findSym(StringRef name) const;
    207 
    208   bool hasSymbolTable() const;
    209   child_iterator getSymbolTableChild() const { return SymbolTable; }
    210 
    211 private:
    212   child_iterator SymbolTable;
    213   child_iterator StringTable;
    214   child_iterator FirstRegular;
    215   unsigned Format : 2;
    216   unsigned IsThin : 1;
    217 };
    218 
    219 }
    220 }
    221 
    222 #endif
    223