Index: include/lldb/Utility/ReproducerInstrumentation.h =================================================================== --- include/lldb/Utility/ReproducerInstrumentation.h +++ include/lldb/Utility/ReproducerInstrumentation.h @@ -22,43 +22,44 @@ template ::value, int>::type = 0> -inline void log_append(llvm::raw_string_ostream &ss, const T &t) { +inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) { ss << t; } template ::value, int>::type = 0> -inline void log_append(llvm::raw_string_ostream &ss, const T &t) { +inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) { ss << &t; } template -inline void log_append(llvm::raw_string_ostream &ss, const T *t) { +inline void stringify_append(llvm::raw_string_ostream &ss, const T *t) { ss << reinterpret_cast(t); } template <> -inline void log_append(llvm::raw_string_ostream &ss, const char *t) { +inline void stringify_append(llvm::raw_string_ostream &ss, + const char *t) { ss << t; } template -inline void log_helper(llvm::raw_string_ostream &ss, const Head &head) { - log_append(ss, head); +inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head) { + stringify_append(ss, head); } template -inline void log_helper(llvm::raw_string_ostream &ss, const Head &head, - const Tail &... tail) { - log_append(ss, head); +inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head, + const Tail &... tail) { + stringify_append(ss, head); ss << ", "; - log_helper(ss, tail...); + stringify_helper(ss, tail...); } -template inline std::string log_args(const Ts &... ts) { +template inline std::string stringify_args(const Ts &... ts) { std::string buffer; llvm::raw_string_ostream ss(buffer); - log_helper(ss, ts...); + stringify_helper(ss, ts...); return ss.str(); } @@ -69,131 +70,111 @@ #define LLDB_REGISTER_CONSTRUCTOR(Class, Signature) \ R.Register(&construct::doit, "", #Class, \ - #Class, #Signature) + #Class, #Signature) #define LLDB_REGISTER_METHOD(Result, Class, Method, Signature) \ R.Register( \ &invoke::method<(&Class::Method)>::doit, \ #Result, #Class, #Method, #Signature) #define LLDB_REGISTER_METHOD_CONST(Result, Class, Method, Signature) \ - R.Register(&invoke::method_const<(&Class::Method)>::doit, \ - #Result, #Class, #Method, #Signature) + R.Register(&invoke::method_const<( \ + &Class::Method)>::doit, \ + #Result, #Class, #Method, #Signature) #define LLDB_REGISTER_STATIC_METHOD(Result, Class, Method, Signature) \ R.Register( \ static_cast(&Class::Method), #Result, #Class, \ #Method, #Signature) #define LLDB_RECORD_CONSTRUCTOR(Class, Signature, ...) \ - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})", \ - LLVM_PRETTY_FUNCTION, log_args(__VA_ARGS__)); \ + lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION, \ + stringify_args(__VA_ARGS__)); \ if (lldb_private::repro::InstrumentationData data = \ LLDB_GET_INSTRUMENTATION_DATA()) { \ - lldb_private::repro::Recorder sb_recorder( \ - data.GetSerializer(), data.GetRegistry(), LLVM_PRETTY_FUNCTION); \ - sb_recorder.Record(&lldb_private::repro::construct::doit, \ + sb_recorder.Record(data.GetSerializer(), data.GetRegistry(), \ + &lldb_private::repro::construct::doit, \ __VA_ARGS__); \ sb_recorder.RecordResult(this); \ } #define LLDB_RECORD_CONSTRUCTOR_NO_ARGS(Class) \ - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0}", \ - LLVM_PRETTY_FUNCTION); \ + lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION); \ if (lldb_private::repro::InstrumentationData data = \ LLDB_GET_INSTRUMENTATION_DATA()) { \ - lldb_private::repro::Recorder sb_recorder( \ - data.GetSerializer(), data.GetRegistry(), LLVM_PRETTY_FUNCTION); \ - sb_recorder.Record(&lldb_private::repro::construct::doit); \ + sb_recorder.Record(data.GetSerializer(), data.GetRegistry(), \ + &lldb_private::repro::construct::doit); \ sb_recorder.RecordResult(this); \ } #define LLDB_RECORD_METHOD(Result, Class, Method, Signature, ...) \ - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})", \ - LLVM_PRETTY_FUNCTION, log_args(__VA_ARGS__)); \ - llvm::Optional sb_recorder; \ + lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION, \ + stringify_args(__VA_ARGS__)); \ if (lldb_private::repro::InstrumentationData data = \ LLDB_GET_INSTRUMENTATION_DATA()) { \ - sb_recorder.emplace(data.GetSerializer(), data.GetRegistry(), \ - LLVM_PRETTY_FUNCTION); \ - sb_recorder->Record( \ + sb_recorder.Record( \ + data.GetSerializer(), data.GetRegistry(), \ &lldb_private::repro::invoke::method<( \ &Class::Method)>::doit, \ this, __VA_ARGS__); \ } #define LLDB_RECORD_METHOD_CONST(Result, Class, Method, Signature, ...) \ - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})", \ - LLVM_PRETTY_FUNCTION, log_args(__VA_ARGS__)); \ - llvm::Optional sb_recorder; \ + lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION, \ + stringify_args(__VA_ARGS__)); \ if (lldb_private::repro::InstrumentationData data = \ LLDB_GET_INSTRUMENTATION_DATA()) { \ - sb_recorder.emplace(data.GetSerializer(), data.GetRegistry(), \ - LLVM_PRETTY_FUNCTION); \ - sb_recorder->Record( \ + sb_recorder.Record( \ + data.GetSerializer(), data.GetRegistry(), \ &lldb_private::repro::invoke::method_const<(&Class::Method)>::doit, \ this, __VA_ARGS__); \ } #define LLDB_RECORD_METHOD_NO_ARGS(Result, Class, Method) \ - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0}", \ - LLVM_PRETTY_FUNCTION); \ - llvm::Optional sb_recorder; \ + lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION); \ if (lldb_private::repro::InstrumentationData data = \ LLDB_GET_INSTRUMENTATION_DATA()) { \ - sb_recorder.emplace(data.GetSerializer(), data.GetRegistry(), \ - LLVM_PRETTY_FUNCTION); \ - sb_recorder->Record(&lldb_private::repro::invoke::method<(&Class::Method)>::doit, \ - this); \ + sb_recorder.Record(data.GetSerializer(), data.GetRegistry(), \ + &lldb_private::repro::invoke::method<(&Class::Method)>::doit, \ + this); \ } #define LLDB_RECORD_METHOD_CONST_NO_ARGS(Result, Class, Method) \ - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0}", \ - LLVM_PRETTY_FUNCTION); \ - llvm::Optional sb_recorder; \ + lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION); \ if (lldb_private::repro::InstrumentationData data = \ LLDB_GET_INSTRUMENTATION_DATA()) { \ - sb_recorder.emplace(data.GetSerializer(), data.GetRegistry(), \ - LLVM_PRETTY_FUNCTION); \ - sb_recorder->Record( \ + sb_recorder.Record( \ + data.GetSerializer(), data.GetRegistry(), \ &lldb_private::repro::invoke::method_const<(&Class::Method)>::doit, \ this); \ } #define LLDB_RECORD_STATIC_METHOD(Result, Class, Method, Signature, ...) \ - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})", \ - LLVM_PRETTY_FUNCTION, log_args(__VA_ARGS__)); \ - llvm::Optional sb_recorder; \ + lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION, \ + stringify_args(__VA_ARGS__)); \ if (lldb_private::repro::InstrumentationData data = \ LLDB_GET_INSTRUMENTATION_DATA()) { \ - sb_recorder.emplace(data.GetSerializer(), data.GetRegistry(), \ - LLVM_PRETTY_FUNCTION); \ - sb_recorder->Record(static_cast(&Class::Method), \ - __VA_ARGS__); \ + sb_recorder.Record(data.GetSerializer(), data.GetRegistry(), \ + static_cast(&Class::Method), \ + __VA_ARGS__); \ } #define LLDB_RECORD_STATIC_METHOD_NO_ARGS(Result, Class, Method) \ - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0}", \ - LLVM_PRETTY_FUNCTION); \ - llvm::Optional sb_recorder; \ + lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION); \ if (lldb_private::repro::InstrumentationData data = \ LLDB_GET_INSTRUMENTATION_DATA()) { \ - sb_recorder.emplace(data.GetSerializer(), data.GetRegistry(), \ - LLVM_PRETTY_FUNCTION); \ - sb_recorder->Record(static_cast(&Class::Method)); \ + sb_recorder.Record(data.GetSerializer(), data.GetRegistry(), \ + static_cast(&Class::Method)); \ } -#define LLDB_RECORD_RESULT(Result) \ - sb_recorder ? sb_recorder->RecordResult(Result) : (Result); +#define LLDB_RECORD_RESULT(Result) sb_recorder.RecordResult(Result); /// The LLDB_RECORD_DUMMY macro is special because it doesn't actually record /// anything. It's used to track API boundaries when we cannot record for /// technical reasons. #define LLDB_RECORD_DUMMY(Result, Class, Method, Signature, ...) \ - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})", \ - LLVM_PRETTY_FUNCTION, log_args(__VA_ARGS__)); \ - llvm::Optional sb_recorder; + lldb_private::repro::Recorder sb_recorder(LLVM_PRETTY_FUNCTION, \ + stringify_args(__VA_ARGS__)); namespace lldb_private { namespace repro { @@ -621,7 +602,7 @@ Registry *m_registry; }; -/// RAII object that tracks the function invocations and their return value. +/// RAII object that records function invocations and their return value. /// /// API calls are only captured when the API boundary is crossed. Once we're in /// the API layer, and another API function is called, it doesn't need to be @@ -630,56 +611,68 @@ /// When a call is recored, its result is always recorded as well, even if the /// function returns a void. For functions that return by value, RecordResult /// should be used. Otherwise a sentinel value (0) will be serialized. +/// +/// Because of the functional overlap between logging and recording API calls, +/// this class is also used for logging. class Recorder { public: - Recorder(Serializer &serializer, Registry ®istry, - llvm::StringRef pretty_func = {}); + Recorder(llvm::StringRef pretty_func = {}, std::string &&pretty_args = {}); ~Recorder(); /// Records a single function call. template - void Record(Result (*f)(FArgs...), const RArgs &... args) { + void Record(Serializer &serializer, Registry ®istry, Result (*f)(FArgs...), + const RArgs &... args) { + m_serializer = &serializer; if (!ShouldCapture()) return; - unsigned id = m_registry.GetID(uintptr_t(f)); + unsigned id = registry.GetID(uintptr_t(f)); + +#ifdef LLDB_REPRO_INSTR_TRACE Log(id); +#endif - m_serializer.SerializeAll(id); - m_serializer.SerializeAll(args...); + serializer.SerializeAll(id); + serializer.SerializeAll(args...); if (std::is_class::type>::type>::value) { m_result_recorded = false; } else { - m_serializer.SerializeAll(0); + serializer.SerializeAll(0); m_result_recorded = true; } } /// Records a single function call. template - void Record(void (*f)(Args...), const Args &... args) { + void Record(Serializer &serializer, Registry ®istry, void (*f)(Args...), + const Args &... args) { + m_serializer = &serializer; if (!ShouldCapture()) return; - unsigned id = m_registry.GetID(uintptr_t(f)); + unsigned id = registry.GetID(uintptr_t(f)); + +#ifdef LLDB_REPRO_INSTR_TRACE Log(id); +#endif - m_serializer.SerializeAll(id); - m_serializer.SerializeAll(args...); + serializer.SerializeAll(id); + serializer.SerializeAll(args...); // Record result. - m_serializer.SerializeAll(0); + serializer.SerializeAll(0); m_result_recorded = true; } /// Record the result of a function call. template Result RecordResult(Result &&r) { UpdateBoundary(); - if (ShouldCapture()) { + if (m_serializer && ShouldCapture()) { assert(!m_result_recorded); - m_serializer.SerializeAll(r); + m_serializer->SerializeAll(r); m_result_recorded = true; } return std::forward(r); @@ -692,13 +685,19 @@ } bool ShouldCapture() { return m_local_boundary; } - void Log(unsigned id); - Serializer &m_serializer; - Registry &m_registry; +#ifdef LLDB_REPRO_INSTR_TRACE + void Log(unsigned id) { + llvm::errs() << "Recording " << id << ": " << m_pretty_func << " (" + << m_pretty_args << ")\n"; + } +#endif + + Serializer *m_serializer; /// Pretty function for logging. llvm::StringRef m_pretty_func; + std::string m_pretty_args; /// Whether this function call was the one crossing the API boundary. bool m_local_boundary; Index: source/Utility/ReproducerInstrumentation.cpp =================================================================== --- source/Utility/ReproducerInstrumentation.cpp +++ source/Utility/ReproducerInstrumentation.cpp @@ -101,14 +101,16 @@ return m_mapping[object]; } -Recorder::Recorder(Serializer &serializer, Registry ®istry, - llvm::StringRef pretty_func) - : m_serializer(serializer), m_registry(registry), - m_pretty_func(pretty_func), m_local_boundary(false), +Recorder::Recorder(llvm::StringRef pretty_func, std::string &&pretty_args) + : m_serializer(nullptr), m_pretty_func(pretty_func), + m_pretty_args(pretty_args), m_local_boundary(false), m_result_recorded(true) { if (!g_global_boundary) { g_global_boundary = true; m_local_boundary = true; + + LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})", + m_pretty_func, m_pretty_args); } } @@ -117,13 +119,4 @@ UpdateBoundary(); } -void Recorder::Log(unsigned id) { -#ifndef LLDB_REPRO_INSTR_TRACE - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "Recording {0}: {1}", id, - m_pretty_func); -#else - llvm::errs() << "Recording " << id << ": " << m_pretty_func << "\n"; -#endif -} - bool lldb_private::repro::Recorder::g_global_boundary;