diff options
Diffstat (limited to 'include/lldb/Utility/Reproducer.h')
-rw-r--r-- | include/lldb/Utility/Reproducer.h | 154 |
1 files changed, 121 insertions, 33 deletions
diff --git a/include/lldb/Utility/Reproducer.h b/include/lldb/Utility/Reproducer.h index ea315ad771a6..670041d06bba 100644 --- a/include/lldb/Utility/Reproducer.h +++ b/include/lldb/Utility/Reproducer.h @@ -1,15 +1,15 @@ //===-- Reproducer.h --------------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #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" @@ -31,24 +31,14 @@ enum class ReproducerMode { Off, }; -/// Abstraction for information associated with a provider. This information -/// is serialized into an index which is used by the loader. -struct ProviderInfo { - std::string name; - std::vector<std::string> files; -}; - /// The provider defines an interface for generating files needed for -/// reproducing. The provider must populate its ProviderInfo to communicate -/// its name and files to the index, before registering with the generator, -/// i.e. in the constructor. +/// reproducing. /// /// Different components will implement different providers. class ProviderBase { public: virtual ~ProviderBase() = default; - const ProviderInfo &GetInfo() const { return m_info; } const FileSpec &GetRoot() const { return m_root; } /// The Keep method is called when it is decided that we need to keep the @@ -65,11 +55,12 @@ public: // Returns the class ID for the dynamic type of this Provider instance. virtual const void *DynamicClassID() const = 0; + virtual llvm::StringRef GetName() const = 0; + virtual llvm::StringRef GetFile() const = 0; + protected: ProviderBase(const FileSpec &root) : m_root(root) {} - /// Every provider keeps track of its own files. - ProviderInfo m_info; private: /// Every provider knows where to dump its potential files. FileSpec m_root; @@ -84,10 +75,112 @@ public: const void *DynamicClassID() const override { return &ThisProviderT::ID; } + llvm::StringRef GetName() const override { return ThisProviderT::Info::name; } + llvm::StringRef GetFile() const override { return ThisProviderT::Info::file; } + protected: using ProviderBase::ProviderBase; // Inherit constructor. }; +class FileProvider : public Provider<FileProvider> { +public: + struct Info { + static const char *name; + static const char *file; + }; + + FileProvider(const FileSpec &directory) + : Provider(directory), + m_collector(directory.CopyByAppendingPathComponent("root"), directory) { + } + + 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)) + return; + m_collector.WriteMapping(mapping); + } + + static char ID; + +private: + FileCollector m_collector; +}; + +/// Provider for the LLDB version number. +/// +/// When the reproducer is kept, it writes the lldb version to a file named +/// version.txt in the reproducer root. +class VersionProvider : public Provider<VersionProvider> { +public: + VersionProvider(const FileSpec &directory) : Provider(directory) {} + struct Info { + static const char *name; + static const char *file; + }; + void SetVersion(std::string version) { + assert(m_version.empty()); + m_version = std::move(version); + } + void Keep() override; + std::string m_version; + 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) {} + + static llvm::Expected<std::unique_ptr<DataRecorder>> + Create(const FileSpec &filename); + + template <typename T> void Record(const T &t, bool newline = false) { + if (!m_record) + return; + m_os << t; + if (newline) + m_os << '\n'; + m_os.flush(); + } + + const FileSpec &GetFilename() { return m_filename; } + + void Stop() { + assert(m_record); + m_record = false; + } + +private: + FileSpec m_filename; + llvm::raw_fd_ostream m_os; + bool m_record; +}; + +class CommandProvider : public Provider<CommandProvider> { +public: + struct Info { + static const char *name; + static const char *file; + }; + + CommandProvider(const FileSpec &directory) : Provider(directory) {} + + DataRecorder *GetNewDataRecorder(); + + void Keep() override; + void Discard() override; + + static char ID; + +private: + std::vector<std::unique_ptr<DataRecorder>> m_data_recorders; +}; + /// 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. @@ -152,14 +245,22 @@ class Loader final { public: Loader(const FileSpec &root); - llvm::Optional<ProviderInfo> GetProviderInfo(llvm::StringRef name); + template <typename T> FileSpec GetFile() { + if (!HasFile(T::file)) + return {}; + + return GetRoot().CopyByAppendingPathComponent(T::file); + } + llvm::Error LoadIndex(); const FileSpec &GetRoot() const { return m_root; } private: - llvm::StringMap<ProviderInfo> m_provider_info; + bool HasFile(llvm::StringRef file); + FileSpec m_root; + std::vector<std::string> m_files; bool m_loaded; }; @@ -170,6 +271,7 @@ public: static Reproducer &Instance(); static llvm::Error Initialize(ReproducerMode mode, llvm::Optional<FileSpec> root); + static bool Initialized(); static void Terminate(); Reproducer() = default; @@ -198,18 +300,4 @@ private: } // namespace repro } // namespace lldb_private -LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(lldb_private::repro::ProviderInfo) - -namespace llvm { -namespace yaml { - -template <> struct MappingTraits<lldb_private::repro::ProviderInfo> { - static void mapping(IO &io, lldb_private::repro::ProviderInfo &info) { - io.mapRequired("name", info.name); - io.mapOptional("files", info.files); - } -}; -} // namespace yaml -} // namespace llvm - #endif // LLDB_UTILITY_REPRODUCER_H |