Warning: This file is not a C or C++ file. It does not have highlighting.

1//===-- Reproducer.h --------------------------------------------*- C++ -*-===//
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#ifndef LLDB_UTILITY_REPRODUCER_H
10#define LLDB_UTILITY_REPRODUCER_H
11
12#include "lldb/Utility/FileSpec.h"
13#include "llvm/ADT/DenseMap.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/Support/Error.h"
16#include "llvm/Support/VirtualFileSystem.h"
17#include "llvm/Support/YAMLTraits.h"
18
19#include <mutex>
20#include <string>
21#include <utility>
22#include <vector>
23
24namespace lldb_private {
25class UUID;
26namespace repro {
27
28class Reproducer;
29
30enum class ReproducerMode {
31 Capture,
32 Off,
33};
34
35/// The provider defines an interface for generating files needed for
36/// reproducing.
37///
38/// Different components will implement different providers.
39class ProviderBase {
40public:
41 virtual ~ProviderBase() = default;
42
43 const FileSpec &GetRoot() const { return m_root; }
44
45 /// The Keep method is called when it is decided that we need to keep the
46 /// data in order to provide a reproducer.
47 virtual void Keep(){};
48
49 /// The Discard method is called when it is decided that we do not need to
50 /// keep any information and will not generate a reproducer.
51 virtual void Discard(){};
52
53 // Returns the class ID for this type.
54 static const void *ClassID() { return &ID; }
55
56 // Returns the class ID for the dynamic type of this Provider instance.
57 virtual const void *DynamicClassID() const = 0;
58
59 virtual llvm::StringRef GetName() const = 0;
60 virtual llvm::StringRef GetFile() const = 0;
61
62protected:
63 ProviderBase(const FileSpec &root) : m_root(root) {}
64
65private:
66 /// Every provider knows where to dump its potential files.
67 FileSpec m_root;
68
69 virtual void anchor();
70 static char ID;
71};
72
73template <typename ThisProviderT> class Provider : public ProviderBase {
74public:
75 static const void *ClassID() { return &ThisProviderT::ID; }
76
77 const void *DynamicClassID() const override { return &ThisProviderT::ID; }
78
79 llvm::StringRef GetName() const override { return ThisProviderT::Info::name; }
80 llvm::StringRef GetFile() const override { return ThisProviderT::Info::file; }
81
82protected:
83 using ProviderBase::ProviderBase; // Inherit constructor.
84};
85
86/// The generator is responsible for the logic needed to generate a
87/// reproducer. For doing so it relies on providers, who serialize data that
88/// is necessary for reproducing a failure.
89class Generator final {
90
91public:
92 Generator(FileSpec root);
93 ~Generator();
94
95 /// Method to indicate we want to keep the reproducer. If reproducer
96 /// generation is disabled, this does nothing.
97 void Keep();
98
99 /// Method to indicate we do not want to keep the reproducer. This is
100 /// unaffected by whether or not generation reproduction is enabled, as we
101 /// might need to clean up files already written to disk.
102 void Discard();
103
104 /// Enable or disable auto generate.
105 void SetAutoGenerate(bool b);
106
107 /// Return whether auto generate is enabled.
108 bool IsAutoGenerate() const;
109
110 /// Create and register a new provider.
111 template <typename T> T *Create() {
112 std::unique_ptr<ProviderBase> provider = std::make_unique<T>(m_root);
113 return static_cast<T *>(Register(std::move(provider)));
114 }
115
116 /// Get an existing provider.
117 template <typename T> T *Get() {
118 auto it = m_providers.find(T::ClassID());
119 if (it == m_providers.end())
120 return nullptr;
121 return static_cast<T *>(it->second.get());
122 }
123
124 /// Get a provider if it exists, otherwise create it.
125 template <typename T> T &GetOrCreate() {
126 auto *provider = Get<T>();
127 if (provider)
128 return *provider;
129 return *Create<T>();
130 }
131
132 const FileSpec &GetRoot() const;
133
134private:
135 friend Reproducer;
136
137 ProviderBase *Register(std::unique_ptr<ProviderBase> provider);
138
139 /// Builds and index with provider info.
140 void AddProvidersToIndex();
141
142 /// Map of provider IDs to provider instances.
143 llvm::DenseMap<const void *, std::unique_ptr<ProviderBase>> m_providers;
144 std::mutex m_providers_mutex;
145
146 /// The reproducer root directory.
147 FileSpec m_root;
148
149 /// Flag to ensure that we never call both keep and discard.
150 bool m_done = false;
151
152 /// Flag to auto generate a reproducer when it would otherwise be discarded.
153 bool m_auto_generate = false;
154};
155
156class Loader final {
157public:
158 Loader(FileSpec root, bool passive = false);
159
160 template <typename T> FileSpec GetFile() {
161 if (!HasFile(T::file))
162 return {};
163
164 return GetRoot().CopyByAppendingPathComponent(T::file);
165 }
166
167 template <typename T> llvm::Expected<std::string> LoadBuffer() {
168 FileSpec file = GetFile<typename T::Info>();
169 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
170 llvm::vfs::getRealFileSystem()->getBufferForFile(file.GetPath());
171 if (!buffer)
172 return llvm::errorCodeToError(buffer.getError());
173 return (*buffer)->getBuffer().str();
174 }
175
176 llvm::Error LoadIndex();
177
178 const FileSpec &GetRoot() const { return m_root; }
179
180private:
181 bool HasFile(llvm::StringRef file);
182
183 FileSpec m_root;
184 std::vector<std::string> m_files;
185 bool m_loaded;
186};
187
188/// The reproducer enables clients to obtain access to the Generator and
189/// Loader.
190class Reproducer {
191public:
192 static Reproducer &Instance();
193 static llvm::Error Initialize(ReproducerMode mode,
194 llvm::Optional<FileSpec> root);
195 static void Initialize();
196 static bool Initialized();
197 static void Terminate();
198
199 Reproducer() = default;
200
201 Generator *GetGenerator();
202 Loader *GetLoader();
203
204 const Generator *GetGenerator() const;
205 const Loader *GetLoader() const;
206
207 FileSpec GetReproducerPath() const;
208
209 bool IsCapturing() { return static_cast<bool>(m_generator); };
210
211protected:
212 llvm::Error SetCapture(llvm::Optional<FileSpec> root);
213
214private:
215 static llvm::Optional<Reproducer> &InstanceImpl();
216
217 llvm::Optional<Generator> m_generator;
218 llvm::Optional<Loader> m_loader;
219
220 mutable std::mutex m_mutex;
221};
222
223struct ReplayOptions {
224 bool verify = true;
225 bool check_version = true;
226};
227
228} // namespace repro
229} // namespace lldb_private
230
231#endif // LLDB_UTILITY_REPRODUCER_H
232

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of lldb/include/lldb/Utility/Reproducer.h