xref: /openbsd-src/gnu/llvm/llvm/tools/dsymutil/BinaryHolder.h (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
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