diff --git a/lldb/include/lldb/Utility/ReproducerInstrumentation.h b/lldb/include/lldb/Utility/ReproducerInstrumentation.h --- a/lldb/include/lldb/Utility/ReproducerInstrumentation.h +++ b/lldb/include/lldb/Utility/ReproducerInstrumentation.h @@ -97,25 +97,25 @@ R.Register(&invoke::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::method<(&Class::Method)>::record, \ - &char_ptr_redirect::method<( \ - &Class::Method)>::record, \ + &invoke_char_ptr::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::method<( \ &Class::Method)>::record, \ - &char_ptr_redirect::method<( \ + &invoke_char_ptr::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::method<(&Class::Method)>::record, \ - &char_ptr_redirect::method<(&Class::Method)>::record, \ + &invoke_char_ptr::method<(&Class::Method)>::record, \ #Result, #Class, #Method, "(char*, size_t"); #define LLDB_CONSTRUCT_(T, Class, ...) \ @@ -167,6 +167,40 @@ #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::method<(T2)>::record, \ + __VA_ARGS__); \ + } else if (lldb_private::repro::Deserializer *_deserializer = \ + _data.GetDeserializer()) { \ + if (_recorder.ShouldCapture()) { \ + return lldb_private::repro::invoke_char_ptr::method::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 @@ -946,34 +980,79 @@ }; }; -template struct char_ptr_redirect; -template -struct char_ptr_redirect { - template 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 struct invoke_char_ptr; +template +struct invoke_char_ptr { + template struct method { static Result record(Class *c, char *s, size_t l) { char *buffer = reinterpret_cast(calloc(l, sizeof(char))); return (c->*m)(buffer, l); } + + static Result replay(Recorder &recorder, Deserializer &deserializer, + Registry ®istry, char *str) { + deserializer.Deserialize(); + Class *c = deserializer.Deserialize(); + deserializer.Deserialize(); + size_t l = deserializer.Deserialize(); + return recorder.ReplayResult( + std::move(deserializer.HandleReplayResult((c->*m)(str, l))), true); + } }; }; -template -struct char_ptr_redirect { - template struct method { + +template struct invoke_char_ptr; +template +struct invoke_char_ptr { + template struct method { static Result record(Class *c, char *s, size_t l) { char *buffer = reinterpret_cast(calloc(l, sizeof(char))); return (c->*m)(buffer, l); } + + static Result replay(Recorder &recorder, Deserializer &deserializer, + Registry ®istry, char *str) { + deserializer.Deserialize(); + Class *c = deserializer.Deserialize(); + deserializer.Deserialize(); + size_t l = deserializer.Deserialize(); + return recorder.ReplayResult( + std::move(deserializer.HandleReplayResult((c->*m)(str, l))), true); + } }; }; -template -struct char_ptr_redirect { - template struct method { + +template +struct invoke_char_ptr { + template struct method { static Result record(char *s, size_t l) { char *buffer = reinterpret_cast(calloc(l, sizeof(char))); return (*m)(buffer, l); } + + static Result replay(Recorder &recorder, Deserializer &deserializer, + Registry ®istry, char *str) { + deserializer.Deserialize(); + deserializer.Deserialize(); + size_t l = deserializer.Deserialize(); + return recorder.ReplayResult( + std::move(deserializer.HandleReplayResult((*m)(str, l))), true); + } }; }; +/// } } // namespace repro } // namespace lldb_private diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -596,8 +596,9 @@ } 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(); @@ -1668,8 +1669,8 @@ 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 &)); diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp --- a/lldb/source/API/SBFileSpec.cpp +++ b/lldb/source/API/SBFileSpec.cpp @@ -143,8 +143,8 @@ } 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); @@ -216,7 +216,7 @@ 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); } } diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp --- a/lldb/source/API/SBProcess.cpp +++ b/lldb/source/API/SBProcess.cpp @@ -271,8 +271,8 @@ } 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()); @@ -285,8 +285,8 @@ } 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()); @@ -299,8 +299,8 @@ } 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()); @@ -1440,9 +1440,9 @@ 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); } } diff --git a/lldb/source/API/SBStructuredData.cpp b/lldb/source/API/SBStructuredData.cpp --- a/lldb/source/API/SBStructuredData.cpp +++ b/lldb/source/API/SBStructuredData.cpp @@ -196,8 +196,8 @@ } 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); } @@ -236,8 +236,7 @@ (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 diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -312,8 +312,8 @@ } 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 lock; ExecutionContext exe_ctx(m_opaque_sp.get(), lock); @@ -1448,7 +1448,7 @@ 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); } } diff --git a/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp b/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp --- a/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp +++ b/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp @@ -134,7 +134,7 @@ 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(); @@ -257,10 +257,11 @@ 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) { @@ -374,7 +375,7 @@ 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, ()); } @@ -814,6 +815,9 @@ 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); } @@ -839,6 +843,9 @@ 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); } @@ -920,6 +927,9 @@ 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); @@ -951,6 +961,9 @@ 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); @@ -985,6 +998,9 @@ 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); @@ -1016,6 +1032,9 @@ 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); @@ -1050,6 +1069,9 @@ 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); @@ -1081,6 +1103,9 @@ 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);