[lldb] Remove LLDB reproducers

This patch removes the remaining reproducer code. The SBReproducer class
remains for ABI stability but is just an empty shell. This completes the
removal process outlined on the mailing list [1].

[1] https://lists.llvm.org/pipermail/lldb-dev/2021-September/017045.html
This commit is contained in:
Jonas Devlieghere
2022-09-19 10:47:09 -07:00
parent 2e8817b90a
commit 70599d7027
102 changed files with 57 additions and 3218 deletions

View File

@@ -32,9 +32,6 @@ public:
void SetCheckVersion(bool check);
bool GetCheckVersion() const;
private:
std::unique_ptr<lldb_private::repro::ReplayOptions> m_opaque_up;
};
/// The SBReproducer class is special because it bootstraps the capture and

View File

@@ -152,11 +152,7 @@ public:
Status SetInputString(const char *data);
// This method will setup data recorder if reproducer enabled.
// On reply mode this method should take instructions from reproducer file.
Status SetInputFile(lldb::FileSP file);
void SetInputFile(lldb::FileSP file, repro::DataRecorder *recorder);
void SetInputFile(lldb::FileSP file);
void SetOutputFile(lldb::FileSP file);
@@ -294,8 +290,6 @@ public:
void SetPrompt(llvm::StringRef p);
void SetPrompt(const char *) = delete;
llvm::StringRef GetReproducerPath() const;
bool GetUseExternalEditor() const;
bool SetUseExternalEditor(bool use_external_editor_p);

View File

@@ -31,9 +31,6 @@
namespace lldb_private {
class Debugger;
namespace repro {
class DataRecorder;
}
} // namespace lldb_private
namespace curses {
@@ -63,8 +60,7 @@ public:
IOHandler(Debugger &debugger, IOHandler::Type type,
const lldb::FileSP &input_sp, const lldb::StreamFileSP &output_sp,
const lldb::StreamFileSP &error_sp, uint32_t flags,
repro::DataRecorder *data_recorder);
const lldb::StreamFileSP &error_sp, uint32_t flags);
virtual ~IOHandler();
@@ -173,7 +169,6 @@ protected:
lldb::StreamFileSP m_output_sp;
lldb::StreamFileSP m_error_sp;
std::recursive_mutex m_output_mutex;
repro::DataRecorder *m_data_recorder;
Predicate<bool> m_popped;
Flags m_flags;
Type m_type;
@@ -338,8 +333,7 @@ public:
uint32_t line_number_start, // If non-zero show line numbers
// starting at
// 'line_number_start'
IOHandlerDelegate &delegate,
repro::DataRecorder *data_recorder);
IOHandlerDelegate &delegate);
IOHandlerEditline(Debugger &debugger, IOHandler::Type type,
const lldb::FileSP &input_sp,
@@ -351,8 +345,7 @@ public:
uint32_t line_number_start, // If non-zero show line numbers
// starting at
// 'line_number_start'
IOHandlerDelegate &delegate,
repro::DataRecorder *data_recorder);
IOHandlerDelegate &delegate);
IOHandlerEditline(Debugger &, IOHandler::Type, const char *, const char *,
const char *, bool, bool, uint32_t,

View File

@@ -124,67 +124,6 @@ static constexpr OptionEnumValueElement g_log_handler_type[] = {
},
};
static constexpr OptionEnumValueElement g_reproducer_provider_type[] = {
{
eReproducerProviderCommands,
"commands",
"Command Interpreter Commands",
},
{
eReproducerProviderFiles,
"files",
"Files",
},
{
eReproducerProviderSymbolFiles,
"symbol-files",
"Symbol Files",
},
{
eReproducerProviderGDB,
"gdb",
"GDB Remote Packets",
},
{
eReproducerProviderProcessInfo,
"processes",
"Process Info",
},
{
eReproducerProviderVersion,
"version",
"Version",
},
{
eReproducerProviderWorkingDirectory,
"cwd",
"Working Directory",
},
{
eReproducerProviderHomeDirectory,
"home",
"Home Directory",
},
{
eReproducerProviderNone,
"none",
"None",
},
};
static constexpr OptionEnumValueElement g_reproducer_signaltype[] = {
{
eReproducerCrashSigill,
"SIGILL",
"Illegal instruction",
},
{
eReproducerCrashSigsegv,
"SIGSEGV",
"Segmentation fault",
},
};
static constexpr OptionEnumValueElement g_script_synchro_type[] = {
{
eScriptedCommandSynchronicitySynchronous,
@@ -318,8 +257,6 @@ static constexpr CommandObject::ArgumentTableEntry g_argument_table[] = {
{ lldb::eArgTypeConnectURL, "process-connect-url", CommandCompletions::eNoCompletion, {}, { nullptr, false }, "A URL-style specification for a remote connection." },
{ lldb::eArgTypeTargetID, "target-id", CommandCompletions::eNoCompletion, {}, { nullptr, false }, "The index ID for an lldb Target." },
{ lldb::eArgTypeStopHookID, "stop-hook-id", CommandCompletions::eNoCompletion, {}, { nullptr, false }, "The ID you receive when you create a stop-hook." },
{ lldb::eArgTypeReproducerProvider, "reproducer-provider", CommandCompletions::eNoCompletion, g_reproducer_provider_type, { nullptr, false }, "The reproducer provider." },
{ lldb::eArgTypeReproducerSignal, "reproducer-signal", CommandCompletions::eNoCompletion, g_reproducer_signaltype, { nullptr, false }, "The signal used to emulate a reproducer crash." },
// clang-format on
};

View File

@@ -16,7 +16,6 @@
#include "lldb/lldb-private-enumerations.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/YAMLTraits.h"
#include <cstddef>
#include <cstdint>
#include <string>
@@ -568,16 +567,4 @@ bool ParseMachCPUDashSubtypeTriple(llvm::StringRef triple_str, ArchSpec &arch);
} // namespace lldb_private
namespace llvm {
namespace yaml {
template <> struct ScalarTraits<lldb_private::ArchSpec> {
static void output(const lldb_private::ArchSpec &, void *, raw_ostream &);
static StringRef input(StringRef, void *, lldb_private::ArchSpec &);
static QuotingType mustQuote(StringRef S) { return QuotingType::Double; }
};
} // namespace yaml
} // namespace llvm
LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ArchSpec)
#endif // LLDB_UTILITY_ARCHSPEC_H

View File

@@ -35,8 +35,6 @@ public:
struct ArgEntry {
private:
friend class Args;
friend struct llvm::yaml::MappingTraits<Args>;
friend struct llvm::yaml::MappingTraits<Args::ArgEntry>;
std::unique_ptr<char[]> ptr;
char quote = '\0';
@@ -287,8 +285,6 @@ public:
char quote_char);
private:
friend struct llvm::yaml::MappingTraits<Args>;
std::vector<ArgEntry> m_entries;
/// The arguments as C strings with a trailing nullptr element.
///
@@ -383,28 +379,4 @@ private:
} // namespace lldb_private
namespace llvm {
namespace yaml {
template <> struct MappingTraits<lldb_private::Args::ArgEntry> {
class NormalizedArgEntry {
public:
NormalizedArgEntry(IO &) {}
NormalizedArgEntry(IO &, lldb_private::Args::ArgEntry &entry)
: value(entry.ref()), quote(entry.quote) {}
lldb_private::Args::ArgEntry denormalize(IO &) {
return lldb_private::Args::ArgEntry(value, quote);
}
StringRef value;
uint8_t quote = '\0';
};
static void mapping(IO &io, lldb_private::Args::ArgEntry &v);
};
template <> struct MappingTraits<lldb_private::Args> {
static void mapping(IO &io, lldb_private::Args &v);
};
} // namespace yaml
} // namespace llvm
LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::Args::ArgEntry)
#endif // LLDB_UTILITY_ARGS_H

View File

@@ -12,7 +12,6 @@
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/YAMLTraits.h"
#include <cstddef>
@@ -450,20 +449,10 @@ template <> struct DenseMapInfo<lldb_private::ConstString> {
};
/// \}
namespace yaml {
template <> struct ScalarTraits<lldb_private::ConstString> {
static void output(const lldb_private::ConstString &, void *, raw_ostream &);
static StringRef input(StringRef, void *, lldb_private::ConstString &);
static QuotingType mustQuote(StringRef S) { return QuotingType::Double; }
};
} // namespace yaml
inline raw_ostream &operator<<(raw_ostream &os, lldb_private::ConstString s) {
os << s.GetStringRef();
return os;
}
} // namespace llvm
LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ConstString)
#endif // LLDB_UTILITY_CONSTSTRING_H

View File

@@ -18,7 +18,6 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/YAMLTraits.h"
#include <cstddef>
#include <cstdint>
@@ -411,8 +410,6 @@ public:
ConstString GetLastPathComponent() const;
protected:
friend struct llvm::yaml::MappingTraits<FileSpec>;
// Convenience method for setting the file without changing the style.
void SetFile(llvm::StringRef path);
@@ -439,9 +436,6 @@ protected:
/// Dump a FileSpec object to a stream
Stream &operator<<(Stream &s, const FileSpec &f);
/// Prevent ODR violations with traits for llvm::sys::path::Style.
LLVM_YAML_STRONG_TYPEDEF(FileSpec::Style, FileSpecStyle)
} // namespace lldb_private
namespace llvm {
@@ -469,15 +463,6 @@ template <> struct format_provider<lldb_private::FileSpec> {
StringRef Style);
};
namespace yaml {
template <> struct ScalarEnumerationTraits<lldb_private::FileSpecStyle> {
static void enumeration(IO &io, lldb_private::FileSpecStyle &style);
};
template <> struct MappingTraits<lldb_private::FileSpec> {
static void mapping(IO &io, lldb_private::FileSpec &f);
};
} // namespace yaml
} // namespace llvm
#endif // LLDB_UTILITY_FILESPEC_H

View File

@@ -10,11 +10,9 @@
#define LLDB_UTILITY_GDBREMOTE_H
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-public.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <cstddef>
@@ -47,12 +45,10 @@ public:
int PutEscapedBytes(const void *s, size_t src_len);
};
/// GDB remote packet as used by the reproducer and the GDB remote
/// communication history. Packets can be serialized to file.
/// GDB remote packet as used by the GDB remote communication history. Packets
/// can be serialized to file.
struct GDBRemotePacket {
friend llvm::yaml::MappingTraits<GDBRemotePacket>;
enum Type { ePacketTypeInvalid = 0, ePacketTypeSend, ePacketTypeRecv };
GDBRemotePacket() = default;
@@ -81,76 +77,6 @@ private:
llvm::StringRef GetTypeStr() const;
};
namespace repro {
class PacketRecorder : public AbstractRecorder {
public:
PacketRecorder(const FileSpec &filename, std::error_code &ec)
: AbstractRecorder(filename, ec) {}
static llvm::Expected<std::unique_ptr<PacketRecorder>>
Create(const FileSpec &filename);
void Record(const GDBRemotePacket &packet);
};
class GDBRemoteProvider : public repro::Provider<GDBRemoteProvider> {
public:
struct Info {
static const char *name;
static const char *file;
};
GDBRemoteProvider(const FileSpec &directory) : Provider(directory) {}
llvm::raw_ostream *GetHistoryStream();
PacketRecorder *GetNewPacketRecorder();
void SetCallback(std::function<void()> callback) {
m_callback = std::move(callback);
}
void Keep() override;
void Discard() override;
static char ID;
private:
std::function<void()> m_callback;
std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
std::vector<std::unique_ptr<PacketRecorder>> m_packet_recorders;
};
} // namespace repro
} // namespace lldb_private
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(lldb_private::GDBRemotePacket)
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(std::vector<lldb_private::GDBRemotePacket>)
namespace llvm {
namespace yaml {
template <>
struct ScalarEnumerationTraits<lldb_private::GDBRemotePacket::Type> {
static void enumeration(IO &io, lldb_private::GDBRemotePacket::Type &value);
};
template <> struct ScalarTraits<lldb_private::GDBRemotePacket::BinaryData> {
static void output(const lldb_private::GDBRemotePacket::BinaryData &, void *,
raw_ostream &);
static StringRef input(StringRef, void *,
lldb_private::GDBRemotePacket::BinaryData &);
static QuotingType mustQuote(StringRef S) { return QuotingType::None; }
};
template <> struct MappingTraits<lldb_private::GDBRemotePacket> {
static void mapping(IO &io, lldb_private::GDBRemotePacket &Packet);
static StringRef validate(IO &io, lldb_private::GDBRemotePacket &);
};
} // namespace yaml
} // namespace llvm
#endif // LLDB_UTILITY_GDBREMOTE_H

View File

@@ -14,7 +14,6 @@
#include "lldb/Utility/Environment.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/NameMatches.h"
#include "llvm/Support/YAMLTraits.h"
#include <vector>
namespace lldb_private {
@@ -88,7 +87,6 @@ public:
const Environment &GetEnvironment() const { return m_environment; }
protected:
template <class T> friend struct llvm::yaml::MappingTraits;
FileSpec m_executable;
std::string m_arg0; // argv[0] if supported. If empty, then use m_executable.
// Not all process plug-ins support specifying an argv[0] that differs from
@@ -148,7 +146,6 @@ public:
bool verbose) const;
protected:
friend struct llvm::yaml::MappingTraits<ProcessInstanceInfo>;
uint32_t m_euid = UINT32_MAX;
uint32_t m_egid = UINT32_MAX;
lldb::pid_t m_parent_pid = LLDB_INVALID_PROCESS_ID;
@@ -210,19 +207,6 @@ protected:
bool m_match_all_users = false;
};
namespace repro {
llvm::Optional<ProcessInstanceInfoList> GetReplayProcessInstanceInfoList();
} // namespace repro
} // namespace lldb_private
LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ProcessInstanceInfo)
namespace llvm {
namespace yaml {
template <> struct MappingTraits<lldb_private::ProcessInstanceInfo> {
static void mapping(IO &io, lldb_private::ProcessInstanceInfo &PII);
};
} // namespace yaml
} // namespace llvm
#endif // LLDB_UTILITY_PROCESSINFO_H

View File

@@ -1,231 +0,0 @@
//===-- 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_H
#define LLDB_UTILITY_REPRODUCER_H
#include "lldb/Utility/FileSpec.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/YAMLTraits.h"
#include <mutex>
#include <string>
#include <utility>
#include <vector>
namespace lldb_private {
class UUID;
namespace repro {
class Reproducer;
enum class ReproducerMode {
Capture,
Off,
};
/// The provider defines an interface for generating files needed for
/// reproducing.
///
/// Different components will implement different providers.
class ProviderBase {
public:
virtual ~ProviderBase() = default;
const FileSpec &GetRoot() const { return m_root; }
/// The Keep method is called when it is decided that we need to keep the
/// data in order to provide a reproducer.
virtual void Keep(){};
/// The Discard method is called when it is decided that we do not need to
/// keep any information and will not generate a reproducer.
virtual void Discard(){};
// Returns the class ID for this type.
static const void *ClassID() { return &ID; }
// 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) {}
private:
/// Every provider knows where to dump its potential files.
FileSpec m_root;
virtual void anchor();
static char ID;
};
template <typename ThisProviderT> class Provider : public ProviderBase {
public:
static const void *ClassID() { return &ThisProviderT::ID; }
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.
};
/// 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(FileSpec root);
~Generator();
/// Method to indicate we want to keep the reproducer. If reproducer
/// generation is disabled, this does nothing.
void Keep();
/// Method to indicate we do not want to keep the reproducer. This is
/// unaffected by whether or not generation reproduction is enabled, as we
/// might need to clean up files already written to disk.
void Discard();
/// Enable or disable auto generate.
void SetAutoGenerate(bool b);
/// Return whether auto generate is enabled.
bool IsAutoGenerate() const;
/// Create and register a new provider.
template <typename T> T *Create() {
std::unique_ptr<ProviderBase> provider = std::make_unique<T>(m_root);
return static_cast<T *>(Register(std::move(provider)));
}
/// Get an existing provider.
template <typename T> T *Get() {
auto it = m_providers.find(T::ClassID());
if (it == m_providers.end())
return nullptr;
return static_cast<T *>(it->second.get());
}
/// Get a provider if it exists, otherwise create it.
template <typename T> T &GetOrCreate() {
auto *provider = Get<T>();
if (provider)
return *provider;
return *Create<T>();
}
const FileSpec &GetRoot() const;
private:
friend Reproducer;
ProviderBase *Register(std::unique_ptr<ProviderBase> provider);
/// Builds and index with provider info.
void AddProvidersToIndex();
/// Map of provider IDs to provider instances.
llvm::DenseMap<const void *, std::unique_ptr<ProviderBase>> m_providers;
std::mutex m_providers_mutex;
/// The reproducer root directory.
FileSpec m_root;
/// Flag to ensure that we never call both keep and discard.
bool m_done = false;
/// Flag to auto generate a reproducer when it would otherwise be discarded.
bool m_auto_generate = false;
};
class Loader final {
public:
Loader(FileSpec root, bool passive = false);
template <typename T> FileSpec GetFile() {
if (!HasFile(T::file))
return {};
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; }
private:
bool HasFile(llvm::StringRef file);
FileSpec m_root;
std::vector<std::string> m_files;
bool m_loaded;
};
/// The reproducer enables clients to obtain access to the Generator and
/// Loader.
class Reproducer {
public:
static Reproducer &Instance();
static llvm::Error Initialize(ReproducerMode mode,
llvm::Optional<FileSpec> root);
static void Initialize();
static bool Initialized();
static void Terminate();
Reproducer() = default;
Generator *GetGenerator();
Loader *GetLoader();
const Generator *GetGenerator() const;
const Loader *GetLoader() const;
FileSpec GetReproducerPath() const;
bool IsCapturing() { return static_cast<bool>(m_generator); };
protected:
llvm::Error SetCapture(llvm::Optional<FileSpec> root);
private:
static llvm::Optional<Reproducer> &InstanceImpl();
llvm::Optional<Generator> m_generator;
llvm::Optional<Loader> m_loader;
mutable std::mutex m_mutex;
};
struct ReplayOptions {
bool verify = true;
bool check_version = true;
};
} // namespace repro
} // namespace lldb_private
#endif // LLDB_UTILITY_REPRODUCER_H

View File

@@ -1,416 +0,0 @@
//===-- 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 "lldb/Utility/UUID.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_TextWithCRLF),
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 Keep() override;
void RecordInterestingDirectory(const llvm::Twine &dir);
void RecordInterestingDirectoryRecursive(const llvm::Twine &dir);
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_TextWithCRLF);
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;
};
/// Provider for mapping UUIDs to symbol and executable files.
class SymbolFileProvider : public Provider<SymbolFileProvider> {
public:
SymbolFileProvider(const FileSpec &directory) : Provider(directory) {}
void AddSymbolFile(const UUID *uuid, const FileSpec &module_path,
const FileSpec &symbol_path);
void Keep() override;
struct Entry {
Entry() = default;
Entry(std::string uuid) : uuid(std::move(uuid)) {}
Entry(std::string uuid, std::string module_path, std::string symbol_path)
: uuid(std::move(uuid)), module_path(std::move(module_path)),
symbol_path(std::move(symbol_path)) {}
bool operator==(const Entry &rhs) const { return uuid == rhs.uuid; }
bool operator<(const Entry &rhs) const { return uuid < rhs.uuid; }
std::string uuid;
std::string module_path;
std::string symbol_path;
};
struct Info {
static const char *name;
static const char *file;
};
static char ID;
private:
std::vector<Entry> m_symbol_files;
};
/// 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_TextWithCRLF);
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;
};
class SymbolFileLoader {
public:
SymbolFileLoader(Loader *loader);
std::pair<FileSpec, FileSpec> GetPaths(const UUID *uuid) const;
private:
// Sorted list of UUID to path mappings.
std::vector<SymbolFileProvider::Entry> m_symbol_files;
};
/// 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
LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::repro::SymbolFileProvider::Entry)
namespace llvm {
namespace yaml {
template <>
struct MappingTraits<lldb_private::repro::SymbolFileProvider::Entry> {
static void mapping(IO &io,
lldb_private::repro::SymbolFileProvider::Entry &entry) {
io.mapRequired("uuid", entry.uuid);
io.mapRequired("module-path", entry.module_path);
io.mapRequired("symbol-path", entry.symbol_path);
}
};
} // namespace yaml
} // namespace llvm
#endif // LLDB_UTILITY_REPRODUCER_PROVIDER_H

View File

@@ -608,8 +608,6 @@ enum CommandArgumentType {
eArgTypeConnectURL,
eArgTypeTargetID,
eArgTypeStopHookID,
eArgTypeReproducerProvider,
eArgTypeReproducerSignal,
eArgTypeLastArg // Always keep this entry as the last entry in this
// enumeration!!
};

View File

@@ -231,23 +231,6 @@ enum LogHandlerKind {
eLogHandlerDefault = eLogHandlerStream,
};
enum ReproducerProvider {
eReproducerProviderCommands,
eReproducerProviderFiles,
eReproducerProviderSymbolFiles,
eReproducerProviderGDB,
eReproducerProviderProcessInfo,
eReproducerProviderVersion,
eReproducerProviderWorkingDirectory,
eReproducerProviderHomeDirectory,
eReproducerProviderNone,
};
enum ReproducerCrashSignal {
eReproducerCrashSigill,
eReproducerCrashSigsegv,
};
enum LoadDependentFiles {
eLoadDependentsDefault,
eLoadDependentsYes,

View File

@@ -377,7 +377,11 @@ SBError SBDebugger::SetInputFile(SBFile file) {
error.ref().SetErrorString("invalid debugger");
return error;
}
error.SetError(m_opaque_sp->SetInputFile(file.m_opaque_sp));
if (!file) {
error.ref().SetErrorString("invalid file");
return error;
}
m_opaque_sp->SetInputFile(file.m_opaque_sp);
return error;
}
@@ -1388,9 +1392,7 @@ void SBDebugger::SetPrompt(const char *prompt) {
const char *SBDebugger::GetReproducerPath() const {
LLDB_INSTRUMENT_VA(this);
return (m_opaque_sp
? ConstString(m_opaque_sp->GetReproducerPath()).GetCString()
: nullptr);
return "GetReproducerPath has been deprecated";
}
ScriptLanguage SBDebugger::GetScriptLanguage() const {

View File

@@ -22,69 +22,49 @@
#include "lldb/API/SBHostOS.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Utility/Instrumentation.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Version/Version.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::repro;
SBReplayOptions::SBReplayOptions()
: m_opaque_up(std::make_unique<ReplayOptions>()){}
SBReplayOptions::SBReplayOptions() {}
SBReplayOptions::SBReplayOptions(const SBReplayOptions &rhs)
: m_opaque_up(std::make_unique<ReplayOptions>(*rhs.m_opaque_up)) {}
SBReplayOptions::SBReplayOptions(const SBReplayOptions &rhs) {}
SBReplayOptions::~SBReplayOptions() = default;
SBReplayOptions &SBReplayOptions::operator=(const SBReplayOptions &rhs) {
LLDB_INSTRUMENT_VA(this, rhs)
if (this == &rhs)
return *this;
*m_opaque_up = *rhs.m_opaque_up;
return *this;
}
void SBReplayOptions::SetVerify(bool verify) {
LLDB_INSTRUMENT_VA(this, verify) m_opaque_up->verify = verify;
LLDB_INSTRUMENT_VA(this, verify);
}
bool SBReplayOptions::GetVerify() const {
LLDB_INSTRUMENT_VA(this) return m_opaque_up->verify;
LLDB_INSTRUMENT_VA(this);
return false;
}
void SBReplayOptions::SetCheckVersion(bool check) {
LLDB_INSTRUMENT_VA(this, check)
m_opaque_up->check_version = check;
LLDB_INSTRUMENT_VA(this, check);
}
bool SBReplayOptions::GetCheckVersion() const {
LLDB_INSTRUMENT_VA(this)
return m_opaque_up->check_version;
LLDB_INSTRUMENT_VA(this);
return false;
}
const char *SBReproducer::Capture() {
LLDB_INSTRUMENT()
static std::string error;
if (auto e = Reproducer::Initialize(ReproducerMode::Capture, llvm::None)) {
error = llvm::toString(std::move(e));
return error.c_str();
}
return nullptr;
return "Reproducer capture has been removed";
}
const char *SBReproducer::Capture(const char *path) {
LLDB_INSTRUMENT_VA(path)
static std::string error;
if (auto e =
Reproducer::Initialize(ReproducerMode::Capture, FileSpec(path))) {
error = llvm::toString(std::move(e));
return error.c_str();
}
return nullptr;
return "Reproducer capture has been removed";
}
const char *SBReproducer::PassiveReplay(const char *path) {
@@ -99,13 +79,13 @@ const char *SBReproducer::Replay(const char *path) {
const char *SBReproducer::Replay(const char *path, bool skip_version_check) {
LLDB_INSTRUMENT_VA(path, skip_version_check)
return Replay(path);
return "Reproducer replay has been removed";
}
const char *SBReproducer::Replay(const char *path,
const SBReplayOptions &options) {
LLDB_INSTRUMENT_VA(path, options)
return Replay(path);
return "Reproducer replay has been removed";
}
const char *SBReproducer::Finalize(const char *path) {
@@ -115,38 +95,19 @@ const char *SBReproducer::Finalize(const char *path) {
bool SBReproducer::Generate() {
LLDB_INSTRUMENT()
auto &r = Reproducer::Instance();
if (auto generator = r.GetGenerator()) {
generator->Keep();
return true;
}
return false;
}
bool SBReproducer::SetAutoGenerate(bool b) {
LLDB_INSTRUMENT_VA(b)
auto &r = Reproducer::Instance();
if (auto generator = r.GetGenerator()) {
generator->SetAutoGenerate(b);
return true;
}
return false;
}
const char *SBReproducer::GetPath() {
LLDB_INSTRUMENT()
ConstString path;
if (FileSpec reproducer_path = Reproducer::Instance().GetReproducerPath())
path = ConstString(reproducer_path.GetPathAsConstString());
return path.GetCString();
return "Reproducer GetPath has been removed";
}
void SBReproducer::SetWorkingDirectory(const char *path) {
LLDB_INSTRUMENT_VA(path)
if (auto *g = lldb_private::repro::Reproducer::Instance().GetGenerator()) {
auto &wp = g->GetOrCreate<repro::WorkingDirectoryProvider>();
wp.SetDirectory(path);
auto &fp = g->GetOrCreate<repro::FileProvider>();
fp.RecordInterestingDirectory(wp.GetDirectory());
}
}

View File

@@ -15,7 +15,6 @@
#include "lldb/Initialization/SystemInitializerCommon.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Target/ProcessTrace.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/Timer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/TargetSelect.h"

View File

@@ -24,7 +24,6 @@ add_lldb_library(lldbCommands
CommandObjectQuit.cpp
CommandObjectRegexCommand.cpp
CommandObjectRegister.cpp
CommandObjectReproducer.cpp
CommandObjectScript.cpp
CommandObjectSession.cpp
CommandObjectSettings.cpp

View File

@@ -891,7 +891,7 @@ protected:
llvm::StringRef(), // Continuation prompt
multiple_lines, color_prompt,
0, // Don't show line numbers
*this, nullptr));
*this));
if (io_handler_sp) {
debugger.RunIOHandlerAsync(io_handler_sp);

View File

@@ -509,7 +509,7 @@ void CommandObjectExpression::GetMultilineExpression() {
llvm::StringRef(), // Continuation prompt
multiple_lines, color_prompt,
1, // Show line numbers starting at 1
*this, nullptr));
*this));
StreamFileSP output_sp = io_handler_sp->GetOutputStreamFileSP();
if (output_sp) {

View File

@@ -1,503 +0,0 @@
//===-- CommandObjectReproducer.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 "CommandObjectReproducer.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Utility/GDBRemote.h"
#include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/Reproducer.h"
#include <csignal>
using namespace lldb;
using namespace llvm;
using namespace lldb_private;
using namespace lldb_private::repro;
#define LLDB_OPTIONS_reproducer_dump
#include "CommandOptions.inc"
#define LLDB_OPTIONS_reproducer_xcrash
#include "CommandOptions.inc"
#define LLDB_OPTIONS_reproducer_verify
#include "CommandOptions.inc"
template <typename T>
llvm::Expected<T> static ReadFromYAML(StringRef filename) {
auto error_or_file = MemoryBuffer::getFile(filename);
if (auto err = error_or_file.getError()) {
return errorCodeToError(err);
}
T t;
yaml::Input yin((*error_or_file)->getBuffer());
yin >> t;
if (auto err = yin.error()) {
return errorCodeToError(err);
}
return t;
}
static void SetError(CommandReturnObject &result, Error err) {
result.AppendError(toString(std::move(err)));
}
/// Create a loader from the given path if specified. Otherwise use the current
/// loader used for replay.
static Loader *
GetLoaderFromPathOrCurrent(llvm::Optional<Loader> &loader_storage,
CommandReturnObject &result,
FileSpec reproducer_path) {
if (reproducer_path) {
loader_storage.emplace(reproducer_path);
Loader *loader = &(*loader_storage);
if (Error err = loader->LoadIndex()) {
// This is a hard error and will set the result to eReturnStatusFailed.
SetError(result, std::move(err));
return nullptr;
}
return loader;
}
if (Loader *loader = Reproducer::Instance().GetLoader())
return loader;
// This is a soft error because this is expected to fail during capture.
result.AppendError(
"Not specifying a reproducer is only support during replay.");
result.SetStatus(eReturnStatusSuccessFinishNoResult);
return nullptr;
}
class CommandObjectReproducerGenerate : public CommandObjectParsed {
public:
CommandObjectReproducerGenerate(CommandInterpreter &interpreter)
: CommandObjectParsed(
interpreter, "reproducer generate",
"Generate reproducer on disk. When the debugger is in capture "
"mode, this command will output the reproducer to a directory on "
"disk and quit. In replay mode this command in a no-op.",
nullptr) {}
~CommandObjectReproducerGenerate() override = default;
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
auto &r = Reproducer::Instance();
if (auto generator = r.GetGenerator()) {
generator->Keep();
} else {
result.AppendErrorWithFormat("Unable to get the reproducer generator");
return false;
}
result.GetOutputStream()
<< "Reproducer written to '" << r.GetReproducerPath() << "'\n";
result.GetOutputStream()
<< "Please have a look at the directory to assess if you're willing to "
"share the contained information.\n";
m_interpreter.BroadcastEvent(
CommandInterpreter::eBroadcastBitQuitCommandReceived);
result.SetStatus(eReturnStatusQuit);
return result.Succeeded();
}
};
class CommandObjectReproducerXCrash : public CommandObjectParsed {
public:
CommandObjectReproducerXCrash(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "reproducer xcrash",
"Intentionally force the debugger to crash in "
"order to trigger and test reproducer generation.",
nullptr) {}
~CommandObjectReproducerXCrash() override = default;
Options *GetOptions() override { return &m_options; }
class CommandOptions : public Options {
public:
CommandOptions() = default;
~CommandOptions() override = default;
Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
ExecutionContext *execution_context) override {
Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
case 's':
signal = (ReproducerCrashSignal)OptionArgParser::ToOptionEnum(
option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
if (!error.Success())
error.SetErrorStringWithFormat("unrecognized value for signal '%s'",
option_arg.str().c_str());
break;
default:
llvm_unreachable("Unimplemented option");
}
return error;
}
void OptionParsingStarting(ExecutionContext *execution_context) override {
signal = eReproducerCrashSigsegv;
}
ArrayRef<OptionDefinition> GetDefinitions() override {
return makeArrayRef(g_reproducer_xcrash_options);
}
ReproducerCrashSignal signal = eReproducerCrashSigsegv;
};
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
auto &r = Reproducer::Instance();
if (!r.IsCapturing()) {
result.AppendError(
"forcing a crash is only supported when capturing a reproducer.");
result.SetStatus(eReturnStatusSuccessFinishNoResult);
return false;
}
switch (m_options.signal) {
case eReproducerCrashSigill:
std::raise(SIGILL);
break;
case eReproducerCrashSigsegv:
std::raise(SIGSEGV);
break;
}
result.SetStatus(eReturnStatusQuit);
return result.Succeeded();
}
private:
CommandOptions m_options;
};
class CommandObjectReproducerStatus : public CommandObjectParsed {
public:
CommandObjectReproducerStatus(CommandInterpreter &interpreter)
: CommandObjectParsed(
interpreter, "reproducer status",
"Show the current reproducer status. In capture mode the "
"debugger "
"is collecting all the information it needs to create a "
"reproducer. In replay mode the reproducer is replaying a "
"reproducer. When the reproducers are off, no data is collected "
"and no reproducer can be generated.",
nullptr) {}
~CommandObjectReproducerStatus() override = default;
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
auto &r = Reproducer::Instance();
if (r.IsCapturing()) {
result.GetOutputStream() << "Reproducer is in capture mode.\n";
result.GetOutputStream()
<< "Path: " << r.GetReproducerPath().GetPath() << '\n';
} else {
result.GetOutputStream() << "Reproducer is off.\n";
}
// Auto generate is hidden unless enabled because this is mostly for
// development and testing.
if (Generator *g = r.GetGenerator()) {
if (g->IsAutoGenerate())
result.GetOutputStream() << "Auto generate: on\n";
}
result.SetStatus(eReturnStatusSuccessFinishResult);
return result.Succeeded();
}
};
class CommandObjectReproducerDump : public CommandObjectParsed {
public:
CommandObjectReproducerDump(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "reproducer dump",
"Dump the information contained in a reproducer. "
"If no reproducer is specified during replay, it "
"dumps the content of the current reproducer.",
nullptr) {}
~CommandObjectReproducerDump() override = default;
Options *GetOptions() override { return &m_options; }
class CommandOptions : public Options {
public:
CommandOptions() = default;
~CommandOptions() override = default;
Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
ExecutionContext *execution_context) override {
Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
case 'f':
file.SetFile(option_arg, FileSpec::Style::native);
FileSystem::Instance().Resolve(file);
break;
case 'p':
provider = (ReproducerProvider)OptionArgParser::ToOptionEnum(
option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
if (!error.Success())
error.SetErrorStringWithFormat("unrecognized value for provider '%s'",
option_arg.str().c_str());
break;
default:
llvm_unreachable("Unimplemented option");
}
return error;
}
void OptionParsingStarting(ExecutionContext *execution_context) override {
file.Clear();
provider = eReproducerProviderNone;
}
ArrayRef<OptionDefinition> GetDefinitions() override {
return makeArrayRef(g_reproducer_dump_options);
}
FileSpec file;
ReproducerProvider provider = eReproducerProviderNone;
};
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
llvm::Optional<Loader> loader_storage;
Loader *loader =
GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file);
if (!loader)
return false;
switch (m_options.provider) {
case eReproducerProviderFiles: {
FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>();
// Read the VFS mapping.
ErrorOr<std::unique_ptr<MemoryBuffer>> buffer =
vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath());
if (!buffer) {
SetError(result, errorCodeToError(buffer.getError()));
return false;
}
// Initialize a VFS from the given mapping.
IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML(
std::move(buffer.get()), nullptr, vfs_mapping.GetPath());
// Dump the VFS to a buffer.
std::string str;
raw_string_ostream os(str);
static_cast<vfs::RedirectingFileSystem &>(*vfs).print(os);
os.flush();
// Return the string.
result.AppendMessage(str);
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
case eReproducerProviderSymbolFiles: {
Expected<std::string> symbol_files =
loader->LoadBuffer<SymbolFileProvider>();
if (!symbol_files) {
SetError(result, symbol_files.takeError());
return false;
}
std::vector<SymbolFileProvider::Entry> entries;
llvm::yaml::Input yin(*symbol_files);
yin >> entries;
for (const auto &entry : entries) {
result.AppendMessageWithFormat("- uuid: %s\n",
entry.uuid.c_str());
result.AppendMessageWithFormat(" module path: %s\n",
entry.module_path.c_str());
result.AppendMessageWithFormat(" symbol path: %s\n",
entry.symbol_path.c_str());
}
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
case eReproducerProviderVersion: {
Expected<std::string> version = loader->LoadBuffer<VersionProvider>();
if (!version) {
SetError(result, version.takeError());
return false;
}
result.AppendMessage(*version);
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
case eReproducerProviderWorkingDirectory: {
Expected<std::string> cwd =
repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader);
if (!cwd) {
SetError(result, cwd.takeError());
return false;
}
result.AppendMessage(*cwd);
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
case eReproducerProviderHomeDirectory: {
Expected<std::string> home =
repro::GetDirectoryFrom<HomeDirectoryProvider>(loader);
if (!home) {
SetError(result, home.takeError());
return false;
}
result.AppendMessage(*home);
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
case eReproducerProviderCommands: {
std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader =
repro::MultiLoader<repro::CommandProvider>::Create(loader);
if (!multi_loader) {
SetError(result,
make_error<StringError>("Unable to create command loader.",
llvm::inconvertibleErrorCode()));
return false;
}
// Iterate over the command files and dump them.
llvm::Optional<std::string> command_file;
while ((command_file = multi_loader->GetNextFile())) {
if (!command_file)
break;
auto command_buffer = llvm::MemoryBuffer::getFile(*command_file);
if (auto err = command_buffer.getError()) {
SetError(result, errorCodeToError(err));
return false;
}
result.AppendMessage((*command_buffer)->getBuffer());
}
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
case eReproducerProviderGDB: {
std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>>
multi_loader =
repro::MultiLoader<repro::GDBRemoteProvider>::Create(loader);
if (!multi_loader) {
SetError(result,
make_error<StringError>("Unable to create GDB loader.",
llvm::inconvertibleErrorCode()));
return false;
}
llvm::Optional<std::string> gdb_file;
while ((gdb_file = multi_loader->GetNextFile())) {
if (llvm::Expected<std::vector<GDBRemotePacket>> packets =
ReadFromYAML<std::vector<GDBRemotePacket>>(*gdb_file)) {
for (GDBRemotePacket &packet : *packets) {
packet.Dump(result.GetOutputStream());
}
} else {
SetError(result, packets.takeError());
return false;
}
}
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
case eReproducerProviderProcessInfo: {
std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>>
multi_loader =
repro::MultiLoader<repro::ProcessInfoProvider>::Create(loader);
if (!multi_loader) {
SetError(result, make_error<StringError>(
llvm::inconvertibleErrorCode(),
"Unable to create process info loader."));
return false;
}
llvm::Optional<std::string> process_file;
while ((process_file = multi_loader->GetNextFile())) {
if (llvm::Expected<ProcessInstanceInfoList> infos =
ReadFromYAML<ProcessInstanceInfoList>(*process_file)) {
for (ProcessInstanceInfo info : *infos)
info.Dump(result.GetOutputStream(), HostInfo::GetUserIDResolver());
} else {
SetError(result, infos.takeError());
return false;
}
}
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
case eReproducerProviderNone:
result.AppendError("No valid provider specified.");
return false;
}
result.SetStatus(eReturnStatusSuccessFinishNoResult);
return result.Succeeded();
}
private:
CommandOptions m_options;
};
CommandObjectReproducer::CommandObjectReproducer(
CommandInterpreter &interpreter)
: CommandObjectMultiword(
interpreter, "reproducer",
"Commands for manipulating reproducers. Reproducers make it "
"possible "
"to capture full debug sessions with all its dependencies. The "
"resulting reproducer is used to replay the debug session while "
"debugging the debugger.\n"
"Because reproducers need the whole the debug session from "
"beginning to end, you need to launch the debugger in capture or "
"replay mode, commonly though the command line driver.\n"
"Reproducers are unrelated record-replay debugging, as you cannot "
"interact with the debugger during replay.\n",
"reproducer <subcommand> [<subcommand-options>]") {
LoadSubCommand(
"generate",
CommandObjectSP(new CommandObjectReproducerGenerate(interpreter)));
LoadSubCommand("status", CommandObjectSP(
new CommandObjectReproducerStatus(interpreter)));
LoadSubCommand("dump",
CommandObjectSP(new CommandObjectReproducerDump(interpreter)));
LoadSubCommand("xcrash", CommandObjectSP(
new CommandObjectReproducerXCrash(interpreter)));
}
CommandObjectReproducer::~CommandObjectReproducer() = default;

View File

@@ -1,27 +0,0 @@
//===-- CommandObjectReproducer.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_SOURCE_COMMANDS_COMMANDOBJECTREPRODUCER_H
#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTREPRODUCER_H
#include "lldb/Interpreter/CommandObjectMultiword.h"
namespace lldb_private {
// CommandObjectReproducer
class CommandObjectReproducer : public CommandObjectMultiword {
public:
CommandObjectReproducer(CommandInterpreter &interpreter);
~CommandObjectReproducer() override;
};
} // namespace lldb_private
#endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTREPRODUCER_H

View File

@@ -466,27 +466,6 @@ let Command = "log dump" in {
Desc<"Set the destination file to dump to.">;
}
let Command = "reproducer dump" in {
def reproducer_provider : Option<"provider", "p">, Group<1>,
EnumArg<"ReproducerProvider">,
Required, Desc<"The reproducer provider to dump.">;
def reproducer_file : Option<"file", "f">, Group<1>, Arg<"Filename">,
Desc<"The reproducer path. If a reproducer is replayed and no path is "
"provided, that reproducer is dumped.">;
}
let Command = "reproducer verify" in {
def reproducer_verify_file : Option<"file", "f">, Group<1>, Arg<"Filename">,
Desc<"The reproducer path. If a reproducer is replayed and no path is "
"provided, that reproducer is dumped.">;
}
let Command = "reproducer xcrash" in {
def reproducer_signal : Option<"signal", "s">, Group<1>,
EnumArg<"ReproducerSignal">,
Required, Desc<"The signal to crash the debugger.">;
}
let Command = "memory read" in {
def memory_read_num_per_line : Option<"num-per-line", "l">, Group<1>,
Arg<"NumberPerLine">, Desc<"The number of items per line to display.">;

View File

@@ -48,8 +48,6 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Listener.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h"
@@ -302,11 +300,6 @@ void Debugger::SetPrompt(llvm::StringRef p) {
GetCommandInterpreter().UpdatePrompt(new_prompt);
}
llvm::StringRef Debugger::GetReproducerPath() const {
auto &r = repro::Reproducer::Instance();
return r.GetReproducerPath().GetPathAsConstString().AsCString();
}
const FormatEntity::Entry *Debugger::GetThreadFormat() const {
const uint32_t idx = ePropertyThreadFormat;
return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
@@ -924,42 +917,12 @@ Status Debugger::SetInputString(const char *data) {
return result;
}
return SetInputFile(
(FileSP)std::make_shared<NativeFile>(commands_file, true));
SetInputFile((FileSP)std::make_shared<NativeFile>(commands_file, true));
return result;
}
Status Debugger::SetInputFile(FileSP file_sp) {
Status error;
repro::DataRecorder *recorder = nullptr;
if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator())
recorder = g->GetOrCreate<repro::CommandProvider>().GetNewRecorder();
static std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> loader =
repro::MultiLoader<repro::CommandProvider>::Create(
repro::Reproducer::Instance().GetLoader());
if (loader) {
llvm::Optional<std::string> nextfile = loader->GetNextFile();
FILE *fh = nextfile ? FileSystem::Instance().Fopen(nextfile->c_str(), "r")
: nullptr;
// FIXME Jonas Devlieghere: shouldn't this error be propagated out to the
// reproducer somehow if fh is NULL?
if (fh) {
file_sp = std::make_shared<NativeFile>(fh, true);
}
}
if (!file_sp || !file_sp->IsValid()) {
error.SetErrorString("invalid file");
return error;
}
SetInputFile(file_sp, recorder);
return error;
}
void Debugger::SetInputFile(FileSP file_sp, repro::DataRecorder *recorder) {
void Debugger::SetInputFile(FileSP file_sp) {
assert(file_sp && file_sp->IsValid());
m_input_recorder = recorder;
m_input_file_sp = std::move(file_sp);
// Save away the terminal state if that is relevant, so that we can restore
// it in RestoreInputState.

View File

@@ -19,7 +19,6 @@
#include "lldb/Host/File.h"
#include "lldb/Utility/AnsiTerminal.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"
@@ -59,19 +58,17 @@ IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type)
FileSP(), // Adopt STDIN from top input reader
StreamFileSP(), // Adopt STDOUT from top input reader
StreamFileSP(), // Adopt STDERR from top input reader
0, // Flags
nullptr // Shadow file recorder
0 // Flags
) {}
IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type,
const lldb::FileSP &input_sp,
const lldb::StreamFileSP &output_sp,
const lldb::StreamFileSP &error_sp, uint32_t flags,
repro::DataRecorder *data_recorder)
const lldb::StreamFileSP &error_sp, uint32_t flags)
: m_debugger(debugger), m_input_sp(input_sp), m_output_sp(output_sp),
m_error_sp(error_sp), m_data_recorder(data_recorder), m_popped(false),
m_flags(flags), m_type(type), m_user_data(nullptr), m_done(false),
m_active(false) {
m_error_sp(error_sp), m_popped(false), m_flags(flags), m_type(type),
m_user_data(nullptr), m_done(false), m_active(false) {
// If any files are not specified, then adopt them from the top input reader.
if (!m_input_sp || !m_output_sp || !m_error_sp)
debugger.AdoptTopIOHandlerFilesIfInvalid(m_input_sp, m_output_sp,
@@ -146,7 +143,7 @@ IOHandlerConfirm::IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt,
llvm::StringRef(), // No continuation prompt
false, // Multi-line
false, // Don't colorize the prompt (i.e. the confirm message.)
0, *this, nullptr),
0, *this),
m_default_response(default_response), m_user_response(default_response) {
StreamString prompt_stream;
prompt_stream.PutCString(prompt);
@@ -231,7 +228,7 @@ IOHandlerEditline::IOHandlerEditline(
const char *editline_name, // Used for saving history files
llvm::StringRef prompt, llvm::StringRef continuation_prompt,
bool multi_line, bool color_prompts, uint32_t line_number_start,
IOHandlerDelegate &delegate, repro::DataRecorder *data_recorder)
IOHandlerDelegate &delegate)
: IOHandlerEditline(debugger, type,
FileSP(), // Inherit input from top input reader
StreamFileSP(), // Inherit output from top input reader
@@ -239,7 +236,7 @@ IOHandlerEditline::IOHandlerEditline(
0, // Flags
editline_name, // Used for saving history files
prompt, continuation_prompt, multi_line, color_prompts,
line_number_start, delegate, data_recorder) {}
line_number_start, delegate) {}
IOHandlerEditline::IOHandlerEditline(
Debugger &debugger, IOHandler::Type type, const lldb::FileSP &input_sp,
@@ -248,9 +245,8 @@ IOHandlerEditline::IOHandlerEditline(
const char *editline_name, // Used for saving history files
llvm::StringRef prompt, llvm::StringRef continuation_prompt,
bool multi_line, bool color_prompts, uint32_t line_number_start,
IOHandlerDelegate &delegate, repro::DataRecorder *data_recorder)
: IOHandler(debugger, type, input_sp, output_sp, error_sp, flags,
data_recorder),
IOHandlerDelegate &delegate)
: IOHandler(debugger, type, input_sp, output_sp, error_sp, flags),
#if LLDB_ENABLE_LIBEDIT
m_editline_up(),
#endif
@@ -354,10 +350,7 @@ static Optional<std::string> SplitLineEOF(std::string &line_buffer) {
bool IOHandlerEditline::GetLine(std::string &line, bool &interrupted) {
#if LLDB_ENABLE_LIBEDIT
if (m_editline_up) {
bool b = m_editline_up->GetLine(line, interrupted);
if (b && m_data_recorder)
m_data_recorder->Record(line, true);
return b;
return m_editline_up->GetLine(line, interrupted);
}
#endif
@@ -437,8 +430,6 @@ bool IOHandlerEditline::GetLine(std::string &line, bool &interrupted) {
if (got_line) {
line = *got_line;
if (m_data_recorder)
m_data_recorder->Record(line, true);
}
return (bool)got_line;

View File

@@ -79,7 +79,7 @@ lldb::IOHandlerSP REPL::GetIOHandler() {
true, // Multi-line
true, // The REPL prompt is always colored
1, // Line number
*this, nullptr);
*this);
// Don't exit if CTRL+C is pressed
static_cast<IOHandlerEditline *>(m_io_handler_sp.get())

View File

@@ -60,7 +60,6 @@
#include "lldb/Utility/LLDBLog.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"
@@ -614,22 +613,7 @@ void llvm::format_provider<WaitStatus>::format(const WaitStatus &WS,
uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
ProcessInstanceInfoList &process_infos) {
if (llvm::Optional<ProcessInstanceInfoList> infos =
repro::GetReplayProcessInstanceInfoList()) {
process_infos = *infos;
return process_infos.size();
}
uint32_t result = FindProcessesImpl(match_info, process_infos);
if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
g->GetOrCreate<repro::ProcessInfoProvider>()
.GetNewProcessInfoRecorder()
->Record(process_infos);
}
return result;
return FindProcessesImpl(match_info, process_infos);
}
char SystemLogHandler::ID;

View File

@@ -13,7 +13,6 @@
#include "lldb/Host/Host.h"
#include "lldb/Host/Socket.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/Timer.h"
#include "lldb/Version/Version.h"
@@ -32,7 +31,6 @@
#include <string>
using namespace lldb_private;
using namespace lldb_private::repro;
SystemInitializerCommon::SystemInitializerCommon(
HostInfo::SharedLibraryDirectoryHelper *helper)
@@ -40,31 +38,6 @@ SystemInitializerCommon::SystemInitializerCommon(
SystemInitializerCommon::~SystemInitializerCommon() = default;
/// Initialize the FileSystem based on the current reproducer mode.
static llvm::Error InitializeFileSystem() {
auto &r = repro::Reproducer::Instance();
if (repro::Generator *g = r.GetGenerator()) {
repro::VersionProvider &vp = g->GetOrCreate<repro::VersionProvider>();
vp.SetVersion(lldb_private::GetVersion());
repro::FileProvider &fp = g->GetOrCreate<repro::FileProvider>();
FileSystem::Initialize(llvm::FileCollector::createCollectorVFS(
llvm::vfs::getRealFileSystem(), fp.GetFileCollector()));
fp.RecordInterestingDirectory(
g->GetOrCreate<repro::WorkingDirectoryProvider>().GetDirectory());
fp.RecordInterestingDirectory(
g->GetOrCreate<repro::HomeDirectoryProvider>().GetDirectory());
return llvm::Error::success();
}
FileSystem::Initialize();
return llvm::Error::success();
}
llvm::Error SystemInitializerCommon::Initialize() {
#if defined(_WIN32)
const char *disable_crash_dialog_var = getenv("LLDB_DISABLE_CRASH_DIALOG");
@@ -88,17 +61,9 @@ llvm::Error SystemInitializerCommon::Initialize() {
}
#endif
// If the reproducer wasn't initialized before, we can safely assume it's
// off.
if (!Reproducer::Initialized()) {
if (auto e = Reproducer::Initialize(ReproducerMode::Off, llvm::None))
return e;
}
if (auto e = InitializeFileSystem())
return e;
InitializeLldbChannel();
FileSystem::Initialize();
HostInfo::Initialize(m_shlib_dir_helper);
llvm::Error error = Socket::Initialize();
@@ -130,5 +95,4 @@ void SystemInitializerCommon::Terminate() {
HostInfo::Terminate();
Log::DisableAllLogChannels();
FileSystem::Terminate();
Reproducer::Terminate();
}

View File

@@ -29,7 +29,6 @@
#include "Commands/CommandObjectQuit.h"
#include "Commands/CommandObjectRegexCommand.h"
#include "Commands/CommandObjectRegister.h"
#include "Commands/CommandObjectReproducer.h"
#include "Commands/CommandObjectScript.h"
#include "Commands/CommandObjectSession.h"
#include "Commands/CommandObjectSettings.h"
@@ -47,7 +46,6 @@
#include "lldb/Core/StreamFile.h"
#include "lldb/Utility/LLDBLog.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"
@@ -532,7 +530,6 @@ void CommandInterpreter::LoadCommandDictionary() {
REGISTER_COMMAND_OBJECT("process", CommandObjectMultiwordProcess);
REGISTER_COMMAND_OBJECT("quit", CommandObjectQuit);
REGISTER_COMMAND_OBJECT("register", CommandObjectRegister);
REGISTER_COMMAND_OBJECT("reproducer", CommandObjectReproducer);
REGISTER_COMMAND_OBJECT("script", CommandObjectScript);
REGISTER_COMMAND_OBJECT("settings", CommandObjectMultiwordSettings);
REGISTER_COMMAND_OBJECT("session", CommandObjectSession);
@@ -2776,7 +2773,7 @@ void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file,
// or written
debugger.GetPrompt(), llvm::StringRef(),
false, // Not multi-line
debugger.GetUseColor(), 0, *this, nullptr));
debugger.GetUseColor(), 0, *this));
const bool old_async_execution = debugger.GetAsyncExecution();
// Set synchronous execution if we are not stopping on continue
@@ -2800,9 +2797,6 @@ void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file,
bool CommandInterpreter::GetSynchronous() { return m_synchronous_execution; }
void CommandInterpreter::SetSynchronous(bool value) {
// Asynchronous mode is not supported during reproducer replay.
if (repro::Reproducer::Instance().GetLoader())
return;
m_synchronous_execution = value;
}
@@ -3249,9 +3243,8 @@ void CommandInterpreter::GetLLDBCommandsFromIOHandler(
llvm::StringRef(), // Continuation prompt
true, // Get multiple lines
debugger.GetUseColor(),
0, // Don't show line numbers
delegate, // IOHandlerDelegate
nullptr)); // FileShadowCollector
0, // Don't show line numbers
delegate)); // IOHandlerDelegate
if (io_handler_sp) {
io_handler_sp->SetUserData(baton);
@@ -3269,9 +3262,8 @@ void CommandInterpreter::GetPythonCommandsFromIOHandler(
llvm::StringRef(), // Continuation prompt
true, // Get multiple lines
debugger.GetUseColor(),
0, // Don't show line numbers
delegate, // IOHandlerDelegate
nullptr)); // FileShadowCollector
0, // Don't show line numbers
delegate)); // IOHandlerDelegate
if (io_handler_sp) {
io_handler_sp->SetUserData(baton);
@@ -3322,9 +3314,8 @@ CommandInterpreter::GetIOHandler(bool force_create,
llvm::StringRef(), // Continuation prompt
false, // Don't enable multiple line input, just single line commands
m_debugger.GetUseColor(),
0, // Don't show line numbers
*this, // IOHandlerDelegate
GetDebugger().GetInputRecorder());
0, // Don't show line numbers
*this); // IOHandlerDelegate
}
return m_command_io_handler_sp;
}

View File

@@ -86,7 +86,6 @@
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StringList.h"
@@ -391,18 +390,6 @@ ClangExpressionParser::ClangExpressionParser(
// 1. Create a new compiler instance.
m_compiler = std::make_unique<CompilerInstance>();
// When capturing a reproducer, hook up the file collector with clang to
// collector modules and headers.
if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
repro::FileProvider &fp = g->GetOrCreate<repro::FileProvider>();
m_compiler->setModuleDepCollector(
std::make_shared<ModuleDependencyCollectorAdaptor>(
fp.GetFileCollector()));
DependencyOutputOptions &opts = m_compiler->getDependencyOutputOpts();
opts.IncludeSystemHeaders = true;
opts.IncludeModuleFiles = true;
}
// Make sure clang uses the same VFS as LLDB.
m_compiler->createFileManager(FileSystem::Instance().GetVirtualFileSystem());

View File

@@ -34,7 +34,6 @@
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/StreamString.h"
#include <memory>
@@ -683,18 +682,6 @@ ClangModulesDeclVendor::Create(Target &target) {
std::unique_ptr<clang::CompilerInstance> instance(
new clang::CompilerInstance);
// When capturing a reproducer, hook up the file collector with clang to
// collector modules and headers.
if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
repro::FileProvider &fp = g->GetOrCreate<repro::FileProvider>();
instance->setModuleDepCollector(
std::make_shared<ModuleDependencyCollectorAdaptor>(
fp.GetFileCollector()));
clang::DependencyOutputOptions &opts = instance->getDependencyOutputOpts();
opts.IncludeSystemHeaders = true;
opts.IncludeModuleFiles = true;
}
// Make sure clang uses the same VFS as LLDB.
instance->createFileManager(FileSystem::Instance().GetVirtualFileSystem());
instance->setDiagnostics(diagnostics_engine.get());

View File

@@ -238,11 +238,6 @@ Status PlatformRemoteGDBServer::ConnectRemote(Args &args) {
client_up->SetPacketTimeout(
process_gdb_remote::ProcessGDBRemote::GetPacketTimeout());
client_up->SetConnection(std::make_unique<ConnectionFileDescriptor>());
if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
repro::GDBRemoteProvider &provider =
g->GetOrCreate<repro::GDBRemoteProvider>();
client_up->SetPacketRecorder(provider.GetNewPacketRecorder());
}
client_up->Connect(url, &error);
if (error.Fail())

View File

@@ -30,7 +30,6 @@
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ScopedPrinter.h"
@@ -1224,11 +1223,6 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); }
void GDBRemoteCommunication::SetPacketRecorder(
repro::PacketRecorder *recorder) {
m_history.SetRecorder(recorder);
}
llvm::Error
GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
GDBRemoteCommunication &server) {

View File

@@ -23,6 +23,7 @@
#include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/Utility/TraceGDBRemotePackets.h"
#include "lldb/Utility/UUID.h"
#if defined(_WIN32)
#include "lldb/Host/windows/PosixApi.h"
#endif

View File

@@ -39,8 +39,6 @@ void GDBRemoteCommunicationHistory::AddPacket(char packet_char,
m_packets[idx].bytes_transmitted = bytes_transmitted;
m_packets[idx].packet_idx = m_total_packet_count;
m_packets[idx].tid = llvm::get_threadid();
if (m_recorder)
m_recorder->Record(m_packets[idx]);
}
void GDBRemoteCommunicationHistory::AddPacket(const std::string &src,
@@ -57,8 +55,6 @@ void GDBRemoteCommunicationHistory::AddPacket(const std::string &src,
m_packets[idx].bytes_transmitted = bytes_transmitted;
m_packets[idx].packet_idx = m_total_packet_count;
m_packets[idx].tid = llvm::get_threadid();
if (m_recorder)
m_recorder->Record(m_packets[idx]);
}
void GDBRemoteCommunicationHistory::Dump(Stream &strm) const {

View File

@@ -13,23 +13,16 @@
#include <vector>
#include "lldb/Utility/GDBRemote.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/lldb-public.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
namespace lldb_private {
namespace repro {
class PacketRecorder;
}
namespace process_gdb_remote {
/// The history keeps a circular buffer of GDB remote packets. The history is
/// used for logging and replaying GDB remote packets.
class GDBRemoteCommunicationHistory {
public:
friend llvm::yaml::MappingTraits<GDBRemoteCommunicationHistory>;
GDBRemoteCommunicationHistory(uint32_t size = 0);
~GDBRemoteCommunicationHistory();
@@ -45,8 +38,6 @@ public:
void Dump(Log *log) const;
bool DidDumpToLog() const { return m_dumped_to_log; }
void SetRecorder(repro::PacketRecorder *recorder) { m_recorder = recorder; }
private:
uint32_t GetFirstSavedPacketIndex() const {
if (m_total_packet_count < m_packets.size())
@@ -77,7 +68,6 @@ private:
uint32_t m_curr_idx = 0;
uint32_t m_total_packet_count = 0;
mutable bool m_dumped_to_log = false;
repro::PacketRecorder *m_recorder = nullptr;
};
} // namespace process_gdb_remote

View File

@@ -60,7 +60,6 @@
#include "lldb/Utility/Args.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/Timer.h"
@@ -266,12 +265,6 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadDidExit,
"async thread did exit");
if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
repro::GDBRemoteProvider &provider =
g->GetOrCreate<repro::GDBRemoteProvider>();
m_gdb_comm.SetPacketRecorder(provider.GetNewPacketRecorder());
}
Log *log = GetLog(GDBRLog::Async);
const uint32_t async_event_mask =

View File

@@ -40,8 +40,8 @@ public:
ScriptInterpreterLua &script_interpreter,
ActiveIOHandler active_io_handler = eIOHandlerNone)
: IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua",
">>> ", "..> ", true, debugger.GetUseColor(), 0,
*this, nullptr),
llvm::StringRef(">>> "), llvm::StringRef("..> "),
true, debugger.GetUseColor(), 0, *this),
m_script_interpreter(script_interpreter),
m_active_io_handler(active_io_handler) {
llvm::cantFail(m_script_interpreter.GetLua().ChangeIO(

View File

@@ -20,7 +20,6 @@
#include "lldb/Symbol/LocateSymbolFile.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/Timer.h"
@@ -279,13 +278,6 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp,
}
symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp);
if (!dsym_root.empty()) {
if (repro::Generator *g =
repro::Reproducer::Instance().GetGenerator()) {
repro::FileProvider &fp = g->GetOrCreate<repro::FileProvider>();
fp.RecordInterestingDirectoryRecursive(dsym_root);
}
}
return symbol_vendor;
}
}

View File

@@ -20,7 +20,6 @@
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/Timer.h"
#include "lldb/Utility/UUID.h"

View File

@@ -1469,15 +1469,3 @@ void ArchSpec::DumpTriple(llvm::raw_ostream &s) const {
if (!environ_str.empty())
s << "-" << environ_str;
}
void llvm::yaml::ScalarTraits<ArchSpec>::output(const ArchSpec &Val, void *,
raw_ostream &Out) {
Val.DumpTriple(Out);
}
llvm::StringRef
llvm::yaml::ScalarTraits<ArchSpec>::input(llvm::StringRef Scalar, void *,
ArchSpec &Val) {
Val = ArchSpec(Scalar);
return {};
}

View File

@@ -687,20 +687,3 @@ void OptionsWithRaw::SetFromString(llvm::StringRef arg_string) {
if (!found_suffix)
m_suffix = std::string(original_args);
}
void llvm::yaml::MappingTraits<Args::ArgEntry>::mapping(IO &io,
Args::ArgEntry &v) {
MappingNormalization<NormalizedArgEntry, Args::ArgEntry> keys(io, v);
io.mapRequired("value", keys->value);
io.mapRequired("quote", keys->quote);
}
void llvm::yaml::MappingTraits<Args>::mapping(IO &io, Args &v) {
io.mapRequired("entries", v.m_entries);
// Recompute m_argv vector.
v.m_argv.clear();
for (auto &entry : v.m_entries)
v.m_argv.push_back(entry.data());
v.m_argv.push_back(nullptr);
}

View File

@@ -48,9 +48,7 @@ add_lldb_library(lldbUtility
ProcessInfo.cpp
RegisterValue.cpp
RegularExpression.cpp
Reproducer.cpp
Instrumentation.cpp
ReproducerProvider.cpp
Scalar.cpp
SelectHelper.cpp
State.cpp

View File

@@ -335,15 +335,3 @@ void llvm::format_provider<ConstString>::format(const ConstString &CS,
llvm::StringRef Options) {
format_provider<StringRef>::format(CS.GetStringRef(), OS, Options);
}
void llvm::yaml::ScalarTraits<ConstString>::output(const ConstString &Val,
void *, raw_ostream &Out) {
Out << Val.GetStringRef();
}
llvm::StringRef
llvm::yaml::ScalarTraits<ConstString>::input(llvm::StringRef Scalar, void *,
ConstString &Val) {
Val = ConstString(Scalar);
return {};
}

View File

@@ -557,19 +557,3 @@ void llvm::format_provider<FileSpec>::format(const FileSpec &F,
if (!file.empty())
Stream << file;
}
void llvm::yaml::ScalarEnumerationTraits<FileSpecStyle>::enumeration(
IO &io, FileSpecStyle &value) {
io.enumCase(value, "windows", FileSpecStyle(FileSpec::Style::windows));
io.enumCase(value, "posix", FileSpecStyle(FileSpec::Style::posix));
io.enumCase(value, "native", FileSpecStyle(FileSpec::Style::native));
}
void llvm::yaml::MappingTraits<FileSpec>::mapping(IO &io, FileSpec &f) {
io.mapRequired("directory", f.m_directory);
io.mapRequired("file", f.m_filename);
io.mapRequired("resolved", f.m_is_resolved);
FileSpecStyle style = f.m_style;
io.mapRequired("style", style);
f.m_style = style;
}

View File

@@ -14,7 +14,6 @@
#include <cstdio>
using namespace lldb;
using namespace lldb_private::repro;
using namespace lldb_private;
using namespace llvm;
@@ -62,99 +61,3 @@ void GDBRemotePacket::Dump(Stream &strm) const {
strm.Printf("tid=0x%4.4" PRIx64 " <%4u> %s packet: %s\n", tid,
bytes_transmitted, GetTypeStr().data(), packet.data.c_str());
}
void yaml::ScalarEnumerationTraits<GDBRemotePacket::Type>::enumeration(
IO &io, GDBRemotePacket::Type &value) {
io.enumCase(value, "Invalid", GDBRemotePacket::ePacketTypeInvalid);
io.enumCase(value, "Send", GDBRemotePacket::ePacketTypeSend);
io.enumCase(value, "Recv", GDBRemotePacket::ePacketTypeRecv);
}
void yaml::ScalarTraits<GDBRemotePacket::BinaryData>::output(
const GDBRemotePacket::BinaryData &Val, void *, raw_ostream &Out) {
Out << toHex(Val.data);
}
StringRef yaml::ScalarTraits<GDBRemotePacket::BinaryData>::input(
StringRef Scalar, void *, GDBRemotePacket::BinaryData &Val) {
Val.data = fromHex(Scalar);
return {};
}
void yaml::MappingTraits<GDBRemotePacket>::mapping(IO &io,
GDBRemotePacket &Packet) {
io.mapRequired("packet", Packet.packet);
io.mapRequired("type", Packet.type);
io.mapRequired("bytes", Packet.bytes_transmitted);
io.mapRequired("index", Packet.packet_idx);
io.mapRequired("tid", Packet.tid);
}
StringRef
yaml::MappingTraits<GDBRemotePacket>::validate(IO &io,
GDBRemotePacket &Packet) {
return {};
}
void GDBRemoteProvider::Keep() {
std::vector<std::string> files;
for (auto &recorder : m_packet_recorders) {
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_TextWithCRLF);
if (ec)
return;
yaml::Output yout(os);
yout << files;
}
void GDBRemoteProvider::Discard() { m_packet_recorders.clear(); }
llvm::Expected<std::unique_ptr<PacketRecorder>>
PacketRecorder::Create(const FileSpec &filename) {
std::error_code ec;
auto recorder = std::make_unique<PacketRecorder>(std::move(filename), ec);
if (ec)
return llvm::errorCodeToError(ec);
return std::move(recorder);
}
PacketRecorder *GDBRemoteProvider::GetNewPacketRecorder() {
std::size_t i = m_packet_recorders.size() + 1;
std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") +
llvm::Twine(i) + llvm::Twine(".yaml"))
.str();
auto recorder_or_error =
PacketRecorder::Create(GetRoot().CopyByAppendingPathComponent(filename));
if (!recorder_or_error) {
llvm::consumeError(recorder_or_error.takeError());
return nullptr;
}
m_packet_recorders.push_back(std::move(*recorder_or_error));
return m_packet_recorders.back().get();
}
void PacketRecorder::Record(const GDBRemotePacket &packet) {
if (!m_record)
return;
yaml::Output yout(m_os);
yout << const_cast<GDBRemotePacket &>(packet);
m_os.flush();
}
llvm::raw_ostream *GDBRemoteProvider::GetHistoryStream() {
FileSpec history_file = GetRoot().CopyByAppendingPathComponent(Info::file);
std::error_code EC;
m_stream_up = std::make_unique<raw_fd_ostream>(
history_file.GetPath(), EC, sys::fs::OpenFlags::OF_TextWithCRLF);
return m_stream_up.get();
}
char GDBRemoteProvider::ID = 0;
const char *GDBRemoteProvider::Info::file = "gdb-remote.yaml";
const char *GDBRemoteProvider::Info::name = "gdb-remote";

View File

@@ -9,7 +9,6 @@
#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"
@@ -19,7 +18,6 @@
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::repro;
ProcessInfo::ProcessInfo()
: m_executable(), m_arguments(), m_environment(), m_arch() {}
@@ -332,45 +330,3 @@ void ProcessInstanceInfoMatch::Clear() {
m_name_match_type = NameMatch::Ignore;
m_match_all_users = false;
}
void llvm::yaml::MappingTraits<ProcessInstanceInfo>::mapping(
IO &io, ProcessInstanceInfo &Info) {
io.mapRequired("executable", Info.m_executable);
io.mapRequired("arg0", Info.m_arg0);
io.mapRequired("args", Info.m_arguments);
io.mapRequired("arch", Info.m_arch);
io.mapRequired("uid", Info.m_uid);
io.mapRequired("gid", Info.m_gid);
io.mapRequired("pid", Info.m_pid);
io.mapRequired("effective-uid", Info.m_euid);
io.mapRequired("effective-gid", Info.m_egid);
io.mapRequired("parent-pid", Info.m_parent_pid);
}
llvm::Optional<ProcessInstanceInfoList>
repro::GetReplayProcessInstanceInfoList() {
static std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>>
loader = repro::MultiLoader<repro::ProcessInfoProvider>::Create(
repro::Reproducer::Instance().GetLoader());
if (!loader)
return {};
llvm::Optional<std::string> nextfile = loader->GetNextFile();
if (!nextfile)
return {};
auto error_or_file = llvm::MemoryBuffer::getFile(*nextfile);
if (std::error_code err = error_or_file.getError())
return {};
ProcessInstanceInfoList infos;
llvm::yaml::Input yin((*error_or_file)->getBuffer());
yin >> infos;
if (auto err = yin.error())
return {};
return infos;
}

View File

@@ -1,230 +0,0 @@
//===-- 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/Reproducer.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/ReproducerProvider.h"
#include "lldb/Utility/Timer.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
using namespace lldb_private;
using namespace lldb_private::repro;
using namespace llvm;
using namespace llvm::yaml;
Reproducer &Reproducer::Instance() { return *InstanceImpl(); }
llvm::Error Reproducer::Initialize(ReproducerMode mode,
llvm::Optional<FileSpec> root) {
lldbassert(!InstanceImpl() && "Already initialized.");
InstanceImpl().emplace();
switch (mode) {
case ReproducerMode::Capture: {
if (!root) {
SmallString<128> repro_dir;
auto ec = sys::fs::createUniqueDirectory("reproducer", repro_dir);
if (ec)
return make_error<StringError>(
"unable to create unique reproducer directory", ec);
root.emplace(repro_dir);
} else {
auto ec = sys::fs::create_directory(root->GetPath());
if (ec)
return make_error<StringError>("unable to create reproducer directory",
ec);
}
return Instance().SetCapture(root);
} break;
case ReproducerMode::Off:
break;
};
return Error::success();
}
void Reproducer::Initialize() {
llvm::cantFail(Initialize(repro::ReproducerMode::Off, llvm::None));
}
bool Reproducer::Initialized() { return InstanceImpl().operator bool(); }
void Reproducer::Terminate() {
lldbassert(InstanceImpl() && "Already terminated.");
InstanceImpl().reset();
}
Optional<Reproducer> &Reproducer::InstanceImpl() {
static Optional<Reproducer> g_reproducer;
return g_reproducer;
}
const Generator *Reproducer::GetGenerator() const {
std::lock_guard<std::mutex> guard(m_mutex);
if (m_generator)
return &(*m_generator);
return nullptr;
}
const Loader *Reproducer::GetLoader() const {
std::lock_guard<std::mutex> guard(m_mutex);
if (m_loader)
return &(*m_loader);
return nullptr;
}
Generator *Reproducer::GetGenerator() {
std::lock_guard<std::mutex> guard(m_mutex);
if (m_generator)
return &(*m_generator);
return nullptr;
}
Loader *Reproducer::GetLoader() {
std::lock_guard<std::mutex> guard(m_mutex);
if (m_loader)
return &(*m_loader);
return nullptr;
}
llvm::Error Reproducer::SetCapture(llvm::Optional<FileSpec> root) {
std::lock_guard<std::mutex> guard(m_mutex);
if (root && m_loader)
return make_error<StringError>(
"cannot generate a reproducer when replay one",
inconvertibleErrorCode());
if (!root) {
m_generator.reset();
return Error::success();
}
m_generator.emplace(*root);
return Error::success();
}
FileSpec Reproducer::GetReproducerPath() const {
if (auto g = GetGenerator())
return g->GetRoot();
if (auto l = GetLoader())
return l->GetRoot();
return {};
}
static FileSpec MakeAbsolute(const FileSpec &file_spec) {
SmallString<128> path;
file_spec.GetPath(path, false);
llvm::sys::fs::make_absolute(path);
return FileSpec(path, file_spec.GetPathStyle());
}
Generator::Generator(FileSpec root) : m_root(MakeAbsolute(std::move(root))) {
GetOrCreate<repro::WorkingDirectoryProvider>();
GetOrCreate<repro::HomeDirectoryProvider>();
}
Generator::~Generator() {
if (!m_done) {
if (m_auto_generate) {
Keep();
} else {
Discard();
}
}
}
ProviderBase *Generator::Register(std::unique_ptr<ProviderBase> provider) {
std::lock_guard<std::mutex> lock(m_providers_mutex);
std::pair<const void *, std::unique_ptr<ProviderBase>> key_value(
provider->DynamicClassID(), std::move(provider));
auto e = m_providers.insert(std::move(key_value));
return e.first->getSecond().get();
}
void Generator::Keep() {
LLDB_SCOPED_TIMER();
assert(!m_done);
m_done = true;
for (auto &provider : m_providers)
provider.second->Keep();
AddProvidersToIndex();
}
void Generator::Discard() {
LLDB_SCOPED_TIMER();
assert(!m_done);
m_done = true;
for (auto &provider : m_providers)
provider.second->Discard();
llvm::sys::fs::remove_directories(m_root.GetPath());
}
void Generator::SetAutoGenerate(bool b) { m_auto_generate = b; }
bool Generator::IsAutoGenerate() const { return m_auto_generate; }
const FileSpec &Generator::GetRoot() const { return m_root; }
void Generator::AddProvidersToIndex() {
FileSpec index = m_root;
index.AppendPathComponent("index.yaml");
std::error_code EC;
auto strm = std::make_unique<raw_fd_ostream>(index.GetPath(), EC,
sys::fs::OpenFlags::OF_None);
yaml::Output yout(*strm);
std::vector<std::string> files;
files.reserve(m_providers.size());
for (auto &provider : m_providers) {
files.emplace_back(provider.second->GetFile());
}
yout << files;
}
Loader::Loader(FileSpec root, bool passive)
: m_root(MakeAbsolute(std::move(root))), m_loaded(false) {}
llvm::Error Loader::LoadIndex() {
if (m_loaded)
return llvm::Error::success();
FileSpec index = m_root.CopyByAppendingPathComponent("index.yaml");
auto error_or_file = MemoryBuffer::getFile(index.GetPath());
if (auto err = error_or_file.getError())
return make_error<StringError>("unable to load reproducer index", err);
yaml::Input yin((*error_or_file)->getBuffer());
yin >> m_files;
if (auto err = yin.error())
return make_error<StringError>("unable to read reproducer index", err);
// Sort files to speed up search.
llvm::sort(m_files);
// Remember that we've loaded the index.
m_loaded = true;
return llvm::Error::success();
}
bool Loader::HasFile(StringRef file) {
assert(m_loaded);
auto it = llvm::lower_bound(m_files, file.str());
return (it != m_files.end()) && (*it == file);
}

View File

@@ -1,194 +0,0 @@
//===-- 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/ADT/ScopeExit.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/WithColor.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_TextWithCRLF);
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 FileProvider::Keep() {
if (m_collector) {
FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
m_collector->writeMapping(file.GetPath());
}
}
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_TextWithCRLF);
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 SymbolFileProvider::AddSymbolFile(const UUID *uuid,
const FileSpec &module_file,
const FileSpec &symbol_file) {
if (!uuid || (!module_file && !symbol_file))
return;
m_symbol_files.emplace_back(uuid->GetAsString(), module_file.GetPath(),
symbol_file.GetPath());
}
void SymbolFileProvider::Keep() {
FileSpec file = this->GetRoot().CopyByAppendingPathComponent(Info::file);
std::error_code ec;
llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
if (ec)
return;
// Remove duplicates.
llvm::sort(m_symbol_files);
m_symbol_files.erase(
std::unique(m_symbol_files.begin(), m_symbol_files.end()),
m_symbol_files.end());
llvm::yaml::Output yout(os);
yout << m_symbol_files;
}
SymbolFileLoader::SymbolFileLoader(Loader *loader) {
if (!loader)
return;
FileSpec file = loader->GetFile<SymbolFileProvider::Info>();
if (!file)
return;
auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
if (auto err = error_or_file.getError())
return;
llvm::yaml::Input yin((*error_or_file)->getBuffer());
yin >> m_symbol_files;
}
std::pair<FileSpec, FileSpec>
SymbolFileLoader::GetPaths(const UUID *uuid) const {
if (!uuid)
return {};
auto it = llvm::lower_bound(m_symbol_files,
SymbolFileProvider::Entry(uuid->GetAsString()));
if (it == m_symbol_files.end())
return {};
return std::make_pair<FileSpec, FileSpec>(FileSpec(it->module_path),
FileSpec(it->symbol_path));
}
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;
char SymbolFileProvider::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";
const char *SymbolFileProvider::Info::file = "symbol-files.yaml";
const char *SymbolFileProvider::Info::name = "symbol-files";

View File

@@ -1,15 +0,0 @@
import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
class ReproducerTestCase(TestBase):
@no_debug_info_test
def test_reproducer_generate_invalid_invocation(self):
self.expect("reproducer generate f", error=True,
substrs=["'reproducer generate' doesn't take any arguments"])
@no_debug_info_test
def test_reproducer_status_invalid_invocation(self):
self.expect("reproducer status f", error=True,
substrs=["'reproducer status' doesn't take any arguments"])

View File

@@ -1,2 +0,0 @@
CXX_SOURCES := main.cpp
include Makefile.rules

View File

@@ -1,60 +0,0 @@
"""
Test reproducer attach.
"""
import lldb
import tempfile
from lldbsuite.test import lldbtest_config
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class ReproducerAttachTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
@skipIfNetBSD
@skipIfWindows
@skipIfRemote
@skipIfiOSSimulator
def test_reproducer_attach(self):
"""Test thread creation after process attach."""
exe = '%s_%d' % (self.testMethodName, os.getpid())
token = self.getBuildArtifact(exe + '.token')
if os.path.exists(token):
os.remove(token)
reproducer = self.getBuildArtifact(exe + '.reproducer')
if os.path.exists(reproducer):
try:
shutil.rmtree(reproducer)
except OSError:
pass
self.build(dictionary={'EXE': exe})
inferior = self.spawnSubprocess(self.getBuildArtifact(exe), [token])
pid = inferior.pid
lldbutil.wait_for_file_on_target(self, token)
# Use Popen because pexpect is overkill and spawnSubprocess is
# asynchronous.
capture = subprocess.Popen([
lldbtest_config.lldbExec, '-b', '--no-lldbinit', '--no-use-colors']
+ sum(map(lambda x: ['-O', x], self.setUpCommands()), [])
+ ['--capture', '--capture-path', reproducer,
'-o', 'proc att -n {}'.format(exe), '-o', 'reproducer generate'
],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
outs, _ = capture.communicate()
outs = outs.decode('utf-8')
self.assertIn('Process {} stopped'.format(pid), outs)
self.assertIn('Reproducer written', outs)
# We can dump the reproducer in the current context.
self.expect('reproducer dump -f {} -p process'.format(reproducer),
substrs=['pid = {}'.format(pid), 'name = {}'.format(exe)])

View File

@@ -1,24 +0,0 @@
#include <chrono>
#include <stdio.h>
#include <thread>
using std::chrono::seconds;
int main(int argc, char const *argv[]) {
lldb_enable_attach();
// Create the synchronization token.
FILE *f;
if (f = fopen(argv[1], "wx")) {
fputs("\n", f);
fflush(f);
fclose(f);
} else
return 1;
while (true) {
std::this_thread::sleep_for(seconds(1));
}
return 0;
}

View File

@@ -1,54 +0,0 @@
"""
Test if the reproducer correctly detects whether the file system is case sensitive.
"""
import lldb
import tempfile
from lldbsuite.test import lldbtest_config
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class ReproducerFileSystemSensitivityTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
@skipIfNetBSD
@skipIfWindows
@skipIfRemote
@skipIfiOSSimulator
def test_reproducer_attach(self):
# The reproducer output path. Note that this is on purpose a lower-case
# file name. See the case-sensitivity check below.
reproducer = self.getBuildArtifact('test.reproducer')
try:
shutil.rmtree(reproducer)
except OSError:
pass
# Use Popen because pexpect is overkill and spawnSubprocess is
# asynchronous.
capture = subprocess.Popen([
lldbtest_config.lldbExec, '-b', '--no-lldbinit', '--no-use-colors']
+ sum(map(lambda x: ['-O', x], self.setUpCommands()), [])
+ ['--capture', '--capture-path', reproducer,
'-o', 'reproducer generate'
],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
outs, _ = capture.communicate()
outs = outs.decode('utf-8')
self.assertIn('Reproducer written', outs)
# Read in the YAML file. We only care about a single value, so no
# need to parse the full file.
with open(os.path.join(reproducer, "files.yaml"), 'r') as file:
files_yaml = file.read()
# Detect the file system case sensitivity by checking if we can
# find the reproducer path after converting it to upper case (the
# file name is lower case before conversion, so this only works
# on case insensitive file systems).
case_sensitive = "false" if os.path.exists(reproducer.upper()) else "true"
self.assertIn("'case-sensitive': '" + case_sensitive + "'", files_yaml)

View File

@@ -35,8 +35,6 @@ CHECK: -x
CHECK: OPTIONS
CHECK: --arch
CHECK: -a
CHECK: --capture-path
CHECK: --capture
CHECK: --core
CHECK: -c
CHECK: --debug

View File

@@ -1,5 +0,0 @@
breakpoint set -f simple.c -l 12
run
bt
cont
reproducer status

View File

@@ -1,4 +0,0 @@
run
reproducer status
reproducer dump -p files
reproducer generate

View File

@@ -1,6 +0,0 @@
breakpoint set -f simple.c -l 4
run
bt
cont
reproducer status
reproducer generate

View File

@@ -1,6 +0,0 @@
breakpoint set -f simple.c -l 4
run
bt
cont
reproducer status
reproducer xcrash -s SIGSEGV

View File

@@ -1,2 +0,0 @@
reproducer status
reproducer generate

View File

@@ -1,12 +0,0 @@
target select 0
breakpoint set -f simple.c -l 4
run
target select 1
breakpoint set -f simple.c -l 8
run
target select 0
cont
target select 1
cont
reproducer status
reproducer generate

View File

@@ -1,4 +0,0 @@
run
reproducer status
reproducer dump -p cwd
reproducer generate

View File

@@ -1 +0,0 @@
print('95126')

View File

@@ -1 +0,0 @@
print('95126')

View File

@@ -1,10 +0,0 @@
#include <stdio.h>
void foo() {
printf("testing\n");
}
int main (int argc, char const *argv[]) {
foo();
return 0;
}

View File

@@ -1,3 +0,0 @@
struct Bar {
int success;
};

View File

@@ -1 +0,0 @@
struct Foo {};

View File

@@ -1,6 +0,0 @@
breakpoint set -f main.cpp -l 5
run
expr -l Objective-C++ -- @import Foo
expr -l Objective-C++ -- @import Bar
expr -- Bar()
reproducer generate

View File

@@ -1,9 +0,0 @@
#include "Foo.h"
void stop() {}
int main(int argc, char **argv) {
Foo foo;
stop(); // break here.
return 0;
}

View File

@@ -1,7 +0,0 @@
module Foo {
header "Foo.h"
}
module Bar {
header "Bar.h"
}

View File

@@ -1,33 +0,0 @@
# REQUIRES: system-darwin
# Start fresh.
# RUN: rm -rf %t.repro
# RUN: rm -rf %t.root
# RUN: rm -rf %t.clang-cache
# RUN: rm -rf %t.lldb-cache
# Create a temporary root we can remove later.
# RUN: mkdir -p %t.root
# RUN: mkdir -p %t.clang-cache
# RUN: mkdir -p %t.lldb-cache
# RUN: cp %S/Inputs/main.cpp %t.root
# RUN: cp %S/Inputs/Foo.h %t.root
# RUN: cp %S/Inputs/Bar.h %t.root
# RUN: cp %S/Inputs/module.modulemap %t.root
# Compile the test case form the temporary root.
# RUN: %clang_host %t.root/main.cpp -g -fmodules -fcxx-modules -fmodules-cache-path=%t.clang-cache -o %t.root/a.out
# Capture the debug session.
# RUN: %lldb -x -b -o 'settings set symbols.clang-modules-cache-path %t.lldb-cache' -s %S/Inputs/ModuleCXX.in --capture --capture-path %t.repro %t.root/a.out | FileCheck %s --check-prefix CAPTURE
# CAPTURE: (success = 0)
# RUN: cat %t.repro/files.yaml | FileCheck %s --check-prefix YAML
# YAML-DAG: Foo.h
# YAML-DAG: Bar.h
# YAML-DAG: module.modulemap
# Remove the temporary root.
# RUN: rm -rf %t.root
# RUN: rm -rf %t.clang-cache
# RUN: rm -rf %t.lldb-cache

View File

@@ -1,11 +0,0 @@
# REQUIRES: system-darwin
# Ensure that the reproducers captures the whole dSYM bundle.
# RUN: rm -rf %t.repro
# RUN: %clang_host %S/Inputs/simple.c -g -o %t.out
# RUN: touch %t.out.dSYM/foo.bar
# RUN: %lldb -x -b --capture --capture-path %t.repro %t.out -o 'b main' -o 'run' -o 'reproducer generate'
# RUN: %lldb -b -o 'reproducer dump -p files -f %t.repro' | FileCheck %s --check-prefix FILES
# FILES: foo.bar

View File

@@ -1,12 +0,0 @@
# This ensures that the reproducer properly cleans up after itself.
# Build the inferior.
# RUN: mkdir -p %t
# RUN: rm -rf %t.repro
# RUN: %clang_host %S/Inputs/simple.c -g -o %t/reproducer.out
# Capture but don't generate the reproducer.
# RUN: not %lldb -x -b -s %S/Inputs/Discard.in --capture --capture-path %t.repro %t/reproducer.out
# Make sure the directory doesn't exist.
# RUN: mkdir %t.repro

View File

@@ -1,24 +0,0 @@
# Check that errors are propagated to the driver.
#
# RUN: not %lldb --capture --capture-path %t/bogus/bogus 2>&1 | FileCheck %s --check-prefix INVALID-CAPTURE
#
# INVALID-CAPTURE: unable to create reproducer directory
# Check that all option combination work as expected.
#
# RUN: %lldb --capture --capture-path %t.repro -b -o 'reproducer status' 2>&1 | FileCheck %s --check-prefix NO-WARNING --check-prefix STATUS-CAPTURE
# RUN: %lldb --capture -b -o 'reproducer status' 2>&1 | FileCheck %s --check-prefix NO-WARNING --check-prefix STATUS-CAPTURE
# RUN: %lldb --capture-path %t.repro -b -o 'reproducer status' 2>&1 | FileCheck %s --check-prefix WARNING --check-prefix STATUS-CAPTURE --check-prefix NOAUTOGEN
# RUN: %lldb --capture-path %t.repro -b -o 'reproducer status' --reproducer-generate-on-exit 2>&1 | FileCheck %s --check-prefix WARNING2
#
# NO-WARNING-NOT: warning: -capture-path specified without -capture
# WARNING: warning: -capture-path specified without -capture
# WARNING2: warning: -reproducer-generate-on-exit specified without -capture
# STATUS-CAPTURE: Reproducer is in capture mode.
# NOAUTOGEN-NOT: Auto generate
# Check auto generate.
# RUN: rm -rf %t.repro
# RUN: %lldb --capture --capture-path %t.repro -b --reproducer-generate-on-exit -o 'reproducer status' 2>&1 | FileCheck %s --check-prefix NO-WARNING --check-prefix AUTOGEN
# RUN: cat %t.repro/index.yaml
# AUTOGEN: Auto generate: on

View File

@@ -1,31 +0,0 @@
# This tests the reproducer dump functionality.
# Generate a reproducer.
# RUN: mkdir -p %t
# RUN: rm -rf %t.repro
# RUN: %clang_host %S/Inputs/simple.c -g -o %t/reproducer.out
# RUN: %lldb -x -b -s %S/Inputs/FileCapture.in -o 'reproducer dump -p files' --capture --capture-path %t.repro %t/reproducer.out
# RUN: %lldb -b -o 'reproducer dump -p files -f %t.repro' | FileCheck %s --check-prefix FILES
# FILES-DAG: 'reproducer.out'
# FILES-DAG: 'FileCapture.in'
# RUN: %lldb -b -o 'reproducer dump -p version -f %t.repro' | FileCheck %s --check-prefix VERSION
# VERSION: lldb version
# RUN: %lldb -b -o 'reproducer dump -p commands -f %t.repro' | FileCheck %s --check-prefix COMMANDS
# COMMANDS: command source
# COMMANDS: target create
# COMMANDS: command source
# RUN: %lldb -b -o 'reproducer dump -p gdb -f %t.repro' | FileCheck %s --check-prefix GDB
# GDB: send packet: $QStartNoAckMode#b0
# GDB: read packet: $OK#9a
# RUN: rm %t.repro/gdb-remote.yaml
# RUN: not %lldb -b -o 'reproducer dump -p gdb -f %t.repro' 2>&1 | FileCheck %s --check-prefix GDB-ERROR
# GDB-ERROR: error: Unable to create GDB loader.
# RUN: rm %t.repro/command-interpreter.yaml
# RUN: not %lldb -b -o 'reproducer dump -p commands -f %t.repro' 2>&1 | FileCheck %s --check-prefix COMMANDS-ERROR
# COMMANDS-ERROR: error: Unable to create command loader.

View File

@@ -1,19 +0,0 @@
# REQUIRES: system-darwin
# This tests the replaying of GDB remote packets.
#
# We issue the same commands and ensure the output is identical to the original
# process. To ensure we're not actually running the original binary we check
# that the string "testing" is not printed.
# RUN: rm -rf %t.repro
# RUN: %clang_host %S/Inputs/simple.c -g -o %t.out
# RUN: %lldb -x -b -s %S/Inputs/FileCapture.in --capture --capture-path %t.repro %t.out | FileCheck %s --check-prefix CHECK --check-prefix CAPTURE
# RUN: rm %t.out
# CAPTURE: testing
# CHECK: Process {{.*}} exited
# CAPTURE: Reproducer is in capture mode.
# CAPTURE: Reproducer written

View File

@@ -1,12 +0,0 @@
# RUN: echo "CHECK: %t.home" > %t.check
# RUN: rm -rf %t.repro
# RUN: rm -rf %t.home
# RUN: mkdir -p %t.repro
# RUN: mkdir -p %t.home
# RUN: echo "print 95000 + 126" > %t.home/.lldbinit
# RUN: env HOME=%t.home %lldb-init -b -s %S/Inputs/HomeDir.in --capture --capture-path %t.repro | FileCheck %s
# RUN: cat %t.repro/home.txt | FileCheck %t.check
# RUN: %lldb -b -o 'reproducer dump -p home -f %t.repro' | FileCheck %t.check
# CHECK: 95126

View File

@@ -1,11 +0,0 @@
# REQUIRES: lua
# UNSUPPORTED: system-windows
# Ensure that the reproducers know about imported Lua modules.
# RUN: rm -rf %t.repro
# RUN: %lldb -x -b --script-language lua --capture --capture-path %t.repro -o 'command script import %S/Inputs/foo.lua' -o 'reproducer generate' | FileCheck %s --check-prefix CAPTURE
# CAPTURE: 95126
# RUN: %lldb -b -o 'reproducer dump -p files -f %t.repro' | FileCheck %s --check-prefix FILES
# FILES: foo.lua

View File

@@ -1,11 +0,0 @@
# REQUIRES: python
# UNSUPPORTED: system-windows
# Ensure that the reproducers know about imported Python modules.
# RUN: rm -rf %t.repro
# RUN: %lldb -x -b --capture --capture-path %t.repro -o 'command script import %S/Inputs/foo.py' -o 'reproducer generate' | FileCheck %s --check-prefix CAPTURE
# CAPTURE: 95126
# RUN: %lldb -b -o 'reproducer dump -p files -f %t.repro' | FileCheck %s --check-prefix FILES
# FILES: foo.py

View File

@@ -1,17 +0,0 @@
# REQUIRES: system-darwin
# This tests the reproducer version check.
# RUN: rm -rf %t.repro
# RUN: %clang_host %S/Inputs/simple.c -g -o %t.out
# RUN: %lldb -x -b -s %S/Inputs/FileCapture.in --capture --capture-path %t.repro %t.out | FileCheck %s --check-prefix CHECK --check-prefix CAPTURE
# Change the reproducer version.
# RUN: echo "bogus" >> %t.repro/version.txt
# CAPTURE: testing
# CHECK: Process {{.*}} exited
# CAPTURE: Reproducer is in capture mode.
# CAPTURE: Reproducer written

View File

@@ -1,30 +0,0 @@
# This tests that the reproducer can deal with relative files. We create a
# binary in a subdirectory and pass its relative path to LLDB.
# RUN: echo "CHECK: %t" > %t.check
# RUN: rm -rf %t.repro
# RUN: mkdir -p %t.repro
# RUN: mkdir -p %t
# RUN: mkdir -p %t/binary
# RUN: cd %t
# RUN: %clang_host %S/Inputs/simple.c -g -o binary/reproducer.out
# RUN: %lldb -x -b -s %S/Inputs/WorkingDir.in --capture --capture-path %t.repro binary/reproducer.out
# RUN: rm -rf %t/binary
# RUN: cat %t.repro/cwd.txt | FileCheck %t.check
# Make sure the current working directory is recorded even when it's not
# referenced.
# RUN: rm -rf %t.repro
# RUN: rm -rf %t
# RUN: mkdir -p %t/probably_unique
# RUN: touch %t/probably_unique/dont_include_me
# RUN: cd %t/probably_unique
# RUN: %lldb -x -b -o 'reproducer generate' --capture --capture-path %t.repro
# RUN: cat %t.repro/cwd.txt | FileCheck %s
# CHECK: probably_unique
# RUN: cat %t.repro/files.yaml | FileCheck %s --check-prefix VFS
# VFS: probably_unique
# VFS-NOT: dont_include_me

View File

@@ -1,9 +0,0 @@
# Enable crash reports for the reproducer tests.
if 'LLVM_DISABLE_CRASH_REPORT' in config.environment:
del config.environment['LLVM_DISABLE_CRASH_REPORT']
if 'system-windows' in config.available_features:
config.unsupported = True
if 'lldb-repro' in config.available_features:
config.unsupported = True

View File

@@ -15,7 +15,6 @@
#include "lldb/API/SBFile.h"
#include "lldb/API/SBHostOS.h"
#include "lldb/API/SBLanguageRuntime.h"
#include "lldb/API/SBReproducer.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBStringList.h"
#include "lldb/API/SBStructuredData.h"
@@ -742,39 +741,6 @@ EXAMPLES:
llvm::outs() << examples << '\n';
}
static llvm::Optional<int> InitializeReproducer(llvm::StringRef argv0,
opt::InputArgList &input_args) {
bool capture = input_args.hasArg(OPT_capture);
bool generate_on_exit = input_args.hasArg(OPT_generate_on_exit);
auto *capture_path = input_args.getLastArg(OPT_capture_path);
if (generate_on_exit && !capture) {
WithColor::warning()
<< "-reproducer-generate-on-exit specified without -capture\n";
}
if (capture || capture_path) {
if (capture_path) {
if (!capture)
WithColor::warning() << "-capture-path specified without -capture\n";
if (const char *error = SBReproducer::Capture(capture_path->getValue())) {
WithColor::error() << "reproducer capture failed: " << error << '\n';
return 1;
}
} else {
const char *error = SBReproducer::Capture();
if (error) {
WithColor::error() << "reproducer capture failed: " << error << '\n';
return 1;
}
}
if (generate_on_exit)
SBReproducer::SetAutoGenerate(true);
}
return llvm::None;
}
int main(int argc, char const *argv[]) {
// Editline uses for example iswprint which is dependent on LC_CTYPE.
std::setlocale(LC_ALL, "");
@@ -816,10 +782,6 @@ int main(int argc, char const *argv[]) {
return 1;
}
if (auto exit_code = InitializeReproducer(argv[0], input_args)) {
return *exit_code;
}
SBError error = SBDebugger::InitializeWithErrorHandling();
if (error.Fail()) {
WithColor::error() << "initialization failed: " << error.GetCString()

View File

@@ -228,12 +228,4 @@ def: Flag<["-"], "d">,
Alias<debug>,
HelpText<"Alias for --debug">;
def capture: F<"capture">,
HelpText<"Tells the debugger to capture a reproducer.">;
def capture_path: Separate<["--", "-"], "capture-path">,
MetaVarName<"<filename>">,
HelpText<"Tells the debugger to use the given filename for the reproducer.">;
def generate_on_exit: F<"reproducer-generate-on-exit">,
HelpText<"Generate reproducer on exit.">;
def REM : R<["--"], "">;

View File

@@ -18,7 +18,6 @@
#include "lldb/Utility/Broadcaster.h"
#include "lldb/Utility/Event.h"
#include "lldb/Utility/Listener.h"
#include "lldb/Utility/Reproducer.h"
using namespace lldb;
using namespace lldb_private;
@@ -33,7 +32,6 @@ namespace {
class DiagnosticEventTest : public ::testing::Test {
public:
void SetUp() override {
llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
FileSystem::Initialize();
HostInfo::Initialize();
PlatformMacOSX::Initialize();
@@ -47,7 +45,6 @@ public:
PlatformMacOSX::Terminate();
HostInfo::Terminate();
FileSystem::Terminate();
Reproducer::Terminate();
}
};
} // namespace

View File

@@ -10,12 +10,11 @@
#include "Plugins/Platform/Linux/PlatformLinux.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/Symbol/YAMLModuleTester.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/dwarf.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Testing/Support/Error.h"
@@ -81,7 +80,6 @@ static Scalar GetScalar(unsigned bits, uint64_t value, bool sign) {
class DWARFExpressionMockProcessTest : public ::testing::Test {
public:
void SetUp() override {
llvm::cantFail(repro::Reproducer::Initialize(repro::ReproducerMode::Off, {}));
FileSystem::Initialize();
HostInfo::Initialize();
platform_linux::PlatformLinux::Initialize();
@@ -90,7 +88,6 @@ public:
platform_linux::PlatformLinux::Terminate();
HostInfo::Terminate();
FileSystem::Terminate();
repro::Reproducer::Terminate();
}
};

View File

@@ -16,7 +16,6 @@
#include "lldb/Interpreter/CommandObjectMultiword.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/Status.h"
#include "gtest/gtest.h"
@@ -28,7 +27,6 @@ using namespace lldb;
namespace {
class VerifyUserMultiwordCmdPathTest : public ::testing::Test {
void SetUp() override {
llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
FileSystem::Initialize();
HostInfo::Initialize();
PlatformMacOSX::Initialize();
@@ -37,7 +35,6 @@ class VerifyUserMultiwordCmdPathTest : public ::testing::Test {
PlatformMacOSX::Terminate();
HostInfo::Terminate();
FileSystem::Terminate();
Reproducer::Terminate();
}
};
} // namespace

View File

@@ -21,7 +21,6 @@
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Reproducer.h"
using namespace lldb;
using namespace lldb_private;
@@ -38,7 +37,6 @@ public:
CompilerType siginfo_type;
void SetUp() override {
llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
platform_freebsd::PlatformFreeBSD::Initialize();
platform_linux::PlatformLinux::Initialize();
platform_netbsd::PlatformNetBSD::Initialize();
@@ -48,7 +46,6 @@ public:
platform_netbsd::PlatformNetBSD::Terminate();
platform_linux::PlatformLinux::Terminate();
platform_freebsd::PlatformFreeBSD::Terminate();
Reproducer::Terminate();
}
typedef std::tuple<const char *, uint64_t, uint64_t> field_tuple;

View File

@@ -16,7 +16,6 @@
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Event.h"
#include "lldb/Utility/Reproducer.h"
#include "gtest/gtest.h"
using namespace lldb_private;
@@ -27,7 +26,6 @@ namespace {
class ProcessEventDataTest : public ::testing::Test {
public:
void SetUp() override {
llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
FileSystem::Initialize();
HostInfo::Initialize();
PlatformMacOSX::Initialize();
@@ -36,7 +34,6 @@ public:
PlatformMacOSX::Terminate();
HostInfo::Terminate();
FileSystem::Terminate();
Reproducer::Terminate();
}
};

View File

@@ -13,7 +13,6 @@
#include "lldb/Host/HostInfo.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Platform.h"
#include "lldb/Utility/Reproducer.h"
#include "gtest/gtest.h"
using namespace lldb_private;
@@ -24,7 +23,6 @@ namespace {
class ScriptInterpreterTest : public ::testing::Test {
public:
void SetUp() override {
llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
FileSystem::Initialize();
HostInfo::Initialize();
@@ -38,7 +36,6 @@ public:
platform_linux::PlatformLinux::Terminate();
HostInfo::Terminate();
FileSystem::Terminate();
Reproducer::Terminate();
}
};
} // namespace

View File

@@ -14,14 +14,13 @@
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/LocateSymbolFile.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Reproducer.h"
using namespace lldb_private;
namespace {
class SymbolsTest : public ::testing::Test {
public:
SubsystemRAII<repro::Reproducer, FileSystem, HostInfo> subsystems;
SubsystemRAII<FileSystem, HostInfo> subsystems;
};
} // namespace

View File

@@ -16,7 +16,6 @@
#include "lldb/Target/Target.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Endian.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private-enumerations.h"
@@ -32,7 +31,6 @@ namespace {
class ExecutionContextTest : public ::testing::Test {
public:
void SetUp() override {
llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
FileSystem::Initialize();
HostInfo::Initialize();
platform_linux::PlatformLinux::Initialize();
@@ -41,7 +39,6 @@ public:
platform_linux::PlatformLinux::Terminate();
HostInfo::Terminate();
FileSystem::Terminate();
Reproducer::Terminate();
}
};

View File

@@ -11,7 +11,6 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Utility/Reproducer.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private-enumerations.h"
@@ -27,7 +26,6 @@ namespace {
class StackFrameRecognizerTest : public ::testing::Test {
public:
void SetUp() override {
llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
FileSystem::Initialize();
HostInfo::Initialize();
@@ -42,7 +40,6 @@ public:
platform_linux::PlatformLinux::Terminate();
HostInfo::Terminate();
FileSystem::Terminate();
Reproducer::Terminate();
}
};

View File

@@ -14,7 +14,6 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Reproducer.h"
#include "gtest/gtest.h"
using namespace lldb_private;
@@ -25,7 +24,6 @@ namespace {
class ThreadTest : public ::testing::Test {
public:
void SetUp() override {
llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
FileSystem::Initialize();
HostInfo::Initialize();
platform_linux::PlatformLinux::Initialize();
@@ -34,7 +32,6 @@ public:
platform_linux::PlatformLinux::Terminate();
HostInfo::Terminate();
FileSystem::Terminate();
Reproducer::Terminate();
}
};

View File

@@ -11,7 +11,6 @@
#include "lldb/Utility/ArchSpec.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/YAMLParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -468,23 +467,3 @@ TEST(ArchSpecTest, TripleComponentsWereSpecified) {
ASSERT_TRUE(D.TripleEnvironmentWasSpecified());
}
}
TEST(ArchSpecTest, YAML) {
std::string buffer;
llvm::raw_string_ostream os(buffer);
// Serialize.
llvm::yaml::Output yout(os);
std::vector<ArchSpec> archs = {ArchSpec("x86_64-pc-linux"),
ArchSpec("x86_64-apple-macosx10.12"),
ArchSpec("i686-pc-windows")};
yout << archs;
os.flush();
// Deserialize.
std::vector<ArchSpec> deserialized;
llvm::yaml::Input yin(buffer);
yin >> deserialized;
EXPECT_EQ(archs, deserialized);
}

View File

@@ -284,37 +284,6 @@ TEST(ArgsTest, ReplaceArgumentAtIndexFarOutOfRange) {
EXPECT_STREQ(args.GetArgumentAtIndex(2), "b");
}
TEST(ArgsTest, Yaml) {
std::string buffer;
llvm::raw_string_ostream os(buffer);
// Serialize.
Args args;
args.SetCommandString("this 'has' \"multiple\" args");
llvm::yaml::Output yout(os);
yout << args;
os.flush();
llvm::outs() << buffer;
// Deserialize.
Args deserialized;
llvm::yaml::Input yin(buffer);
yin >> deserialized;
EXPECT_EQ(4u, deserialized.GetArgumentCount());
EXPECT_STREQ(deserialized.GetArgumentAtIndex(0), "this");
EXPECT_STREQ(deserialized.GetArgumentAtIndex(1), "has");
EXPECT_STREQ(deserialized.GetArgumentAtIndex(2), "multiple");
EXPECT_STREQ(deserialized.GetArgumentAtIndex(3), "args");
llvm::ArrayRef<Args::ArgEntry> entries = deserialized.entries();
EXPECT_EQ(entries[0].GetQuoteChar(), '\0');
EXPECT_EQ(entries[1].GetQuoteChar(), '\'');
EXPECT_EQ(entries[2].GetQuoteChar(), '"');
EXPECT_EQ(entries[3].GetQuoteChar(), '\0');
}
TEST(ArgsTest, GetShellSafeArgument) {
// Try escaping with bash at start/middle/end of the argument.
FileSpec bash("/bin/bash", FileSpec::Style::posix);

View File

@@ -23,7 +23,6 @@ add_lldb_unittest(UtilityTests
RangeTest.cpp
RegisterValueTest.cpp
RegularExpressionTest.cpp
ReproducerTest.cpp
ScalarTest.cpp
SharedClusterTest.cpp
StateTest.cpp

View File

@@ -8,7 +8,6 @@
#include "lldb/Utility/ConstString.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/YAMLParser.h"
#include "gtest/gtest.h"
using namespace lldb_private;
@@ -138,22 +137,3 @@ TEST(ConstStringTest, CompareStringRef) {
EXPECT_TRUE(null == static_cast<const char *>(nullptr));
EXPECT_TRUE(null != "bar");
}
TEST(ConstStringTest, YAML) {
std::string buffer;
llvm::raw_string_ostream os(buffer);
// Serialize.
std::vector<ConstString> strings = {ConstString("foo"), ConstString("bar"),
ConstString("")};
llvm::yaml::Output yout(os);
yout << strings;
os.flush();
// Deserialize.
std::vector<ConstString> deserialized;
llvm::yaml::Input yin(buffer);
yin >> deserialized;
EXPECT_EQ(strings, deserialized);
}

View File

@@ -424,34 +424,6 @@ TEST(FileSpecTest, Match) {
}
TEST(FileSpecTest, Yaml) {
std::string buffer;
llvm::raw_string_ostream os(buffer);
// Serialize.
FileSpec fs_windows("F:\\bar", FileSpec::Style::windows);
llvm::yaml::Output yout(os);
yout << fs_windows;
os.flush();
// Deserialize.
FileSpec deserialized;
llvm::yaml::Input yin(buffer);
yin >> deserialized;
EXPECT_EQ(deserialized.GetPathStyle(), fs_windows.GetPathStyle());
EXPECT_EQ(deserialized.GetFilename(), fs_windows.GetFilename());
EXPECT_EQ(deserialized.GetDirectory(), fs_windows.GetDirectory());
EXPECT_EQ(deserialized, fs_windows);
}
TEST(FileSpecTest, OperatorBool) {
EXPECT_FALSE(FileSpec());
EXPECT_FALSE(FileSpec(""));
EXPECT_TRUE(FileSpec("/foo/bar"));
}
TEST(FileSpecTest, TestAbsoluteCaching) {
// Test that if we modify a path that we recalculate if a path is relative
// or absolute correctly. The test below calls set accessors and functions

Some files were not shown because too many files have changed in this diff Show More