BinaryHolder.h 5.9 KB

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