LLDB  mainline
Reproducer.h
Go to the documentation of this file.
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 
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 struct FileInfo {
86  static const char *name;
87  static const char *file;
88 };
89 
90 class FileProvider : public Provider<FileProvider> {
91 public:
92  typedef FileInfo info;
93 
94  FileProvider(const FileSpec &directory)
95  : Provider(directory),
96  m_collector(directory.CopyByAppendingPathComponent("root")) {}
97 
98  FileCollector &GetFileCollector() { return m_collector; }
99 
100  void Keep() override {
101  auto mapping = GetRoot().CopyByAppendingPathComponent(info::file);
102  // Temporary files that are removed during execution can cause copy errors.
103  if (auto ec = m_collector.CopyFiles(/*stop_on_error=*/false))
104  return;
105  m_collector.WriteMapping(mapping);
106  }
107 
108  static char ID;
109 
110 private:
111  FileCollector m_collector;
112 };
113 
115 public:
116  DataRecorder(FileSpec filename, std::error_code &ec)
117  : m_filename(std::move(filename)),
118  m_os(m_filename.GetPath(), ec, llvm::sys::fs::F_Text), m_record(true) {}
119 
120  static llvm::Expected<std::unique_ptr<DataRecorder>>
121  Create(FileSpec filename);
122 
123  template <typename T> void Record(const T &t, bool newline = false) {
124  if (!m_record)
125  return;
126  m_os << t;
127  if (newline)
128  m_os << '\n';
129  }
130 
131  const FileSpec &GetFilename() { return m_filename; }
132 
133  void Stop() {
134  assert(m_record);
135  m_record = false;
136  }
137 
138 private:
139  FileSpec m_filename;
140  llvm::raw_fd_ostream m_os;
141  bool m_record;
142 };
143 
144 struct CommandInfo {
145  static const char *name;
146  static const char *file;
147 };
148 
149 class CommandProvider : public Provider<CommandProvider> {
150 public:
151  typedef CommandInfo info;
152 
153  CommandProvider(const FileSpec &directory) : Provider(directory) {}
154 
155  DataRecorder *GetNewDataRecorder();
156 
157  void Keep() override;
158  void Discard() override;
159 
160  static char ID;
161 
162 private:
163  std::vector<std::unique_ptr<DataRecorder>> m_data_recorders;
164 };
165 
166 /// The generator is responsible for the logic needed to generate a
167 /// reproducer. For doing so it relies on providers, who serialize data that
168 /// is necessary for reproducing a failure.
169 class Generator final {
170 public:
171  Generator(const FileSpec &root);
172  ~Generator();
173 
174  /// Method to indicate we want to keep the reproducer. If reproducer
175  /// generation is disabled, this does nothing.
176  void Keep();
177 
178  /// Method to indicate we do not want to keep the reproducer. This is
179  /// unaffected by whether or not generation reproduction is enabled, as we
180  /// might need to clean up files already written to disk.
181  void Discard();
182 
183  /// Create and register a new provider.
184  template <typename T> T *Create() {
185  std::unique_ptr<ProviderBase> provider = llvm::make_unique<T>(m_root);
186  return static_cast<T *>(Register(std::move(provider)));
187  }
188 
189  /// Get an existing provider.
190  template <typename T> T *Get() {
191  auto it = m_providers.find(T::ClassID());
192  if (it == m_providers.end())
193  return nullptr;
194  return static_cast<T *>(it->second.get());
195  }
196 
197  /// Get a provider if it exists, otherwise create it.
198  template <typename T> T &GetOrCreate() {
199  auto *provider = Get<T>();
200  if (provider)
201  return *provider;
202  return *Create<T>();
203  }
204 
205  const FileSpec &GetRoot() const;
206 
207 private:
208  friend Reproducer;
209 
210  ProviderBase *Register(std::unique_ptr<ProviderBase> provider);
211 
212  /// Builds and index with provider info.
213  void AddProvidersToIndex();
214 
215  /// Map of provider IDs to provider instances.
216  llvm::DenseMap<const void *, std::unique_ptr<ProviderBase>> m_providers;
217  std::mutex m_providers_mutex;
218 
219  /// The reproducer root directory.
220  FileSpec m_root;
221 
222  /// Flag to ensure that we never call both keep and discard.
223  bool m_done;
224 };
225 
226 class Loader final {
227 public:
228  Loader(const FileSpec &root);
229 
230  template <typename T> FileSpec GetFile() {
231  if (!HasFile(T::file))
232  return {};
233 
234  return GetRoot().CopyByAppendingPathComponent(T::file);
235  }
236 
237  llvm::Error LoadIndex();
238 
239  const FileSpec &GetRoot() const { return m_root; }
240 
241 private:
242  bool HasFile(llvm::StringRef file);
243 
244  FileSpec m_root;
245  std::vector<std::string> m_files;
246  bool m_loaded;
247 };
248 
249 /// The reproducer enables clients to obtain access to the Generator and
250 /// Loader.
251 class Reproducer {
252 public:
253  static Reproducer &Instance();
254  static llvm::Error Initialize(ReproducerMode mode,
255  llvm::Optional<FileSpec> root);
256  static bool Initialized();
257  static void Terminate();
258 
259  Reproducer() = default;
260 
261  Generator *GetGenerator();
262  Loader *GetLoader();
263 
264  const Generator *GetGenerator() const;
265  const Loader *GetLoader() const;
266 
267  FileSpec GetReproducerPath() const;
268 
269 protected:
270  llvm::Error SetCapture(llvm::Optional<FileSpec> root);
271  llvm::Error SetReplay(llvm::Optional<FileSpec> root);
272 
273 private:
274  static llvm::Optional<Reproducer> &InstanceImpl();
275 
276  llvm::Optional<Generator> m_generator;
277  llvm::Optional<Loader> m_loader;
278 
279  mutable std::mutex m_mutex;
280 };
281 
282 } // namespace repro
283 } // namespace lldb_private
284 
285 #endif // LLDB_UTILITY_REPRODUCER_H
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
Definition: Debugger.h:71
void Keep() override
The Keep method is called when it is decided that we need to keep the data in order to provide a repr...
Definition: Reproducer.h:100
const FileSpec & GetRoot() const
Definition: Reproducer.h:239
ProviderBase(const FileSpec &root)
Definition: Reproducer.h:62
llvm::Error Error
static const char * file
Definition: Reproducer.h:87
const void * DynamicClassID() const override
Definition: Reproducer.h:76
A file utility class.
Definition: FileSpec.h:55
DataRecorder(FileSpec filename, std::error_code &ec)
Definition: Reproducer.h:116
CommandProvider(const FileSpec &directory)
Definition: Reproducer.h:153
The reproducer enables clients to obtain access to the Generator and Loader.
Definition: Reproducer.h:251
const FileSpec & GetFilename()
Definition: Reproducer.h:131
static const void * ClassID()
Definition: Reproducer.h:53
FileSpec CopyByAppendingPathComponent(llvm::StringRef component) const
Definition: FileSpec.cpp:428
static const char * name
Definition: Reproducer.h:145
llvm::StringRef GetName() const override
Definition: Reproducer.h:78
static const char * file
Definition: Reproducer.h:146
Collects files into a directory and generates a mapping that can be used by the VFS.
Definition: FileCollector.h:26
const FileSpec & GetRoot() const
Definition: Reproducer.h:42
static char ID
The provider defines an interface for generating files needed for reproducing.
Definition: Reproducer.h:38
static const char * name
Definition: Reproducer.h:86
The generator is responsible for the logic needed to generate a reproducer.
Definition: Reproducer.h:169
virtual void Keep()
The Keep method is called when it is decided that we need to keep the data in order to provide a repr...
Definition: Reproducer.h:46
static const void * ClassID()
Definition: Reproducer.h:74
llvm::StringRef GetFile() const override
Definition: Reproducer.h:79
FileProvider(const FileSpec &directory)
Definition: Reproducer.h:94
T * Get()
Get an existing provider.
Definition: Reproducer.h:190
FileCollector & GetFileCollector()
Definition: Reproducer.h:98
T & GetOrCreate()
Get a provider if it exists, otherwise create it.
Definition: Reproducer.h:198
void Record(const T &t, bool newline=false)
Definition: Reproducer.h:123
T * Create()
Create and register a new provider.
Definition: Reproducer.h:184
virtual void Discard()
The Discard method is called when it is decided that we do not need to keep any information and will ...
Definition: Reproducer.h:50