blob: c78bff2f8f3132c878ef00def4292568cfc1ec33 [file] [log] [blame]
Frederic Riss5a0743e2015-01-05 21:29:28 +00001//===-- BinaryHolder.h - Utility class for accessing binaries -------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This program is a utility that aims to be a dropin replacement for
11// Darwin's dsymutil.
12//
13//===----------------------------------------------------------------------===//
14#ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
15#define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
16
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +000017#include "llvm/ADT/DenseMap.h"
Frederic Riss155629662015-07-24 06:41:04 +000018#include "llvm/ADT/Triple.h"
Frederic Riss5a0743e2015-01-05 21:29:28 +000019#include "llvm/Object/Archive.h"
20#include "llvm/Object/Error.h"
Frederic Rissfa7f7bd2015-07-24 06:41:11 +000021#include "llvm/Object/MachOUniversal.h"
Frederic Riss5a0743e2015-01-05 21:29:28 +000022#include "llvm/Object/ObjectFile.h"
Pavel Labath73ce0c02016-11-09 11:43:52 +000023#include "llvm/Support/Chrono.h"
Frederic Riss5a0743e2015-01-05 21:29:28 +000024#include "llvm/Support/Errc.h"
25#include "llvm/Support/ErrorOr.h"
26
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +000027#include <mutex>
28
Frederic Riss5a0743e2015-01-05 21:29:28 +000029namespace llvm {
30namespace dsymutil {
31
Jonas Devlieghere9f33bbfe2018-06-29 16:51:52 +000032/// The BinaryHolder class is responsible for creating and owning
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +000033/// ObjectFiles and their underlying MemoryBuffers. It differs from a simple
34/// OwningBinary in that it handles accessing and caching of archives and its
35/// members.
Jonas Devlieghere9f33bbfe2018-06-29 16:51:52 +000036class BinaryHolder {
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +000037public:
38 using TimestampTy = sys::TimePoint<std::chrono::seconds>;
39
Jonas Devlieghere9f33bbfe2018-06-29 16:51:52 +000040 BinaryHolder(bool Verbose = false) : Verbose(Verbose) {}
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +000041
42 // Forward declarations for friend declaration.
43 class ObjectEntry;
44 class ArchiveEntry;
45
46 /// Base class shared by cached entries, representing objects and archives.
47 class EntryBase {
48 protected:
Jonas Devlieghered36457d2018-06-29 17:11:34 +000049 std::unique_ptr<MemoryBuffer> MemBuffer;
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +000050 std::unique_ptr<object::MachOUniversalBinary> FatBinary;
51 std::string FatBinaryName;
52 };
53
54 /// Cached entry holding one or more (in case of a fat binary) object files.
55 class ObjectEntry : public EntryBase {
56 public:
57 /// Load the given object binary in memory.
58 Error load(StringRef Filename, bool Verbose = false);
59
60 /// Access all owned ObjectFiles.
61 std::vector<const object::ObjectFile *> getObjects() const;
62
63 /// Access to a derived version of all the currently owned ObjectFiles. The
64 /// conversion might be invalid, in which case an Error is returned.
65 template <typename ObjectFileType>
66 Expected<std::vector<const ObjectFileType *>> getObjectsAs() const {
Jonas Devlieghere9f33bbfe2018-06-29 16:51:52 +000067 std::vector<const ObjectFileType *> Result;
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +000068 Result.reserve(Objects.size());
69 for (auto &Object : Objects) {
70 const auto *Derived = dyn_cast<ObjectFileType>(Object.get());
71 if (!Derived)
72 return errorCodeToError(object::object_error::invalid_file_type);
73 Result.push_back(Derived);
74 }
75 return Result;
76 }
77
78 /// Access the owned ObjectFile with architecture \p T.
79 Expected<const object::ObjectFile &> getObject(const Triple &T) const;
80
81 /// Access to a derived version of the currently owned ObjectFile with
82 /// architecture \p T. The conversion must be known to be valid.
83 template <typename ObjectFileType>
84 Expected<const ObjectFileType &> getObjectAs(const Triple &T) const {
85 auto Object = getObject(T);
86 if (!Object)
87 return Object.takeError();
88 return cast<ObjectFileType>(*Object);
89 }
90
91 private:
92 std::vector<std::unique_ptr<object::ObjectFile>> Objects;
93 friend ArchiveEntry;
94 };
95
96 /// Cached entry holding one or more (in the of a fat binary) archive files.
97 class ArchiveEntry : public EntryBase {
98 public:
99 struct KeyTy {
100 std::string Filename;
101 TimestampTy Timestamp;
102
103 KeyTy() : Filename(), Timestamp() {}
104 KeyTy(StringRef Filename, TimestampTy Timestamp)
105 : Filename(Filename.str()), Timestamp(Timestamp) {}
106 };
107
108 /// Load the given object binary in memory.
109 Error load(StringRef Filename, TimestampTy Timestamp, bool Verbose = false);
110
111 Expected<const ObjectEntry &> getObjectEntry(StringRef Filename,
112 TimestampTy Timestamp,
113 bool Verbose = false);
114
115 private:
116 std::vector<std::unique_ptr<object::Archive>> Archives;
117 DenseMap<KeyTy, ObjectEntry> MemberCache;
118 std::mutex MemberCacheMutex;
119 };
120
Jonas Devlieghere9f33bbfe2018-06-29 16:51:52 +0000121 Expected<const ObjectEntry &>
122 getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy());
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +0000123
124 void clear();
125
126private:
127 /// Cache of static archives. Objects that are part of a static archive are
128 /// stored under this object, rather than in the map below.
129 StringMap<ArchiveEntry> ArchiveCache;
130 std::mutex ArchiveCacheMutex;
131
132 /// Object entries for objects that are not in a static archive.
133 StringMap<ObjectEntry> ObjectCache;
134 std::mutex ObjectCacheMutex;
135
136 bool Verbose;
137};
138
Jonas Devlieghere3ad0c5a2018-02-22 11:32:51 +0000139} // namespace dsymutil
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +0000140
Jonas Devlieghere9f33bbfe2018-06-29 16:51:52 +0000141template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> {
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +0000142
Jonas Devlieghere9f33bbfe2018-06-29 16:51:52 +0000143 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() {
144 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy();
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +0000145 }
146
Jonas Devlieghere9f33bbfe2018-06-29 16:51:52 +0000147 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() {
148 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {});
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +0000149 }
150
151 static unsigned
Jonas Devlieghere9f33bbfe2018-06-29 16:51:52 +0000152 getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) {
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +0000153 return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename),
154 DenseMapInfo<unsigned>::getHashValue(
155 K.Timestamp.time_since_epoch().count()));
156 }
157
Jonas Devlieghere9f33bbfe2018-06-29 16:51:52 +0000158 static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS,
159 const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) {
Jonas Devlieghere4d3e6c12018-06-29 16:50:41 +0000160 return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp;
161 }
162};
163
Jonas Devlieghere3ad0c5a2018-02-22 11:32:51 +0000164} // namespace llvm
Frederic Riss5a0743e2015-01-05 21:29:28 +0000165#endif