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