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