JDevlieghere updated this revision to Diff 258390.
JDevlieghere marked an inline comment as done.
JDevlieghere added a comment.

- Remove const_cast
- Initialize instrumentation data in `SBReproducer.cpp`


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77602/new/

https://reviews.llvm.org/D77602

Files:
  lldb/include/lldb/Utility/Reproducer.h
  lldb/include/lldb/Utility/ReproducerInstrumentation.h
  lldb/source/API/SBDebugger.cpp
  lldb/source/API/SBReproducer.cpp
  lldb/source/API/SBReproducerPrivate.h
  lldb/source/Utility/Reproducer.cpp
  lldb/source/Utility/ReproducerInstrumentation.cpp
  lldb/unittests/Utility/ReproducerInstrumentationTest.cpp

Index: lldb/unittests/Utility/ReproducerInstrumentationTest.cpp
===================================================================
--- lldb/unittests/Utility/ReproducerInstrumentationTest.cpp
+++ lldb/unittests/Utility/ReproducerInstrumentationTest.cpp
@@ -52,23 +52,62 @@
 
 static llvm::Optional<TestingRegistry> g_registry;
 static llvm::Optional<Serializer> g_serializer;
+static llvm::Optional<Deserializer> g_deserializer;
 
-inline InstrumentationData GetTestInstrumentationData() {
+class TestInstrumentationData : public InstrumentationData {
+public:
+  TestInstrumentationData() : InstrumentationData() {}
+  TestInstrumentationData(Serializer &serializer, Registry &registry)
+      : InstrumentationData(serializer, registry) {}
+  TestInstrumentationData(Deserializer &deserializer, Registry &registry)
+      : InstrumentationData(deserializer, registry) {}
+};
+
+inline TestInstrumentationData GetTestInstrumentationData() {
+  assert(!(g_serializer && g_deserializer));
   if (g_serializer)
-    return InstrumentationData(*g_serializer, *g_registry);
-  return InstrumentationData();
+    return TestInstrumentationData(*g_serializer, *g_registry);
+  if (g_deserializer)
+    return TestInstrumentationData(*g_deserializer, *g_registry);
+  return TestInstrumentationData();
 }
 
 class TestInstrumentationDataRAII {
-public:
+private:
   TestInstrumentationDataRAII(llvm::raw_string_ostream &os) {
     g_registry.emplace();
     g_serializer.emplace(os);
+    g_deserializer.reset();
   }
 
-  ~TestInstrumentationDataRAII() {
+  TestInstrumentationDataRAII(llvm::StringRef buffer) {
+    g_registry.emplace();
+    g_serializer.reset();
+    g_deserializer.emplace(buffer);
+  }
+
+  friend std::unique_ptr<TestInstrumentationDataRAII>
+  std::make_unique<TestInstrumentationDataRAII>(llvm::raw_string_ostream &os);
+  friend std::unique_ptr<TestInstrumentationDataRAII>
+  std::make_unique<TestInstrumentationDataRAII>(llvm::StringRef &buffer);
+
+public:
+  ~TestInstrumentationDataRAII() { Reset(); }
+
+  void Reset() {
     g_registry.reset();
     g_serializer.reset();
+    g_deserializer.reset();
+  }
+
+  static std::unique_ptr<TestInstrumentationDataRAII>
+  GetRecordingData(llvm::raw_string_ostream &os) {
+    return std::make_unique<TestInstrumentationDataRAII>(os);
+  }
+
+  static std::unique_ptr<TestInstrumentationDataRAII>
+  GetReplayData(llvm::StringRef buffer) {
+    return std::make_unique<TestInstrumentationDataRAII>(buffer);
   }
 };
 
@@ -95,11 +134,17 @@
   InstrumentedFoo(const InstrumentedFoo &foo);
   InstrumentedFoo &operator=(const InstrumentedFoo &foo);
   void A(int a);
+  int GetA();
   void B(int &b) const;
+  int &GetB();
   int C(float *c);
+  float GetC();
   int D(const char *d) const;
+  void GetD(char *buffer, size_t length);
   static void E(double e);
+  double GetE();
   static int F();
+  bool GetF();
   void Validate() override;
   //// }
   virtual bool IsA(Class c) override { return c == Class::Foo; }
@@ -182,35 +227,71 @@
   m_a = a;
 }
 
+int InstrumentedFoo::GetA() {
+  LLDB_RECORD_METHOD_NO_ARGS(int, InstrumentedFoo, GetA);
+
+  return m_a;
+}
+
 void InstrumentedFoo::B(int &b) const {
   LLDB_RECORD_METHOD_CONST(void, InstrumentedFoo, B, (int &), b);
   m_called++;
   m_b = b;
 }
 
+int &InstrumentedFoo::GetB() {
+  LLDB_RECORD_METHOD_NO_ARGS(int &, InstrumentedFoo, GetB);
+
+  return m_b;
+}
+
 int InstrumentedFoo::C(float *c) {
   LLDB_RECORD_METHOD(int, InstrumentedFoo, C, (float *), c);
   m_c = *c;
   return 1;
 }
 
+float InstrumentedFoo::GetC() {
+  LLDB_RECORD_METHOD_NO_ARGS(float, InstrumentedFoo, GetC);
+
+  return m_c;
+}
+
 int InstrumentedFoo::D(const char *d) const {
   LLDB_RECORD_METHOD_CONST(int, InstrumentedFoo, D, (const char *), d);
   m_d = std::string(d);
   return 2;
 }
 
+void InstrumentedFoo::GetD(char *buffer, size_t length) {
+  LLDB_RECORD_METHOD(void, InstrumentedFoo, GetD, (char *, size_t), buffer,
+                     length);
+  ::snprintf(buffer, length, "%s", m_d.c_str());
+}
+
 void InstrumentedFoo::E(double e) {
   LLDB_RECORD_STATIC_METHOD(void, InstrumentedFoo, E, (double), e);
   g_e = e;
 }
 
+double InstrumentedFoo::GetE() {
+  LLDB_RECORD_METHOD_NO_ARGS(double, InstrumentedFoo, GetE);
+
+  return g_e;
+}
+
 int InstrumentedFoo::F() {
   LLDB_RECORD_STATIC_METHOD_NO_ARGS(int, InstrumentedFoo, F);
   g_f = true;
   return 3;
 }
 
+bool InstrumentedFoo::GetF() {
+  LLDB_RECORD_METHOD_NO_ARGS(bool, InstrumentedFoo, GetF);
+
+  return g_f;
+}
+
 void InstrumentedFoo::Validate() {
   LLDB_RECORD_METHOD_NO_ARGS(void, InstrumentedFoo, Validate);
   EXPECT_EQ(m_a, 100);
@@ -296,6 +377,12 @@
   LLDB_REGISTER_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
                        (InstrumentedFoo &));
   LLDB_REGISTER_METHOD(void, InstrumentedBar, Validate, ());
+  LLDB_REGISTER_METHOD(int, InstrumentedFoo, GetA, ());
+  LLDB_REGISTER_METHOD(int &, InstrumentedFoo, GetB, ());
+  LLDB_REGISTER_METHOD(float, InstrumentedFoo, GetC, ());
+  LLDB_REGISTER_METHOD(void, InstrumentedFoo, GetD, (char *, size_t));
+  LLDB_REGISTER_METHOD(double, InstrumentedFoo, GetE, ());
+  LLDB_REGISTER_METHOD(bool, InstrumentedFoo, GetF, ());
 }
 
 static const Pod p;
@@ -534,7 +621,7 @@
   llvm::raw_string_ostream os(str);
 
   {
-    TestInstrumentationDataRAII data(os);
+    auto data = TestInstrumentationDataRAII::GetRecordingData(os);
 
     int b = 200;
     float c = 300.3f;
@@ -563,7 +650,7 @@
   llvm::raw_string_ostream os(str);
 
   {
-    TestInstrumentationDataRAII data(os);
+    auto data = TestInstrumentationDataRAII::GetRecordingData(os);
 
     int b = 200;
     float c = 300.3f;
@@ -603,7 +690,7 @@
   llvm::raw_string_ostream os(str);
 
   {
-    TestInstrumentationDataRAII data(os);
+    auto data = TestInstrumentationDataRAII::GetRecordingData(os);
 
     InstrumentedBar bar;
     InstrumentedFoo foo = bar.GetInstrumentedFoo();
@@ -643,7 +730,7 @@
   llvm::raw_string_ostream os(str);
 
   {
-    TestInstrumentationDataRAII data(os);
+    auto data = TestInstrumentationDataRAII::GetRecordingData(os);
 
     InstrumentedBar bar;
     InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
@@ -679,7 +766,7 @@
   llvm::raw_string_ostream os(str);
 
   {
-    TestInstrumentationDataRAII data(os);
+    auto data = TestInstrumentationDataRAII::GetRecordingData(os);
 
     InstrumentedBar bar;
     InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
@@ -709,3 +796,302 @@
       deserializer.GetAllObjects(),
       {{Class::Bar, Validator::valid}, {Class::Foo, Validator::valid}});
 }
+
+TEST(PassiveReplayTest, InstrumentedFoo) {
+  std::string str;
+  llvm::raw_string_ostream os(str);
+
+  {
+    auto data = TestInstrumentationDataRAII::GetRecordingData(os);
+
+    int b = 200;
+    float c = 300.3f;
+    double e = 400.4;
+
+    InstrumentedFoo foo(0);
+    foo.A(100);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("bar");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+  }
+
+  std::string buffer = os.str();
+
+  {
+    auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
+
+    int b = 999;
+    float c = 999.9f;
+    double e = 999.9;
+
+    InstrumentedFoo foo(9);
+    foo.A(999);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("999");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+  }
+}
+
+TEST(PassiveReplayTest, InstrumentedFooInvalid) {
+  std::string str;
+  llvm::raw_string_ostream os(str);
+
+  {
+    auto data = TestInstrumentationDataRAII::GetRecordingData(os);
+
+    int b = 200;
+    float c = 300.3f;
+    double e = 400.4;
+
+    InstrumentedFoo foo(0);
+    foo.A(100);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("bar");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+  }
+
+  std::string buffer = os.str();
+
+  {
+    auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
+
+    int b = 999;
+    float c = 999.9f;
+    double e = 999.9;
+
+    InstrumentedFoo foo(9);
+    foo.A(999);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("999");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    // Detect divergence.
+    EXPECT_DEATH(foo.GetA(), "");
+  }
+}
+
+TEST(PassiveReplayTest, InstrumentedBar) {
+  std::string str;
+  llvm::raw_string_ostream os(str);
+
+  {
+    auto data = TestInstrumentationDataRAII::GetRecordingData(os);
+
+    InstrumentedBar bar;
+    InstrumentedFoo foo = bar.GetInstrumentedFoo();
+
+    int b = 200;
+    float c = 300.3f;
+    double e = 400.4;
+
+    foo.A(100);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("bar");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+
+  std::string buffer = os.str();
+
+  {
+    auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
+
+    InstrumentedBar bar;
+    InstrumentedFoo foo = bar.GetInstrumentedFoo();
+
+    int b = 99;
+    float c = 999.9f;
+    double e = 999.9;
+
+    foo.A(999);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("999");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+}
+
+TEST(PassiveReplayTest, InstrumentedBarRef) {
+  std::string str;
+  llvm::raw_string_ostream os(str);
+
+  {
+    auto data = TestInstrumentationDataRAII::GetRecordingData(os);
+
+    InstrumentedBar bar;
+    InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
+
+    int b = 200;
+    float c = 300.3f;
+    double e = 400.4;
+
+    foo.A(100);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("bar");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+
+  std::string buffer = os.str();
+
+  {
+    auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
+
+    InstrumentedBar bar;
+    InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
+
+    int b = 99;
+    float c = 999.9f;
+    double e = 999.9;
+
+    foo.A(999);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("999");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+}
+
+TEST(PassiveReplayTest, InstrumentedBarPtr) {
+  std::string str;
+  llvm::raw_string_ostream os(str);
+
+  {
+    auto data = TestInstrumentationDataRAII::GetRecordingData(os);
+
+    InstrumentedBar bar;
+    InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
+
+    int b = 200;
+    float c = 300.3f;
+    double e = 400.4;
+
+    foo.A(100);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("bar");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+
+  std::string buffer = os.str();
+
+  {
+    auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
+
+    InstrumentedBar bar;
+    InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
+
+    int b = 99;
+    float c = 999.9f;
+    double e = 999.9;
+
+    foo.A(999);
+    foo.B(b);
+    foo.C(&c);
+    foo.D("999");
+    InstrumentedFoo::E(e);
+    InstrumentedFoo::F();
+    foo.Validate();
+
+    EXPECT_EQ(foo.GetA(), 100);
+    EXPECT_EQ(foo.GetB(), 200);
+    EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+    EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
+    EXPECT_EQ(foo.GetF(), true);
+
+    bar.SetInstrumentedFoo(foo);
+    bar.SetInstrumentedFoo(&foo);
+    bar.Validate();
+  }
+}
Index: lldb/source/Utility/ReproducerInstrumentation.cpp
===================================================================
--- lldb/source/Utility/ReproducerInstrumentation.cpp
+++ lldb/source/Utility/ReproducerInstrumentation.cpp
@@ -8,9 +8,9 @@
 
 #include "lldb/Utility/ReproducerInstrumentation.h"
 #include "lldb/Utility/Reproducer.h"
-#include <thread>
 #include <stdio.h>
 #include <stdlib.h>
+#include <thread>
 
 using namespace lldb_private;
 using namespace lldb_private::repro;
@@ -120,7 +120,7 @@
 
   // Add a small artificial delay to ensure that all asynchronous events have
   // completed before we exit.
-  std::this_thread::sleep_for (std::chrono::milliseconds(100));
+  std::this_thread::sleep_for(std::chrono::milliseconds(100));
 
   return true;
 }
@@ -145,6 +145,22 @@
   return m_ids[id].second.ToString();
 }
 
+void Registry::CheckID(unsigned expected, unsigned actual) {
+  if (expected != actual) {
+    llvm::errs() << "Reproducer expected signature " << expected << ": '"
+                 << GetSignature(expected) << "'\n";
+    llvm::errs() << "Reproducer actual signature " << actual << ": '"
+                 << GetSignature(actual) << "'\n";
+    llvm::report_fatal_error(
+        "Detected reproducer replay divergence. Refusing to continue.");
+  }
+
+#ifdef LLDB_REPRO_INSTR_TRACE
+  llvm::errs() << "Replaying " << actual << ": " << GetSignature(actual)
+               << "\n";
+#endif
+}
+
 Replayer *Registry::GetReplayer(unsigned id) {
   assert(m_ids.count(id) != 0 && "ID not in registry");
   return m_ids[id].first;
@@ -181,4 +197,25 @@
   UpdateBoundary();
 }
 
+void InstrumentationData::Initialize(Serializer &serializer,
+                                     Registry &registry) {
+  InstanceImpl().emplace(serializer, registry);
+}
+
+void InstrumentationData::Initialize(Deserializer &deserializer,
+                                     Registry &registry) {
+  InstanceImpl().emplace(deserializer, registry);
+}
+
+InstrumentationData &InstrumentationData::Instance() {
+  if (!InstanceImpl())
+    InstanceImpl().emplace();
+  return *InstanceImpl();
+}
+
+llvm::Optional<InstrumentationData> &InstrumentationData::InstanceImpl() {
+  static llvm::Optional<InstrumentationData> g_instrumentation_data;
+  return g_instrumentation_data;
+}
+
 bool lldb_private::repro::Recorder::g_global_boundary;
Index: lldb/source/Utility/Reproducer.cpp
===================================================================
--- lldb/source/Utility/Reproducer.cpp
+++ lldb/source/Utility/Reproducer.cpp
@@ -62,7 +62,9 @@
     return Instance().SetCapture(root);
   } break;
   case ReproducerMode::Replay:
-    return Instance().SetReplay(root);
+    return Instance().SetReplay(root, /*passive*/ false);
+  case ReproducerMode::PassiveReplay:
+    return Instance().SetReplay(root, /*passive*/ true);
   case ReproducerMode::Off:
     break;
   };
@@ -127,7 +129,7 @@
   return Error::success();
 }
 
-llvm::Error Reproducer::SetReplay(llvm::Optional<FileSpec> root) {
+llvm::Error Reproducer::SetReplay(llvm::Optional<FileSpec> root, bool passive) {
   std::lock_guard<std::mutex> guard(m_mutex);
 
   if (root && m_generator)
@@ -140,7 +142,7 @@
     return Error::success();
   }
 
-  m_loader.emplace(*root);
+  m_loader.emplace(*root, passive);
   if (auto e = m_loader->LoadIndex())
     return e;
 
@@ -227,8 +229,9 @@
   yout << files;
 }
 
-Loader::Loader(FileSpec root)
-    : m_root(MakeAbsolute(std::move(root))), m_loaded(false) {}
+Loader::Loader(FileSpec root, bool passive)
+    : m_root(MakeAbsolute(std::move(root))), m_loaded(false),
+      m_passive_replay(passive) {}
 
 llvm::Error Loader::LoadIndex() {
   if (m_loaded)
Index: lldb/source/API/SBReproducerPrivate.h
===================================================================
--- lldb/source/API/SBReproducerPrivate.h
+++ lldb/source/API/SBReproducerPrivate.h
@@ -20,7 +20,7 @@
 #include "llvm/ADT/DenseMap.h"
 
 #define LLDB_GET_INSTRUMENTATION_DATA()                                        \
-  lldb_private::repro::GetInstrumentationData()
+  lldb_private::repro::InstrumentationData::Instance()
 
 namespace lldb_private {
 namespace repro {
@@ -55,17 +55,19 @@
   SBRegistry m_registry;
 };
 
-inline InstrumentationData GetInstrumentationData() {
-  if (!lldb_private::repro::Reproducer::Initialized())
-    return {};
-
-  if (auto *g = lldb_private::repro::Reproducer::Instance().GetGenerator()) {
-    auto &p = g->GetOrCreate<SBProvider>();
-    return {p.GetSerializer(), p.GetRegistry()};
-  }
+class ReplayData {
+public:
+  ReplayData(std::unique_ptr<llvm::MemoryBuffer> memory_buffer)
+      : m_memory_buffer(std::move(memory_buffer)), m_registry(),
+        m_deserializer(m_memory_buffer->getBuffer()) {}
+  Deserializer &GetDeserializer() { return m_deserializer; }
+  Registry &GetRegistry() { return m_registry; }
 
-  return {};
-}
+private:
+  std::unique_ptr<llvm::MemoryBuffer> m_memory_buffer;
+  SBRegistry m_registry;
+  Deserializer m_deserializer;
+};
 
 template <typename T> void RegisterMethods(Registry &R);
 
Index: lldb/source/API/SBReproducer.cpp
===================================================================
--- lldb/source/API/SBReproducer.cpp
+++ lldb/source/API/SBReproducer.cpp
@@ -111,6 +111,12 @@
     error = llvm::toString(std::move(e));
     return error.c_str();
   }
+
+  if (auto *g = lldb_private::repro::Reproducer::Instance().GetGenerator()) {
+    auto &p = g->GetOrCreate<SBProvider>();
+    InstrumentationData::Initialize(p.GetSerializer(), p.GetRegistry());
+  }
+
   return nullptr;
 }
 
@@ -121,15 +127,35 @@
     error = llvm::toString(std::move(e));
     return error.c_str();
   }
+
+  if (auto *g = lldb_private::repro::Reproducer::Instance().GetGenerator()) {
+    auto &p = g->GetOrCreate<SBProvider>();
+    InstrumentationData::Initialize(p.GetSerializer(), p.GetRegistry());
+  }
+
   return nullptr;
 }
 
 const char *SBReproducer::PassiveReplay(const char *path) {
   static std::string error;
-  if (auto e = Reproducer::Initialize(ReproducerMode::Replay, FileSpec(path))) {
+  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;
 }
 
Index: lldb/source/API/SBDebugger.cpp
===================================================================
--- lldb/source/API/SBDebugger.cpp
+++ lldb/source/API/SBDebugger.cpp
@@ -1629,31 +1629,31 @@
 
 template <> void RegisterMethods<SBDebugger>(Registry &R) {
   // Custom implementation.
-  R.Register(&invoke<void (SBDebugger::*)(
-                 FILE *, bool)>::method<&SBDebugger::SetErrorFileHandle>::doit,
+  R.Register(&invoke<void (SBDebugger::*)(FILE *, bool)>::method<
+                 &SBDebugger::SetErrorFileHandle>::record,
              &SetFileHandleRedirect);
-  R.Register(&invoke<void (SBDebugger::*)(
-                 FILE *, bool)>::method<&SBDebugger::SetOutputFileHandle>::doit,
+  R.Register(&invoke<void (SBDebugger::*)(FILE *, bool)>::method<
+                 &SBDebugger::SetOutputFileHandle>::record,
              &SetFileHandleRedirect);
 
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 SBFile)>::method<&SBDebugger::SetInputFile>::doit,
+                 SBFile)>::method<&SBDebugger::SetInputFile>::record,
              &SetFileRedirect);
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 SBFile)>::method<&SBDebugger::SetOutputFile>::doit,
+                 SBFile)>::method<&SBDebugger::SetOutputFile>::record,
              &SetFileRedirect);
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 SBFile)>::method<&SBDebugger::SetErrorFile>::doit,
+                 SBFile)>::method<&SBDebugger::SetErrorFile>::record,
              &SetFileRedirect);
 
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 FileSP)>::method<&SBDebugger::SetInputFile>::doit,
+                 FileSP)>::method<&SBDebugger::SetInputFile>::record,
              &SetFileRedirect);
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 FileSP)>::method<&SBDebugger::SetOutputFile>::doit,
+                 FileSP)>::method<&SBDebugger::SetOutputFile>::record,
              &SetFileRedirect);
   R.Register(&invoke<SBError (SBDebugger::*)(
-                 FileSP)>::method<&SBDebugger::SetErrorFile>::doit,
+                 FileSP)>::method<&SBDebugger::SetErrorFile>::record,
              &SetFileRedirect);
 
   LLDB_REGISTER_CHAR_PTR_REDIRECT_STATIC(bool, SBDebugger,
Index: lldb/include/lldb/Utility/ReproducerInstrumentation.h
===================================================================
--- lldb/include/lldb/Utility/ReproducerInstrumentation.h
+++ lldb/include/lldb/Utility/ReproducerInstrumentation.h
@@ -80,68 +80,72 @@
 // #define LLDB_REPRO_INSTR_TRACE
 
 #define LLDB_REGISTER_CONSTRUCTOR(Class, Signature)                            \
-  R.Register<Class * Signature>(&construct<Class Signature>::doit, "", #Class, \
-                                #Class, #Signature)
+  R.Register<Class * Signature>(&construct<Class Signature>::record, "",       \
+                                #Class, #Class, #Signature)
 
 #define LLDB_REGISTER_METHOD(Result, Class, Method, Signature)                 \
   R.Register(                                                                  \
-      &invoke<Result(Class::*) Signature>::method<(&Class::Method)>::doit,     \
+      &invoke<Result(Class::*) Signature>::method<(&Class::Method)>::record,   \
       #Result, #Class, #Method, #Signature)
 
 #define LLDB_REGISTER_METHOD_CONST(Result, Class, Method, Signature)           \
   R.Register(&invoke<Result(Class::*)                                          \
-                         Signature const>::method<(&Class::Method)>::doit,     \
+                         Signature const>::method<(&Class::Method)>::record,   \
              #Result, #Class, #Method, #Signature)
 
 #define LLDB_REGISTER_STATIC_METHOD(Result, Class, Method, Signature)          \
-  R.Register(&invoke<Result(*) Signature>::method<(&Class::Method)>::doit,     \
+  R.Register(&invoke<Result(*) Signature>::method<(&Class::Method)>::record,   \
              #Result, #Class, #Method, #Signature)
 
 #define LLDB_REGISTER_CHAR_PTR_REDIRECT_STATIC(Result, Class, Method)          \
   R.Register(                                                                  \
-      &invoke<Result (*)(char *, size_t)>::method<(&Class::Method)>::doit,     \
-      &char_ptr_redirect<Result (*)(char *,                                    \
-                                    size_t)>::method<(&Class::Method)>::doit,  \
+      &invoke<Result (*)(char *, size_t)>::method<(&Class::Method)>::record,   \
+      &char_ptr_redirect<Result (*)(char *, size_t)>::method<(                 \
+          &Class::Method)>::record,                                            \
       #Result, #Class, #Method, "(char*, size_t");
 
 #define LLDB_REGISTER_CHAR_PTR_REDIRECT(Result, Class, Method)                 \
   R.Register(&invoke<Result (Class::*)(char *, size_t)>::method<(              \
-                 &Class::Method)>::doit,                                       \
+                 &Class::Method)>::record,                                     \
              &char_ptr_redirect<Result (Class::*)(char *, size_t)>::method<(   \
-                 &Class::Method)>::doit,                                       \
+                 &Class::Method)>::record,                                     \
              #Result, #Class, #Method, "(char*, size_t");
 
 #define LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(Result, Class, Method)           \
   R.Register(&invoke<Result (Class::*)(char *, size_t)                         \
-                         const>::method<(&Class::Method)>::doit,               \
+                         const>::method<(&Class::Method)>::record,             \
              &char_ptr_redirect<Result (Class::*)(char *, size_t)              \
-                                    const>::method<(&Class::Method)>::doit,    \
+                                    const>::method<(&Class::Method)>::record,  \
              #Result, #Class, #Method, "(char*, size_t");
 
-#define LLDB_CONSTRUCT_(T, ...)                                                \
-  lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION,                \
-                                          stringify_args(this, __VA_ARGS__));  \
-  if (lldb_private::repro::InstrumentationData _data =                         \
-          LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
-    _recorder.Record(_data.GetSerializer(), _data.GetRegistry(),               \
-                     &lldb_private::repro::construct<T>::doit, __VA_ARGS__);   \
-    _recorder.RecordResult(this, false);                                       \
-  }
+#define LLDB_CONSTRUCT_(T, Class, ...)                                         \
+  lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION);               \
+  lldb_private::repro::construct<T>::handle(LLDB_GET_INSTRUMENTATION_DATA(),   \
+                                            _recorder, Class, __VA_ARGS__);
 
 #define LLDB_RECORD_CONSTRUCTOR(Class, Signature, ...)                         \
-  LLDB_CONSTRUCT_(Class Signature, __VA_ARGS__)
+  LLDB_CONSTRUCT_(Class Signature, this, __VA_ARGS__)
 
 #define LLDB_RECORD_CONSTRUCTOR_NO_ARGS(Class)                                 \
-  LLDB_CONSTRUCT_(Class(), lldb_private::repro::EmptyArg())
+  LLDB_CONSTRUCT_(Class(), this, lldb_private::repro::EmptyArg())
 
 #define LLDB_RECORD_(T1, T2, ...)                                              \
   lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION,                \
                                           stringify_args(__VA_ARGS__));        \
   if (lldb_private::repro::InstrumentationData _data =                         \
           LLDB_GET_INSTRUMENTATION_DATA()) {                                   \
-    _recorder.Record(_data.GetSerializer(), _data.GetRegistry(),               \
-                     &lldb_private::repro::invoke<T1>::method<T2>::doit,       \
-                     __VA_ARGS__);                                             \
+    if (lldb_private::repro::Serializer *_serializer =                         \
+            _data.GetSerializer()) {                                           \
+      _recorder.Record(*_serializer, _data.GetRegistry(),                      \
+                       &lldb_private::repro::invoke<T1>::method<T2>::record,   \
+                       __VA_ARGS__);                                           \
+    } else if (lldb_private::repro::Deserializer *_deserializer =              \
+                   _data.GetDeserializer()) {                                  \
+      if (_recorder.ShouldCapture()) {                                         \
+        return lldb_private::repro::invoke<T1>::method<T2>::replay(            \
+            _recorder, *_deserializer, _data.GetRegistry());                   \
+      }                                                                        \
+    }                                                                          \
   }
 
 #define LLDB_RECORD_METHOD(Result, Class, Method, Signature, ...)              \
@@ -171,6 +175,7 @@
 #define LLDB_RECORD_DUMMY(Result, Class, Method, Signature, ...)               \
   lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION,                \
                                           stringify_args(__VA_ARGS__));
+
 #define LLDB_RECORD_DUMMY_NO_ARGS(Result, Class, Method)                       \
   lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION);
 
@@ -198,23 +203,26 @@
   /// Returns an object as a pointer for the given index or nullptr if not
   /// present in the map.
   template <typename T> T *GetObjectForIndex(unsigned idx) {
-    assert(idx != 0 && "Cannot get object for sentinel");
+    assert(idx != 0 && "Cannot get object for "
+                       "sentinel");
     void *object = GetObjectForIndexImpl(idx);
     return static_cast<T *>(object);
   }
 
   /// Adds a pointer to an object to the mapping for the given index.
-  template <typename T> void AddObjectForIndex(unsigned idx, T *object) {
+  template <typename T> T *AddObjectForIndex(unsigned idx, T *object) {
     AddObjectForIndexImpl(
         idx, static_cast<void *>(
                  const_cast<typename std::remove_const<T>::type *>(object)));
+    return object;
   }
 
   /// Adds a reference to an object to the mapping for the given index.
-  template <typename T> void AddObjectForIndex(unsigned idx, T &object) {
+  template <typename T> T &AddObjectForIndex(unsigned idx, T &object) {
     AddObjectForIndexImpl(
         idx, static_cast<void *>(
                  const_cast<typename std::remove_const<T>::type *>(&object)));
+    return object;
   }
 
   /// Get all objects sorted by their index.
@@ -285,21 +293,29 @@
     return t;
   }
 
+  template <typename T> const T &HandleReplayResult(const T &t) {
+    unsigned result = Deserialize<unsigned>();
+    if (is_trivially_serializable<T>::value)
+      return t;
+    // We need to make a copy as the original object might go out of scope.
+    return *m_index_to_object.AddObjectForIndex(result, new T(t));
+  }
+
   /// Store the returned value in the index-to-object mapping.
-  template <typename T> void HandleReplayResult(const T &t) {
+  template <typename T> T &HandleReplayResult(T &t) {
     unsigned result = Deserialize<unsigned>();
     if (is_trivially_serializable<T>::value)
-      return;
+      return t;
     // We need to make a copy as the original object might go out of scope.
-    m_index_to_object.AddObjectForIndex(result, new T(t));
+    return *m_index_to_object.AddObjectForIndex(result, new T(t));
   }
 
   /// Store the returned value in the index-to-object mapping.
-  template <typename T> void HandleReplayResult(T *t) {
+  template <typename T> T *HandleReplayResult(T *t) {
     unsigned result = Deserialize<unsigned>();
     if (is_trivially_serializable<T>::value)
-      return;
-    m_index_to_object.AddObjectForIndex(result, t);
+      return t;
+    return m_index_to_object.AddObjectForIndex(result, t);
   }
 
   /// All returned types are recorded, even when the function returns a void.
@@ -411,7 +427,11 @@
   DefaultReplayer(Result (*f)(Args...)) : Replayer(), f(f) {}
 
   void operator()(Deserializer &deserializer) const override {
-    deserializer.HandleReplayResult(
+    Replay(deserializer);
+  }
+
+  Result Replay(Deserializer &deserializer) const {
+    return deserializer.HandleReplayResult(
         DeserializationHelper<Args...>::template deserialized<Result>::doit(
             deserializer, f));
   }
@@ -426,6 +446,10 @@
   DefaultReplayer(void (*f)(Args...)) : Replayer(), f(f) {}
 
   void operator()(Deserializer &deserializer) const override {
+    Replay(deserializer);
+  }
+
+  void Replay(Deserializer &deserializer) const {
     DeserializationHelper<Args...>::template deserialized<void>::doit(
         deserializer, f);
     deserializer.HandleReplayResultVoid();
@@ -487,15 +511,19 @@
   /// Returns the ID for a given function address.
   unsigned GetID(uintptr_t addr);
 
+  /// Get the replayer matching the given ID.
+  Replayer *GetReplayer(unsigned id);
+
+  std::string GetSignature(unsigned id);
+
+  void CheckID(unsigned expected, unsigned actual);
+
 protected:
   /// Register the given replayer for a function (and the ID mapping).
   void DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer,
                   SignatureStr signature);
 
 private:
-  std::string GetSignature(unsigned id);
-  Replayer *GetReplayer(unsigned id);
-
   /// Mapping of function addresses to replayers and their ID.
   std::map<uintptr_t, std::pair<std::unique_ptr<Replayer>, unsigned>>
       m_replayers;
@@ -504,50 +532,6 @@
   std::map<unsigned, std::pair<Replayer *, SignatureStr>> m_ids;
 };
 
-/// To be used as the "Runtime ID" of a constructor. It also invokes the
-/// constructor when called.
-template <typename Signature> struct construct;
-template <typename Class, typename... Args> struct construct<Class(Args...)> {
-  static Class *doit(Args... args) { return new Class(args...); }
-};
-
-/// To be used as the "Runtime ID" of a member function. It also invokes the
-/// member function when called.
-template <typename Signature> struct invoke;
-template <typename Result, typename Class, typename... Args>
-struct invoke<Result (Class::*)(Args...)> {
-  template <Result (Class::*m)(Args...)> struct method {
-    static Result doit(Class *c, Args... args) { return (c->*m)(args...); }
-  };
-};
-
-template <typename Result, typename Class, typename... Args>
-struct invoke<Result (Class::*)(Args...) const> {
-  template <Result (Class::*m)(Args...) const> struct method {
-    static Result doit(Class *c, Args... args) { return (c->*m)(args...); }
-  };
-};
-
-template <typename Result, typename... Args>
-struct invoke<Result (*)(Args...)> {
-  template <Result (*m)(Args...)> struct method {
-    static Result doit(Args... args) { return (*m)(args...); }
-  };
-};
-
-template <typename... Args> struct invoke<void (*)(Args...)> {
-  template <void (*m)(Args...)> struct method {
-    static void doit(Args... args) { return (*m)(args...); }
-  };
-};
-
-template <typename Class, typename... Args>
-struct invoke<void (Class::*)(Args...)> {
-  template <void (Class::*m)(Args...)> struct method {
-    static void doit(Class *c, Args... args) { (c->*m)(args...); }
-  };
-};
-
 /// Maps an object to an index for serialization. Indices are unique and
 /// incremented for every new object.
 ///
@@ -656,21 +640,41 @@
 
   /// Mapping of objects to indices.
   ObjectToIndex m_tracker;
-};
+}; // namespace repro
 
 class InstrumentationData {
 public:
-  InstrumentationData() : m_serializer(nullptr), m_registry(nullptr){};
-  InstrumentationData(Serializer &serializer, Registry &registry)
-      : m_serializer(&serializer), m_registry(&registry){};
-
-  Serializer &GetSerializer() { return *m_serializer; }
+  Serializer *GetSerializer() { return m_serializer; }
+  Deserializer *GetDeserializer() { return m_deserializer; }
   Registry &GetRegistry() { return *m_registry; }
 
-  operator bool() { return m_serializer != nullptr && m_registry != nullptr; }
+  operator bool() {
+    return (m_serializer != nullptr || m_deserializer != nullptr) &&
+           m_registry != nullptr;
+  }
+
+  static void Initialize(Serializer &serializer, Registry &registry);
+  static void Initialize(Deserializer &serializer, Registry &registry);
+  static InstrumentationData &Instance();
+
+protected:
+  friend llvm::optional_detail::OptionalStorage<InstrumentationData, true>;
+  friend llvm::Optional<InstrumentationData>;
+
+  InstrumentationData()
+      : m_serializer(nullptr), m_deserializer(nullptr), m_registry(nullptr) {}
+  InstrumentationData(Serializer &serializer, Registry &registry)
+      : m_serializer(&serializer), m_deserializer(nullptr),
+        m_registry(&registry) {}
+  InstrumentationData(Deserializer &deserializer, Registry &registry)
+      : m_serializer(nullptr), m_deserializer(&deserializer),
+        m_registry(&registry) {}
 
 private:
+  static llvm::Optional<InstrumentationData> &InstanceImpl();
+
   Serializer *m_serializer;
+  Deserializer *m_deserializer;
   Registry *m_registry;
 };
 
@@ -769,14 +773,41 @@
     return std::forward<Result>(r);
   }
 
+  template <typename Result, typename T>
+  Result Replay(Deserializer &deserializer, Registry &registry, uintptr_t addr,
+                bool update_boundary) {
+    unsigned actual_id = registry.GetID(addr);
+    unsigned id = deserializer.Deserialize<unsigned>();
+    registry.CheckID(id, actual_id);
+    return ReplayResult<Result>(
+        static_cast<DefaultReplayer<T> *>(registry.GetReplayer(id))
+            ->Replay(deserializer),
+        update_boundary);
+  }
+
+  void Replay(Deserializer &deserializer, Registry &registry, uintptr_t addr) {
+    unsigned actual_id = registry.GetID(addr);
+    unsigned id = deserializer.Deserialize<unsigned>();
+    registry.CheckID(id, actual_id);
+    registry.GetReplayer(id)->operator()(deserializer);
+  }
+
+  template <typename Result>
+  Result ReplayResult(Result &&r, bool update_boundary) {
+    if (update_boundary)
+      UpdateBoundary();
+    return std::forward<Result>(r);
+  }
+
+  bool ShouldCapture() { return m_local_boundary; }
+
 private:
+  template <typename T> friend struct replay;
   void UpdateBoundary() {
     if (m_local_boundary)
       g_global_boundary = false;
   }
 
-  bool ShouldCapture() { return m_local_boundary; }
-
 #ifdef LLDB_REPRO_INSTR_TRACE
   void Log(unsigned id) {
     llvm::errs() << "Recording " << id << ": " << m_pretty_func << " ("
@@ -800,11 +831,127 @@
   static bool g_global_boundary;
 };
 
+/// To be used as the "Runtime ID" of a constructor. It also invokes the
+/// constructor when called.
+template <typename Signature> struct construct;
+template <typename Class, typename... Args> struct construct<Class(Args...)> {
+  static Class *handle(lldb_private::repro::InstrumentationData data,
+                       lldb_private::repro::Recorder &recorder, Class *c,
+                       const EmptyArg &) {
+    return handle(data, recorder, c);
+  }
+
+  static Class *handle(lldb_private::repro::InstrumentationData data,
+                       lldb_private::repro::Recorder &recorder, Class *c,
+                       Args... args) {
+    if (!data)
+      return nullptr;
+
+    if (Serializer *serializer = data.GetSerializer()) {
+      recorder.Record(*serializer, data.GetRegistry(), &record, args...);
+      recorder.RecordResult(c, false);
+    } else if (Deserializer *deserializer = data.GetDeserializer()) {
+      if (recorder.ShouldCapture()) {
+        replay(recorder, *deserializer, data.GetRegistry());
+      }
+    }
+
+    return nullptr;
+  }
+
+  static Class *record(Args... args) { return new Class(args...); }
+
+  static Class *replay(Recorder &recorder, Deserializer &deserializer,
+                       Registry &registry) {
+    return recorder.Replay<Class *, Class *(Args...)>(
+        deserializer, registry, uintptr_t(&record), false);
+  }
+};
+
+/// To be used as the "Runtime ID" of a member function. It also invokes the
+/// member function when called.
+template <typename Signature> struct invoke;
+template <typename Result, typename Class, typename... Args>
+struct invoke<Result (Class::*)(Args...)> {
+  template <Result (Class::*m)(Args...)> struct method {
+    static Result record(Class *c, Args... args) { return (c->*m)(args...); }
+
+    static Result replay(Recorder &recorder, Deserializer &deserializer,
+                         Registry &registry) {
+      return recorder.Replay<Result, Result(Class *, Args...)>(
+          deserializer, registry, uintptr_t(&record), true);
+    }
+  };
+};
+
+template <typename Class, typename... Args>
+struct invoke<void (Class::*)(Args...)> {
+  template <void (Class::*m)(Args...)> struct method {
+    static void record(Class *c, Args... args) { (c->*m)(args...); }
+    static void replay(Recorder &recorder, Deserializer &deserializer,
+                       Registry &registry) {
+      recorder.Replay(deserializer, registry, uintptr_t(&record));
+    }
+  };
+};
+
+template <typename Result, typename Class, typename... Args>
+struct invoke<Result (Class::*)(Args...) const> {
+  template <Result (Class::*m)(Args...) const> struct method {
+    static Result record(Class *c, Args... args) { return (c->*m)(args...); }
+    static Result replay(Recorder &recorder, Deserializer &deserializer,
+                         Registry &registry) {
+      return recorder.Replay<Result, Result(Class *, Args...)>(
+          deserializer, registry, uintptr_t(&record), true);
+    }
+  };
+};
+
+template <typename Class, typename... Args>
+struct invoke<void (Class::*)(Args...) const> {
+  template <void (Class::*m)(Args...) const> struct method {
+    static void record(Class *c, Args... args) { return (c->*m)(args...); }
+    static void replay(Recorder &recorder, Deserializer &deserializer,
+                       Registry &registry) {
+      recorder.Replay(deserializer, registry, uintptr_t(&record));
+    }
+  };
+};
+
+template <typename Signature> struct replay;
+
+template <typename Result, typename Class, typename... Args>
+struct replay<Result (Class::*)(Args...)> {
+  template <Result (Class::*m)(Args...)> struct method {};
+};
+
+template <typename Result, typename... Args>
+struct invoke<Result (*)(Args...)> {
+  template <Result (*m)(Args...)> struct method {
+    static Result record(Args... args) { return (*m)(args...); }
+    static Result replay(Recorder &recorder, Deserializer &deserializer,
+                         Registry &registry) {
+      return recorder.Replay<Result, Result(Args...)>(deserializer, registry,
+                                                      uintptr_t(&record), true);
+    }
+  };
+};
+
+template <typename... Args> struct invoke<void (*)(Args...)> {
+  template <void (*m)(Args...)> struct method {
+    static void record(Args... args) { return (*m)(args...); }
+    static void replay(Recorder &recorder, Deserializer &deserializer,
+                       Registry &registry) {
+      recorder.Replay(deserializer, registry, uintptr_t(&record));
+    }
+  };
+};
+
 template <typename Signature> struct char_ptr_redirect;
 template <typename Result, typename Class>
 struct char_ptr_redirect<Result (Class::*)(char *, size_t) const> {
   template <Result (Class::*m)(char *, size_t) const> struct method {
-    static Result doit(Class *c, char *s, size_t l) {
+    static Result record(Class *c, char *s, size_t l) {
       char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
       return (c->*m)(buffer, l);
     }
@@ -813,17 +960,16 @@
 template <typename Result, typename Class>
 struct char_ptr_redirect<Result (Class::*)(char *, size_t)> {
   template <Result (Class::*m)(char *, size_t)> struct method {
-    static Result doit(Class *c, char *s, size_t l) {
+    static Result record(Class *c, char *s, size_t l) {
       char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
       return (c->*m)(buffer, l);
     }
   };
 };
-
 template <typename Result>
 struct char_ptr_redirect<Result (*)(char *, size_t)> {
   template <Result (*m)(char *, size_t)> struct method {
-    static Result doit(char *s, size_t l) {
+    static Result record(char *s, size_t l) {
       char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
       return (*m)(buffer, l);
     }
Index: lldb/include/lldb/Utility/Reproducer.h
===================================================================
--- lldb/include/lldb/Utility/Reproducer.h
+++ lldb/include/lldb/Utility/Reproducer.h
@@ -27,6 +27,7 @@
 enum class ReproducerMode {
   Capture,
   Replay,
+  PassiveReplay,
   Off,
 };
 
@@ -287,7 +288,7 @@
 
 class Loader final {
 public:
-  Loader(FileSpec root);
+  Loader(FileSpec root, bool passive = false);
 
   template <typename T> FileSpec GetFile() {
     if (!HasFile(T::file))
@@ -309,12 +310,15 @@
 
   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
@@ -342,7 +346,7 @@
 
 protected:
   llvm::Error SetCapture(llvm::Optional<FileSpec> root);
-  llvm::Error SetReplay(llvm::Optional<FileSpec> root);
+  llvm::Error SetReplay(llvm::Optional<FileSpec> root, bool passive = false);
 
 private:
   static llvm::Optional<Reproducer> &InstanceImpl();
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to