JDevlieghere created this revision.
JDevlieghere added reviewers: labath, rupprecht, bulbazord, aprantl.
Herald added a project: All.
JDevlieghere requested review of this revision.

When hitting an lldbassert in a non-assert build, we emit a blurb including the 
assertion, the triggering file and line and a pretty backtrace leading up to 
the issue. Currently, this emitted to stderr. That's fine for the command line, 
but when used as library, for example from Xcode or VSCode, this information 
doesn't make it to the user. This patch redirects these messages to use the 
diagnostic infrastructure so they're emitted as diagnostic events.

The patch is slightly more complicated than I would've liked because of 
layering. `lldbassert` is part of `Utility` while the diagnostics are 
implemented in `Core`.


https://reviews.llvm.org/D152866

Files:
  lldb/include/lldb/Core/Debugger.h
  lldb/include/lldb/Utility/LLDBAssert.h
  lldb/source/API/SystemInitializerFull.cpp
  lldb/source/Core/Debugger.cpp
  lldb/source/Target/Target.cpp
  lldb/source/Utility/LLDBAssert.cpp

Index: lldb/source/Utility/LLDBAssert.cpp
===================================================================
--- lldb/source/Utility/LLDBAssert.cpp
+++ lldb/source/Utility/LLDBAssert.cpp
@@ -8,7 +8,7 @@
 
 #include "lldb/Utility/LLDBAssert.h"
 #include "llvm/Config/llvm-config.h"
-#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -16,12 +16,17 @@
 #include <os/log.h>
 #endif
 
-using namespace llvm;
-using namespace lldb_private;
+namespace lldb_private {
 
-void lldb_private::lldb_assert(bool expression, const char *expr_text,
-                               const char *func, const char *file,
-                               unsigned int line) {
+static void DefaultLLDBAssertCallback(std::string message) {
+  llvm::errs() << message << '\n';
+}
+
+static std::atomic<LLDBAssertCallback> g_lldb_assert_callback =
+    &DefaultLLDBAssertCallback;
+
+void lldb_assert(bool expression, const char *expr_text, const char *func,
+                 const char *file, unsigned int line) {
   if (LLVM_LIKELY(expression))
     return;
 
@@ -35,10 +40,22 @@
 
   // Print a warning and encourage the user to file a bug report, similar to
   // LLVM’s crash handler, and then return execution.
-  errs() << format("Assertion failed: (%s), function %s, file %s, line %u\n",
-                   expr_text, func, file, line);
-  errs() << "backtrace leading to the failure:\n";
-  llvm::sys::PrintStackTrace(errs());
-  errs() << "please file a bug report against lldb reporting this failure "
-            "log, and as many details as possible\n";
+  std::string buffer;
+  llvm::raw_string_ostream backtrace(buffer);
+  llvm::sys::PrintStackTrace(backtrace);
+
+  std::string message =
+      llvm::formatv("Assertion failed: ({0}), function {1}, file {2}, line "
+                    "{3}\n{4}Please file a bug report against lldb reporting "
+                    "this failure log, and as many details as possible",
+                    expr_text, func, file, line, backtrace.str())
+          .str();
+
+  (*g_lldb_assert_callback.load())(std::move(message));
+}
+
+void SetLLDBAssertCallback(LLDBAssertCallback callback) {
+  g_lldb_assert_callback.exchange(callback);
 }
+
+} // namespace lldb_private
Index: lldb/source/Target/Target.cpp
===================================================================
--- lldb/source/Target/Target.cpp
+++ lldb/source/Target/Target.cpp
@@ -112,6 +112,7 @@
   SetEventName(eBroadcastBitWatchpointChanged, "watchpoint-changed");
   SetEventName(eBroadcastBitSymbolsLoaded, "symbols-loaded");
 
+  lldbassert(false && "foo");
   CheckInWithManager();
 
   LLDB_LOG(GetLog(LLDBLog::Object), "{0} Target::Target()",
Index: lldb/source/Core/Debugger.cpp
===================================================================
--- lldb/source/Core/Debugger.cpp
+++ lldb/source/Core/Debugger.cpp
@@ -1352,6 +1352,10 @@
                               function_changed, initial_function);
 }
 
+void Debugger::AssertCallback(std::string message) {
+  Debugger::ReportError(std::move(message));
+}
+
 void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback,
                                   void *baton) {
   // For simplicity's sake, I am not going to deal with how to close down any
Index: lldb/source/API/SystemInitializerFull.cpp
===================================================================
--- lldb/source/API/SystemInitializerFull.cpp
+++ lldb/source/API/SystemInitializerFull.cpp
@@ -78,6 +78,9 @@
   // Settings must be initialized AFTER PluginManager::Initialize is called.
   Debugger::SettingsInitialize();
 
+  // Use the Debugger's LLDBAssert callback.
+  SetLLDBAssertCallback(Debugger::AssertCallback);
+
   return llvm::Error::success();
 }
 
Index: lldb/include/lldb/Utility/LLDBAssert.h
===================================================================
--- lldb/include/lldb/Utility/LLDBAssert.h
+++ lldb/include/lldb/Utility/LLDBAssert.h
@@ -9,6 +9,8 @@
 #ifndef LLDB_UTILITY_LLDBASSERT_H
 #define LLDB_UTILITY_LLDBASSERT_H
 
+#include <string>
+
 #ifndef NDEBUG
 #define lldbassert(x) assert(x)
 #else
@@ -29,6 +31,10 @@
 namespace lldb_private {
 void lldb_assert(bool expression, const char *expr_text, const char *func,
                  const char *file, unsigned int line);
+
+typedef void (*LLDBAssertCallback)(std::string message);
+
+void SetLLDBAssertCallback(LLDBAssertCallback callback);
 } // namespace lldb_private
 
 #endif // LLDB_UTILITY_LLDBASSERT_H
Index: lldb/include/lldb/Core/Debugger.h
===================================================================
--- lldb/include/lldb/Core/Debugger.h
+++ lldb/include/lldb/Core/Debugger.h
@@ -128,6 +128,8 @@
                                         const ExecutionContext *exe_ctx,
                                         const Address *addr, Stream &s);
 
+  static void AssertCallback(std::string message);
+
   void Clear();
 
   bool GetAsyncExecution();
@@ -395,7 +397,6 @@
   /// Since the two checks are mutually exclusive, however, it's also convenient
   /// to have just one function to check the interrupt state.
 
-
   /// Bump the "interrupt requested" count on the debugger to support
   /// cooperative interruption.  If this is non-zero, InterruptRequested will
   /// return true.  Interruptible operations are expected to query the
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to