[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.
This commit is contained in:
Jonas Devlieghere 2020-08-22 00:36:32 -07:00
parent 8e06bf6b3a
commit bb894b9782
18 changed files with 506 additions and 452 deletions

View File

@ -15,7 +15,6 @@
#include "lldb/Utility/ConstString.h" #include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Flags.h" #include "lldb/Utility/Flags.h"
#include "lldb/Utility/Predicate.h" #include "lldb/Utility/Predicate.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/Stream.h" #include "lldb/Utility/Stream.h"
#include "lldb/Utility/StringList.h" #include "lldb/Utility/StringList.h"
#include "lldb/lldb-defines.h" #include "lldb/lldb-defines.h"
@ -32,6 +31,9 @@
namespace lldb_private { namespace lldb_private {
class Debugger; class Debugger;
namespace repro {
class DataRecorder;
}
} }
namespace curses { namespace curses {

View File

@ -10,7 +10,7 @@
#define LLDB_UTILITY_GDBREMOTE_H #define LLDB_UTILITY_GDBREMOTE_H
#include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/StreamString.h" #include "lldb/Utility/StreamString.h"
#include "lldb/lldb-enumerations.h" #include "lldb/lldb-enumerations.h"
#include "lldb/lldb-public.h" #include "lldb/lldb-public.h"

View File

@ -14,7 +14,6 @@
#include "lldb/Utility/Environment.h" #include "lldb/Utility/Environment.h"
#include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/NameMatches.h" #include "lldb/Utility/NameMatches.h"
#include "lldb/Utility/Reproducer.h"
#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/YAMLTraits.h"
#include <vector> #include <vector>
@ -217,40 +216,7 @@ protected:
}; };
namespace repro { 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(); llvm::Optional<ProcessInstanceInfoList> GetReplayProcessInstanceInfoList();
} // namespace repro } // namespace repro
} // namespace lldb_private } // namespace lldb_private

View File

@ -13,7 +13,7 @@
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h" #include "llvm/Support/Error.h"
#include "llvm/Support/FileCollector.h" #include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/YAMLTraits.h"
#include <mutex> #include <mutex>
@ -84,250 +84,6 @@ protected:
using ProviderBase::ProviderBase; // Inherit constructor. 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 different 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 /// The generator is responsible for the logic needed to generate a
/// reproducer. For doing so it relies on providers, who serialize data that /// reproducer. For doing so it relies on providers, who serialize data that
/// is necessary for reproducing a failure. /// is necessary for reproducing a failure.
@ -469,60 +225,6 @@ private:
mutable std::mutex m_mutex; 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 repro
} // namespace lldb_private } // namespace lldb_private

View File

@ -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 different 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

View File

@ -16,6 +16,7 @@
#include "lldb/Utility/Log.h" #include "lldb/Utility/Log.h"
#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/ReproducerInstrumentation.h" #include "lldb/Utility/ReproducerInstrumentation.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"

View File

@ -18,6 +18,7 @@
#include "lldb/Host/Config.h" #include "lldb/Host/Config.h"
#include "lldb/Host/File.h" #include "lldb/Host/File.h"
#include "lldb/Utility/Predicate.h" #include "lldb/Utility/Predicate.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/Status.h" #include "lldb/Utility/Status.h"
#include "lldb/Utility/StreamString.h" #include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StringList.h" #include "lldb/Utility/StringList.h"

View File

@ -60,6 +60,7 @@
#include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Log.h" #include "lldb/Utility/Log.h"
#include "lldb/Utility/Predicate.h" #include "lldb/Utility/Predicate.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/Status.h" #include "lldb/Utility/Status.h"
#include "lldb/lldb-private-forward.h" #include "lldb/lldb-private-forward.h"
#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallString.h"

View File

@ -14,7 +14,7 @@
#include "lldb/Host/HostInfo.h" #include "lldb/Host/HostInfo.h"
#include "lldb/Host/Socket.h" #include "lldb/Host/Socket.h"
#include "lldb/Utility/Log.h" #include "lldb/Utility/Log.h"
#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/Timer.h" #include "lldb/Utility/Timer.h"
#include "lldb/lldb-private.h" #include "lldb/lldb-private.h"

View File

@ -46,6 +46,7 @@
#include "lldb/Core/PluginManager.h" #include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamFile.h"
#include "lldb/Utility/Log.h" #include "lldb/Utility/Log.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/State.h" #include "lldb/Utility/State.h"
#include "lldb/Utility/Stream.h" #include "lldb/Utility/Stream.h"
#include "lldb/Utility/Timer.h" #include "lldb/Utility/Timer.h"

View File

@ -85,7 +85,7 @@
#include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h" #include "lldb/Utility/Log.h"
#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/Stream.h" #include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h" #include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StringList.h" #include "lldb/Utility/StringList.h"

View File

@ -33,7 +33,7 @@
#include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h" #include "lldb/Utility/Log.h"
#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/StreamString.h" #include "lldb/Utility/StreamString.h"
#include <memory> #include <memory>

View File

@ -20,7 +20,7 @@
#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/LocateSymbolFile.h"
#include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Target.h" #include "lldb/Target/Target.h"
#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/StreamString.h" #include "lldb/Utility/StreamString.h"
#include "lldb/Utility/Timer.h" #include "lldb/Utility/Timer.h"

View File

@ -50,6 +50,7 @@ add_lldb_library(lldbUtility
RegularExpression.cpp RegularExpression.cpp
Reproducer.cpp Reproducer.cpp
ReproducerInstrumentation.cpp ReproducerInstrumentation.cpp
ReproducerProvider.cpp
Scalar.cpp Scalar.cpp
SelectHelper.cpp SelectHelper.cpp
State.cpp State.cpp

View File

@ -9,6 +9,7 @@
#include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/Stream.h" #include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h" #include "lldb/Utility/StreamString.h"
#include "lldb/Utility/UserIDResolver.h" #include "lldb/Utility/UserIDResolver.h"
@ -347,57 +348,6 @@ void llvm::yaml::MappingTraits<ProcessInstanceInfo>::mapping(
io.mapRequired("parent-pid", Info.m_parent_pid); 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> llvm::Optional<ProcessInstanceInfoList>
repro::GetReplayProcessInstanceInfoList() { repro::GetReplayProcessInstanceInfoList() {
@ -425,7 +375,3 @@ repro::GetReplayProcessInstanceInfoList() {
return infos; return infos;
} }
char ProcessInfoProvider::ID = 0;
const char *ProcessInfoProvider::Info::file = "process-info.yaml";
const char *ProcessInfoProvider::Info::name = "process-info";

View File

@ -8,6 +8,7 @@
#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileSystem.h"
#include "llvm/Support/Threading.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()); auto it = std::lower_bound(m_files.begin(), m_files.end(), file.str());
return (it != m_files.end()) && (*it == file); 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";

View File

@ -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";

View File

@ -9,13 +9,13 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.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/ADT/ScopeExit.h"
#include "llvm/Support/Error.h" #include "llvm/Support/Error.h"
#include "llvm/Testing/Support/Error.h" #include "llvm/Testing/Support/Error.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Reproducer.h"
using namespace llvm; using namespace llvm;
using namespace lldb_private; using namespace lldb_private;
using namespace lldb_private::repro; using namespace lldb_private::repro;