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 /// 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 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 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 110 const Archive *getParent() const { return Parent; } 111 Expected<Child> getNext() const; 112 113 Expected<StringRef> getName() const; 114 Expected<std::string> getFullName() const; 115 Expected<StringRef> getRawName() const { return Header.getRawName(); } 116 117 Expected<sys::TimePoint<std::chrono::seconds>> getLastModified() const { 118 return Header.getLastModified(); 119 } 120 121 StringRef getRawLastModified() const { 122 return Header.getRawLastModified(); 123 } 124 125 Expected<unsigned> getUID() const { return Header.getUID(); } 126 Expected<unsigned> getGID() const { return Header.getGID(); } 127 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 ChildFallibleIterator { 147 Child C; 148 149 public: 150 ChildFallibleIterator() : C(Child(nullptr, nullptr, nullptr)) {} 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 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: 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: 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 enum Kind { 225 K_GNU, 226 K_GNU64, 227 K_BSD, 228 K_DARWIN, 229 K_DARWIN64, 230 K_COFF 231 }; 232 233 Kind kind() const { return (Kind)Format; } 234 bool isThin() const { return IsThin; } 235 236 child_iterator child_begin(Error &Err, bool SkipInternal = true) const; 237 child_iterator child_end() const; 238 iterator_range<child_iterator> children(Error &Err, 239 bool SkipInternal = true) const { 240 return make_range(child_begin(Err, SkipInternal), child_end()); 241 } 242 243 symbol_iterator symbol_begin() const; 244 symbol_iterator symbol_end() const; 245 iterator_range<symbol_iterator> symbols() const { 246 return make_range(symbol_begin(), symbol_end()); 247 } 248 249 // Cast methods. 250 static bool classof(Binary const *v) { 251 return v->isArchive(); 252 } 253 254 // check if a symbol is in the archive 255 Expected<Optional<Child>> findSym(StringRef name) const; 256 257 bool isEmpty() const; 258 bool hasSymbolTable() const; 259 StringRef getSymbolTable() const { return SymbolTable; } 260 StringRef getStringTable() const { return StringTable; } 261 uint32_t getNumberOfSymbols() const; 262 263 std::vector<std::unique_ptr<MemoryBuffer>> takeThinBuffers() { 264 return std::move(ThinBuffers); 265 } 266 267 private: 268 StringRef SymbolTable; 269 StringRef StringTable; 270 271 StringRef FirstRegularData; 272 uint16_t FirstRegularStartOfFile = -1; 273 void setFirstRegular(const Child &C); 274 275 unsigned Format : 3; 276 unsigned IsThin : 1; 277 mutable std::vector<std::unique_ptr<MemoryBuffer>> ThinBuffers; 278 }; 279 280 } // end namespace object 281 } // end namespace llvm 282 283 #endif // LLVM_OBJECT_ARCHIVE_H 284