aboutsummaryrefslogtreecommitdiffstats
path: root/include/lldb/Utility/Reproducer.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/lldb/Utility/Reproducer.h')
-rw-r--r--include/lldb/Utility/Reproducer.h99
1 files changed, 87 insertions, 12 deletions
diff --git a/include/lldb/Utility/Reproducer.h b/include/lldb/Utility/Reproducer.h
index 670041d06bba..3db98a781d4c 100644
--- a/include/lldb/Utility/Reproducer.h
+++ b/include/lldb/Utility/Reproducer.h
@@ -9,11 +9,10 @@
#ifndef LLDB_UTILITY_REPRODUCER_H
#define LLDB_UTILITY_REPRODUCER_H
-#include "lldb/Utility/FileCollector.h"
#include "lldb/Utility/FileSpec.h"
-
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/FileCollector.h"
#include "llvm/Support/YAMLTraits.h"
#include <mutex>
@@ -91,23 +90,26 @@ public:
FileProvider(const FileSpec &directory)
: Provider(directory),
- m_collector(directory.CopyByAppendingPathComponent("root"), directory) {
- }
+ m_collector(std::make_shared<llvm::FileCollector>(
+ directory.CopyByAppendingPathComponent("root").GetPath(),
+ directory.GetPath())) {}
- FileCollector &GetFileCollector() { return m_collector; }
+ std::shared_ptr<llvm::FileCollector> GetFileCollector() {
+ return m_collector;
+ }
void Keep() override {
auto mapping = GetRoot().CopyByAppendingPathComponent(Info::file);
// Temporary files that are removed during execution can cause copy errors.
- if (auto ec = m_collector.CopyFiles(/*stop_on_error=*/false))
+ if (auto ec = m_collector->copyFiles(/*stop_on_error=*/false))
return;
- m_collector.WriteMapping(mapping);
+ m_collector->writeMapping(mapping.GetPath());
}
static char ID;
private:
- FileCollector m_collector;
+ std::shared_ptr<llvm::FileCollector> m_collector;
};
/// Provider for the LLDB version number.
@@ -130,11 +132,32 @@ public:
static char ID;
};
+/// Provider for the LLDB current working directroy.
+///
+/// When the reproducer is kept, it writes lldb's current working directory to
+/// a file named cwd.txt in the reproducer root.
+class WorkingDirectoryProvider : public Provider<WorkingDirectoryProvider> {
+public:
+ WorkingDirectoryProvider(const FileSpec &directory) : Provider(directory) {
+ llvm::SmallString<128> cwd;
+ if (std::error_code EC = llvm::sys::fs::current_path(cwd))
+ return;
+ m_cwd = cwd.str();
+ }
+ struct Info {
+ static const char *name;
+ static const char *file;
+ };
+ void Keep() override;
+ std::string m_cwd;
+ static char ID;
+};
+
class DataRecorder {
public:
DataRecorder(const FileSpec &filename, std::error_code &ec)
: m_filename(filename.GetFilename().GetStringRef()),
- m_os(filename.GetPath(), ec, llvm::sys::fs::F_Text), m_record(true) {}
+ m_os(filename.GetPath(), ec, llvm::sys::fs::OF_Text), m_record(true) {}
static llvm::Expected<std::unique_ptr<DataRecorder>>
Create(const FileSpec &filename);
@@ -181,12 +204,39 @@ private:
std::vector<std::unique_ptr<DataRecorder>> m_data_recorders;
};
+class ProcessGDBRemoteProvider
+ : public repro::Provider<ProcessGDBRemoteProvider> {
+public:
+ struct Info {
+ static const char *name;
+ static const char *file;
+ };
+
+ ProcessGDBRemoteProvider(const FileSpec &directory) : Provider(directory) {}
+
+ llvm::raw_ostream *GetHistoryStream();
+
+ void SetCallback(std::function<void()> callback) {
+ m_callback = std::move(callback);
+ }
+
+ void Keep() override { m_callback(); }
+ void Discard() override { m_callback(); }
+
+ static char ID;
+
+private:
+ std::function<void()> m_callback;
+ std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
+};
+
/// The generator is responsible for the logic needed to generate a
/// reproducer. For doing so it relies on providers, who serialize data that
/// is necessary for reproducing a failure.
class Generator final {
+
public:
- Generator(const FileSpec &root);
+ Generator(FileSpec root);
~Generator();
/// Method to indicate we want to keep the reproducer. If reproducer
@@ -200,7 +250,7 @@ public:
/// Create and register a new provider.
template <typename T> T *Create() {
- std::unique_ptr<ProviderBase> provider = llvm::make_unique<T>(m_root);
+ std::unique_ptr<ProviderBase> provider = std::make_unique<T>(m_root);
return static_cast<T *>(Register(std::move(provider)));
}
@@ -243,7 +293,7 @@ private:
class Loader final {
public:
- Loader(const FileSpec &root);
+ Loader(FileSpec root);
template <typename T> FileSpec GetFile() {
if (!HasFile(T::file))
@@ -252,6 +302,15 @@ public:
return GetRoot().CopyByAppendingPathComponent(T::file);
}
+ template <typename T> llvm::Expected<std::string> LoadBuffer() {
+ FileSpec file = GetFile<typename T::Info>();
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
+ llvm::vfs::getRealFileSystem()->getBufferForFile(file.GetPath());
+ if (!buffer)
+ return llvm::errorCodeToError(buffer.getError());
+ return (*buffer)->getBuffer().str();
+ }
+
llvm::Error LoadIndex();
const FileSpec &GetRoot() const { return m_root; }
@@ -284,6 +343,9 @@ public:
FileSpec GetReproducerPath() const;
+ bool IsCapturing() { return static_cast<bool>(m_generator); };
+ bool IsReplaying() { return static_cast<bool>(m_loader); };
+
protected:
llvm::Error SetCapture(llvm::Optional<FileSpec> root);
llvm::Error SetReplay(llvm::Optional<FileSpec> root);
@@ -297,6 +359,19 @@ private:
mutable std::mutex m_mutex;
};
+/// Helper class for replaying commands through the reproducer.
+class CommandLoader {
+public:
+ CommandLoader(std::vector<std::string> files) : m_files(files) {}
+
+ static std::unique_ptr<CommandLoader> Create(Loader *loader);
+ llvm::Optional<std::string> GetNextFile();
+
+private:
+ std::vector<std::string> m_files;
+ unsigned m_index = 0;
+};
+
} // namespace repro
} // namespace lldb_private