mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 13:35:38 +08:00
[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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -608,8 +608,6 @@ enum CommandArgumentType {
|
||||
eArgTypeConnectURL,
|
||||
eArgTypeTargetID,
|
||||
eArgTypeStopHookID,
|
||||
eArgTypeReproducerProvider,
|
||||
eArgTypeReproducerSignal,
|
||||
eArgTypeLastArg // Always keep this entry as the last entry in this
|
||||
// enumeration!!
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -24,7 +24,6 @@ add_lldb_library(lldbCommands
|
||||
CommandObjectQuit.cpp
|
||||
CommandObjectRegexCommand.cpp
|
||||
CommandObjectRegister.cpp
|
||||
CommandObjectReproducer.cpp
|
||||
CommandObjectScript.cpp
|
||||
CommandObjectSession.cpp
|
||||
CommandObjectSettings.cpp
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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.">;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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";
|
||||
@@ -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"])
|
||||
@@ -1,2 +0,0 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
include Makefile.rules
|
||||
@@ -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)])
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -35,8 +35,6 @@ CHECK: -x
|
||||
CHECK: OPTIONS
|
||||
CHECK: --arch
|
||||
CHECK: -a
|
||||
CHECK: --capture-path
|
||||
CHECK: --capture
|
||||
CHECK: --core
|
||||
CHECK: -c
|
||||
CHECK: --debug
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
breakpoint set -f simple.c -l 12
|
||||
run
|
||||
bt
|
||||
cont
|
||||
reproducer status
|
||||
@@ -1,4 +0,0 @@
|
||||
run
|
||||
reproducer status
|
||||
reproducer dump -p files
|
||||
reproducer generate
|
||||
@@ -1,6 +0,0 @@
|
||||
breakpoint set -f simple.c -l 4
|
||||
run
|
||||
bt
|
||||
cont
|
||||
reproducer status
|
||||
reproducer generate
|
||||
@@ -1,6 +0,0 @@
|
||||
breakpoint set -f simple.c -l 4
|
||||
run
|
||||
bt
|
||||
cont
|
||||
reproducer status
|
||||
reproducer xcrash -s SIGSEGV
|
||||
@@ -1,2 +0,0 @@
|
||||
reproducer status
|
||||
reproducer generate
|
||||
@@ -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
|
||||
@@ -1,4 +0,0 @@
|
||||
run
|
||||
reproducer status
|
||||
reproducer dump -p cwd
|
||||
reproducer generate
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
print('95126')
|
||||
@@ -1 +0,0 @@
|
||||
print('95126')
|
||||
@@ -1,10 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void foo() {
|
||||
printf("testing\n");
|
||||
}
|
||||
|
||||
int main (int argc, char const *argv[]) {
|
||||
foo();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
struct Bar {
|
||||
int success;
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
struct Foo {};
|
||||
@@ -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
|
||||
@@ -1,9 +0,0 @@
|
||||
#include "Foo.h"
|
||||
|
||||
void stop() {}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
Foo foo;
|
||||
stop(); // break here.
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
module Foo {
|
||||
header "Foo.h"
|
||||
}
|
||||
|
||||
module Bar {
|
||||
header "Bar.h"
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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<["--"], "">;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -23,7 +23,6 @@ add_lldb_unittest(UtilityTests
|
||||
RangeTest.cpp
|
||||
RegisterValueTest.cpp
|
||||
RegularExpressionTest.cpp
|
||||
ReproducerTest.cpp
|
||||
ScalarTest.cpp
|
||||
SharedClusterTest.cpp
|
||||
StateTest.cpp
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user