Index: lldb/include/lldb/Utility/ReproducerInstrumentation.h =================================================================== --- lldb/include/lldb/Utility/ReproducerInstrumentation.h +++ lldb/include/lldb/Utility/ReproducerInstrumentation.h @@ -268,6 +268,78 @@ } \ } +#define LLDB_RECORD_CHAR_PTR_METHOD(Result, Class, Method, Signature, StrOut, \ + ...) \ + lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION, \ + stringify_args(*this, __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<( \ + &Class::Method)>::record, \ + this, __VA_ARGS__); \ + } else if (lldb_private::repro::Deserializer *_deserializer = \ + _data.GetDeserializer()) { \ + if (_recorder.ShouldCapture()) { \ + return lldb_private::repro::invoke_char_ptr::method<&Class::Method>:: \ + replay(_recorder, *_deserializer, _data.GetRegistry(), \ + LLVM_PRETTY_FUNCTION, StrOut); \ + } \ + } \ + } + +#define LLDB_RECORD_CHAR_PTR_METHOD_CONST(Result, Class, Method, Signature, \ + StrOut, ...) \ + lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION, \ + stringify_args(*this, __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_const<(&Class::Method)>::record, \ + this, __VA_ARGS__); \ + } else if (lldb_private::repro::Deserializer *_deserializer = \ + _data.GetDeserializer()) { \ + if (_recorder.ShouldCapture()) { \ + return lldb_private::repro::invoke_char_ptr::method_const<&Class::Method>:: \ + replay(_recorder, *_deserializer, _data.GetRegistry(), \ + LLVM_PRETTY_FUNCTION, StrOut); \ + } \ + } \ + } + +#define LLDB_RECORD_CHAR_PTR_STATIC_METHOD(Result, Class, Method, Signature, \ + 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_static<( \ + &Class::Method)>::record, \ + __VA_ARGS__); \ + } else if (lldb_private::repro::Deserializer *_deserializer = \ + _data.GetDeserializer()) { \ + if (_recorder.ShouldCapture()) { \ + return lldb_private::repro::invoke_char_ptr:: \ + method_static<(&Class::Method)>::replay( \ + _recorder, *_deserializer, _data.GetRegistry(), \ + LLVM_PRETTY_FUNCTION, StrOut); \ + } \ + } \ + } + #define LLDB_RECORD_RESULT(Result) _recorder.RecordResult(Result, true); /// The LLDB_RECORD_DUMMY macro is special because it doesn't actually record @@ -1028,6 +1100,68 @@ }; }; +/// 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_const { + static Result replay(Recorder &recorder, Deserializer &deserializer, + Registry ®istry, llvm::StringRef signature, + 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 invoke_char_ptr; +template +struct invoke_char_ptr { + template struct method { + static Result replay(Recorder &recorder, Deserializer &deserializer, + Registry ®istry, llvm::StringRef signature, + 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 invoke_char_ptr { + template struct method_static { + static Result replay(Recorder &recorder, Deserializer &deserializer, + Registry ®istry, llvm::StringRef signature, + char *str) { + deserializer.Deserialize(); + deserializer.Deserialize(); + size_t l = deserializer.Deserialize(); + return recorder.ReplayResult( + std::move(deserializer.HandleReplayResult((*m)(str, l))), + true); + } + }; +}; + template struct char_ptr_redirect; template struct char_ptr_redirect { @@ -1057,6 +1191,8 @@ }; }; +/// } + } // namespace repro } // namespace lldb_private Index: lldb/source/API/SBDebugger.cpp =================================================================== --- lldb/source/API/SBDebugger.cpp +++ 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(); Index: lldb/source/API/SBFileSpec.cpp =================================================================== --- lldb/source/API/SBFileSpec.cpp +++ 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); Index: lldb/source/API/SBProcess.cpp =================================================================== --- lldb/source/API/SBProcess.cpp +++ 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()); Index: lldb/source/API/SBStructuredData.cpp =================================================================== --- lldb/source/API/SBStructuredData.cpp +++ 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); } Index: lldb/source/API/SBThread.cpp =================================================================== --- lldb/source/API/SBThread.cpp +++ 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); Index: lldb/unittests/Utility/ReproducerInstrumentationTest.cpp =================================================================== --- lldb/unittests/Utility/ReproducerInstrumentationTest.cpp +++ lldb/unittests/Utility/ReproducerInstrumentationTest.cpp @@ -125,7 +125,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(); @@ -248,10 +248,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) { @@ -365,7 +366,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, ()); } @@ -811,6 +812,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); } @@ -837,6 +841,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); } @@ -868,6 +875,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); @@ -900,6 +910,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); @@ -935,6 +948,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); @@ -967,6 +983,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); @@ -1002,6 +1021,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); @@ -1034,6 +1056,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);