]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/include/lldb/Utility/Reproducer.h
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / include / lldb / Utility / Reproducer.h
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/FileCollector.h"
13 #include "lldb/Utility/FileSpec.h"
14
15 #include "llvm/ADT/DenseMap.h"
16 #include "llvm/Support/Error.h"
17 #include "llvm/Support/YAMLTraits.h"
18
19 #include <mutex>
20 #include <string>
21 #include <vector>
22
23 namespace lldb_private {
24 namespace repro {
25
26 class Reproducer;
27
28 enum class ReproducerMode {
29   Capture,
30   Replay,
31   Off,
32 };
33
34 /// The provider defines an interface for generating files needed for
35 /// reproducing.
36 ///
37 /// Different components will implement different providers.
38 class ProviderBase {
39 public:
40   virtual ~ProviderBase() = default;
41
42   const FileSpec &GetRoot() const { return m_root; }
43
44   /// The Keep method is called when it is decided that we need to keep the
45   /// data in order to provide a reproducer.
46   virtual void Keep(){};
47
48   /// The Discard method is called when it is decided that we do not need to
49   /// keep any information and will not generate a reproducer.
50   virtual void Discard(){};
51
52   // Returns the class ID for this type.
53   static const void *ClassID() { return &ID; }
54
55   // Returns the class ID for the dynamic type of this Provider instance.
56   virtual const void *DynamicClassID() const = 0;
57
58   virtual llvm::StringRef GetName() const = 0;
59   virtual llvm::StringRef GetFile() const = 0;
60
61 protected:
62   ProviderBase(const FileSpec &root) : m_root(root) {}
63
64 private:
65   /// Every provider knows where to dump its potential files.
66   FileSpec m_root;
67
68   virtual void anchor();
69   static char ID;
70 };
71
72 template <typename ThisProviderT> class Provider : public ProviderBase {
73 public:
74   static const void *ClassID() { return &ThisProviderT::ID; }
75
76   const void *DynamicClassID() const override { return &ThisProviderT::ID; }
77
78   llvm::StringRef GetName() const override { return ThisProviderT::Info::name; }
79   llvm::StringRef GetFile() const override { return ThisProviderT::Info::file; }
80
81 protected:
82   using ProviderBase::ProviderBase; // Inherit constructor.
83 };
84
85 class FileProvider : public Provider<FileProvider> {
86 public:
87   struct Info {
88     static const char *name;
89     static const char *file;
90   };
91
92   FileProvider(const FileSpec &directory)
93       : Provider(directory),
94         m_collector(directory.CopyByAppendingPathComponent("root"), directory) {
95   }
96
97   FileCollector &GetFileCollector() { return m_collector; }
98
99   void Keep() override {
100     auto mapping = GetRoot().CopyByAppendingPathComponent(Info::file);
101     // Temporary files that are removed during execution can cause copy errors.
102     if (auto ec = m_collector.CopyFiles(/*stop_on_error=*/false))
103       return;
104     m_collector.WriteMapping(mapping);
105   }
106
107   static char ID;
108
109 private:
110   FileCollector m_collector;
111 };
112
113 /// Provider for the LLDB version number.
114 ///
115 /// When the reproducer is kept, it writes the lldb version to a file named
116 /// version.txt in the reproducer root.
117 class VersionProvider : public Provider<VersionProvider> {
118 public:
119   VersionProvider(const FileSpec &directory) : Provider(directory) {}
120   struct Info {
121     static const char *name;
122     static const char *file;
123   };
124   void SetVersion(std::string version) {
125     assert(m_version.empty());
126     m_version = std::move(version);
127   }
128   void Keep() override;
129   std::string m_version;
130   static char ID;
131 };
132
133 class DataRecorder {
134 public:
135   DataRecorder(const FileSpec &filename, std::error_code &ec)
136       : m_filename(filename.GetFilename().GetStringRef()),
137         m_os(filename.GetPath(), ec, llvm::sys::fs::F_Text), m_record(true) {}
138
139   static llvm::Expected<std::unique_ptr<DataRecorder>>
140   Create(const FileSpec &filename);
141
142   template <typename T> void Record(const T &t, bool newline = false) {
143     if (!m_record)
144       return;
145     m_os << t;
146     if (newline)
147       m_os << '\n';
148     m_os.flush();
149   }
150
151   const FileSpec &GetFilename() { return m_filename; }
152
153   void Stop() {
154     assert(m_record);
155     m_record = false;
156   }
157
158 private:
159   FileSpec m_filename;
160   llvm::raw_fd_ostream m_os;
161   bool m_record;
162 };
163
164 class CommandProvider : public Provider<CommandProvider> {
165 public:
166   struct Info {
167     static const char *name;
168     static const char *file;
169   };
170
171   CommandProvider(const FileSpec &directory) : Provider(directory) {}
172
173   DataRecorder *GetNewDataRecorder();
174
175   void Keep() override;
176   void Discard() override;
177
178   static char ID;
179
180 private:
181   std::vector<std::unique_ptr<DataRecorder>> m_data_recorders;
182 };
183
184 /// The generator is responsible for the logic needed to generate a
185 /// reproducer. For doing so it relies on providers, who serialize data that
186 /// is necessary for reproducing  a failure.
187 class Generator final {
188 public:
189   Generator(const FileSpec &root);
190   ~Generator();
191
192   /// Method to indicate we want to keep the reproducer. If reproducer
193   /// generation is disabled, this does nothing.
194   void Keep();
195
196   /// Method to indicate we do not want to keep the reproducer. This is
197   /// unaffected by whether or not generation reproduction is enabled, as we
198   /// might need to clean up files already written to disk.
199   void Discard();
200
201   /// Create and register a new provider.
202   template <typename T> T *Create() {
203     std::unique_ptr<ProviderBase> provider = llvm::make_unique<T>(m_root);
204     return static_cast<T *>(Register(std::move(provider)));
205   }
206
207   /// Get an existing provider.
208   template <typename T> T *Get() {
209     auto it = m_providers.find(T::ClassID());
210     if (it == m_providers.end())
211       return nullptr;
212     return static_cast<T *>(it->second.get());
213   }
214
215   /// Get a provider if it exists, otherwise create it.
216   template <typename T> T &GetOrCreate() {
217     auto *provider = Get<T>();
218     if (provider)
219       return *provider;
220     return *Create<T>();
221   }
222
223   const FileSpec &GetRoot() const;
224
225 private:
226   friend Reproducer;
227
228   ProviderBase *Register(std::unique_ptr<ProviderBase> provider);
229
230   /// Builds and index with provider info.
231   void AddProvidersToIndex();
232
233   /// Map of provider IDs to provider instances.
234   llvm::DenseMap<const void *, std::unique_ptr<ProviderBase>> m_providers;
235   std::mutex m_providers_mutex;
236
237   /// The reproducer root directory.
238   FileSpec m_root;
239
240   /// Flag to ensure that we never call both keep and discard.
241   bool m_done;
242 };
243
244 class Loader final {
245 public:
246   Loader(const FileSpec &root);
247
248   template <typename T> FileSpec GetFile() {
249     if (!HasFile(T::file))
250       return {};
251
252     return GetRoot().CopyByAppendingPathComponent(T::file);
253   }
254
255   llvm::Error LoadIndex();
256
257   const FileSpec &GetRoot() const { return m_root; }
258
259 private:
260   bool HasFile(llvm::StringRef file);
261
262   FileSpec m_root;
263   std::vector<std::string> m_files;
264   bool m_loaded;
265 };
266
267 /// The reproducer enables clients to obtain access to the Generator and
268 /// Loader.
269 class Reproducer {
270 public:
271   static Reproducer &Instance();
272   static llvm::Error Initialize(ReproducerMode mode,
273                                 llvm::Optional<FileSpec> root);
274   static bool Initialized();
275   static void Terminate();
276
277   Reproducer() = default;
278
279   Generator *GetGenerator();
280   Loader *GetLoader();
281
282   const Generator *GetGenerator() const;
283   const Loader *GetLoader() const;
284
285   FileSpec GetReproducerPath() const;
286
287 protected:
288   llvm::Error SetCapture(llvm::Optional<FileSpec> root);
289   llvm::Error SetReplay(llvm::Optional<FileSpec> root);
290
291 private:
292   static llvm::Optional<Reproducer> &InstanceImpl();
293
294   llvm::Optional<Generator> m_generator;
295   llvm::Optional<Loader> m_loader;
296
297   mutable std::mutex m_mutex;
298 };
299
300 } // namespace repro
301 } // namespace lldb_private
302
303 #endif // LLDB_UTILITY_REPRODUCER_H