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/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 #include "llvm/Support/VirtualFileSystem.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 BinaryHolder(IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool Verbose = false) VFS(VFS)42 : VFS(VFS), Verbose(Verbose) {} 43 44 // Forward declarations for friend declaration. 45 class ObjectEntry; 46 class ArchiveEntry; 47 48 /// Base class shared by cached entries, representing objects and archives. 49 class EntryBase { 50 protected: 51 std::unique_ptr<MemoryBuffer> MemBuffer; 52 std::unique_ptr<object::MachOUniversalBinary> FatBinary; 53 std::string FatBinaryName; 54 }; 55 56 /// Cached entry holding one or more (in case of a fat binary) object files. 57 class ObjectEntry : public EntryBase { 58 public: 59 /// Load the given object binary in memory. 60 Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename, 61 TimestampTy Timestamp, bool Verbose = false); 62 63 /// Access all owned ObjectFiles. 64 std::vector<const object::ObjectFile *> getObjects() const; 65 66 /// Access to a derived version of all the currently owned ObjectFiles. The 67 /// conversion might be invalid, in which case an Error is returned. 68 template <typename ObjectFileType> getObjectsAs()69 Expected<std::vector<const ObjectFileType *>> getObjectsAs() const { 70 std::vector<const ObjectFileType *> Result; 71 Result.reserve(Objects.size()); 72 for (auto &Object : Objects) { 73 const auto *Derived = dyn_cast<ObjectFileType>(Object.get()); 74 if (!Derived) 75 return errorCodeToError(object::object_error::invalid_file_type); 76 Result.push_back(Derived); 77 } 78 return Result; 79 } 80 81 /// Access the owned ObjectFile with architecture \p T. 82 Expected<const object::ObjectFile &> getObject(const Triple &T) const; 83 84 /// Access to a derived version of the currently owned ObjectFile with 85 /// architecture \p T. The conversion must be known to be valid. 86 template <typename ObjectFileType> getObjectAs(const Triple & T)87 Expected<const ObjectFileType &> getObjectAs(const Triple &T) const { 88 auto Object = getObject(T); 89 if (!Object) 90 return Object.takeError(); 91 return cast<ObjectFileType>(*Object); 92 } 93 94 private: 95 std::vector<std::unique_ptr<object::ObjectFile>> Objects; 96 friend ArchiveEntry; 97 }; 98 99 /// Cached entry holding one or more (in the of a fat binary) archive files. 100 class ArchiveEntry : public EntryBase { 101 public: 102 struct KeyTy { 103 std::string Filename; 104 TimestampTy Timestamp; 105 KeyTyKeyTy106 KeyTy() {} KeyTyKeyTy107 KeyTy(StringRef Filename, TimestampTy Timestamp) 108 : Filename(Filename.str()), Timestamp(Timestamp) {} 109 }; 110 111 /// Load the given object binary in memory. 112 Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename, 113 TimestampTy Timestamp, bool Verbose = false); 114 115 Expected<const ObjectEntry &> getObjectEntry(StringRef Filename, 116 TimestampTy Timestamp, 117 bool Verbose = false); 118 119 private: 120 std::vector<std::unique_ptr<object::Archive>> Archives; 121 DenseMap<KeyTy, std::unique_ptr<ObjectEntry>> MemberCache; 122 std::mutex MemberCacheMutex; 123 }; 124 125 Expected<const ObjectEntry &> 126 getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy()); 127 128 void clear(); 129 130 private: 131 /// Cache of static archives. Objects that are part of a static archive are 132 /// stored under this object, rather than in the map below. 133 StringMap<std::unique_ptr<ArchiveEntry>> ArchiveCache; 134 std::mutex ArchiveCacheMutex; 135 136 /// Object entries for objects that are not in a static archive. 137 StringMap<std::unique_ptr<ObjectEntry>> ObjectCache; 138 std::mutex ObjectCacheMutex; 139 140 /// Virtual File System instance. 141 IntrusiveRefCntPtr<vfs::FileSystem> VFS; 142 143 bool Verbose; 144 }; 145 146 } // namespace dsymutil 147 148 template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> { 149 150 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() { 151 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy(); 152 } 153 154 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() { 155 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {}); 156 } 157 158 static unsigned 159 getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) { 160 return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename), 161 DenseMapInfo<unsigned>::getHashValue( 162 K.Timestamp.time_since_epoch().count())); 163 } 164 165 static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS, 166 const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) { 167 return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp; 168 } 169 }; 170 171 } // namespace llvm 172 #endif 173