[lldb] Remove reproducer replay functionality

This is part of a bigger rework of the reproducer feature. See [1] for
more details.

[1] https://lists.llvm.org/pipermail/lldb-dev/2021-September/017045.html
This commit is contained in:
Jonas Devlieghere
2021-12-17 14:45:24 -08:00
parent 713ee230f8
commit fa1260697e
34 changed files with 19 additions and 665 deletions

View File

@@ -29,8 +29,6 @@ class Reproducer;
enum class ReproducerMode {
Capture,
Replay,
PassiveReplay,
Off,
};
@@ -179,15 +177,12 @@ public:
const FileSpec &GetRoot() const { return m_root; }
bool IsPassiveReplay() const { return m_passive_replay; }
private:
bool HasFile(llvm::StringRef file);
FileSpec m_root;
std::vector<std::string> m_files;
bool m_loaded;
bool m_passive_replay;
};
/// The reproducer enables clients to obtain access to the Generator and
@@ -212,11 +207,9 @@ public:
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, bool passive = false);
private:
static llvm::Optional<Reproducer> &InstanceImpl();

View File

@@ -165,111 +165,24 @@ const char *SBReproducer::Capture(const char *path) {
}
const char *SBReproducer::PassiveReplay(const char *path) {
static std::string error;
if (auto e = Reproducer::Initialize(ReproducerMode::PassiveReplay,
FileSpec(path))) {
error = llvm::toString(std::move(e));
return error.c_str();
}
if (auto *l = lldb_private::repro::Reproducer::Instance().GetLoader()) {
FileSpec file = l->GetFile<SBProvider::Info>();
auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
if (!error_or_file) {
error =
"unable to read SB API data: " + error_or_file.getError().message();
return error.c_str();
}
static ReplayData r(std::move(*error_or_file));
InstrumentationData::Initialize(r.GetDeserializer(), r.GetRegistry());
}
return nullptr;
return "Reproducer replay has been removed";
}
const char *SBReproducer::Replay(const char *path) {
SBReplayOptions options;
return SBReproducer::Replay(path, options);
return "Reproducer replay has been removed";
}
const char *SBReproducer::Replay(const char *path, bool skip_version_check) {
SBReplayOptions options;
options.SetCheckVersion(!skip_version_check);
return SBReproducer::Replay(path, options);
return Replay(path);
}
const char *SBReproducer::Replay(const char *path,
const SBReplayOptions &options) {
static std::string error;
if (auto e = Reproducer::Initialize(ReproducerMode::Replay, FileSpec(path))) {
error = llvm::toString(std::move(e));
return error.c_str();
}
repro::Loader *loader = repro::Reproducer::Instance().GetLoader();
if (!loader) {
error = "unable to get replay loader.";
return error.c_str();
}
if (options.GetCheckVersion()) {
llvm::Expected<std::string> version = loader->LoadBuffer<VersionProvider>();
if (!version) {
error = llvm::toString(version.takeError());
return error.c_str();
}
if (lldb_private::GetVersion() != llvm::StringRef(*version).rtrim()) {
error = "reproducer capture and replay version don't match:\n";
error.append("reproducer captured with:\n");
error.append(*version);
error.append("reproducer replayed with:\n");
error.append(lldb_private::GetVersion());
return error.c_str();
}
}
if (options.GetVerify()) {
bool verification_failed = false;
llvm::raw_string_ostream os(error);
auto error_callback = [&](llvm::StringRef error) {
verification_failed = true;
os << "\nerror: " << error;
};
auto warning_callback = [&](llvm::StringRef warning) {
verification_failed = true;
os << "\nwarning: " << warning;
};
auto note_callback = [&](llvm::StringRef warning) {};
Verifier verifier(loader);
verifier.Verify(error_callback, warning_callback, note_callback);
if (verification_failed) {
os.flush();
return error.c_str();
}
}
FileSpec file = loader->GetFile<SBProvider::Info>();
if (!file) {
error = "unable to get replay data from reproducer.";
return error.c_str();
}
SBRegistry registry;
registry.Replay(file);
return nullptr;
return Replay(path);
}
const char *SBReproducer::Finalize(const char *path) {
static std::string error;
if (auto e = Reproducer::Initialize(ReproducerMode::Replay, FileSpec(path))) {
error = llvm::toString(std::move(e));
return error.c_str();
}
repro::Loader *loader = repro::Reproducer::Instance().GetLoader();
if (!loader) {

View File

@@ -50,15 +50,8 @@ SystemInitializerFull::~SystemInitializerFull() = default;
llvm::Error SystemInitializerFull::Initialize() {
llvm::Error error = SystemInitializerCommon::Initialize();
if (error) {
// During active replay, the ::Initialize call is replayed like any other
// SB API call and the return value is ignored. Since we can't intercept
// this, we terminate here before the uninitialized debugger inevitably
// crashes.
if (repro::Reproducer::Instance().IsReplaying())
llvm::report_fatal_error(std::move(error));
if (error)
return error;
}
// Initialize LLVM and Clang
llvm::InitializeAllTargets();

View File

@@ -195,10 +195,6 @@ protected:
SetError(result, std::move(e));
return result.Succeeded();
}
} else if (r.IsReplaying()) {
// Make this operation a NO-OP in replay mode.
result.SetStatus(eReturnStatusSuccessFinishNoResult);
return result.Succeeded();
} else {
result.AppendErrorWithFormat("Unable to get the reproducer generator");
return false;
@@ -276,7 +272,7 @@ protected:
auto &r = Reproducer::Instance();
if (!r.IsCapturing() && !r.IsReplaying()) {
if (!r.IsCapturing()) {
result.AppendError(
"forcing a crash is only supported when capturing a reproducer.");
result.SetStatus(eReturnStatusSuccessFinishNoResult);
@@ -326,15 +322,10 @@ protected:
auto &r = Reproducer::Instance();
if (r.IsCapturing()) {
result.GetOutputStream() << "Reproducer is in capture mode.\n";
} else if (r.IsReplaying()) {
result.GetOutputStream() << "Reproducer is in replay mode.\n";
} else {
result.GetOutputStream() << "Reproducer is off.\n";
}
if (r.IsCapturing() || r.IsReplaying()) {
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

View File

@@ -225,18 +225,12 @@ Status PlatformRemoteGDBServer::ConnectRemote(Args &args) {
m_platform_hostname = parsed_url->hostname.str();
m_gdb_client.SetConnection(std::make_unique<ConnectionFileDescriptor>());
if (repro::Reproducer::Instance().IsReplaying()) {
error = m_gdb_replay_server.Connect(m_gdb_client);
if (error.Success())
m_gdb_replay_server.StartAsyncThread();
} else {
if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
repro::GDBRemoteProvider &provider =
g->GetOrCreate<repro::GDBRemoteProvider>();
m_gdb_client.SetPacketRecorder(provider.GetNewPacketRecorder());
}
m_gdb_client.Connect(url, &error);
if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
repro::GDBRemoteProvider &provider =
g->GetOrCreate<repro::GDBRemoteProvider>();
m_gdb_client.SetPacketRecorder(provider.GetNewPacketRecorder());
}
m_gdb_client.Connect(url, &error);
if (error.Fail())
return error;

View File

@@ -526,18 +526,15 @@ Status ProcessGDBRemote::WillAttachToProcessWithName(const char *process_name,
Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
Status error(WillLaunchOrAttach());
if (error.Fail())
return error;
if (repro::Reproducer::Instance().IsReplaying())
error = ConnectToReplayServer();
else
error = ConnectToDebugserver(remote_url);
error = ConnectToDebugserver(remote_url);
if (error.Fail())
return error;
StartAsyncThread();
lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID();
@@ -3259,9 +3256,6 @@ ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) {
if (platform_sp && !platform_sp->IsHost())
return Status("Lost debug server connection");
if (repro::Reproducer::Instance().IsReplaying())
return ConnectToReplayServer();
auto error = LaunchAndConnectToDebugserver(process_info);
if (error.Fail()) {
const char *error_string = error.AsCString();
@@ -3540,7 +3534,7 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) {
// So it is safer to simply ignore any remaining packets by
// explicitly checking for eStateExited before reentering the
// fetch loop.
bool done = false;
while (!done && process->GetPrivateState() != eStateExited) {
LLDB_LOGF(log,

View File

@@ -44,10 +44,6 @@ llvm::Error Reproducer::Initialize(ReproducerMode mode,
}
return Instance().SetCapture(root);
} break;
case ReproducerMode::Replay:
return Instance().SetReplay(root, /*passive*/ false);
case ReproducerMode::PassiveReplay:
return Instance().SetReplay(root, /*passive*/ true);
case ReproducerMode::Off:
break;
};
@@ -116,26 +112,6 @@ llvm::Error Reproducer::SetCapture(llvm::Optional<FileSpec> root) {
return Error::success();
}
llvm::Error Reproducer::SetReplay(llvm::Optional<FileSpec> root, bool passive) {
std::lock_guard<std::mutex> guard(m_mutex);
if (root && m_generator)
return make_error<StringError>(
"cannot replay a reproducer when generating one",
inconvertibleErrorCode());
if (!root) {
m_loader.reset();
return Error::success();
}
m_loader.emplace(*root, passive);
if (auto e = m_loader->LoadIndex())
return e;
return Error::success();
}
FileSpec Reproducer::GetReproducerPath() const {
if (auto g = GetGenerator())
return g->GetRoot();
@@ -222,8 +198,7 @@ void Generator::AddProvidersToIndex() {
}
Loader::Loader(FileSpec root, bool passive)
: m_root(MakeAbsolute(std::move(root))), m_loaded(false),
m_passive_replay(passive) {}
: m_root(MakeAbsolute(std::move(root))), m_loaded(false) {}
llvm::Error Loader::LoadIndex() {
if (m_loaded)

View File

@@ -57,16 +57,6 @@ class ReproducerAttachTestCase(TestBase):
self.assertIn('Process {} stopped'.format(pid), outs)
self.assertIn('Reproducer written', outs)
# Check that replay works.
replay = subprocess.Popen(
[lldbtest_config.lldbExec, '-replay', reproducer],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
outs, _ = replay.communicate()
outs = outs.decode('utf-8')
self.assertIn('Process {} stopped'.format(pid), outs)
# We can dump the reproducer in the current context.
self.expect('reproducer dump -f {} -p process'.format(reproducer),
substrs=['pid = {}'.format(pid), 'name = {}'.format(exe)])

View File

@@ -48,7 +48,6 @@ CHECK: -f
CHECK: --help
CHECK: -h
CHECK: --no-use-colors
CHECK: --replay
CHECK: --version
CHECK: -v
CHECK: -X

View File

@@ -1,7 +0,0 @@
breakpoint set -f foo.cpp -l 11
run
frame var foo
next
frame var foo
cont
reproducer generate

View File

@@ -1,10 +0,0 @@
breakpoint set -f foo.cpp -l 11
run
p foo
next
p Foo(2, 3.33);
p $1
p foo = Foo(3, 4.44);
p foo
cont
reproducer generate

View File

@@ -1,13 +0,0 @@
class Foo {
public:
Foo(int i, double d) : m_i(i), m_d(d){};
private:
int m_i;
int m_d;
};
int main(int argc, char **argv) {
static Foo foo(1, 2.22);
return 0;
}

View File

@@ -1,37 +0,0 @@
int a(int);
int b(int);
int c(int);
int complex(int, int, int);
int a(int val) {
int return_value = val;
if (val <= 1) {
return_value = b(val);
} else if (val >= 3) {
return_value = c(val);
}
return return_value;
}
int b(int val) {
int rc = c(val);
return rc;
}
int c(int val) { return val + 3; }
int complex(int first, int second, int third) { return first + second + third; }
int main(int argc, char const *argv[]) {
int A1 = a(1);
int B2 = b(2);
int A3 = a(3);
int A4 = complex(a(1), b(2), c(3));
return 0;
}

View File

@@ -1,16 +0,0 @@
# UNSUPPORTED: system-freebsd
# This tests that data formatters continue to work when replaying a reproducer.
# RUN: rm -rf %t.repro
# RUN: %clangxx_host %S/Inputs/foo.cpp -g -o %t.out
# RUN: %lldb -x -b -s %S/Inputs/DataFormatter.in --capture --capture-path %t.repro %t.out | FileCheck %s
# RUN: %lldb --replay %t.repro | FileCheck %s
# CHECK: stop reason = breakpoint 1.1
# CHECK: (Foo) foo = (m_i = 0, m_d = 0)
# CHECK: stop reason = step over
# CHECK: (Foo) foo = (m_i = 1, m_d = 2)
# CHECK: Process {{.*}} resuming
# CHECK: Process {{.*}} exited with status = 0

View File

@@ -1,22 +0,0 @@
# UNSUPPORTED: system-freebsd
# UNSUPPORTED: system-netbsd
# Flaky
# UNSUPPORTED: system-linux
# This tests that expression evaluation continues to work when replaying a
# reproducer.
# RUN: rm -rf %t.repro
# RUN: %clangxx_host %S/Inputs/foo.cpp -g -o %t.out
# RUN: %lldb -x -b -s %S/Inputs/ExpressionEvaluation.in --capture --capture-path %t.repro %t.out | FileCheck %s
# RUN: %lldb --replay %t.repro | FileCheck %s
# CHECK: stop reason = breakpoint 1.1
# CHECK: (Foo) $0 = (m_i = 0, m_d = 0)
# CHECK: stop reason = step over
# CHECK: (Foo) $1 = (m_i = 2, m_d = 3)
# CHECK: (Foo) $1 = (m_i = 2, m_d = 3)
# CHECK: (Foo) $2 = (m_i = 3, m_d = 4)
# CHECK: (Foo) $3 = (m_i = 3, m_d = 4)

View File

@@ -1,31 +0,0 @@
# UNSUPPORTED: system-freebsd
# This tests that image list works when replaying. We arbitrarily assume
# there's at least two entries and compare that they're identical.
# RUN: %clang_host %S/Inputs/stepping.c -g -o %t.out
# RUN: rm -rf %t.txt
# RUN: rm -rf %t.repro
# RUN: echo "CAPTURE" >> %t.txt
# RUN: %lldb -x -b --capture --capture-path %t.repro \
# RUN: -o 'run' \
# RUN: -o 'image list' \
# RUN: -o 'reproducer generate' \
# RUN: %t.out >> %t.txt 2>&1
# RUN: echo "REPLAY" >> %t.txt
# RUN: %lldb -x -b --replay %t.repro >> %t.txt 2>&1
# RUN: cat %t.txt | FileCheck %s
# CHECK: CAPTURE
# CHECK: image list
# CHECK: [ 0] [[ZERO:.*]]
# CHECK: [ 1] [[ONE:.*]]
# CHECK: REPLAY
# CHECK: image list
# CHECK: [ 0] {{.*}}[[ZERO]]
# CHECK: [ 1] {{.*}}[[ONE]]

View File

@@ -1,100 +0,0 @@
# UNSUPPORTED: system-freebsd
# This tests that stepping continues to work when replaying a reproducer.
# RUN: rm -rf %t.repro
# RUN: %clang_host %S/Inputs/stepping.c -O0 -g -o %t.out
# RUN: grep -v '#' %s > %t.in
# RUN: %lldb -x -b -s %t.in --capture --capture-path %t.repro %t.out | FileCheck %s --check-prefix CHECK
# RUN: %lldb --replay %t.repro | FileCheck %s --check-prefix CHECK
# Set breakpoints in a,b and c and verify we stop there when stepping.
breakpoint set -f stepping.c -l 28
# CHECK: Breakpoint 1: {{.*}} stepping.c:28
breakpoint set -f stepping.c -l 10
# CHECK: Breakpoint 2: {{.*}} stepping.c:10
breakpoint set -f stepping.c -l 19
# CHECK: Breakpoint 3: {{.*}} stepping.c:19
breakpoint set -f stepping.c -l 23
# CHECK: Breakpoint 4: {{.*}} stepping.c:23
run
# CHECK: Process {{.*}} stopped
# CHECK: stop reason = breakpoint 1.1
next
# CHECK: Process {{.*}} stopped
# CHECK: stop reason = breakpoint 2.1
next
# CHECK: Process {{.*}} stopped
# CHECK: stop reason = breakpoint 3.1
next
# CHECK: Process {{.*}} stopped
# CHECK: stop reason = breakpoint 4.1
bt
# CHECK: frame #0: {{.*}}`c
# CHECK: frame #1: {{.*}}`b
# CHECK: frame #2: {{.*}}`a
# Continue and stop resulting from the step overs.
cont
# CHECK: Process {{.*}} resuming
# CHECK: Process {{.*}} stopped
# CHECK: stop reason = step over
cont
# CHECK: Process {{.*}} resuming
# CHECK: Process {{.*}} stopped
# CHECK: stop reason = step over
cont
# CHECK: Process {{.*}} resuming
# CHECK: Process {{.*}} stopped
# CHECK: stop reason = step over
breakpoint disable 1
# CHECK: 1 breakpoints disabled.
breakpoint disable 2
# CHECK: 1 breakpoints disabled.
breakpoint disable 3
# CHECK: 1 breakpoints disabled.
breakpoint disable 4
# CHECK: 1 breakpoints disabled.
# Continue to line 48.
next
# CHECK: stop reason = step over
next
# CHECK: stop reason = step over
# Step into c.
thread step-in
# CHECK: stop reason = step in
thread step-in
# CHECK: stop reason = step in
thread step-in
# CHECK: stop reason = step in
thread step-in
# CHECK: stop reason = step in
thread step-in
# CHECK: stop reason = step in
# Finally continue until the end.
cont
# CHECK: Process {{.*}} resuming
# CHECK: Process {{.*}} exited with status = 0
# Generate the reproducer.
reproducer generate

View File

@@ -31,7 +31,3 @@
# RUN: rm -rf %t.root
# RUN: rm -rf %t.clang-cache
# RUN: rm -rf %t.lldb-cache
# Replay the debug session.
# RUN: %lldb -x -b -o 'settings set symbols.clang-modules-cache-path %t.lldb-cache' -s %S/Inputs/ModuleCXX.in --replay %t.repro %t.root/a.out | FileCheck %s --check-prefix REPLAY
# REPLAY: (success = 0)

View File

@@ -1,10 +1,8 @@
# 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
# RUN: not %lldb --replay %t/bogus/bogus 2>&1 | FileCheck %s --check-prefix INVALID-REPLAY
#
# INVALID-CAPTURE: unable to create reproducer directory
# INVALID-REPLAY: unable to load reproducer index
# Check that all option combination work as expected.
#

View File

@@ -22,8 +22,6 @@
# GDB: send packet: $QStartNoAckMode#b0
# GDB: read packet: $OK#9a
# RUN: %lldb --replay %t.repro | FileCheck %s --check-prefix FILES
# 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.

View File

@@ -10,15 +10,10 @@
# 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
# RUN: %lldb --replay %t.repro | FileCheck %s --check-prefix CHECK --check-prefix REPLAY
# RUN: cat %t.repro/version.txt | FileCheck %s --check-prefix VERSION
# CAPTURE: testing
# REPLAY-NOT: testing
# CHECK: Process {{.*}} exited
# CAPTURE: Reproducer is in capture mode.
# CAPTURE: Reproducer written
# VERSION: lldb version

View File

@@ -1,29 +0,0 @@
# UNSUPPORTED: system-freebsd
# 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: %clang_host %S/Inputs/simple.c -g -o %t.out
# Test reproducer generate command.
# RUN: rm -rf %t.repro
# RUN: %lldb -x -b -s %S/Inputs/GDBRemoteCapture.in --capture --capture-path %t.repro %t.out | FileCheck %s --check-prefix CHECK --check-prefix CAPTURE
# RUN: env FOO=BAR %lldb --replay %t.repro | FileCheck %s --check-prefix CHECK --check-prefix REPLAY
# CHECK: Breakpoint 1
# CHECK: Process {{.*}} stopped
# CHECK: Process {{.*}} launched
# CHECK: thread {{.*}} stop reason = breakpoint
# CHECK: frame {{.*}} simple.c
# CAPTURE: testing
# REPLAY-NOT: testing
# CHECK: Process {{.*}} resuming
# CHECK: Process {{.*}} exited
# CAPTURE: Reproducer is in capture mode.
# CAPTURE: Reproducer written

View File

@@ -9,6 +9,4 @@
# RUN: cat %t.repro/home.txt | FileCheck %t.check
# RUN: %lldb -b -o 'reproducer dump -p home -f %t.repro' | FileCheck %t.check
# RUN: %lldb --replay %t.repro | FileCheck %s
# CHECK: 95126

View File

@@ -1,25 +0,0 @@
# UNSUPPORTED: system-freebsd
# This tests the replaying with multiple targets.
# RUN: %clang_host %S/Inputs/simple.c -g -o %t.out
# RUN: rm -rf %t.repro
# RUN: %lldb -x -b --capture --capture-path %t.repro -o 'target create %t.out' -o 'target create %t.out' -s %S/Inputs/MultipleTargetsCapture.in | FileCheck %s --check-prefix CHECK --check-prefix CAPTURE
# RUN: env FOO=BAR %lldb --replay %t.repro | FileCheck %s --check-prefix CHECK --check-prefix REPLAY
# CHECK: Process [[TARGET0:[0-9]+]] stopped
# CHECK: stop reason = breakpoint 1.1
# CHECK: simple.c:4:5
# CHECK: Process [[TARGET1:[0-9]+]] stopped
# CHECK: stop reason = breakpoint 1.1
# CHECK: simple.c:8:5
# CHECK: Process [[TARGET0]] resuming
# CHECK: Process [[TARGET0]] exited
# CHECK: Process [[TARGET1]] resuming
# CHECK: Process [[TARGET1]] exited
# CAPTURE: Reproducer is in capture mode.
# CAPTURE: Reproducer written
# REPLAY: Reproducer is in replay mode.

View File

@@ -1,21 +0,0 @@
# UNSUPPORTED: system-freebsd
# Test that ProcessInfo is correctly serialized by comparing the output of
# 'platform process list -v' during capture and replay. The test assumes that
# there's at least two processes.
# RUN: %lldb -x -b -o 'platform process list -v' -o 'reproducer generate' --capture --capture-path %t.repro > %t.log
# RUN: %lldb --replay %t.repro >> %t.log
# RUN: cat %t.log | FileCheck %s
# CHECK: [[PROCS:[0-9]+]] matching processes were found
# CHECK: PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE ARGUMENTS
# CHECK-NEXT: ====== ====== ========== ========== ========== ========== ============================== ============================
# CHECK-NEXT: [[PID0:[0-9]+]] [[PROC0:.*]]
# CHECK-NEXT: [[PID1:[0-9]+]] [[PROC1:.*]]
# CHECK: Reproducer written to
# CHECK: [[PROCS]] matching processes were found
# CHECK: PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE ARGUMENTS
# CHECK-NEXT: ====== ====== ========== ========== ========== ========== ============================== ============================
# CHECK-NEXT: [[PID0]] [[PROC0]]
# CHECK-NEXT: [[PID1]] [[PROC1]]

View File

@@ -1,8 +0,0 @@
# This tests relative capture paths.
# RUN: mkdir -p %t
# RUN: cd %t
# RUN: rm -rf ./foo
# 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 ./foo %t/reproducer.out
# RUN: %lldb --replay ./foo

View File

@@ -1,17 +0,0 @@
# UNSUPPORTED: system-freebsd
# Test that we can capture twice to the same directory without breaking the
# reproducer functionality.
# RUN: rm -rf %t.repro
# RUN: %clang_host %S/Inputs/simple.c -g -o %t.out
# RUN: %lldb -x -b -s %S/Inputs/GDBRemoteCapture.in --capture --capture-path %t.repro %t.out | FileCheck %S/TestGDBRemoteRepro.test --check-prefix CHECK --check-prefix CAPTURE
# RUN: %lldb -x -b -s %S/Inputs/GDBRemoteCapture.in --capture --capture-path %t.repro %t.out | FileCheck %S/TestGDBRemoteRepro.test --check-prefix CHECK --check-prefix CAPTURE
# RUN: %lldb --replay %t.repro | FileCheck %S/TestGDBRemoteRepro.test --check-prefix CHECK --check-prefix REPLAY
# Test that we can replay from a different location, i.e. that the reproducer
# is relocatable.
# RUN: rm -rf %t.repro_moved
# RUN: mv %t.repro %t.repro_moved
# RUN: %lldb --replay %t.repro_moved | FileCheck %S/TestGDBRemoteRepro.test --check-prefix CHECK --check-prefix REPLAY

View File

@@ -1,14 +0,0 @@
# REQUIRES: python
# Ensure that replay happens in synchronous mode.
# RUN: rm -rf %t.repro
# RUN: %lldb -x -b --capture --capture-path %t.repro -o 'script lldb.debugger.SetAsync(True)' -o 'script lldb.debugger.GetAsync()' -o 'reproducer generate' | FileCheck %s --check-prefix CAPTURE
# RUN: %lldb --replay %t.repro | FileCheck %s --check-prefix REPLAY
# CAPTURE: script lldb.debugger.SetAsync(True)
# CAPTURE-NEXT: script lldb.debugger.GetAsync()
# CAPTURE-NEXT: True
# REPLAY: script lldb.debugger.SetAsync(True)
# REPLAY-NEXT: script lldb.debugger.GetAsync()
# REPLAY-NEXT: False

View File

@@ -2,7 +2,6 @@
# RUN: rm -rf %t.repro2
# RUN: %clang_host %S/Inputs/simple.c -g -o %t.out
# RUN: %lldb -x -b -s %S/Inputs/GDBRemoteCapture.in --capture --capture-path %t.repro %t.out
# RUN: %lldb --replay %t.repro
# RUN: echo "/bogus/home/dir" > %t.repro/home.txt
# RUN: echo "/bogus/current/working/dir" > %t.repro/cwd.txt
@@ -14,14 +13,3 @@
# RUN: rm %t.repro/root/%S/Inputs/GDBRemoteCapture.in
# RUN: echo "CHECK: '%S/Inputs/GDBRemoteCapture.in': No such file or directory" > %t.check
# RUN: not %lldb -b -o 'reproducer verify -f %t.repro' 2>&1 | FileCheck %t.check
# RUN: not %lldb --replay %t.repro 2>&1 | FileCheck %s
# At this point the reproducer is too broken to ignore the verification issues.
# Capture a new reproducer and only change the home directory, which is
# recoverable as far as this test goes.
# RUN: %lldb -x -b -s %S/Inputs/GDBRemoteCapture.in --capture --capture-path %t.repro2 %t.out
# RUN: echo "/bogus/home/dir" > %t.repro2/home.txt
# RUN: %lldb --replay %t.repro2 --reproducer-no-verify 2>&1 | FileCheck %s --check-prefix NO-VERIFY
# NO-VERIFY-NOT: home directory '/bogus/home/dir' not in VFS

View File

@@ -6,24 +6,12 @@
# 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
# Make sure that replay works.
# RUN: %lldb --replay %t.repro | FileCheck %s --check-prefix CHECK --check-prefix REPLAY
# Change the reproducer version.
# RUN: echo "bogus" >> %t.repro/version.txt
# Make sure that replay works.
# RUN: not %lldb --replay %t.repro 2>&1 | FileCheck %s --check-prefix ERROR
# Make sure that we can circumvent the version check with -reproducer-no-version-check.
# RUN: %lldb --replay %t.repro -reproducer-no-version-check | FileCheck %s --check-prefix CHECK --check-prefix REPLAY
# CAPTURE: testing
# REPLAY-NOT: testing
# CHECK: Process {{.*}} exited
# CAPTURE: Reproducer is in capture mode.
# CAPTURE: Reproducer written
# ERROR: error: reproducer replay failed: reproducer capture and replay version don't match

View File

@@ -1,6 +1,5 @@
# 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.
# binary in a subdirectory and pass its relative path to LLDB.
# RUN: echo "CHECK: %t" > %t.check
@@ -14,7 +13,6 @@
# RUN: rm -rf %t/binary
# RUN: cat %t.repro/cwd.txt | FileCheck %t.check
# RUN: %lldb --replay %t.repro | FileCheck %t.check
# Make sure the current working directory is recorded even when it's not
# referenced.

View File

@@ -736,18 +736,6 @@ EXAMPLES:
static llvm::Optional<int> InitializeReproducer(llvm::StringRef argv0,
opt::InputArgList &input_args) {
if (auto *replay_path = input_args.getLastArg(OPT_replay)) {
SBReplayOptions replay_options;
replay_options.SetCheckVersion(!input_args.hasArg(OPT_no_version_check));
replay_options.SetVerify(!input_args.hasArg(OPT_no_verification));
if (const char *error =
SBReproducer::Replay(replay_path->getValue(), replay_options)) {
WithColor::error() << "reproducer replay failed: " << error << '\n';
return 1;
}
return 0;
}
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);

View File

@@ -233,15 +233,6 @@ def capture: F<"capture">,
def capture_path: Separate<["--", "-"], "capture-path">,
MetaVarName<"<filename>">,
HelpText<"Tells the debugger to use the given filename for the reproducer.">;
def replay: Separate<["--", "-"], "replay">,
MetaVarName<"<filename>">,
HelpText<"Tells the debugger to replay a reproducer from <filename>.">;
def no_version_check: F<"reproducer-no-version-check">,
HelpText<"Disable the reproducer version check.">;
def no_verification: F<"reproducer-no-verify">,
HelpText<"Disable the reproducer verification.">;
def no_generate_on_signal: F<"reproducer-no-generate-on-signal">,
HelpText<"Don't generate reproducer when a signal is received.">;
def generate_on_exit: F<"reproducer-generate-on-exit">,
HelpText<"Generate reproducer on exit.">;

View File

@@ -57,7 +57,6 @@ public:
DummyReproducer() : Reproducer(){};
using Reproducer::SetCapture;
using Reproducer::SetReplay;
};
struct YamlData {
@@ -98,9 +97,6 @@ TEST(ReproducerTest, SetCapture) {
reproducer.GetReproducerPath());
// Ensure that we cannot enable replay.
EXPECT_THAT_ERROR(
reproducer.SetReplay(FileSpec("//bogus/path", FileSpec::Style::posix)),
Failed());
EXPECT_EQ(nullptr, reproducer.GetLoader());
// Ensure we can disable the generator again.
@@ -109,33 +105,6 @@ TEST(ReproducerTest, SetCapture) {
EXPECT_EQ(nullptr, reproducer.GetLoader());
}
TEST(ReproducerTest, SetReplay) {
DummyReproducer reproducer;
// Initially both generator and loader are unset.
EXPECT_EQ(nullptr, reproducer.GetGenerator());
EXPECT_EQ(nullptr, reproducer.GetLoader());
// Expected to fail because we can't load the index.
EXPECT_THAT_ERROR(
reproducer.SetReplay(FileSpec("//bogus/path", FileSpec::Style::posix)),
Failed());
// However the loader should still be set, which we check here.
EXPECT_NE(nullptr, reproducer.GetLoader());
// Make sure the bogus path is correctly set.
EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
reproducer.GetLoader()->GetRoot());
EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
reproducer.GetReproducerPath());
// Ensure that we cannot enable replay.
EXPECT_THAT_ERROR(
reproducer.SetCapture(FileSpec("//bogus/path", FileSpec::Style::posix)),
Failed());
EXPECT_EQ(nullptr, reproducer.GetGenerator());
}
TEST(GeneratorTest, Create) {
DummyReproducer reproducer;
@@ -214,49 +183,4 @@ TEST(GeneratorTest, YamlMultiProvider) {
generator.Keep();
}
{
DummyReproducer reproducer;
EXPECT_THAT_ERROR(reproducer.SetReplay(FileSpec(root.str())), Succeeded());
auto &loader = *reproducer.GetLoader();
std::unique_ptr<repro::MultiLoader<YamlMultiProvider>> multi_loader =
repro::MultiLoader<YamlMultiProvider>::Create(&loader);
// Read the first file.
{
llvm::Optional<std::string> file = multi_loader->GetNextFile();
EXPECT_TRUE(static_cast<bool>(file));
auto buffer = llvm::MemoryBuffer::getFile(*file);
EXPECT_TRUE(static_cast<bool>(buffer));
yaml::Input yin((*buffer)->getBuffer());
std::vector<YamlData> data;
yin >> data;
ASSERT_EQ(data.size(), 2U);
EXPECT_THAT(data, testing::ElementsAre(data0, data1));
}
// Read the second file.
{
llvm::Optional<std::string> file = multi_loader->GetNextFile();
EXPECT_TRUE(static_cast<bool>(file));
auto buffer = llvm::MemoryBuffer::getFile(*file);
EXPECT_TRUE(static_cast<bool>(buffer));
yaml::Input yin((*buffer)->getBuffer());
std::vector<YamlData> data;
yin >> data;
ASSERT_EQ(data.size(), 2U);
EXPECT_THAT(data, testing::ElementsAre(data2, data3));
}
// There is no third file.
llvm::Optional<std::string> file = multi_loader->GetNextFile();
EXPECT_FALSE(static_cast<bool>(file));
}
}