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 ErrorOr<uint32_t> getSize() const; 41 42 sys::fs::perms getAccessMode() const; 43 sys::TimeValue getLastModified() const; getRawLastModifiedArchiveMemberHeader44 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 friend Archive; 56 const Archive *Parent; 57 /// \brief Includes header but not padding byte. 58 StringRef Data; 59 /// \brief Offset from Data to the start of the file. 60 uint16_t StartOfFile; 61 getHeader()62 const ArchiveMemberHeader *getHeader() const { 63 return reinterpret_cast<const ArchiveMemberHeader *>(Data.data()); 64 } 65 66 bool isThinMember() const; 67 68 public: 69 Child(const Archive *Parent, const char *Start, std::error_code *EC); 70 Child(const Archive *Parent, StringRef Data, uint16_t StartOfFile); 71 72 bool operator ==(const Child &other) const { 73 assert(Parent == other.Parent); 74 return Data.begin() == other.Data.begin(); 75 } 76 getParent()77 const Archive *getParent() const { return Parent; } 78 ErrorOr<Child> getNext() const; 79 80 ErrorOr<StringRef> getName() const; getRawName()81 StringRef getRawName() const { return getHeader()->getName(); } getLastModified()82 sys::TimeValue getLastModified() const { 83 return getHeader()->getLastModified(); 84 } getRawLastModified()85 StringRef getRawLastModified() const { 86 return getHeader()->getRawLastModified(); 87 } getUID()88 unsigned getUID() const { return getHeader()->getUID(); } getGID()89 unsigned getGID() const { return getHeader()->getGID(); } getAccessMode()90 sys::fs::perms getAccessMode() const { 91 return getHeader()->getAccessMode(); 92 } 93 /// \return the size of the archive member without the header or padding. 94 ErrorOr<uint64_t> getSize() const; 95 /// \return the size in the archive header for this member. 96 ErrorOr<uint64_t> getRawSize() const; 97 98 ErrorOr<StringRef> getBuffer() const; 99 uint64_t getChildOffset() const; 100 101 ErrorOr<MemoryBufferRef> getMemoryBufferRef() const; 102 103 ErrorOr<std::unique_ptr<Binary>> 104 getAsBinary(LLVMContext *Context = nullptr) const; 105 }; 106 107 class child_iterator { 108 ErrorOr<Child> child; 109 110 public: child_iterator()111 child_iterator() : child(Child(nullptr, nullptr, nullptr)) {} child_iterator(const Child & c)112 child_iterator(const Child &c) : child(c) {} child_iterator(std::error_code EC)113 child_iterator(std::error_code EC) : child(EC) {} 114 const ErrorOr<Child> *operator->() const { return &child; } 115 const ErrorOr<Child> &operator*() const { return child; } 116 117 bool operator==(const child_iterator &other) const { 118 // We ignore error states so that comparisions with end() work, which 119 // allows range loops. 120 if (child.getError() || other.child.getError()) 121 return false; 122 return *child == *other.child; 123 } 124 125 bool operator!=(const child_iterator &other) const { 126 return !(*this == other); 127 } 128 129 // Code in loops with child_iterators must check for errors on each loop 130 // iteration. And if there is an error break out of the loop. 131 child_iterator &operator++() { // Preincrement 132 assert(child && "Can't increment iterator with error"); 133 child = child->getNext(); 134 return *this; 135 } 136 }; 137 138 class Symbol { 139 const Archive *Parent; 140 uint32_t SymbolIndex; 141 uint32_t StringIndex; // Extra index to the string. 142 143 public: 144 bool operator ==(const Symbol &other) const { 145 return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex); 146 } 147 Symbol(const Archive * p,uint32_t symi,uint32_t stri)148 Symbol(const Archive *p, uint32_t symi, uint32_t stri) 149 : Parent(p) 150 , SymbolIndex(symi) 151 , StringIndex(stri) {} 152 StringRef getName() const; 153 ErrorOr<Child> getMember() const; 154 Symbol getNext() const; 155 }; 156 157 class symbol_iterator { 158 Symbol symbol; 159 public: symbol_iterator(const Symbol & s)160 symbol_iterator(const Symbol &s) : symbol(s) {} 161 const Symbol *operator->() const { return &symbol; } 162 const Symbol &operator*() const { return symbol; } 163 164 bool operator==(const symbol_iterator &other) const { 165 return symbol == other.symbol; 166 } 167 168 bool operator!=(const symbol_iterator &other) const { 169 return !(*this == other); 170 } 171 172 symbol_iterator& operator++() { // Preincrement 173 symbol = symbol.getNext(); 174 return *this; 175 } 176 }; 177 178 Archive(MemoryBufferRef Source, std::error_code &EC); 179 static ErrorOr<std::unique_ptr<Archive>> create(MemoryBufferRef Source); 180 181 enum Kind { 182 K_GNU, 183 K_MIPS64, 184 K_BSD, 185 K_COFF 186 }; 187 kind()188 Kind kind() const { return (Kind)Format; } isThin()189 bool isThin() const { return IsThin; } 190 191 child_iterator child_begin(bool SkipInternal = true) const; 192 child_iterator child_end() const; 193 iterator_range<child_iterator> children(bool SkipInternal = true) const { 194 return make_range(child_begin(SkipInternal), child_end()); 195 } 196 197 symbol_iterator symbol_begin() const; 198 symbol_iterator symbol_end() const; symbols()199 iterator_range<symbol_iterator> symbols() const { 200 return make_range(symbol_begin(), symbol_end()); 201 } 202 203 // Cast methods. classof(Binary const * v)204 static inline bool classof(Binary const *v) { 205 return v->isArchive(); 206 } 207 208 // check if a symbol is in the archive 209 child_iterator findSym(StringRef name) const; 210 211 bool hasSymbolTable() const; getSymbolTable()212 StringRef getSymbolTable() const { return SymbolTable; } 213 uint32_t getNumberOfSymbols() const; 214 215 private: 216 StringRef SymbolTable; 217 StringRef StringTable; 218 219 StringRef FirstRegularData; 220 uint16_t FirstRegularStartOfFile = -1; 221 void setFirstRegular(const Child &C); 222 223 unsigned Format : 2; 224 unsigned IsThin : 1; 225 mutable std::vector<std::unique_ptr<MemoryBuffer>> ThinBuffers; 226 }; 227 228 } 229 } 230 231 #endif 232