| //===-- BinaryHolder.h - Utility class for accessing binaries -------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This program is a utility that aims to be a dropin replacement for |
| // Darwin's dsymutil. |
| // |
| //===----------------------------------------------------------------------===// |
| #ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H |
| #define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H |
| |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/Triple.h" |
| #include "llvm/Object/Archive.h" |
| #include "llvm/Object/Error.h" |
| #include "llvm/Object/MachOUniversal.h" |
| #include "llvm/Object/ObjectFile.h" |
| #include "llvm/Support/Chrono.h" |
| #include "llvm/Support/Errc.h" |
| #include "llvm/Support/ErrorOr.h" |
| |
| #include <mutex> |
| |
| namespace llvm { |
| namespace dsymutil { |
| |
| /// The BinaryHolder class is responsible for creating and owning |
| /// ObjectFiles and their underlying MemoryBuffers. It differs from a simple |
| /// OwningBinary in that it handles accessing and caching of archives and its |
| /// members. |
| class BinaryHolder { |
| public: |
| using TimestampTy = sys::TimePoint<std::chrono::seconds>; |
| |
| BinaryHolder(bool Verbose = false) : Verbose(Verbose) {} |
| |
| // Forward declarations for friend declaration. |
| class ObjectEntry; |
| class ArchiveEntry; |
| |
| /// Base class shared by cached entries, representing objects and archives. |
| class EntryBase { |
| protected: |
| std::unique_ptr<MemoryBuffer> MemBuffer; |
| std::unique_ptr<object::MachOUniversalBinary> FatBinary; |
| std::string FatBinaryName; |
| }; |
| |
| /// Cached entry holding one or more (in case of a fat binary) object files. |
| class ObjectEntry : public EntryBase { |
| public: |
| /// Load the given object binary in memory. |
| Error load(StringRef Filename, bool Verbose = false); |
| |
| /// Access all owned ObjectFiles. |
| std::vector<const object::ObjectFile *> getObjects() const; |
| |
| /// Access to a derived version of all the currently owned ObjectFiles. The |
| /// conversion might be invalid, in which case an Error is returned. |
| template <typename ObjectFileType> |
| Expected<std::vector<const ObjectFileType *>> getObjectsAs() const { |
| std::vector<const ObjectFileType *> Result; |
| Result.reserve(Objects.size()); |
| for (auto &Object : Objects) { |
| const auto *Derived = dyn_cast<ObjectFileType>(Object.get()); |
| if (!Derived) |
| return errorCodeToError(object::object_error::invalid_file_type); |
| Result.push_back(Derived); |
| } |
| return Result; |
| } |
| |
| /// Access the owned ObjectFile with architecture \p T. |
| Expected<const object::ObjectFile &> getObject(const Triple &T) const; |
| |
| /// Access to a derived version of the currently owned ObjectFile with |
| /// architecture \p T. The conversion must be known to be valid. |
| template <typename ObjectFileType> |
| Expected<const ObjectFileType &> getObjectAs(const Triple &T) const { |
| auto Object = getObject(T); |
| if (!Object) |
| return Object.takeError(); |
| return cast<ObjectFileType>(*Object); |
| } |
| |
| private: |
| std::vector<std::unique_ptr<object::ObjectFile>> Objects; |
| friend ArchiveEntry; |
| }; |
| |
| /// Cached entry holding one or more (in the of a fat binary) archive files. |
| class ArchiveEntry : public EntryBase { |
| public: |
| struct KeyTy { |
| std::string Filename; |
| TimestampTy Timestamp; |
| |
| KeyTy() : Filename(), Timestamp() {} |
| KeyTy(StringRef Filename, TimestampTy Timestamp) |
| : Filename(Filename.str()), Timestamp(Timestamp) {} |
| }; |
| |
| /// Load the given object binary in memory. |
| Error load(StringRef Filename, TimestampTy Timestamp, bool Verbose = false); |
| |
| Expected<const ObjectEntry &> getObjectEntry(StringRef Filename, |
| TimestampTy Timestamp, |
| bool Verbose = false); |
| |
| private: |
| std::vector<std::unique_ptr<object::Archive>> Archives; |
| DenseMap<KeyTy, ObjectEntry> MemberCache; |
| std::mutex MemberCacheMutex; |
| }; |
| |
| Expected<const ObjectEntry &> |
| getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy()); |
| |
| void clear(); |
| |
| private: |
| /// Cache of static archives. Objects that are part of a static archive are |
| /// stored under this object, rather than in the map below. |
| StringMap<ArchiveEntry> ArchiveCache; |
| std::mutex ArchiveCacheMutex; |
| |
| /// Object entries for objects that are not in a static archive. |
| StringMap<ObjectEntry> ObjectCache; |
| std::mutex ObjectCacheMutex; |
| |
| bool Verbose; |
| }; |
| |
| } // namespace dsymutil |
| |
| template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> { |
| |
| static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() { |
| return dsymutil::BinaryHolder::ArchiveEntry::KeyTy(); |
| } |
| |
| static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() { |
| return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {}); |
| } |
| |
| static unsigned |
| getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) { |
| return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename), |
| DenseMapInfo<unsigned>::getHashValue( |
| K.Timestamp.time_since_epoch().count())); |
| } |
| |
| static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS, |
| const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) { |
| return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp; |
| } |
| }; |
| |
| } // namespace llvm |
| #endif |