1 //===-- BinaryHolder.h - Utility class for accessing binaries -------------===// 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 program is a utility that aims to be a dropin replacement for 11 // Darwin's dsymutil. 12 // 13 //===----------------------------------------------------------------------===// 14 #ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H 15 #define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H 16 17 #include "llvm/ADT/DenseMap.h" 18 #include "llvm/ADT/Triple.h" 19 #include "llvm/Object/Archive.h" 20 #include "llvm/Object/Error.h" 21 #include "llvm/Object/MachOUniversal.h" 22 #include "llvm/Object/ObjectFile.h" 23 #include "llvm/Support/Chrono.h" 24 #include "llvm/Support/Errc.h" 25 #include "llvm/Support/ErrorOr.h" 26 27 #include <mutex> 28 29 namespace llvm { 30 namespace dsymutil { 31 32 /// The BinaryHolder class is responsible for creating and owning 33 /// ObjectFiles and their underlying MemoryBuffers. It differs from a simple 34 /// OwningBinary in that it handles accessing and caching of archives and its 35 /// members. 36 class BinaryHolder { 37 public: 38 using TimestampTy = sys::TimePoint<std::chrono::seconds>; 39 Verbose(Verbose)40 BinaryHolder(bool Verbose = false) : Verbose(Verbose) {} 41 42 // Forward declarations for friend declaration. 43 class ObjectEntry; 44 class ArchiveEntry; 45 46 /// Base class shared by cached entries, representing objects and archives. 47 class EntryBase { 48 protected: 49 std::unique_ptr<MemoryBuffer> MemBuffer; 50 std::unique_ptr<object::MachOUniversalBinary> FatBinary; 51 std::string FatBinaryName; 52 }; 53 54 /// Cached entry holding one or more (in case of a fat binary) object files. 55 class ObjectEntry : public EntryBase { 56 public: 57 /// Load the given object binary in memory. 58 Error load(StringRef Filename, bool Verbose = false); 59 60 /// Access all owned ObjectFiles. 61 std::vector<const object::ObjectFile *> getObjects() const; 62 63 /// Access to a derived version of all the currently owned ObjectFiles. The 64 /// conversion might be invalid, in which case an Error is returned. 65 template <typename ObjectFileType> getObjectsAs()66 Expected<std::vector<const ObjectFileType *>> getObjectsAs() const { 67 std::vector<const ObjectFileType *> Result; 68 Result.reserve(Objects.size()); 69 for (auto &Object : Objects) { 70 const auto *Derived = dyn_cast<ObjectFileType>(Object.get()); 71 if (!Derived) 72 return errorCodeToError(object::object_error::invalid_file_type); 73 Result.push_back(Derived); 74 } 75 return Result; 76 } 77 78 /// Access the owned ObjectFile with architecture \p T. 79 Expected<const object::ObjectFile &> getObject(const Triple &T) const; 80 81 /// Access to a derived version of the currently owned ObjectFile with 82 /// architecture \p T. The conversion must be known to be valid. 83 template <typename ObjectFileType> getObjectAs(const Triple & T)84 Expected<const ObjectFileType &> getObjectAs(const Triple &T) const { 85 auto Object = getObject(T); 86 if (!Object) 87 return Object.takeError(); 88 return cast<ObjectFileType>(*Object); 89 } 90 91 private: 92 std::vector<std::unique_ptr<object::ObjectFile>> Objects; 93 friend ArchiveEntry; 94 }; 95 96 /// Cached entry holding one or more (in the of a fat binary) archive files. 97 class ArchiveEntry : public EntryBase { 98 public: 99 struct KeyTy { 100 std::string Filename; 101 TimestampTy Timestamp; 102 KeyTyKeyTy103 KeyTy() : Filename(), Timestamp() {} KeyTyKeyTy104 KeyTy(StringRef Filename, TimestampTy Timestamp) 105 : Filename(Filename.str()), Timestamp(Timestamp) {} 106 }; 107 108 /// Load the given object binary in memory. 109 Error load(StringRef Filename, TimestampTy Timestamp, bool Verbose = false); 110 111 Expected<const ObjectEntry &> getObjectEntry(StringRef Filename, 112 TimestampTy Timestamp, 113 bool Verbose = false); 114 115 private: 116 std::vector<std::unique_ptr<object::Archive>> Archives; 117 DenseMap<KeyTy, ObjectEntry> MemberCache; 118 std::mutex MemberCacheMutex; 119 }; 120 121 Expected<const ObjectEntry &> 122 getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy()); 123 124 void clear(); 125 126 private: 127 /// Cache of static archives. Objects that are part of a static archive are 128 /// stored under this object, rather than in the map below. 129 StringMap<ArchiveEntry> ArchiveCache; 130 std::mutex ArchiveCacheMutex; 131 132 /// Object entries for objects that are not in a static archive. 133 StringMap<ObjectEntry> ObjectCache; 134 std::mutex ObjectCacheMutex; 135 136 bool Verbose; 137 }; 138 139 } // namespace dsymutil 140 141 template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> { 142 143 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() { 144 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy(); 145 } 146 147 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() { 148 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {}); 149 } 150 151 static unsigned 152 getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) { 153 return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename), 154 DenseMapInfo<unsigned>::getHashValue( 155 K.Timestamp.time_since_epoch().count())); 156 } 157 158 static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS, 159 const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) { 160 return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp; 161 } 162 }; 163 164 } // namespace llvm 165 #endif 166