R.Register(&invoke<Result(*) Signature>::method<(&Class::Method)>::record, \
#Result, #Class, #Method, #Signature)
-#define LLDB_REGISTER_CHAR_PTR_REDIRECT_STATIC(Result, Class, Method) \
+#define LLDB_REGISTER_CHAR_PTR_METHOD_STATIC(Result, Class, Method) \
R.Register( \
&invoke<Result (*)(char *, size_t)>::method<(&Class::Method)>::record, \
- &char_ptr_redirect<Result (*)(char *, size_t)>::method<( \
- &Class::Method)>::record, \
+ &invoke_char_ptr<Result (*)(char *, \
+ size_t)>::method<(&Class::Method)>::record, \
#Result, #Class, #Method, "(char*, size_t");
-#define LLDB_REGISTER_CHAR_PTR_REDIRECT(Result, Class, Method) \
+#define LLDB_REGISTER_CHAR_PTR_METHOD(Result, Class, Method) \
R.Register(&invoke<Result (Class::*)(char *, size_t)>::method<( \
&Class::Method)>::record, \
- &char_ptr_redirect<Result (Class::*)(char *, size_t)>::method<( \
+ &invoke_char_ptr<Result (Class::*)(char *, size_t)>::method<( \
&Class::Method)>::record, \
#Result, #Class, #Method, "(char*, size_t");
-#define LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(Result, Class, Method) \
+#define LLDB_REGISTER_CHAR_PTR_METHOD_CONST(Result, Class, Method) \
R.Register(&invoke<Result (Class::*)(char *, size_t) \
const>::method<(&Class::Method)>::record, \
- &char_ptr_redirect<Result (Class::*)(char *, size_t) \
- const>::method<(&Class::Method)>::record, \
+ &invoke_char_ptr<Result (Class::*)(char *, size_t) \
+ const>::method<(&Class::Method)>::record, \
#Result, #Class, #Method, "(char*, size_t");
#define LLDB_CONSTRUCT_(T, Class, ...) \
#define LLDB_RECORD_STATIC_METHOD_NO_ARGS(Result, Class, Method) \
LLDB_RECORD_(Result (*)(), (&Class::Method), lldb_private::repro::EmptyArg())
+#define LLDB_RECORD_CHAR_PTR_(T1, T2, StrOut, ...) \
+ lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION, \
+ stringify_args(__VA_ARGS__)); \
+ if (lldb_private::repro::InstrumentationData _data = \
+ LLDB_GET_INSTRUMENTATION_DATA()) { \
+ 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_char_ptr<T1>::method<T2>::replay( \
+ _recorder, *_deserializer, _data.GetRegistry(), StrOut); \
+ } \
+ } \
+ }
+
+#define LLDB_RECORD_CHAR_PTR_METHOD(Result, Class, Method, Signature, StrOut, \
+ ...) \
+ LLDB_RECORD_CHAR_PTR_(Result(Class::*) Signature, (&Class::Method), StrOut, \
+ this, __VA_ARGS__)
+
+#define LLDB_RECORD_CHAR_PTR_METHOD_CONST(Result, Class, Method, Signature, \
+ StrOut, ...) \
+ LLDB_RECORD_CHAR_PTR_(Result(Class::*) Signature const, (&Class::Method), \
+ StrOut, this, __VA_ARGS__)
+
+#define LLDB_RECORD_CHAR_PTR_STATIC_METHOD(Result, Class, Method, Signature, \
+ StrOut, ...) \
+ LLDB_RECORD_CHAR_PTR_(Result(*) Signature, (&Class::Method), StrOut, \
+ __VA_ARGS__)
+
#define LLDB_RECORD_RESULT(Result) _recorder.RecordResult(Result, true);
/// The LLDB_RECORD_DUMMY macro is special because it doesn't actually 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 {
+/// Special handling for functions returning strings as (char*, size_t).
+/// {
+
+/// For inline replay, we ignore the arguments and use the ones from the
+/// serializer instead. This doesn't work for methods that use a char* and a
+/// size to return a string. For one these functions have a custom replayer to
+/// prevent override the input buffer. Furthermore, the template-generated
+/// deserialization is not easy to hook into.
+///
+/// The specializations below hand-implement the serialization logic for the
+/// inline replay. Instead of using the function from the registry, it uses the
+/// one passed into the macro.
+template <typename Signature> struct invoke_char_ptr;
+template <typename Result, typename Class, typename... Args>
+struct invoke_char_ptr<Result (Class::*)(Args...) const> {
+ template <Result (Class::*m)(Args...) const> struct method {
static Result record(Class *c, char *s, size_t l) {
char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
return (c->*m)(buffer, l);
}
+
+ static Result replay(Recorder &recorder, Deserializer &deserializer,
+ Registry ®istry, char *str) {
+ deserializer.Deserialize<unsigned>();
+ Class *c = deserializer.Deserialize<Class *>();
+ deserializer.Deserialize<const char *>();
+ size_t l = deserializer.Deserialize<size_t>();
+ return recorder.ReplayResult(
+ std::move(deserializer.HandleReplayResult((c->*m)(str, l))), true);
+ }
};
};
-template <typename Result, typename Class>
-struct char_ptr_redirect<Result (Class::*)(char *, size_t)> {
- template <Result (Class::*m)(char *, size_t)> struct method {
+
+template <typename Signature> struct invoke_char_ptr;
+template <typename Result, typename Class, typename... Args>
+struct invoke_char_ptr<Result (Class::*)(Args...)> {
+ template <Result (Class::*m)(Args...)> struct method {
static Result record(Class *c, char *s, size_t l) {
char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
return (c->*m)(buffer, l);
}
+
+ static Result replay(Recorder &recorder, Deserializer &deserializer,
+ Registry ®istry, char *str) {
+ deserializer.Deserialize<unsigned>();
+ Class *c = deserializer.Deserialize<Class *>();
+ deserializer.Deserialize<const char *>();
+ size_t l = deserializer.Deserialize<size_t>();
+ return recorder.ReplayResult(
+ std::move(deserializer.HandleReplayResult((c->*m)(str, l))), true);
+ }
};
};
-template <typename Result>
-struct char_ptr_redirect<Result (*)(char *, size_t)> {
- template <Result (*m)(char *, size_t)> struct method {
+
+template <typename Result, typename... Args>
+struct invoke_char_ptr<Result (*)(Args...)> {
+ template <Result (*m)(Args...)> struct method {
static Result record(char *s, size_t l) {
char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
return (*m)(buffer, l);
}
+
+ static Result replay(Recorder &recorder, Deserializer &deserializer,
+ Registry ®istry, char *str) {
+ deserializer.Deserialize<unsigned>();
+ deserializer.Deserialize<const char *>();
+ size_t l = deserializer.Deserialize<size_t>();
+ return recorder.ReplayResult(
+ std::move(deserializer.HandleReplayResult((*m)(str, l))), true);
+ }
};
};
+/// }
} // namespace repro
} // namespace lldb_private
}
bool SBDebugger::GetDefaultArchitecture(char *arch_name, size_t arch_name_len) {
- LLDB_RECORD_STATIC_METHOD(bool, SBDebugger, GetDefaultArchitecture,
- (char *, size_t), "", arch_name_len);
+ LLDB_RECORD_CHAR_PTR_STATIC_METHOD(bool, SBDebugger, GetDefaultArchitecture,
+ (char *, size_t), arch_name, "",
+ arch_name_len);
if (arch_name && arch_name_len) {
ArchSpec default_arch = Target::GetDefaultArchitecture();
FileSP)>::method<&SBDebugger::SetErrorFile>::record,
&SetFileRedirect);
- LLDB_REGISTER_CHAR_PTR_REDIRECT_STATIC(bool, SBDebugger,
- GetDefaultArchitecture);
+ LLDB_REGISTER_CHAR_PTR_METHOD_STATIC(bool, SBDebugger,
+ GetDefaultArchitecture);
LLDB_REGISTER_CONSTRUCTOR(SBDebugger, ());
LLDB_REGISTER_CONSTRUCTOR(SBDebugger, (const lldb::DebuggerSP &));
}
uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const {
- LLDB_RECORD_METHOD_CONST(uint32_t, SBFileSpec, GetPath, (char *, size_t), "",
- dst_len);
+ LLDB_RECORD_CHAR_PTR_METHOD_CONST(uint32_t, SBFileSpec, GetPath,
+ (char *, size_t), dst_path, "", dst_len);
uint32_t result = m_opaque_up->GetPath(dst_path, dst_len);
LLDB_REGISTER_METHOD_CONST(bool, SBFileSpec, GetDescription,
(lldb::SBStream &));
LLDB_REGISTER_METHOD(void, SBFileSpec, AppendPathComponent, (const char *));
- LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(uint32_t, SBFileSpec, GetPath);
+ LLDB_REGISTER_CHAR_PTR_METHOD_CONST(uint32_t, SBFileSpec, GetPath);
}
}
}
size_t SBProcess::GetSTDOUT(char *dst, size_t dst_len) const {
- LLDB_RECORD_METHOD_CONST(size_t, SBProcess, GetSTDOUT, (char *, size_t), "",
- dst_len);
+ LLDB_RECORD_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDOUT,
+ (char *, size_t), dst, "", dst_len);
size_t bytes_read = 0;
ProcessSP process_sp(GetSP());
}
size_t SBProcess::GetSTDERR(char *dst, size_t dst_len) const {
- LLDB_RECORD_METHOD_CONST(size_t, SBProcess, GetSTDERR, (char *, size_t), "",
- dst_len);
+ LLDB_RECORD_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDERR,
+ (char *, size_t), dst, "", dst_len);
size_t bytes_read = 0;
ProcessSP process_sp(GetSP());
}
size_t SBProcess::GetAsyncProfileData(char *dst, size_t dst_len) const {
- LLDB_RECORD_METHOD_CONST(size_t, SBProcess, GetAsyncProfileData,
- (char *, size_t), "", dst_len);
+ LLDB_RECORD_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetAsyncProfileData,
+ (char *, size_t), dst, "", dst_len);
size_t bytes_read = 0;
ProcessSP process_sp(GetSP());
GetMemoryRegions, ());
LLDB_REGISTER_METHOD(lldb::SBProcessInfo, SBProcess, GetProcessInfo, ());
- LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(size_t, SBProcess, GetSTDOUT);
- LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(size_t, SBProcess, GetSTDERR);
- LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(size_t, SBProcess, GetAsyncProfileData);
+ LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDOUT);
+ LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDERR);
+ LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetAsyncProfileData);
}
}
}
size_t SBStructuredData::GetStringValue(char *dst, size_t dst_len) const {
- LLDB_RECORD_METHOD_CONST(size_t, SBStructuredData, GetStringValue,
- (char *, size_t), "", dst_len);
+ LLDB_RECORD_CHAR_PTR_METHOD_CONST(size_t, SBStructuredData, GetStringValue,
+ (char *, size_t), dst, "", dst_len);
return (m_impl_up ? m_impl_up->GetStringValue(dst, dst_len) : 0);
}
(uint64_t));
LLDB_REGISTER_METHOD_CONST(double, SBStructuredData, GetFloatValue, (double));
LLDB_REGISTER_METHOD_CONST(bool, SBStructuredData, GetBooleanValue, (bool));
- LLDB_REGISTER_CHAR_PTR_REDIRECT_CONST(size_t, SBStructuredData,
- GetStringValue);
+ LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBStructuredData, GetStringValue);
}
} // namespace repro
}
size_t SBThread::GetStopDescription(char *dst, size_t dst_len) {
- LLDB_RECORD_METHOD(size_t, SBThread, GetStopDescription, (char *, size_t), "",
- dst_len);
+ LLDB_RECORD_CHAR_PTR_METHOD(size_t, SBThread, GetStopDescription,
+ (char *, size_t), dst, "", dst_len);
std::unique_lock<std::recursive_mutex> lock;
ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
LLDB_REGISTER_METHOD(lldb::SBThread, SBThread, GetCurrentExceptionBacktrace,
());
LLDB_REGISTER_METHOD(bool, SBThread, SafeToCallFunctions, ());
- LLDB_REGISTER_CHAR_PTR_REDIRECT(size_t, SBThread, GetStopDescription);
+ LLDB_REGISTER_CHAR_PTR_METHOD(size_t, SBThread, GetStopDescription);
}
}
int C(float *c);
float GetC();
int D(const char *d) const;
- void GetD(char *buffer, size_t length);
+ size_t GetD(char *buffer, size_t length);
static void E(double e);
double GetE();
static int F();
return 2;
}
-void InstrumentedFoo::GetD(char *buffer, size_t length) {
- LLDB_RECORD_METHOD(void, InstrumentedFoo, GetD, (char *, size_t), buffer,
- length);
+size_t InstrumentedFoo::GetD(char *buffer, size_t length) {
+ LLDB_RECORD_CHAR_PTR_METHOD(size_t, InstrumentedFoo, GetD, (char *, size_t),
+ buffer, "", length);
::snprintf(buffer, length, "%s", m_d.c_str());
+ return m_d.size();
}
void InstrumentedFoo::E(double e) {
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(size_t, InstrumentedFoo, GetD, (char *, size_t));
LLDB_REGISTER_METHOD(double, InstrumentedFoo, GetE, ());
LLDB_REGISTER_METHOD(bool, InstrumentedFoo, GetF, ());
}
EXPECT_EQ(foo.GetA(), 100);
EXPECT_EQ(foo.GetB(), 200);
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+ char buffer[100];
+ foo.GetD(buffer, 100);
+ EXPECT_STREQ(buffer, "bar");
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
EXPECT_EQ(foo.GetF(), true);
}
EXPECT_EQ(foo.GetA(), 100);
EXPECT_EQ(foo.GetB(), 200);
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+ char buffer[100];
+ foo.GetD(buffer, 100);
+ EXPECT_STREQ(buffer, "bar");
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
EXPECT_EQ(foo.GetF(), true);
}
EXPECT_EQ(foo.GetA(), 100);
EXPECT_EQ(foo.GetB(), 200);
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+ char buffer[100];
+ foo.GetD(buffer, 100);
+ EXPECT_STREQ(buffer, "bar");
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
EXPECT_EQ(foo.GetF(), true);
EXPECT_EQ(foo.GetA(), 100);
EXPECT_EQ(foo.GetB(), 200);
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+ char buffer[100];
+ foo.GetD(buffer, 100);
+ EXPECT_STREQ(buffer, "bar");
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
EXPECT_EQ(foo.GetF(), true);
EXPECT_EQ(foo.GetA(), 100);
EXPECT_EQ(foo.GetB(), 200);
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+ char buffer[100];
+ foo.GetD(buffer, 100);
+ EXPECT_STREQ(buffer, "bar");
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
EXPECT_EQ(foo.GetF(), true);
EXPECT_EQ(foo.GetA(), 100);
EXPECT_EQ(foo.GetB(), 200);
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+ char buffer[100];
+ foo.GetD(buffer, 100);
+ EXPECT_STREQ(buffer, "bar");
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
EXPECT_EQ(foo.GetF(), true);
EXPECT_EQ(foo.GetA(), 100);
EXPECT_EQ(foo.GetB(), 200);
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+ char buffer[100];
+ foo.GetD(buffer, 100);
+ EXPECT_STREQ(buffer, "bar");
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
EXPECT_EQ(foo.GetF(), true);
EXPECT_EQ(foo.GetA(), 100);
EXPECT_EQ(foo.GetB(), 200);
EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
+ char buffer[100];
+ foo.GetD(buffer, 100);
+ EXPECT_STREQ(buffer, "bar");
EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
EXPECT_EQ(foo.GetF(), true);