[Lldb-commits] [lldb] bb894b9 - [lldb] Extract reproducer providers & co into their own header.

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Sat Aug 22 10:04:34 PDT 2020


Author: Jonas Devlieghere
Date: 2020-08-22T10:04:27-07:00
New Revision: bb894b97821a1c970ce0c3243aaebbfa94add15c

URL: https://github.com/llvm/llvm-project/commit/bb894b97821a1c970ce0c3243aaebbfa94add15c
DIFF: https://github.com/llvm/llvm-project/commit/bb894b97821a1c970ce0c3243aaebbfa94add15c.diff

LOG: [lldb] Extract reproducer providers & co into their own header.

Extract all the provider related logic from Reproducer.h and move it
into its own header ReproducerProvider.h. These classes are seeing most
of the development these days and this reorganization reduces
incremental compilation from ~520 to ~110 files when making changes to
the new header.

Added: 
    lldb/include/lldb/Utility/ReproducerProvider.h
    lldb/source/Utility/ReproducerProvider.cpp

Modified: 
    lldb/include/lldb/Core/IOHandler.h
    lldb/include/lldb/Utility/GDBRemote.h
    lldb/include/lldb/Utility/ProcessInfo.h
    lldb/include/lldb/Utility/Reproducer.h
    lldb/source/API/SBReproducerPrivate.h
    lldb/source/Core/IOHandler.cpp
    lldb/source/Host/common/Host.cpp
    lldb/source/Initialization/SystemInitializerCommon.cpp
    lldb/source/Interpreter/CommandInterpreter.cpp
    lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
    lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
    lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
    lldb/source/Utility/CMakeLists.txt
    lldb/source/Utility/ProcessInfo.cpp
    lldb/source/Utility/Reproducer.cpp
    lldb/unittests/Utility/ReproducerTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Core/IOHandler.h b/lldb/include/lldb/Core/IOHandler.h
index f29482c0c97a..c96dc1cd1888 100644
--- a/lldb/include/lldb/Core/IOHandler.h
+++ b/lldb/include/lldb/Core/IOHandler.h
@@ -15,7 +15,6 @@
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/Flags.h"
 #include "lldb/Utility/Predicate.h"
-#include "lldb/Utility/Reproducer.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/StringList.h"
 #include "lldb/lldb-defines.h"
@@ -32,6 +31,9 @@
 
 namespace lldb_private {
 class Debugger;
+namespace repro {
+class DataRecorder;
+}
 }
 
 namespace curses {

diff  --git a/lldb/include/lldb/Utility/GDBRemote.h b/lldb/include/lldb/Utility/GDBRemote.h
index f5749b7e6eaf..2ee706efbea2 100644
--- a/lldb/include/lldb/Utility/GDBRemote.h
+++ b/lldb/include/lldb/Utility/GDBRemote.h
@@ -10,7 +10,7 @@
 #define LLDB_UTILITY_GDBREMOTE_H
 
 #include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/Reproducer.h"
+#include "lldb/Utility/ReproducerProvider.h"
 #include "lldb/Utility/StreamString.h"
 #include "lldb/lldb-enumerations.h"
 #include "lldb/lldb-public.h"

diff  --git a/lldb/include/lldb/Utility/ProcessInfo.h b/lldb/include/lldb/Utility/ProcessInfo.h
index ec91060cda54..8f5a5f6d21fb 100644
--- a/lldb/include/lldb/Utility/ProcessInfo.h
+++ b/lldb/include/lldb/Utility/ProcessInfo.h
@@ -14,7 +14,6 @@
 #include "lldb/Utility/Environment.h"
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/NameMatches.h"
-#include "lldb/Utility/Reproducer.h"
 #include "llvm/Support/YAMLTraits.h"
 #include <vector>
 
@@ -217,40 +216,7 @@ class ProcessInstanceInfoMatch {
 };
 
 namespace repro {
-class ProcessInfoRecorder : public AbstractRecorder {
-public:
-  ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec)
-      : AbstractRecorder(filename, ec) {}
-
-  static llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
-  Create(const FileSpec &filename);
-
-  void Record(const ProcessInstanceInfoList &process_infos);
-};
-
-class ProcessInfoProvider : public repro::Provider<ProcessInfoProvider> {
-public:
-  struct Info {
-    static const char *name;
-    static const char *file;
-  };
-
-  ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {}
-
-  ProcessInfoRecorder *GetNewProcessInfoRecorder();
-
-  void Keep() override;
-  void Discard() override;
-
-  static char ID;
-
-private:
-  std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
-  std::vector<std::unique_ptr<ProcessInfoRecorder>> m_process_info_recorders;
-};
-
 llvm::Optional<ProcessInstanceInfoList> GetReplayProcessInstanceInfoList();
-
 } // namespace repro
 } // namespace lldb_private
 

diff  --git a/lldb/include/lldb/Utility/Reproducer.h b/lldb/include/lldb/Utility/Reproducer.h
index 8a406658fdfb..4dc6ddd51394 100644
--- a/lldb/include/lldb/Utility/Reproducer.h
+++ b/lldb/include/lldb/Utility/Reproducer.h
@@ -13,7 +13,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
-#include "llvm/Support/FileCollector.h"
+#include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Support/YAMLTraits.h"
 
 #include <mutex>
@@ -84,250 +84,6 @@ template <typename ThisProviderT> class Provider : public ProviderBase {
   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(std::make_shared<llvm::FileCollector>(
-            directory.CopyByAppendingPathComponent("root").GetPath(),
-            directory.GetPath())) {}
-
-  std::shared_ptr<llvm::FileCollector> GetFileCollector() {
-    return m_collector;
-  }
-
-  void RecordInterestingDirectory(const llvm::Twine &dir);
-  void RecordInterestingDirectoryRecursive(const llvm::Twine &dir);
-
-  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.GetPath());
-  }
-
-  static char ID;
-
-private:
-  std::shared_ptr<llvm::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;
-};
-
-/// Abstract provider to storing directory paths.
-template <typename T> class DirectoryProvider : public repro::Provider<T> {
-public:
-  DirectoryProvider(const FileSpec &root) : Provider<T>(root) {}
-  void SetDirectory(std::string directory) {
-    m_directory = std::move(directory);
-  }
-  llvm::StringRef GetDirectory() { return m_directory; }
-
-  void Keep() override {
-    FileSpec file = this->GetRoot().CopyByAppendingPathComponent(T::Info::file);
-    std::error_code ec;
-    llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
-    if (ec)
-      return;
-    os << m_directory << "\n";
-  }
-
-protected:
-  std::string m_directory;
-};
-
-/// Provider for the current working directory.
-///
-/// 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 DirectoryProvider<WorkingDirectoryProvider> {
-public:
-  WorkingDirectoryProvider(const FileSpec &directory)
-      : DirectoryProvider(directory) {
-    llvm::SmallString<128> cwd;
-    if (std::error_code EC = llvm::sys::fs::current_path(cwd))
-      return;
-    SetDirectory(std::string(cwd));
-  }
-  struct Info {
-    static const char *name;
-    static const char *file;
-  };
-  static char ID;
-};
-
-/// Provider for the home directory.
-///
-/// When the reproducer is kept, it writes the user's home directory to a file
-/// a file named home.txt in the reproducer root.
-class HomeDirectoryProvider : public DirectoryProvider<HomeDirectoryProvider> {
-public:
-  HomeDirectoryProvider(const FileSpec &directory)
-      : DirectoryProvider(directory) {
-    llvm::SmallString<128> home_dir;
-    llvm::sys::path::home_directory(home_dir);
-    SetDirectory(std::string(home_dir));
-  }
-  struct Info {
-    static const char *name;
-    static const char *file;
-  };
-  static char ID;
-};
-
-/// The recorder is a small object handed out by a provider to record data. It
-/// is commonly used in combination with a MultiProvider which is meant to
-/// record information for multiple instances of the same source of data.
-class AbstractRecorder {
-protected:
-  AbstractRecorder(const FileSpec &filename, std::error_code &ec)
-      : m_filename(filename.GetFilename().GetStringRef()),
-        m_os(filename.GetPath(), ec, llvm::sys::fs::OF_Text), m_record(true) {}
-
-public:
-  const FileSpec &GetFilename() { return m_filename; }
-
-  void Stop() {
-    assert(m_record);
-    m_record = false;
-  }
-
-private:
-  FileSpec m_filename;
-
-protected:
-  llvm::raw_fd_ostream m_os;
-  bool m_record;
-};
-
-/// Recorder that records its data as text to a file.
-class DataRecorder : public AbstractRecorder {
-public:
-  DataRecorder(const FileSpec &filename, std::error_code &ec)
-      : AbstractRecorder(filename, ec) {}
-
-  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();
-  }
-};
-
-/// Recorder that records its data as YAML to a file.
-class YamlRecorder : public AbstractRecorder {
-public:
-  YamlRecorder(const FileSpec &filename, std::error_code &ec)
-      : AbstractRecorder(filename, ec) {}
-
-  static llvm::Expected<std::unique_ptr<YamlRecorder>>
-  Create(const FileSpec &filename);
-
-  template <typename T> void Record(const T &t) {
-    if (!m_record)
-      return;
-    llvm::yaml::Output yout(m_os);
-    // The YAML traits are defined as non-const because they are used for
-    // serialization and deserialization. The cast is safe because
-    // serialization doesn't modify the object.
-    yout << const_cast<T &>(t);
-    m_os.flush();
-  }
-};
-
-/// The MultiProvider is a provider that hands out recorder which can be used
-/// to capture data for 
diff erent instances of the same object. The recorders
-/// can be passed around or stored as an instance member.
-///
-/// The Info::file for the MultiProvider contains an index of files for every
-/// recorder. Use the MultiLoader to read the index and get the individual
-/// files.
-template <typename T, typename V>
-class MultiProvider : public repro::Provider<V> {
-public:
-  MultiProvider(const FileSpec &directory) : Provider<V>(directory) {}
-
-  T *GetNewRecorder() {
-    std::size_t i = m_recorders.size() + 1;
-    std::string filename = (llvm::Twine(V::Info::name) + llvm::Twine("-") +
-                            llvm::Twine(i) + llvm::Twine(".yaml"))
-                               .str();
-    auto recorder_or_error =
-        T::Create(this->GetRoot().CopyByAppendingPathComponent(filename));
-    if (!recorder_or_error) {
-      llvm::consumeError(recorder_or_error.takeError());
-      return nullptr;
-    }
-
-    m_recorders.push_back(std::move(*recorder_or_error));
-    return m_recorders.back().get();
-  }
-
-  void Keep() override {
-    std::vector<std::string> files;
-    for (auto &recorder : m_recorders) {
-      recorder->Stop();
-      files.push_back(recorder->GetFilename().GetPath());
-    }
-
-    FileSpec file = this->GetRoot().CopyByAppendingPathComponent(V::Info::file);
-    std::error_code ec;
-    llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
-    if (ec)
-      return;
-    llvm::yaml::Output yout(os);
-    yout << files;
-  }
-
-  void Discard() override { m_recorders.clear(); }
-
-private:
-  std::vector<std::unique_ptr<T>> m_recorders;
-};
-
-class CommandProvider : public MultiProvider<DataRecorder, CommandProvider> {
-public:
-  struct Info {
-    static const char *name;
-    static const char *file;
-  };
-
-  CommandProvider(const FileSpec &directory)
-      : MultiProvider<DataRecorder, CommandProvider>(directory) {}
-
-  static char ID;
-};
-
 /// 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.
@@ -469,60 +225,6 @@ class Reproducer {
   mutable std::mutex m_mutex;
 };
 
-/// Loader for data captured with the MultiProvider. It will read the index and
-/// return the path to the files in the index.
-template <typename T> class MultiLoader {
-public:
-  MultiLoader(std::vector<std::string> files) : m_files(std::move(files)) {}
-
-  static std::unique_ptr<MultiLoader> Create(Loader *loader) {
-    if (!loader)
-      return {};
-
-    FileSpec file = loader->GetFile<typename T::Info>();
-    if (!file)
-      return {};
-
-    auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
-    if (auto err = error_or_file.getError())
-      return {};
-
-    std::vector<std::string> files;
-    llvm::yaml::Input yin((*error_or_file)->getBuffer());
-    yin >> files;
-
-    if (auto err = yin.error())
-      return {};
-
-    for (auto &file : files) {
-      FileSpec absolute_path =
-          loader->GetRoot().CopyByAppendingPathComponent(file);
-      file = absolute_path.GetPath();
-    }
-
-    return std::make_unique<MultiLoader<T>>(std::move(files));
-  }
-
-  llvm::Optional<std::string> GetNextFile() {
-    if (m_index >= m_files.size())
-      return {};
-    return m_files[m_index++];
-  }
-
-private:
-  std::vector<std::string> m_files;
-  unsigned m_index = 0;
-};
-
-/// Helper to read directories written by the DirectoryProvider.
-template <typename T>
-llvm::Expected<std::string> GetDirectoryFrom(repro::Loader *loader) {
-  llvm::Expected<std::string> dir = loader->LoadBuffer<T>();
-  if (!dir)
-    return dir.takeError();
-  return std::string(llvm::StringRef(*dir).rtrim());
-}
-
 } // namespace repro
 } // namespace lldb_private
 

diff  --git a/lldb/include/lldb/Utility/ReproducerProvider.h b/lldb/include/lldb/Utility/ReproducerProvider.h
new file mode 100644
index 000000000000..b84b8a67c4ca
--- /dev/null
+++ b/lldb/include/lldb/Utility/ReproducerProvider.h
@@ -0,0 +1,360 @@
+//===-- Reproducer.h --------------------------------------------*- C++ -*-===//
+//
+// 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_PROVIDER_H
+#define LLDB_UTILITY_REPRODUCER_PROVIDER_H
+
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/ProcessInfo.h"
+#include "lldb/Utility/Reproducer.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileCollector.h"
+#include "llvm/Support/YAMLTraits.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace lldb_private {
+namespace repro {
+
+/// The recorder is a small object handed out by a provider to record data. It
+/// is commonly used in combination with a MultiProvider which is meant to
+/// record information for multiple instances of the same source of data.
+class AbstractRecorder {
+protected:
+  AbstractRecorder(const FileSpec &filename, std::error_code &ec)
+      : m_filename(filename.GetFilename().GetStringRef()),
+        m_os(filename.GetPath(), ec, llvm::sys::fs::OF_Text), m_record(true) {}
+
+public:
+  const FileSpec &GetFilename() { return m_filename; }
+
+  void Stop() {
+    assert(m_record);
+    m_record = false;
+  }
+
+private:
+  FileSpec m_filename;
+
+protected:
+  llvm::raw_fd_ostream m_os;
+  bool m_record;
+};
+
+/// Recorder that records its data as text to a file.
+class DataRecorder : public AbstractRecorder {
+public:
+  DataRecorder(const FileSpec &filename, std::error_code &ec)
+      : AbstractRecorder(filename, ec) {}
+
+  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();
+  }
+};
+
+/// Recorder that records its data as YAML to a file.
+class YamlRecorder : public AbstractRecorder {
+public:
+  YamlRecorder(const FileSpec &filename, std::error_code &ec)
+      : AbstractRecorder(filename, ec) {}
+
+  static llvm::Expected<std::unique_ptr<YamlRecorder>>
+  Create(const FileSpec &filename);
+
+  template <typename T> void Record(const T &t) {
+    if (!m_record)
+      return;
+    llvm::yaml::Output yout(m_os);
+    // The YAML traits are defined as non-const because they are used for
+    // serialization and deserialization. The cast is safe because
+    // serialization doesn't modify the object.
+    yout << const_cast<T &>(t);
+    m_os.flush();
+  }
+};
+
+class FileProvider : public Provider<FileProvider> {
+public:
+  struct Info {
+    static const char *name;
+    static const char *file;
+  };
+
+  FileProvider(const FileSpec &directory)
+      : Provider(directory),
+        m_collector(std::make_shared<llvm::FileCollector>(
+            directory.CopyByAppendingPathComponent("root").GetPath(),
+            directory.GetPath())) {}
+
+  std::shared_ptr<llvm::FileCollector> GetFileCollector() {
+    return m_collector;
+  }
+
+  void RecordInterestingDirectory(const llvm::Twine &dir);
+  void RecordInterestingDirectoryRecursive(const llvm::Twine &dir);
+
+  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.GetPath());
+  }
+
+  static char ID;
+
+private:
+  std::shared_ptr<llvm::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;
+};
+
+/// Abstract provider to storing directory paths.
+template <typename T> class DirectoryProvider : public repro::Provider<T> {
+public:
+  DirectoryProvider(const FileSpec &root) : Provider<T>(root) {}
+  void SetDirectory(std::string directory) {
+    m_directory = std::move(directory);
+  }
+  llvm::StringRef GetDirectory() { return m_directory; }
+
+  void Keep() override {
+    FileSpec file = this->GetRoot().CopyByAppendingPathComponent(T::Info::file);
+    std::error_code ec;
+    llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
+    if (ec)
+      return;
+    os << m_directory << "\n";
+  }
+
+protected:
+  std::string m_directory;
+};
+
+/// Provider for the current working directory.
+///
+/// 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 DirectoryProvider<WorkingDirectoryProvider> {
+public:
+  WorkingDirectoryProvider(const FileSpec &directory)
+      : DirectoryProvider(directory) {
+    llvm::SmallString<128> cwd;
+    if (std::error_code EC = llvm::sys::fs::current_path(cwd))
+      return;
+    SetDirectory(std::string(cwd));
+  }
+  struct Info {
+    static const char *name;
+    static const char *file;
+  };
+  static char ID;
+};
+
+/// Provider for the home directory.
+///
+/// When the reproducer is kept, it writes the user's home directory to a file
+/// a file named home.txt in the reproducer root.
+class HomeDirectoryProvider : public DirectoryProvider<HomeDirectoryProvider> {
+public:
+  HomeDirectoryProvider(const FileSpec &directory)
+      : DirectoryProvider(directory) {
+    llvm::SmallString<128> home_dir;
+    llvm::sys::path::home_directory(home_dir);
+    SetDirectory(std::string(home_dir));
+  }
+  struct Info {
+    static const char *name;
+    static const char *file;
+  };
+  static char ID;
+};
+
+/// The MultiProvider is a provider that hands out recorder which can be used
+/// to capture data for 
diff erent instances of the same object. The recorders
+/// can be passed around or stored as an instance member.
+///
+/// The Info::file for the MultiProvider contains an index of files for every
+/// recorder. Use the MultiLoader to read the index and get the individual
+/// files.
+template <typename T, typename V>
+class MultiProvider : public repro::Provider<V> {
+public:
+  MultiProvider(const FileSpec &directory) : Provider<V>(directory) {}
+
+  T *GetNewRecorder() {
+    std::size_t i = m_recorders.size() + 1;
+    std::string filename = (llvm::Twine(V::Info::name) + llvm::Twine("-") +
+                            llvm::Twine(i) + llvm::Twine(".yaml"))
+                               .str();
+    auto recorder_or_error =
+        T::Create(this->GetRoot().CopyByAppendingPathComponent(filename));
+    if (!recorder_or_error) {
+      llvm::consumeError(recorder_or_error.takeError());
+      return nullptr;
+    }
+
+    m_recorders.push_back(std::move(*recorder_or_error));
+    return m_recorders.back().get();
+  }
+
+  void Keep() override {
+    std::vector<std::string> files;
+    for (auto &recorder : m_recorders) {
+      recorder->Stop();
+      files.push_back(recorder->GetFilename().GetPath());
+    }
+
+    FileSpec file = this->GetRoot().CopyByAppendingPathComponent(V::Info::file);
+    std::error_code ec;
+    llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
+    if (ec)
+      return;
+    llvm::yaml::Output yout(os);
+    yout << files;
+  }
+
+  void Discard() override { m_recorders.clear(); }
+
+private:
+  std::vector<std::unique_ptr<T>> m_recorders;
+};
+
+class CommandProvider : public MultiProvider<DataRecorder, CommandProvider> {
+public:
+  struct Info {
+    static const char *name;
+    static const char *file;
+  };
+
+  CommandProvider(const FileSpec &directory)
+      : MultiProvider<DataRecorder, CommandProvider>(directory) {}
+
+  static char ID;
+};
+
+class ProcessInfoRecorder : public AbstractRecorder {
+public:
+  ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec)
+      : AbstractRecorder(filename, ec) {}
+
+  static llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
+  Create(const FileSpec &filename);
+
+  void Record(const ProcessInstanceInfoList &process_infos);
+};
+
+class ProcessInfoProvider : public repro::Provider<ProcessInfoProvider> {
+public:
+  struct Info {
+    static const char *name;
+    static const char *file;
+  };
+
+  ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {}
+
+  ProcessInfoRecorder *GetNewProcessInfoRecorder();
+
+  void Keep() override;
+  void Discard() override;
+
+  static char ID;
+
+private:
+  std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
+  std::vector<std::unique_ptr<ProcessInfoRecorder>> m_process_info_recorders;
+};
+
+/// Loader for data captured with the MultiProvider. It will read the index and
+/// return the path to the files in the index.
+template <typename T> class MultiLoader {
+public:
+  MultiLoader(std::vector<std::string> files) : m_files(std::move(files)) {}
+
+  static std::unique_ptr<MultiLoader> Create(Loader *loader) {
+    if (!loader)
+      return {};
+
+    FileSpec file = loader->GetFile<typename T::Info>();
+    if (!file)
+      return {};
+
+    auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
+    if (auto err = error_or_file.getError())
+      return {};
+
+    std::vector<std::string> files;
+    llvm::yaml::Input yin((*error_or_file)->getBuffer());
+    yin >> files;
+
+    if (auto err = yin.error())
+      return {};
+
+    for (auto &file : files) {
+      FileSpec absolute_path =
+          loader->GetRoot().CopyByAppendingPathComponent(file);
+      file = absolute_path.GetPath();
+    }
+
+    return std::make_unique<MultiLoader<T>>(std::move(files));
+  }
+
+  llvm::Optional<std::string> GetNextFile() {
+    if (m_index >= m_files.size())
+      return {};
+    return m_files[m_index++];
+  }
+
+private:
+  std::vector<std::string> m_files;
+  unsigned m_index = 0;
+};
+
+/// Helper to read directories written by the DirectoryProvider.
+template <typename T>
+llvm::Expected<std::string> GetDirectoryFrom(repro::Loader *loader) {
+  llvm::Expected<std::string> dir = loader->LoadBuffer<T>();
+  if (!dir)
+    return dir.takeError();
+  return std::string(llvm::StringRef(*dir).rtrim());
+}
+
+} // namespace repro
+} // namespace lldb_private
+
+#endif // LLDB_UTILITY_REPRODUCER_PROVIDER_H

diff  --git a/lldb/source/API/SBReproducerPrivate.h b/lldb/source/API/SBReproducerPrivate.h
index a4c6eb94627b..02ac31c2ad89 100644
--- a/lldb/source/API/SBReproducerPrivate.h
+++ b/lldb/source/API/SBReproducerPrivate.h
@@ -16,6 +16,7 @@
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/Reproducer.h"
 #include "lldb/Utility/ReproducerInstrumentation.h"
+#include "lldb/Utility/ReproducerProvider.h"
 
 #include "llvm/ADT/DenseMap.h"
 

diff  --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp
index ca35d9fb315d..0648cf41f28a 100644
--- a/lldb/source/Core/IOHandler.cpp
+++ b/lldb/source/Core/IOHandler.cpp
@@ -18,6 +18,7 @@
 #include "lldb/Host/Config.h"
 #include "lldb/Host/File.h"
 #include "lldb/Utility/Predicate.h"
+#include "lldb/Utility/ReproducerProvider.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/StreamString.h"
 #include "lldb/Utility/StringList.h"

diff  --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp
index 4128fa19c142..71c2983ab00f 100644
--- a/lldb/source/Host/common/Host.cpp
+++ b/lldb/source/Host/common/Host.cpp
@@ -60,6 +60,7 @@
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/Predicate.h"
+#include "lldb/Utility/ReproducerProvider.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/lldb-private-forward.h"
 #include "llvm/ADT/SmallString.h"

diff  --git a/lldb/source/Initialization/SystemInitializerCommon.cpp b/lldb/source/Initialization/SystemInitializerCommon.cpp
index 4d72f6e2ad33..d352173e1158 100644
--- a/lldb/source/Initialization/SystemInitializerCommon.cpp
+++ b/lldb/source/Initialization/SystemInitializerCommon.cpp
@@ -14,7 +14,7 @@
 #include "lldb/Host/HostInfo.h"
 #include "lldb/Host/Socket.h"
 #include "lldb/Utility/Log.h"
-#include "lldb/Utility/Reproducer.h"
+#include "lldb/Utility/ReproducerProvider.h"
 #include "lldb/Utility/Timer.h"
 #include "lldb/lldb-private.h"
 

diff  --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index b3b0277ec667..e25c24ccd401 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -46,6 +46,7 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/StreamFile.h"
 #include "lldb/Utility/Log.h"
+#include "lldb/Utility/Reproducer.h"
 #include "lldb/Utility/State.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/Timer.h"

diff  --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 6ff028cf6980..202eb87cca3d 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -85,7 +85,7 @@
 #include "lldb/Utility/DataBufferHeap.h"
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/Log.h"
-#include "lldb/Utility/Reproducer.h"
+#include "lldb/Utility/ReproducerProvider.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/StreamString.h"
 #include "lldb/Utility/StringList.h"

diff  --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
index 95acb883774d..6bd2d4425b7b 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -33,7 +33,7 @@
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/Log.h"
-#include "lldb/Utility/Reproducer.h"
+#include "lldb/Utility/ReproducerProvider.h"
 #include "lldb/Utility/StreamString.h"
 
 #include <memory>

diff  --git a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
index 336538241b6a..10c1b7cc1351 100644
--- a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
+++ b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
@@ -20,7 +20,7 @@
 #include "lldb/Symbol/LocateSymbolFile.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Target/Target.h"
-#include "lldb/Utility/Reproducer.h"
+#include "lldb/Utility/ReproducerProvider.h"
 #include "lldb/Utility/StreamString.h"
 #include "lldb/Utility/Timer.h"
 

diff  --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt
index c89d4f9e0072..1e3d859e2a6c 100644
--- a/lldb/source/Utility/CMakeLists.txt
+++ b/lldb/source/Utility/CMakeLists.txt
@@ -50,6 +50,7 @@ add_lldb_library(lldbUtility
   RegularExpression.cpp
   Reproducer.cpp
   ReproducerInstrumentation.cpp
+  ReproducerProvider.cpp
   Scalar.cpp
   SelectHelper.cpp
   State.cpp

diff  --git a/lldb/source/Utility/ProcessInfo.cpp b/lldb/source/Utility/ProcessInfo.cpp
index aae48d6a4872..310d2b22b174 100644
--- a/lldb/source/Utility/ProcessInfo.cpp
+++ b/lldb/source/Utility/ProcessInfo.cpp
@@ -9,6 +9,7 @@
 #include "lldb/Utility/ProcessInfo.h"
 
 #include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/ReproducerProvider.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/StreamString.h"
 #include "lldb/Utility/UserIDResolver.h"
@@ -347,57 +348,6 @@ void llvm::yaml::MappingTraits<ProcessInstanceInfo>::mapping(
   io.mapRequired("parent-pid", Info.m_parent_pid);
 }
 
-llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
-ProcessInfoRecorder::Create(const FileSpec &filename) {
-  std::error_code ec;
-  auto recorder =
-      std::make_unique<ProcessInfoRecorder>(std::move(filename), ec);
-  if (ec)
-    return llvm::errorCodeToError(ec);
-  return std::move(recorder);
-}
-
-void ProcessInfoProvider::Keep() {
-  std::vector<std::string> files;
-  for (auto &recorder : m_process_info_recorders) {
-    recorder->Stop();
-    files.push_back(recorder->GetFilename().GetPath());
-  }
-
-  FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
-  std::error_code ec;
-  llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
-  if (ec)
-    return;
-  llvm::yaml::Output yout(os);
-  yout << files;
-}
-
-void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); }
-
-ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() {
-  std::size_t i = m_process_info_recorders.size() + 1;
-  std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") +
-                          llvm::Twine(i) + llvm::Twine(".yaml"))
-                             .str();
-  auto recorder_or_error = ProcessInfoRecorder::Create(
-      GetRoot().CopyByAppendingPathComponent(filename));
-  if (!recorder_or_error) {
-    llvm::consumeError(recorder_or_error.takeError());
-    return nullptr;
-  }
-
-  m_process_info_recorders.push_back(std::move(*recorder_or_error));
-  return m_process_info_recorders.back().get();
-}
-
-void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) {
-  if (!m_record)
-    return;
-  llvm::yaml::Output yout(m_os);
-  yout << const_cast<ProcessInstanceInfoList &>(process_infos);
-  m_os.flush();
-}
 
 llvm::Optional<ProcessInstanceInfoList>
 repro::GetReplayProcessInstanceInfoList() {
@@ -425,7 +375,3 @@ repro::GetReplayProcessInstanceInfoList() {
 
   return infos;
 }
-
-char ProcessInfoProvider::ID = 0;
-const char *ProcessInfoProvider::Info::file = "process-info.yaml";
-const char *ProcessInfoProvider::Info::name = "process-info";

diff  --git a/lldb/source/Utility/Reproducer.cpp b/lldb/source/Utility/Reproducer.cpp
index 35d145e4d61b..9276c7449d7b 100644
--- a/lldb/source/Utility/Reproducer.cpp
+++ b/lldb/source/Utility/Reproducer.cpp
@@ -8,6 +8,7 @@
 
 #include "lldb/Utility/Reproducer.h"
 #include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/ReproducerProvider.h"
 
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Threading.h"
@@ -263,58 +264,3 @@ bool Loader::HasFile(StringRef file) {
   auto it = std::lower_bound(m_files.begin(), m_files.end(), file.str());
   return (it != m_files.end()) && (*it == file);
 }
-
-llvm::Expected<std::unique_ptr<DataRecorder>>
-DataRecorder::Create(const FileSpec &filename) {
-  std::error_code ec;
-  auto recorder = std::make_unique<DataRecorder>(std::move(filename), ec);
-  if (ec)
-    return llvm::errorCodeToError(ec);
-  return std::move(recorder);
-}
-
-llvm::Expected<std::unique_ptr<YamlRecorder>>
-YamlRecorder::Create(const FileSpec &filename) {
-  std::error_code ec;
-  auto recorder = std::make_unique<YamlRecorder>(std::move(filename), ec);
-  if (ec)
-    return llvm::errorCodeToError(ec);
-  return std::move(recorder);
-}
-
-void VersionProvider::Keep() {
-  FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
-  std::error_code ec;
-  llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
-  if (ec)
-    return;
-  os << m_version << "\n";
-}
-
-void FileProvider::RecordInterestingDirectory(const llvm::Twine &dir) {
-  if (m_collector)
-    m_collector->addFile(dir);
-}
-
-void FileProvider::RecordInterestingDirectoryRecursive(const llvm::Twine &dir) {
-  if (m_collector)
-    m_collector->addDirectory(dir);
-}
-
-void ProviderBase::anchor() {}
-char CommandProvider::ID = 0;
-char FileProvider::ID = 0;
-char ProviderBase::ID = 0;
-char VersionProvider::ID = 0;
-char WorkingDirectoryProvider::ID = 0;
-char HomeDirectoryProvider::ID = 0;
-const char *CommandProvider::Info::file = "command-interpreter.yaml";
-const char *CommandProvider::Info::name = "command-interpreter";
-const char *FileProvider::Info::file = "files.yaml";
-const char *FileProvider::Info::name = "files";
-const char *VersionProvider::Info::file = "version.txt";
-const char *VersionProvider::Info::name = "version";
-const char *WorkingDirectoryProvider::Info::file = "cwd.txt";
-const char *WorkingDirectoryProvider::Info::name = "cwd";
-const char *HomeDirectoryProvider::Info::file = "home.txt";
-const char *HomeDirectoryProvider::Info::name = "home";

diff  --git a/lldb/source/Utility/ReproducerProvider.cpp b/lldb/source/Utility/ReproducerProvider.cpp
new file mode 100644
index 000000000000..54f3a870b7dd
--- /dev/null
+++ b/lldb/source/Utility/ReproducerProvider.cpp
@@ -0,0 +1,127 @@
+//===-- Reproducer.cpp ----------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/ReproducerProvider.h"
+#include "lldb/Utility/ProcessInfo.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lldb_private;
+using namespace lldb_private::repro;
+using namespace llvm;
+using namespace llvm::yaml;
+
+llvm::Expected<std::unique_ptr<DataRecorder>>
+DataRecorder::Create(const FileSpec &filename) {
+  std::error_code ec;
+  auto recorder = std::make_unique<DataRecorder>(std::move(filename), ec);
+  if (ec)
+    return llvm::errorCodeToError(ec);
+  return std::move(recorder);
+}
+
+llvm::Expected<std::unique_ptr<YamlRecorder>>
+YamlRecorder::Create(const FileSpec &filename) {
+  std::error_code ec;
+  auto recorder = std::make_unique<YamlRecorder>(std::move(filename), ec);
+  if (ec)
+    return llvm::errorCodeToError(ec);
+  return std::move(recorder);
+}
+
+void VersionProvider::Keep() {
+  FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
+  std::error_code ec;
+  llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
+  if (ec)
+    return;
+  os << m_version << "\n";
+}
+
+void FileProvider::RecordInterestingDirectory(const llvm::Twine &dir) {
+  if (m_collector)
+    m_collector->addFile(dir);
+}
+
+void FileProvider::RecordInterestingDirectoryRecursive(const llvm::Twine &dir) {
+  if (m_collector)
+    m_collector->addDirectory(dir);
+}
+
+llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
+ProcessInfoRecorder::Create(const FileSpec &filename) {
+  std::error_code ec;
+  auto recorder =
+      std::make_unique<ProcessInfoRecorder>(std::move(filename), ec);
+  if (ec)
+    return llvm::errorCodeToError(ec);
+  return std::move(recorder);
+}
+
+void ProcessInfoProvider::Keep() {
+  std::vector<std::string> files;
+  for (auto &recorder : m_process_info_recorders) {
+    recorder->Stop();
+    files.push_back(recorder->GetFilename().GetPath());
+  }
+
+  FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
+  std::error_code ec;
+  llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
+  if (ec)
+    return;
+  llvm::yaml::Output yout(os);
+  yout << files;
+}
+
+void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); }
+
+ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() {
+  std::size_t i = m_process_info_recorders.size() + 1;
+  std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") +
+                          llvm::Twine(i) + llvm::Twine(".yaml"))
+                             .str();
+  auto recorder_or_error = ProcessInfoRecorder::Create(
+      GetRoot().CopyByAppendingPathComponent(filename));
+  if (!recorder_or_error) {
+    llvm::consumeError(recorder_or_error.takeError());
+    return nullptr;
+  }
+
+  m_process_info_recorders.push_back(std::move(*recorder_or_error));
+  return m_process_info_recorders.back().get();
+}
+
+void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) {
+  if (!m_record)
+    return;
+  llvm::yaml::Output yout(m_os);
+  yout << const_cast<ProcessInstanceInfoList &>(process_infos);
+  m_os.flush();
+}
+
+void ProviderBase::anchor() {}
+char CommandProvider::ID = 0;
+char FileProvider::ID = 0;
+char ProviderBase::ID = 0;
+char VersionProvider::ID = 0;
+char WorkingDirectoryProvider::ID = 0;
+char HomeDirectoryProvider::ID = 0;
+char ProcessInfoProvider::ID = 0;
+const char *CommandProvider::Info::file = "command-interpreter.yaml";
+const char *CommandProvider::Info::name = "command-interpreter";
+const char *FileProvider::Info::file = "files.yaml";
+const char *FileProvider::Info::name = "files";
+const char *VersionProvider::Info::file = "version.txt";
+const char *VersionProvider::Info::name = "version";
+const char *WorkingDirectoryProvider::Info::file = "cwd.txt";
+const char *WorkingDirectoryProvider::Info::name = "cwd";
+const char *HomeDirectoryProvider::Info::file = "home.txt";
+const char *HomeDirectoryProvider::Info::name = "home";
+const char *ProcessInfoProvider::Info::file = "process-info.yaml";
+const char *ProcessInfoProvider::Info::name = "process-info";

diff  --git a/lldb/unittests/Utility/ReproducerTest.cpp b/lldb/unittests/Utility/ReproducerTest.cpp
index 5a9dea3450f0..b276de3bf1af 100644
--- a/lldb/unittests/Utility/ReproducerTest.cpp
+++ b/lldb/unittests/Utility/ReproducerTest.cpp
@@ -9,13 +9,13 @@
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Reproducer.h"
+#include "lldb/Utility/ReproducerProvider.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Testing/Support/Error.h"
 
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/Reproducer.h"
-
 using namespace llvm;
 using namespace lldb_private;
 using namespace lldb_private::repro;


        


More information about the lldb-commits mailing list