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; getRawLastModifiedArchiveMemberHeader45 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 getHeader()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 getParent()78 const Archive *getParent() const { return Parent; } 79 ErrorOr<Child> getNext() const; 80 81 ErrorOr<StringRef> getName() const; 82 ErrorOr<std::string> getFullName() const; getRawName()83 StringRef getRawName() const { return getHeader()->getName(); } getLastModified()84 sys::TimeValue getLastModified() const { 85 return getHeader()->getLastModified(); 86 } getRawLastModified()87 StringRef getRawLastModified() const { 88 return getHeader()->getRawLastModified(); 89 } getUID()90 unsigned getUID() const { return getHeader()->getUID(); } getGID()91 unsigned getGID() const { return getHeader()->getGID(); } getAccessMode()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: child_iterator()114 child_iterator() : C(Child(nullptr, nullptr, nullptr)), E(nullptr) {} child_iterator(const Child & C,Error * E)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 Symbol(const Archive * p,uint32_t symi,uint32_t stri)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: symbol_iterator(const Symbol & s)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 kind()197 Kind kind() const { return (Kind)Format; } isThin()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; symbols()209 iterator_range<symbol_iterator> symbols() const { 210 return make_range(symbol_begin(), symbol_end()); 211 } 212 213 // Cast methods. classof(Binary const * v)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; getSymbolTable()222 StringRef getSymbolTable() const { return SymbolTable; } 223 uint32_t getNumberOfSymbols() const; 224 takeThinBuffers()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