1 //===-- BinaryHolder.h - Utility class for accessing binaries -------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This program is a utility that aims to be a dropin replacement for
12 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
14 #define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
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"
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
39 using TimestampTy
= sys::TimePoint
<std::chrono::seconds
>;
41 BinaryHolder(IntrusiveRefCntPtr
<vfs::FileSystem
> VFS
, bool Verbose
= false)
42 : VFS(VFS
), Verbose(Verbose
) {}
44 // Forward declarations for friend declaration.
48 /// Base class shared by cached entries, representing objects and archives.
51 std::unique_ptr
<MemoryBuffer
> MemBuffer
;
52 std::unique_ptr
<object::MachOUniversalBinary
> FatBinary
;
53 std::string FatBinaryName
;
56 /// Cached entry holding one or more (in case of a fat binary) object files.
57 class ObjectEntry
: public EntryBase
{
59 /// Load the given object binary in memory.
60 Error
load(IntrusiveRefCntPtr
<vfs::FileSystem
> VFS
, StringRef Filename
,
61 TimestampTy Timestamp
, bool Verbose
= false);
63 /// Access all owned ObjectFiles.
64 std::vector
<const object::ObjectFile
*> getObjects() const;
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
>
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());
75 return errorCodeToError(object::object_error::invalid_file_type
);
76 Result
.push_back(Derived
);
81 /// Access the owned ObjectFile with architecture \p T.
82 Expected
<const object::ObjectFile
&> getObject(const Triple
&T
) const;
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
>
87 Expected
<const ObjectFileType
&> getObjectAs(const Triple
&T
) const {
88 auto Object
= getObject(T
);
90 return Object
.takeError();
91 return cast
<ObjectFileType
>(*Object
);
95 std::vector
<std::unique_ptr
<object::ObjectFile
>> Objects
;
99 /// Cached entry holding one or more (in the of a fat binary) archive files.
100 class ArchiveEntry
: public EntryBase
{
103 std::string Filename
;
104 TimestampTy Timestamp
;
107 KeyTy(StringRef Filename
, TimestampTy Timestamp
)
108 : Filename(Filename
.str()), Timestamp(Timestamp
) {}
111 /// Load the given object binary in memory.
112 Error
load(IntrusiveRefCntPtr
<vfs::FileSystem
> VFS
, StringRef Filename
,
113 TimestampTy Timestamp
, bool Verbose
= false);
115 Expected
<const ObjectEntry
&> getObjectEntry(StringRef Filename
,
116 TimestampTy Timestamp
,
117 bool Verbose
= false);
120 std::vector
<std::unique_ptr
<object::Archive
>> Archives
;
121 DenseMap
<KeyTy
, std::unique_ptr
<ObjectEntry
>> MemberCache
;
122 std::mutex MemberCacheMutex
;
125 Expected
<const ObjectEntry
&>
126 getObjectEntry(StringRef Filename
, TimestampTy Timestamp
= TimestampTy());
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
;
136 /// Object entries for objects that are not in a static archive.
137 StringMap
<std::unique_ptr
<ObjectEntry
>> ObjectCache
;
138 std::mutex ObjectCacheMutex
;
140 /// Virtual File System instance.
141 IntrusiveRefCntPtr
<vfs::FileSystem
> VFS
;
146 } // namespace dsymutil
148 template <> struct DenseMapInfo
<dsymutil::BinaryHolder::ArchiveEntry::KeyTy
> {
150 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy
getEmptyKey() {
151 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy();
154 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy
getTombstoneKey() {
155 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {});
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()));
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
;