1 //===- Archive.h - ar archive file format -----------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file declares the ar archive file format class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_OBJECT_ARCHIVE_H 14 #define LLVM_OBJECT_ARCHIVE_H 15 16 #include "llvm/ADT/Optional.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/ADT/fallible_iterator.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 Expected<uint64_t> getSize() const; 52 53 Expected<sys::fs::perms> getAccessMode() const; 54 Expected<sys::TimePoint<std::chrono::seconds>> getLastModified() const; 55 getRawLastModified()56 StringRef getRawLastModified() const { 57 return StringRef(ArMemHdr->LastModified, 58 sizeof(ArMemHdr->LastModified)).rtrim(' '); 59 } 60 61 Expected<unsigned> getUID() const; 62 Expected<unsigned> getGID() const; 63 64 // This returns the size of the private struct ArMemHdrType getSizeOf()65 uint64_t getSizeOf() const { 66 return sizeof(ArMemHdrType); 67 } 68 69 private: 70 struct ArMemHdrType { 71 char Name[16]; 72 char LastModified[12]; 73 char UID[6]; 74 char GID[6]; 75 char AccessMode[8]; 76 char Size[10]; ///< Size of data, not including header or padding. 77 char Terminator[2]; 78 }; 79 Archive const *Parent; 80 ArMemHdrType const *ArMemHdr; 81 }; 82 83 class Archive : public Binary { 84 virtual void anchor(); 85 86 public: 87 class Child { 88 friend Archive; 89 friend ArchiveMemberHeader; 90 91 const Archive *Parent; 92 ArchiveMemberHeader Header; 93 /// Includes header but not padding byte. 94 StringRef Data; 95 /// Offset from Data to the start of the file. 96 uint16_t StartOfFile; 97 98 Expected<bool> isThinMember() const; 99 100 public: 101 Child(const Archive *Parent, const char *Start, Error *Err); 102 Child(const Archive *Parent, StringRef Data, uint16_t StartOfFile); 103 104 bool operator ==(const Child &other) const { 105 assert(!Parent || !other.Parent || Parent == other.Parent); 106 return Data.begin() == other.Data.begin(); 107 } 108 getParent()109 const Archive *getParent() const { return Parent; } 110 Expected<Child> getNext() const; 111 112 Expected<StringRef> getName() const; 113 Expected<std::string> getFullName() const; getRawName()114 Expected<StringRef> getRawName() const { return Header.getRawName(); } 115 getLastModified()116 Expected<sys::TimePoint<std::chrono::seconds>> getLastModified() const { 117 return Header.getLastModified(); 118 } 119 getRawLastModified()120 StringRef getRawLastModified() const { 121 return Header.getRawLastModified(); 122 } 123 getUID()124 Expected<unsigned> getUID() const { return Header.getUID(); } getGID()125 Expected<unsigned> getGID() const { return Header.getGID(); } 126 getAccessMode()127 Expected<sys::fs::perms> getAccessMode() const { 128 return Header.getAccessMode(); 129 } 130 131 /// \return the size of the archive member without the header or padding. 132 Expected<uint64_t> getSize() const; 133 /// \return the size in the archive header for this member. 134 Expected<uint64_t> getRawSize() const; 135 136 Expected<StringRef> getBuffer() const; 137 uint64_t getChildOffset() const; getDataOffset()138 uint64_t getDataOffset() const { return getChildOffset() + StartOfFile; } 139 140 Expected<MemoryBufferRef> getMemoryBufferRef() const; 141 142 Expected<std::unique_ptr<Binary>> 143 getAsBinary(LLVMContext *Context = nullptr) const; 144 }; 145 146 class ChildFallibleIterator { 147 Child C; 148 149 public: ChildFallibleIterator()150 ChildFallibleIterator() : C(Child(nullptr, nullptr, nullptr)) {} ChildFallibleIterator(const Child & C)151 ChildFallibleIterator(const Child &C) : C(C) {} 152 153 const Child *operator->() const { return &C; } 154 const Child &operator*() const { return C; } 155 156 bool operator==(const ChildFallibleIterator &other) const { 157 // Ignore errors here: If an error occurred during increment then getNext 158 // will have been set to child_end(), and the following comparison should 159 // do the right thing. 160 return C == other.C; 161 } 162 163 bool operator!=(const ChildFallibleIterator &other) const { 164 return !(*this == other); 165 } 166 inc()167 Error inc() { 168 auto NextChild = C.getNext(); 169 if (!NextChild) 170 return NextChild.takeError(); 171 C = std::move(*NextChild); 172 return Error::success(); 173 } 174 }; 175 176 using child_iterator = fallible_iterator<ChildFallibleIterator>; 177 178 class Symbol { 179 const Archive *Parent; 180 uint32_t SymbolIndex; 181 uint32_t StringIndex; // Extra index to the string. 182 183 public: Symbol(const Archive * p,uint32_t symi,uint32_t stri)184 Symbol(const Archive *p, uint32_t symi, uint32_t stri) 185 : Parent(p) 186 , SymbolIndex(symi) 187 , StringIndex(stri) {} 188 189 bool operator ==(const Symbol &other) const { 190 return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex); 191 } 192 193 StringRef getName() const; 194 Expected<Child> getMember() const; 195 Symbol getNext() const; 196 }; 197 198 class symbol_iterator { 199 Symbol symbol; 200 201 public: symbol_iterator(const Symbol & s)202 symbol_iterator(const Symbol &s) : symbol(s) {} 203 204 const Symbol *operator->() const { return &symbol; } 205 const Symbol &operator*() const { return symbol; } 206 207 bool operator==(const symbol_iterator &other) const { 208 return symbol == other.symbol; 209 } 210 211 bool operator!=(const symbol_iterator &other) const { 212 return !(*this == other); 213 } 214 215 symbol_iterator& operator++() { // Preincrement 216 symbol = symbol.getNext(); 217 return *this; 218 } 219 }; 220 221 Archive(MemoryBufferRef Source, Error &Err); 222 static Expected<std::unique_ptr<Archive>> create(MemoryBufferRef Source); 223 224 /// Size field is 10 decimal digits long 225 static const uint64_t MaxMemberSize = 9999999999; 226 227 enum Kind { 228 K_GNU, 229 K_GNU64, 230 K_BSD, 231 K_DARWIN, 232 K_DARWIN64, 233 K_COFF 234 }; 235 kind()236 Kind kind() const { return (Kind)Format; } isThin()237 bool isThin() const { return IsThin; } 238 239 child_iterator child_begin(Error &Err, bool SkipInternal = true) const; 240 child_iterator child_end() const; 241 iterator_range<child_iterator> children(Error &Err, 242 bool SkipInternal = true) const { 243 return make_range(child_begin(Err, SkipInternal), child_end()); 244 } 245 246 symbol_iterator symbol_begin() const; 247 symbol_iterator symbol_end() const; symbols()248 iterator_range<symbol_iterator> symbols() const { 249 return make_range(symbol_begin(), symbol_end()); 250 } 251 252 // Cast methods. classof(Binary const * v)253 static bool classof(Binary const *v) { 254 return v->isArchive(); 255 } 256 257 // check if a symbol is in the archive 258 Expected<Optional<Child>> findSym(StringRef name) const; 259 260 bool isEmpty() const; 261 bool hasSymbolTable() const; getSymbolTable()262 StringRef getSymbolTable() const { return SymbolTable; } getStringTable()263 StringRef getStringTable() const { return StringTable; } 264 uint32_t getNumberOfSymbols() const; 265 takeThinBuffers()266 std::vector<std::unique_ptr<MemoryBuffer>> takeThinBuffers() { 267 return std::move(ThinBuffers); 268 } 269 270 private: 271 StringRef SymbolTable; 272 StringRef StringTable; 273 274 StringRef FirstRegularData; 275 uint16_t FirstRegularStartOfFile = -1; 276 void setFirstRegular(const Child &C); 277 278 unsigned Format : 3; 279 unsigned IsThin : 1; 280 mutable std::vector<std::unique_ptr<MemoryBuffer>> ThinBuffers; 281 }; 282 283 } // end namespace object 284 } // end namespace llvm 285 286 #endif // LLVM_OBJECT_ARCHIVE_H 287