Skip to content

Commit 83a6a0a

Browse files
committed
[lldb] Print lldbassert to debugger diagnostics
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 is all printed to stderr. That's fine on the command line, but when used as library, for example from Xcode, this information doesn't make it to the user. This patch uses the diagnostic infrastructure to report LLDB asserts as diagnostic events. The patch is slightly more complicated than I would've liked because of layering. lldbassert is part of Utility while the debugger diagnostics are implemented in Core. Differential revision: https://reviews.llvm.org/D152866
1 parent cf875ca commit 83a6a0a

File tree

5 files changed

+53
-12
lines changed

5 files changed

+53
-12
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
128128
const ExecutionContext *exe_ctx,
129129
const Address *addr, Stream &s);
130130

131+
static void AssertCallback(llvm::StringRef message, llvm::StringRef backtrace,
132+
llvm::StringRef prompt);
133+
131134
void Clear();
132135

133136
bool GetAsyncExecution();

lldb/include/lldb/Utility/LLDBAssert.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#ifndef LLDB_UTILITY_LLDBASSERT_H
1010
#define LLDB_UTILITY_LLDBASSERT_H
1111

12+
#include "llvm/ADT/StringRef.h"
13+
1214
#ifndef NDEBUG
1315
#define lldbassert(x) assert(x)
1416
#else
@@ -29,6 +31,12 @@
2931
namespace lldb_private {
3032
void lldb_assert(bool expression, const char *expr_text, const char *func,
3133
const char *file, unsigned int line);
34+
35+
typedef void (*LLDBAssertCallback)(llvm::StringRef message,
36+
llvm::StringRef backtrace,
37+
llvm::StringRef prompt);
38+
39+
void SetLLDBAssertCallback(LLDBAssertCallback callback);
3240
} // namespace lldb_private
3341

3442
#endif // LLDB_UTILITY_LLDBASSERT_H

lldb/source/API/SystemInitializerFull.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ llvm::Error SystemInitializerFull::Initialize() {
7878
// Settings must be initialized AFTER PluginManager::Initialize is called.
7979
Debugger::SettingsInitialize();
8080

81+
// Use the Debugger's LLDBAssert callback.
82+
SetLLDBAssertCallback(Debugger::AssertCallback);
83+
8184
return llvm::Error::success();
8285
}
8386

lldb/source/Core/Debugger.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,13 @@ bool Debugger::FormatDisassemblerAddress(const FormatEntity::Entry *format,
13521352
function_changed, initial_function);
13531353
}
13541354

1355+
void Debugger::AssertCallback(llvm::StringRef message,
1356+
llvm::StringRef backtrace,
1357+
llvm::StringRef prompt) {
1358+
Debugger::ReportError(
1359+
llvm::formatv("{0}\n{1}{2}", message, backtrace, prompt).str());
1360+
}
1361+
13551362
void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback,
13561363
void *baton) {
13571364
// For simplicity's sake, I am not going to deal with how to close down any

lldb/source/Utility/LLDBAssert.cpp

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,29 @@
88

99
#include "lldb/Utility/LLDBAssert.h"
1010
#include "llvm/Config/llvm-config.h"
11-
#include "llvm/Support/Format.h"
11+
#include "llvm/Support/FormatVariadic.h"
1212
#include "llvm/Support/Signals.h"
1313
#include "llvm/Support/raw_ostream.h"
1414

1515
#if LLVM_SUPPORT_XCODE_SIGNPOSTS
1616
#include <os/log.h>
1717
#endif
1818

19-
using namespace llvm;
20-
using namespace lldb_private;
19+
namespace lldb_private {
2120

22-
void lldb_private::lldb_assert(bool expression, const char *expr_text,
23-
const char *func, const char *file,
24-
unsigned int line) {
21+
static void DefaultAssertCallback(llvm::StringRef message,
22+
llvm::StringRef backtrace,
23+
llvm::StringRef prompt) {
24+
llvm::errs() << message << '\n';
25+
llvm::errs() << backtrace; // Backtrace includes a newline.
26+
llvm::errs() << prompt << '\n';
27+
}
28+
29+
static std::atomic<LLDBAssertCallback> g_lldb_assert_callback =
30+
&DefaultAssertCallback;
31+
32+
void lldb_assert(bool expression, const char *expr_text, const char *func,
33+
const char *file, unsigned int line) {
2534
if (LLVM_LIKELY(expression))
2635
return;
2736

@@ -35,10 +44,21 @@ void lldb_private::lldb_assert(bool expression, const char *expr_text,
3544

3645
// Print a warning and encourage the user to file a bug report, similar to
3746
// LLVM’s crash handler, and then return execution.
38-
errs() << format("Assertion failed: (%s), function %s, file %s, line %u\n",
39-
expr_text, func, file, line);
40-
errs() << "backtrace leading to the failure:\n";
41-
llvm::sys::PrintStackTrace(errs());
42-
errs() << "please file a bug report against lldb reporting this failure "
43-
"log, and as many details as possible\n";
47+
std::string buffer;
48+
llvm::raw_string_ostream backtrace(buffer);
49+
llvm::sys::PrintStackTrace(backtrace);
50+
51+
(*g_lldb_assert_callback.load())(
52+
llvm::formatv("Assertion failed: ({0}), function {1}, file {2}, line {3}",
53+
expr_text, func, file, line)
54+
.str(),
55+
backtrace.str(),
56+
"Please file a bug report against lldb reporting this failure log, and "
57+
"as many details as possible");
4458
}
59+
60+
void SetLLDBAssertCallback(LLDBAssertCallback callback) {
61+
g_lldb_assert_callback.exchange(callback);
62+
}
63+
64+
} // namespace lldb_private

0 commit comments

Comments
 (0)