diff options
Diffstat (limited to 'include/lldb/Utility/Reproducer.h')
-rw-r--r-- | include/lldb/Utility/Reproducer.h | 99 |
1 files changed, 87 insertions, 12 deletions
diff --git a/include/lldb/Utility/Reproducer.h b/include/lldb/Utility/Reproducer.h index 670041d06bbac..3db98a781d4ce 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 |