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/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 "llvm/TargetParser/Triple.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
>;
42 Options(bool Verbose
= false, bool Warn
= true)
43 : Verbose(Verbose
), Warn(Warn
) {}
48 BinaryHolder(IntrusiveRefCntPtr
<vfs::FileSystem
> VFS
,
49 BinaryHolder::Options Opts
= {});
51 // Forward declarations for friend declaration.
55 /// Base class shared by cached entries, representing objects and archives.
58 std::unique_ptr
<MemoryBuffer
> MemBuffer
;
59 std::unique_ptr
<object::MachOUniversalBinary
> FatBinary
;
60 std::string FatBinaryName
;
63 /// Cached entry holding one or more (in case of a fat binary) object files.
64 class ObjectEntry
: public EntryBase
{
66 /// Load the given object binary in memory.
67 Error
load(IntrusiveRefCntPtr
<vfs::FileSystem
> VFS
, StringRef Filename
,
68 TimestampTy Timestamp
, BinaryHolder::Options
= {});
70 /// Access all owned ObjectFiles.
71 std::vector
<const object::ObjectFile
*> getObjects() const;
73 /// Access to a derived version of all the currently owned ObjectFiles. The
74 /// conversion might be invalid, in which case an Error is returned.
75 template <typename ObjectFileType
>
76 Expected
<std::vector
<const ObjectFileType
*>> getObjectsAs() const {
77 std::vector
<const ObjectFileType
*> Result
;
78 Result
.reserve(Objects
.size());
79 for (auto &Object
: Objects
) {
80 const auto *Derived
= dyn_cast
<ObjectFileType
>(Object
.get());
82 return errorCodeToError(object::object_error::invalid_file_type
);
83 Result
.push_back(Derived
);
88 /// Access the owned ObjectFile with architecture \p T.
89 Expected
<const object::ObjectFile
&> getObject(const Triple
&T
) const;
91 /// Access to a derived version of the currently owned ObjectFile with
92 /// architecture \p T. The conversion must be known to be valid.
93 template <typename ObjectFileType
>
94 Expected
<const ObjectFileType
&> getObjectAs(const Triple
&T
) const {
95 auto Object
= getObject(T
);
97 return Object
.takeError();
98 return cast
<ObjectFileType
>(*Object
);
102 std::vector
<std::unique_ptr
<object::ObjectFile
>> Objects
;
106 /// Cached entry holding one or more (in the of a fat binary) archive files.
107 class ArchiveEntry
: public EntryBase
{
110 std::string Filename
;
111 TimestampTy Timestamp
;
114 KeyTy(StringRef Filename
, TimestampTy Timestamp
)
115 : Filename(Filename
.str()), Timestamp(Timestamp
) {}
118 /// Load the given object binary in memory.
119 Error
load(IntrusiveRefCntPtr
<vfs::FileSystem
> VFS
, StringRef Filename
,
120 TimestampTy Timestamp
, BinaryHolder::Options
= {});
122 Expected
<const ObjectEntry
&> getObjectEntry(StringRef Filename
,
123 TimestampTy Timestamp
,
124 BinaryHolder::Options
= {});
127 std::vector
<std::unique_ptr
<object::Archive
>> Archives
;
128 DenseMap
<KeyTy
, std::unique_ptr
<ObjectEntry
>> MemberCache
;
129 std::mutex MemberCacheMutex
;
132 Expected
<const ObjectEntry
&>
133 getObjectEntry(StringRef Filename
, TimestampTy Timestamp
= TimestampTy());
136 void eraseObjectEntry(StringRef Filename
);
139 /// Cache of static archives. Objects that are part of a static archive are
140 /// stored under this object, rather than in the map below.
141 StringMap
<std::unique_ptr
<ArchiveEntry
>> ArchiveCache
;
142 StringMap
<uint32_t> ArchiveRefCounter
;
143 std::mutex ArchiveCacheMutex
;
145 /// Object entries for objects that are not in a static archive.
146 StringMap
<std::unique_ptr
<ObjectEntry
>> ObjectCache
;
147 StringMap
<uint32_t> ObjectRefCounter
;
148 std::mutex ObjectCacheMutex
;
150 /// Virtual File System instance.
151 IntrusiveRefCntPtr
<vfs::FileSystem
> VFS
;
156 } // namespace dsymutil
158 template <> struct DenseMapInfo
<dsymutil::BinaryHolder::ArchiveEntry::KeyTy
> {
160 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy
getEmptyKey() {
161 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy();
164 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy
getTombstoneKey() {
165 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {});
169 getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy
&K
) {
170 return hash_combine(DenseMapInfo
<StringRef
>::getHashValue(K
.Filename
),
171 DenseMapInfo
<unsigned>::getHashValue(
172 K
.Timestamp
.time_since_epoch().count()));
175 static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy
&LHS
,
176 const dsymutil::BinaryHolder::ArchiveEntry::KeyTy
&RHS
) {
177 return LHS
.Filename
== RHS
.Filename
&& LHS
.Timestamp
== RHS
.Timestamp
;