[Reproducers] Add more logging to reproducer instrumentation
authorJonas Devlieghere <jonas@devlieghere.com>
Wed, 27 Feb 2019 16:40:08 +0000 (16:40 +0000)
committerJonas Devlieghere <jonas@devlieghere.com>
Wed, 27 Feb 2019 16:40:08 +0000 (16:40 +0000)
Debugging issues with instrumentation capture and replay can be
particularly tricky, especially because part of the process takes places
even before the debugger is initialized. This patch adds more logging
capabilities to these classes, hidden behind a macro define.

Differential revision: https://reviews.llvm.org/D58566

llvm-svn: 355002

lldb/include/lldb/Utility/ReproducerInstrumentation.h
lldb/source/Utility/ReproducerInstrumentation.cpp

index b2e2701..f10398e 100644 (file)
 
 #include <map>
 
+// Define LLDB_REPRO_INSTR_TRACE to trace to stderr instead of LLDB's log
+// infrastructure. This is useful when you need to see traces before the logger
+// is initialized or enabled.
+#define LLDB_REPRO_INSTR_TRACE
+
 #define LLDB_REGISTER_CONSTRUCTOR(Class, Signature)                            \
-  Register<Class * Signature>(&construct<Class Signature>::doit)
+  Register<Class * Signature>(&construct<Class Signature>::doit, "", #Class,   \
+                              #Class, #Signature)
 #define LLDB_REGISTER_METHOD(Result, Class, Method, Signature)                 \
-  Register(&invoke<Result(Class::*) Signature>::method<&Class::Method>::doit)
+  Register(&invoke<Result(Class::*) Signature>::method<&Class::Method>::doit,  \
+           #Result, #Class, #Method, #Signature)
 #define LLDB_REGISTER_METHOD_CONST(Result, Class, Method, Signature)           \
   Register(&invoke<Result(Class::*)                                            \
-                       Signature const>::method_const<&Class::Method>::doit)
+                       Signature const>::method_const<&Class::Method>::doit,   \
+           #Result, #Class, #Method, #Signature)
 #define LLDB_REGISTER_STATIC_METHOD(Result, Class, Method, Signature)          \
-  Register<Result Signature>(static_cast<Result(*) Signature>(&Class::Method))
+  Register<Result Signature>(static_cast<Result(*) Signature>(&Class::Method), \
+                             #Result, #Class, #Method, #Signature)
 
 #define LLDB_RECORD_CONSTRUCTOR(Class, Signature, ...)                         \
   LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0}",                   \
@@ -224,6 +233,9 @@ public:
 
   /// Deserialize and interpret value as T.
   template <typename T> T Deserialize() {
+#ifdef LLDB_REPRO_INSTR_TRACE
+    llvm::errs() << "Deserializing with " << LLVM_PRETTY_FUNCTION << "\n";
+#endif
     return Read<T>(typename serializer_tag<T>::type());
   }
 
@@ -371,19 +383,41 @@ struct DefaultReplayer<void(Args...)> : public Replayer {
 /// IDs can be serialized and deserialized to replay a function. Functions need
 /// to be registered with the registry for this to work.
 class Registry {
+private:
+  struct SignatureStr {
+    SignatureStr(llvm::StringRef result = {}, llvm::StringRef scope = {},
+                 llvm::StringRef name = {}, llvm::StringRef args = {})
+        : result(result), scope(scope), name(name), args(args) {}
+
+    std::string ToString() const;
+
+    llvm::StringRef result;
+    llvm::StringRef scope;
+    llvm::StringRef name;
+    llvm::StringRef args;
+  };
+
 public:
   Registry() = default;
   virtual ~Registry() = default;
 
   /// Register a default replayer for a function.
-  template <typename Signature> void Register(Signature *f) {
-    DoRegister(uintptr_t(f), llvm::make_unique<DefaultReplayer<Signature>>(f));
+  template <typename Signature>
+  void Register(Signature *f, llvm::StringRef result = {},
+                llvm::StringRef scope = {}, llvm::StringRef name = {},
+                llvm::StringRef args = {}) {
+    DoRegister(uintptr_t(f), llvm::make_unique<DefaultReplayer<Signature>>(f),
+               SignatureStr(result, scope, name, args));
   }
 
   /// Register a replayer that invokes a custom function with the same
   /// signature as the replayed function.
-  template <typename Signature> void Register(Signature *f, Signature *g) {
-    DoRegister(uintptr_t(f), llvm::make_unique<DefaultReplayer<Signature>>(g));
+  template <typename Signature>
+  void Register(Signature *f, Signature *g, llvm::StringRef result = {},
+                llvm::StringRef scope = {}, llvm::StringRef name = {},
+                llvm::StringRef args = {}) {
+    DoRegister(uintptr_t(f), llvm::make_unique<DefaultReplayer<Signature>>(g),
+               SignatureStr(result, scope, name, args));
   }
 
   /// Replay functions from a file.
@@ -397,15 +431,19 @@ public:
 
 protected:
   /// Register the given replayer for a function (and the ID mapping).
-  void DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer);
+  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;
 
   /// Mapping of IDs to replayer instances.
-  std::map<unsigned, Replayer *> m_ids;
+  std::map<unsigned, std::pair<Replayer *, SignatureStr>> m_ids;
 };
 
 /// To be used as the "Runtime ID" of a constructor. It also invokes the
@@ -551,8 +589,12 @@ public:
 
     unsigned id = m_registry.GetID(uintptr_t(f));
 
-    LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "Recording ({0}) '{1}'",
+#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
 
     m_serializer.SerializeAll(id);
     m_serializer.SerializeAll(args...);
@@ -574,8 +616,12 @@ public:
 
     unsigned id = m_registry.GetID(uintptr_t(f));
 
-    LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "Recording ({0}) '{1}'",
+#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
 
     m_serializer.SerializeAll(id);
     m_serializer.SerializeAll(args...);
index f4ae7e8..dc42f6f 100644 (file)
@@ -43,23 +43,33 @@ bool Registry::Replay(const FileSpec &file) {
 }
 
 bool Registry::Replay(llvm::StringRef buffer) {
+#ifndef LLDB_REPRO_INSTR_TRACE
   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_API);
+#endif
 
   Deserializer deserializer(buffer);
   while (deserializer.HasData(1)) {
     unsigned id = deserializer.Deserialize<unsigned>();
-    LLDB_LOG(log, "Replaying function #{0}", id);
-    m_ids[id]->operator()(deserializer);
+
+#ifndef LLDB_REPRO_INSTR_TRACE
+    LLDB_LOG(log, "Replaying {0}: {1}", id, GetSignature(id));
+#else
+    llvm::errs() << "Replaying " << id << ": " << GetSignature(id) << "\n";
+#endif
+
+    GetReplayer(id)->operator()(deserializer);
   }
 
   return true;
 }
 
-void Registry::DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer) {
+void Registry::DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer,
+                          SignatureStr signature) {
   const unsigned id = m_replayers.size() + 1;
   assert(m_replayers.find(RunID) == m_replayers.end());
   m_replayers[RunID] = std::make_pair(std::move(replayer), id);
-  m_ids[id] = m_replayers[RunID].first.get();
+  m_ids[id] =
+      std::make_pair(m_replayers[RunID].first.get(), std::move(signature));
 }
 
 unsigned Registry::GetID(uintptr_t addr) {
@@ -68,6 +78,21 @@ unsigned Registry::GetID(uintptr_t addr) {
   return id;
 }
 
+std::string Registry::GetSignature(unsigned id) {
+  assert(m_ids.count(id) != 0 && "ID not in registry");
+  return m_ids[id].second.ToString();
+}
+
+Replayer *Registry::GetReplayer(unsigned id) {
+  assert(m_ids.count(id) != 0 && "ID not in registry");
+  return m_ids[id].first;
+}
+
+std::string Registry::SignatureStr::ToString() const {
+  return (result + (result.empty() ? "" : " ") + scope + "::" + name + args)
+      .str();
+}
+
 unsigned ObjectToIndex::GetIndexForObjectImpl(const void *object) {
   unsigned index = m_mapping.size() + 1;
   auto it = m_mapping.find(object);