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/Optional.h"
     18 #include "llvm/ADT/StringRef.h"
     19 #include "llvm/ADT/iterator_range.h"
     20 #include "llvm/Object/Binary.h"
     21 #include "llvm/Support/ErrorHandling.h"
     22 #include "llvm/Support/ErrorOr.h"
     23 #include "llvm/Support/FileSystem.h"
     24 #include "llvm/Support/MemoryBuffer.h"
     25 
     26 namespace llvm {
     27 namespace object {
     28 struct ArchiveMemberHeader {
     29   char Name[16];
     30   char LastModified[12];
     31   char UID[6];
     32   char GID[6];
     33   char AccessMode[8];
     34   char Size[10]; ///< Size of data, not including header or padding.
     35   char Terminator[2];
     36 
     37   /// Get the name without looking up long names.
     38   llvm::StringRef getName() const;
     39 
     40   /// Members are not larger than 4GB.
     41   ErrorOr<uint32_t> getSize() const;
     42 
     43   sys::fs::perms getAccessMode() const;
     44   sys::TimeValue getLastModified() const;
     45   llvm::StringRef getRawLastModified() const {
     46     return StringRef(LastModified, sizeof(LastModified)).rtrim(' ');
     47   }
     48   unsigned getUID() const;
     49   unsigned getGID() const;
     50 };
     51 
     52 class Archive : public Binary {
     53   virtual void anchor();
     54 public:
     55   class Child {
     56     friend Archive;
     57     const Archive *Parent;
     58     /// \brief Includes header but not padding byte.
     59     StringRef Data;
     60     /// \brief Offset from Data to the start of the file.
     61     uint16_t StartOfFile;
     62 
     63     const ArchiveMemberHeader *getHeader() const {
     64       return reinterpret_cast<const ArchiveMemberHeader *>(Data.data());
     65     }
     66 
     67     bool isThinMember() const;
     68 
     69   public:
     70     Child(const Archive *Parent, const char *Start, std::error_code *EC);
     71     Child(const Archive *Parent, StringRef Data, uint16_t StartOfFile);
     72 
     73     bool operator ==(const Child &other) const {
     74       assert(Parent == other.Parent);
     75       return Data.begin() == other.Data.begin();
     76     }
     77 
     78     const Archive *getParent() const { return Parent; }
     79     ErrorOr<Child> getNext() const;
     80 
     81     ErrorOr<StringRef> getName() const;
     82     ErrorOr<std::string> getFullName() const;
     83     StringRef getRawName() const { return getHeader()->getName(); }
     84     sys::TimeValue getLastModified() const {
     85       return getHeader()->getLastModified();
     86     }
     87     StringRef getRawLastModified() const {
     88       return getHeader()->getRawLastModified();
     89     }
     90     unsigned getUID() const { return getHeader()->getUID(); }
     91     unsigned getGID() const { return getHeader()->getGID(); }
     92     sys::fs::perms getAccessMode() const {
     93       return getHeader()->getAccessMode();
     94     }
     95     /// \return the size of the archive member without the header or padding.
     96     ErrorOr<uint64_t> getSize() const;
     97     /// \return the size in the archive header for this member.
     98     ErrorOr<uint64_t> getRawSize() const;
     99 
    100     ErrorOr<StringRef> getBuffer() const;
    101     uint64_t getChildOffset() const;
    102 
    103     ErrorOr<MemoryBufferRef> getMemoryBufferRef() const;
    104 
    105     Expected<std::unique_ptr<Binary>>
    106     getAsBinary(LLVMContext *Context = nullptr) const;
    107   };
    108 
    109   class child_iterator {
    110     Child C;
    111     Error *E;
    112 
    113   public:
    114     child_iterator() : C(Child(nullptr, nullptr, nullptr)), E(nullptr) {}
    115     child_iterator(const Child &C, Error *E) : C(C), E(E) {}
    116     const Child *operator->() const { return &C; }
    117     const Child &operator*() const { return C; }
    118 
    119     bool operator==(const child_iterator &other) const {
    120       // Ignore errors here: If an error occurred during increment then getNext
    121       // will have been set to child_end(), and the following comparison should
    122       // do the right thing.
    123       return C == other.C;
    124     }
    125 
    126     bool operator!=(const child_iterator &other) const {
    127       return !(*this == other);
    128     }
    129 
    130     // Code in loops with child_iterators must check for errors on each loop
    131     // iteration.  And if there is an error break out of the loop.
    132     child_iterator &operator++() { // Preincrement
    133       assert(E && "Can't increment iterator with no Error attached");
    134       if (auto ChildOrErr = C.getNext())
    135         C = *ChildOrErr;
    136       else {
    137         ErrorAsOutParameter ErrAsOutParam(*E);
    138         C = C.getParent()->child_end().C;
    139         *E = errorCodeToError(ChildOrErr.getError());
    140         E = nullptr;
    141       }
    142       return *this;
    143     }
    144   };
    145 
    146   class Symbol {
    147     const Archive *Parent;
    148     uint32_t SymbolIndex;
    149     uint32_t StringIndex; // Extra index to the string.
    150 
    151   public:
    152     bool operator ==(const Symbol &other) const {
    153       return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex);
    154     }
    155 
    156     Symbol(const Archive *p, uint32_t symi, uint32_t stri)
    157       : Parent(p)
    158       , SymbolIndex(symi)
    159       , StringIndex(stri) {}
    160     StringRef getName() const;
    161     ErrorOr<Child> getMember() const;
    162     Symbol getNext() const;
    163   };
    164 
    165   class symbol_iterator {
    166     Symbol symbol;
    167   public:
    168     symbol_iterator(const Symbol &s) : symbol(s) {}
    169     const Symbol *operator->() const { return &symbol; }
    170     const Symbol &operator*() const { return symbol; }
    171 
    172     bool operator==(const symbol_iterator &other) const {
    173       return symbol == other.symbol;
    174     }
    175 
    176     bool operator!=(const symbol_iterator &other) const {
    177       return !(*this == other);
    178     }
    179 
    180     symbol_iterator& operator++() {  // Preincrement
    181       symbol = symbol.getNext();
    182       return *this;
    183     }
    184   };
    185 
    186   Archive(MemoryBufferRef Source, Error &Err);
    187   static Expected<std::unique_ptr<Archive>> create(MemoryBufferRef Source);
    188 
    189   enum Kind {
    190     K_GNU,
    191     K_MIPS64,
    192     K_BSD,
    193     K_DARWIN64,
    194     K_COFF
    195   };
    196 
    197   Kind kind() const { return (Kind)Format; }
    198   bool isThin() const { return IsThin; }
    199 
    200   child_iterator child_begin(Error &Err, bool SkipInternal = true) const;
    201   child_iterator child_end() const;
    202   iterator_range<child_iterator> children(Error &Err,
    203                                           bool SkipInternal = true) const {
    204     return make_range(child_begin(Err, SkipInternal), child_end());
    205   }
    206 
    207   symbol_iterator symbol_begin() const;
    208   symbol_iterator symbol_end() const;
    209   iterator_range<symbol_iterator> symbols() const {
    210     return make_range(symbol_begin(), symbol_end());
    211   }
    212 
    213   // Cast methods.
    214   static inline bool classof(Binary const *v) {
    215     return v->isArchive();
    216   }
    217 
    218   // check if a symbol is in the archive
    219   Expected<Optional<Child>> findSym(StringRef name) const;
    220 
    221   bool hasSymbolTable() const;
    222   StringRef getSymbolTable() const { return SymbolTable; }
    223   uint32_t getNumberOfSymbols() const;
    224 
    225   std::vector<std::unique_ptr<MemoryBuffer>> takeThinBuffers() {
    226     return std::move(ThinBuffers);
    227   }
    228 
    229 private:
    230   StringRef SymbolTable;
    231   StringRef StringTable;
    232 
    233   StringRef FirstRegularData;
    234   uint16_t FirstRegularStartOfFile = -1;
    235   void setFirstRegular(const Child &C);
    236 
    237   unsigned Format : 3;
    238   unsigned IsThin : 1;
    239   mutable std::vector<std::unique_ptr<MemoryBuffer>> ThinBuffers;
    240 };
    241 
    242 }
    243 }
    244 
    245 #endif
    246