Skip to content

Cherrypick upstream reproducer changes. #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions lldb/include/lldb/Utility/Reproducer.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,27 @@ class VersionProvider : public Provider<VersionProvider> {
static char ID;
};

/// Provider for the LLDB current working directroy.
///
/// 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 Provider<WorkingDirectoryProvider> {
public:
WorkingDirectoryProvider(const FileSpec &directory) : Provider(directory) {
llvm::SmallString<128> cwd;
if (std::error_code EC = llvm::sys::fs::current_path(cwd))
return;
m_cwd = cwd.str();
}
struct Info {
static const char *name;
static const char *file;
};
void Keep() override;
std::string m_cwd;
static char ID;
};

class DataRecorder {
public:
DataRecorder(const FileSpec &filename, std::error_code &ec)
Expand Down Expand Up @@ -184,10 +205,37 @@ class CommandProvider : public Provider<CommandProvider> {
std::vector<std::unique_ptr<DataRecorder>> m_data_recorders;
};

class ProcessGDBRemoteProvider
: public repro::Provider<ProcessGDBRemoteProvider> {
public:
struct Info {
static const char *name;
static const char *file;
};

ProcessGDBRemoteProvider(const FileSpec &directory) : Provider(directory) {}

llvm::raw_ostream *GetHistoryStream();

void SetCallback(std::function<void()> callback) {
m_callback = std::move(callback);
}

void Keep() override { m_callback(); }
void Discard() override { m_callback(); }

static char ID;

private:
std::function<void()> m_callback;
std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
};

/// 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();
Expand Down Expand Up @@ -255,6 +303,15 @@ class Loader final {
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; }
Expand Down Expand Up @@ -287,6 +344,9 @@ class Reproducer {

FileSpec GetReproducerPath() const;

bool IsCapturing() { return static_cast<bool>(m_generator); };
bool IsReplaying() { return static_cast<bool>(m_loader); };

protected:
llvm::Error SetCapture(llvm::Optional<FileSpec> root);
llvm::Error SetReplay(llvm::Optional<FileSpec> root);
Expand All @@ -300,6 +360,19 @@ class Reproducer {
mutable std::mutex m_mutex;
};

/// Helper class for replaying commands through the reproducer.
class CommandLoader {
public:
CommandLoader(std::vector<std::string> files) : m_files(files) {}

static std::unique_ptr<CommandLoader> Create(Loader *loader);
llvm::Optional<std::string> GetNextFile();

private:
std::vector<std::string> m_files;
unsigned m_index = 0;
};

} // namespace repro
} // namespace lldb_private

Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/Utility/ReproducerInstrumentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ template <typename... Ts> inline std::string stringify_args(const Ts &... ts) {
#define LLDB_RECORD_DUMMY(Result, Class, Method, Signature, ...) \
lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION, \
stringify_args(__VA_ARGS__));
#define LLDB_RECORD_DUMMY_NO_ARGS(Result, Class, Method) \
lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION);

namespace lldb_private {
namespace repro {
Expand Down
1 change: 1 addition & 0 deletions lldb/lit/Reproducer/Inputs/FileCapture.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
run
reproducer status
reproducer dump -p files
reproducer generate
4 changes: 4 additions & 0 deletions lldb/lit/Reproducer/Inputs/WorkingDir.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
run
reproducer status
reproducer dump -p cwd
reproducer generate
25 changes: 25 additions & 0 deletions lldb/lit/Reproducer/TestDump.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# This tests the reproducer dump functionality.

# Generate a reproducer.
# RUN: mkdir -p %t
# RUN: rm -rf %t.repro
# RUN: %clang %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: 'reproducer.out'
# FILES: '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: %lldb --replay %t.repro | FileCheck %s --check-prefix FILES
19 changes: 19 additions & 0 deletions lldb/lit/Reproducer/TestWorkingDir.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# XFAIL: system-windows

# This tests that the reproducer can deal with relative files. We create a
# binary in a subdirectory and pass its relative path to LLDB. The subdirectory
# is removed before replay so that it only exists in the reproducer's VFS.

# 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 %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
# RUN: %lldb --replay %t.repro | FileCheck %t.check
63 changes: 10 additions & 53 deletions lldb/source/API/SBDebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,51 +57,6 @@
using namespace lldb;
using namespace lldb_private;

/// Helper class for replaying commands through the reproducer.
class CommandLoader {
public:
CommandLoader(std::vector<std::string> files) : m_files(files) {}

static std::unique_ptr<CommandLoader> Create() {
repro::Loader *loader = repro::Reproducer::Instance().GetLoader();
if (!loader)
return {};

FileSpec file = loader->GetFile<repro::CommandProvider::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<CommandLoader>(std::move(files));
}

FILE *GetNextFile() {
if (m_index >= m_files.size())
return nullptr;
return FileSystem::Instance().Fopen(m_files[m_index++].c_str(), "r");
}

private:
std::vector<std::string> m_files;
unsigned m_index = 0;
};

static llvm::sys::DynamicLibrary LoadPlugin(const lldb::DebuggerSP &debugger_sp,
const FileSpec &spec,
Status &error) {
Expand Down Expand Up @@ -349,9 +304,12 @@ void SBDebugger::SetInputFileHandle(FILE *fh, bool transfer_ownership) {
if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator())
recorder = g->GetOrCreate<repro::CommandProvider>().GetNewDataRecorder();

static std::unique_ptr<CommandLoader> loader = CommandLoader::Create();
if (loader)
fh = loader->GetNextFile();
static std::unique_ptr<repro::CommandLoader> loader =
repro::CommandLoader::Create(repro::Reproducer::Instance().GetLoader());
if (loader) {
llvm::Optional<std::string> file = loader->GetNextFile();
fh = file ? FileSystem::Instance().Fopen(file->c_str(), "r") : nullptr;
}

m_opaque_sp->SetInputFileHandle(fh, transfer_ownership, recorder);
}
Expand Down Expand Up @@ -407,14 +365,14 @@ FILE *SBDebugger::GetErrorFileHandle() {
}

void SBDebugger::SaveInputTerminalState() {
LLDB_RECORD_METHOD_NO_ARGS(void, SBDebugger, SaveInputTerminalState);
LLDB_RECORD_DUMMY_NO_ARGS(void, SBDebugger, SaveInputTerminalState);

if (m_opaque_sp)
m_opaque_sp->SaveInputTerminalState();
}

void SBDebugger::RestoreInputTerminalState() {
LLDB_RECORD_METHOD_NO_ARGS(void, SBDebugger, RestoreInputTerminalState);
LLDB_RECORD_DUMMY_NO_ARGS(void, SBDebugger, RestoreInputTerminalState);

if (m_opaque_sp)
m_opaque_sp->RestoreInputTerminalState();
Expand Down Expand Up @@ -1075,7 +1033,7 @@ void SBDebugger::DispatchInput(const void *data, size_t data_len) {
}

void SBDebugger::DispatchInputInterrupt() {
LLDB_RECORD_METHOD_NO_ARGS(void, SBDebugger, DispatchInputInterrupt);
LLDB_RECORD_DUMMY_NO_ARGS(void, SBDebugger, DispatchInputInterrupt);

if (m_opaque_sp)
m_opaque_sp->DispatchInputInterrupt();
Expand Down Expand Up @@ -1235,8 +1193,7 @@ uint32_t SBDebugger::GetTerminalWidth() const {
}

void SBDebugger::SetTerminalWidth(uint32_t term_width) {
LLDB_RECORD_METHOD(void, SBDebugger, SetTerminalWidth, (uint32_t),
term_width);
LLDB_RECORD_DUMMY(void, SBDebugger, SetTerminalWidth, (uint32_t), term_width);

if (m_opaque_sp)
m_opaque_sp->SetTerminalWidth(term_width);
Expand Down
Loading