109467b48Spatrick //===-- BinaryHolder.h - Utility class for accessing binaries -------------===// 209467b48Spatrick // 309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information. 509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 609467b48Spatrick // 709467b48Spatrick //===----------------------------------------------------------------------===// 809467b48Spatrick // 909467b48Spatrick // This program is a utility that aims to be a dropin replacement for 1009467b48Spatrick // Darwin's dsymutil. 1109467b48Spatrick // 1209467b48Spatrick //===----------------------------------------------------------------------===// 1309467b48Spatrick #ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H 1409467b48Spatrick #define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H 1509467b48Spatrick 1609467b48Spatrick #include "llvm/ADT/DenseMap.h" 17097a140dSpatrick #include "llvm/ADT/StringMap.h" 1809467b48Spatrick #include "llvm/ADT/Triple.h" 1909467b48Spatrick #include "llvm/Object/Archive.h" 2009467b48Spatrick #include "llvm/Object/Error.h" 2109467b48Spatrick #include "llvm/Object/MachOUniversal.h" 2209467b48Spatrick #include "llvm/Object/ObjectFile.h" 2309467b48Spatrick #include "llvm/Support/Chrono.h" 2409467b48Spatrick #include "llvm/Support/Errc.h" 2509467b48Spatrick #include "llvm/Support/ErrorOr.h" 26097a140dSpatrick #include "llvm/Support/VirtualFileSystem.h" 2709467b48Spatrick 2809467b48Spatrick #include <mutex> 2909467b48Spatrick 3009467b48Spatrick namespace llvm { 3109467b48Spatrick namespace dsymutil { 3209467b48Spatrick 3309467b48Spatrick /// The BinaryHolder class is responsible for creating and owning 3409467b48Spatrick /// ObjectFiles and their underlying MemoryBuffers. It differs from a simple 3509467b48Spatrick /// OwningBinary in that it handles accessing and caching of archives and its 3609467b48Spatrick /// members. 3709467b48Spatrick class BinaryHolder { 3809467b48Spatrick public: 3909467b48Spatrick using TimestampTy = sys::TimePoint<std::chrono::seconds>; 4009467b48Spatrick 41097a140dSpatrick BinaryHolder(IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool Verbose = false) VFS(VFS)42097a140dSpatrick : VFS(VFS), Verbose(Verbose) {} 4309467b48Spatrick 4409467b48Spatrick // Forward declarations for friend declaration. 4509467b48Spatrick class ObjectEntry; 4609467b48Spatrick class ArchiveEntry; 4709467b48Spatrick 4809467b48Spatrick /// Base class shared by cached entries, representing objects and archives. 4909467b48Spatrick class EntryBase { 5009467b48Spatrick protected: 5109467b48Spatrick std::unique_ptr<MemoryBuffer> MemBuffer; 5209467b48Spatrick std::unique_ptr<object::MachOUniversalBinary> FatBinary; 5309467b48Spatrick std::string FatBinaryName; 5409467b48Spatrick }; 5509467b48Spatrick 5609467b48Spatrick /// Cached entry holding one or more (in case of a fat binary) object files. 5709467b48Spatrick class ObjectEntry : public EntryBase { 5809467b48Spatrick public: 5909467b48Spatrick /// Load the given object binary in memory. 60097a140dSpatrick Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename, 6173471bf0Spatrick TimestampTy Timestamp, bool Verbose = false); 6209467b48Spatrick 6309467b48Spatrick /// Access all owned ObjectFiles. 6409467b48Spatrick std::vector<const object::ObjectFile *> getObjects() const; 6509467b48Spatrick 6609467b48Spatrick /// Access to a derived version of all the currently owned ObjectFiles. The 6709467b48Spatrick /// conversion might be invalid, in which case an Error is returned. 6809467b48Spatrick template <typename ObjectFileType> getObjectsAs()6909467b48Spatrick Expected<std::vector<const ObjectFileType *>> getObjectsAs() const { 7009467b48Spatrick std::vector<const ObjectFileType *> Result; 7109467b48Spatrick Result.reserve(Objects.size()); 7209467b48Spatrick for (auto &Object : Objects) { 7309467b48Spatrick const auto *Derived = dyn_cast<ObjectFileType>(Object.get()); 7409467b48Spatrick if (!Derived) 7509467b48Spatrick return errorCodeToError(object::object_error::invalid_file_type); 7609467b48Spatrick Result.push_back(Derived); 7709467b48Spatrick } 7809467b48Spatrick return Result; 7909467b48Spatrick } 8009467b48Spatrick 8109467b48Spatrick /// Access the owned ObjectFile with architecture \p T. 8209467b48Spatrick Expected<const object::ObjectFile &> getObject(const Triple &T) const; 8309467b48Spatrick 8409467b48Spatrick /// Access to a derived version of the currently owned ObjectFile with 8509467b48Spatrick /// architecture \p T. The conversion must be known to be valid. 8609467b48Spatrick template <typename ObjectFileType> getObjectAs(const Triple & T)8709467b48Spatrick Expected<const ObjectFileType &> getObjectAs(const Triple &T) const { 8809467b48Spatrick auto Object = getObject(T); 8909467b48Spatrick if (!Object) 9009467b48Spatrick return Object.takeError(); 9109467b48Spatrick return cast<ObjectFileType>(*Object); 9209467b48Spatrick } 9309467b48Spatrick 9409467b48Spatrick private: 9509467b48Spatrick std::vector<std::unique_ptr<object::ObjectFile>> Objects; 9609467b48Spatrick friend ArchiveEntry; 9709467b48Spatrick }; 9809467b48Spatrick 9909467b48Spatrick /// Cached entry holding one or more (in the of a fat binary) archive files. 10009467b48Spatrick class ArchiveEntry : public EntryBase { 10109467b48Spatrick public: 10209467b48Spatrick struct KeyTy { 10309467b48Spatrick std::string Filename; 10409467b48Spatrick TimestampTy Timestamp; 10509467b48Spatrick KeyTyKeyTy106*d415bd75Srobert KeyTy() {} KeyTyKeyTy10709467b48Spatrick KeyTy(StringRef Filename, TimestampTy Timestamp) 10809467b48Spatrick : Filename(Filename.str()), Timestamp(Timestamp) {} 10909467b48Spatrick }; 11009467b48Spatrick 11109467b48Spatrick /// Load the given object binary in memory. 112097a140dSpatrick Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename, 113097a140dSpatrick TimestampTy Timestamp, bool Verbose = false); 11409467b48Spatrick 11509467b48Spatrick Expected<const ObjectEntry &> getObjectEntry(StringRef Filename, 11609467b48Spatrick TimestampTy Timestamp, 11709467b48Spatrick bool Verbose = false); 11809467b48Spatrick 11909467b48Spatrick private: 12009467b48Spatrick std::vector<std::unique_ptr<object::Archive>> Archives; 121*d415bd75Srobert DenseMap<KeyTy, std::unique_ptr<ObjectEntry>> MemberCache; 12209467b48Spatrick std::mutex MemberCacheMutex; 12309467b48Spatrick }; 12409467b48Spatrick 12509467b48Spatrick Expected<const ObjectEntry &> 12609467b48Spatrick getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy()); 12709467b48Spatrick 12809467b48Spatrick void clear(); 12909467b48Spatrick 13009467b48Spatrick private: 13109467b48Spatrick /// Cache of static archives. Objects that are part of a static archive are 13209467b48Spatrick /// stored under this object, rather than in the map below. 133*d415bd75Srobert StringMap<std::unique_ptr<ArchiveEntry>> ArchiveCache; 13409467b48Spatrick std::mutex ArchiveCacheMutex; 13509467b48Spatrick 13609467b48Spatrick /// Object entries for objects that are not in a static archive. 137*d415bd75Srobert StringMap<std::unique_ptr<ObjectEntry>> ObjectCache; 13809467b48Spatrick std::mutex ObjectCacheMutex; 13909467b48Spatrick 140097a140dSpatrick /// Virtual File System instance. 141097a140dSpatrick IntrusiveRefCntPtr<vfs::FileSystem> VFS; 142097a140dSpatrick 14309467b48Spatrick bool Verbose; 14409467b48Spatrick }; 14509467b48Spatrick 14609467b48Spatrick } // namespace dsymutil 14709467b48Spatrick 14809467b48Spatrick template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> { 14909467b48Spatrick 15009467b48Spatrick static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() { 15109467b48Spatrick return dsymutil::BinaryHolder::ArchiveEntry::KeyTy(); 15209467b48Spatrick } 15309467b48Spatrick 15409467b48Spatrick static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() { 15509467b48Spatrick return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {}); 15609467b48Spatrick } 15709467b48Spatrick 15809467b48Spatrick static unsigned 15909467b48Spatrick getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) { 16009467b48Spatrick return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename), 16109467b48Spatrick DenseMapInfo<unsigned>::getHashValue( 16209467b48Spatrick K.Timestamp.time_since_epoch().count())); 16309467b48Spatrick } 16409467b48Spatrick 16509467b48Spatrick static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS, 16609467b48Spatrick const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) { 16709467b48Spatrick return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp; 16809467b48Spatrick } 16909467b48Spatrick }; 17009467b48Spatrick 17109467b48Spatrick } // namespace llvm 17209467b48Spatrick #endif 173