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