// #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, ...) \
#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);
}
/// 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.
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.
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));
}
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();
/// 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;
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.
///
/// Mapping of objects to indices.
ObjectToIndex m_tracker;
-};
+}; // namespace repro
class InstrumentationData {
public:
- InstrumentationData() : m_serializer(nullptr), m_registry(nullptr){};
- InstrumentationData(Serializer &serializer, Registry ®istry)
- : m_serializer(&serializer), m_registry(®istry){};
-
- 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 ®istry);
+ static void Initialize(Deserializer &serializer, Registry ®istry);
+ 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 ®istry)
+ : m_serializer(&serializer), m_deserializer(nullptr),
+ m_registry(®istry) {}
+ InstrumentationData(Deserializer &deserializer, Registry ®istry)
+ : m_serializer(nullptr), m_deserializer(&deserializer),
+ m_registry(®istry) {}
private:
+ static llvm::Optional<InstrumentationData> &InstanceImpl();
+
Serializer *m_serializer;
+ Deserializer *m_deserializer;
Registry *m_registry;
};
return std::forward<Result>(r);
}
+ template <typename Result, typename T>
+ Result Replay(Deserializer &deserializer, Registry ®istry, 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 ®istry, 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 << " ("
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 ®istry) {
+ 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 ®istry) {
+ 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 ®istry) {
+ 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 ®istry) {
+ 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 ®istry) {
+ 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 ®istry) {
+ 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 ®istry) {
+ 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);
}
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);
}
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 ®istry)
+ : InstrumentationData(serializer, registry) {}
+ TestInstrumentationData(Deserializer &deserializer, Registry ®istry)
+ : 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);
}
};
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; }
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);
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;
llvm::raw_string_ostream os(str);
{
- TestInstrumentationDataRAII data(os);
+ auto data = TestInstrumentationDataRAII::GetRecordingData(os);
int b = 200;
float c = 300.3f;
llvm::raw_string_ostream os(str);
{
- TestInstrumentationDataRAII data(os);
+ auto data = TestInstrumentationDataRAII::GetRecordingData(os);
int b = 200;
float c = 300.3f;
llvm::raw_string_ostream os(str);
{
- TestInstrumentationDataRAII data(os);
+ auto data = TestInstrumentationDataRAII::GetRecordingData(os);
InstrumentedBar bar;
InstrumentedFoo foo = bar.GetInstrumentedFoo();
llvm::raw_string_ostream os(str);
{
- TestInstrumentationDataRAII data(os);
+ auto data = TestInstrumentationDataRAII::GetRecordingData(os);
InstrumentedBar bar;
InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
llvm::raw_string_ostream os(str);
{
- TestInstrumentationDataRAII data(os);
+ auto data = TestInstrumentationDataRAII::GetRecordingData(os);
InstrumentedBar bar;
InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
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();
+ }
+}