Skip to content

Commit 1bf6f55

Browse files
ashgtiDavidGoldman
authored andcommitted
[lldb-vscode] Adding support for displaying backtraces.
On Apple platforms when debugging with libBacktraceRecording.dylib backtraces are stored as part of the thread stack. This change includes support for displaying the back traces when they are present in the stack trace. To use this on macOS a binary needs to be run with the following environment variables configured: DYLD_LIBRARY_PATH=/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/usr/lib/libBacktraceRecording.dylib {F28473587} Reviewed By: wallace Differential Revision: https://reviews.llvm.org/D156465
1 parent e777e44 commit 1bf6f55

File tree

2 files changed

+83
-11
lines changed

2 files changed

+83
-11
lines changed

lldb/tools/lldb-vscode/JSONUtils.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -815,17 +815,30 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame) {
815815
llvm::json::Value CreateThread(lldb::SBThread &thread) {
816816
llvm::json::Object object;
817817
object.try_emplace("id", (int64_t)thread.GetThreadID());
818-
char thread_str[64];
819-
snprintf(thread_str, sizeof(thread_str), "Thread #%u", thread.GetIndexID());
820-
const char *name = thread.GetName();
821-
if (name) {
822-
std::string thread_with_name(thread_str);
823-
thread_with_name += ' ';
824-
thread_with_name += name;
825-
EmplaceSafeString(object, "name", thread_with_name);
818+
const char *thread_name = thread.GetName();
819+
const char *queue_name = thread.GetQueueName();
820+
821+
std::string thread_str;
822+
if (thread_name) {
823+
thread_str = std::string(thread_name);
824+
} else if (queue_name) {
825+
auto kind = thread.GetQueue().GetKind();
826+
std::string queue_kind_label = "";
827+
if (kind == lldb::eQueueKindSerial) {
828+
queue_kind_label = " (serial)";
829+
} else if (kind == lldb::eQueueKindConcurrent) {
830+
queue_kind_label = " (concurrent)";
831+
}
832+
833+
thread_str = llvm::formatv("Thread {0} Queue: {1}{2}", thread.GetIndexID(),
834+
queue_name, queue_kind_label)
835+
.str();
826836
} else {
827-
EmplaceSafeString(object, "name", std::string(thread_str));
837+
thread_str = llvm::formatv("Thread {0}", thread.GetIndexID()).str();
828838
}
839+
840+
EmplaceSafeString(object, "name", thread_str);
841+
829842
return llvm::json::Value(std::move(object));
830843
}
831844

lldb/tools/lldb-vscode/lldb-vscode.cpp

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2687,13 +2687,72 @@ void request_stackTrace(const llvm::json::Object &request) {
26872687
const auto startFrame = GetUnsigned(arguments, "startFrame", 0);
26882688
const auto levels = GetUnsigned(arguments, "levels", 0);
26892689
const auto endFrame = (levels == 0) ? INT64_MAX : (startFrame + levels);
2690+
auto totalFrames = thread.GetNumFrames();
2691+
2692+
// This will always return an invalid thread when
2693+
// libBacktraceRecording.dylib is not loaded or if there is no extended
2694+
// backtrace.
2695+
lldb::SBThread queue_backtrace_thread =
2696+
thread.GetExtendedBacktraceThread("libdispatch");
2697+
if (queue_backtrace_thread.IsValid()) {
2698+
// One extra frame as a label to mark the enqueued thread.
2699+
totalFrames += queue_backtrace_thread.GetNumFrames() + 1;
2700+
}
2701+
2702+
// This will always return an invalid thread when there is no exception in
2703+
// the current thread.
2704+
lldb::SBThread exception_backtrace_thread =
2705+
thread.GetCurrentExceptionBacktrace();
2706+
if (exception_backtrace_thread.IsValid()) {
2707+
// One extra frame as a label to mark the exception thread.
2708+
totalFrames += exception_backtrace_thread.GetNumFrames() + 1;
2709+
}
2710+
26902711
for (uint32_t i = startFrame; i < endFrame; ++i) {
2691-
auto frame = thread.GetFrameAtIndex(i);
2712+
lldb::SBFrame frame;
2713+
std::string prefix;
2714+
if (i < thread.GetNumFrames()) {
2715+
frame = thread.GetFrameAtIndex(i);
2716+
} else if (queue_backtrace_thread.IsValid() &&
2717+
i < (thread.GetNumFrames() +
2718+
queue_backtrace_thread.GetNumFrames() + 1)) {
2719+
if (i == thread.GetNumFrames()) {
2720+
const uint32_t thread_idx =
2721+
queue_backtrace_thread.GetExtendedBacktraceOriginatingIndexID();
2722+
const char *queue_name = queue_backtrace_thread.GetQueueName();
2723+
auto name = llvm::formatv("Enqueued from {0} (Thread {1})",
2724+
queue_name, thread_idx);
2725+
stackFrames.emplace_back(
2726+
llvm::json::Object{{"id", thread.GetThreadID() + 1},
2727+
{"name", name},
2728+
{"presentationHint", "label"}});
2729+
continue;
2730+
}
2731+
frame = queue_backtrace_thread.GetFrameAtIndex(
2732+
i - thread.GetNumFrames() - 1);
2733+
} else if (exception_backtrace_thread.IsValid()) {
2734+
if (i == thread.GetNumFrames() +
2735+
(queue_backtrace_thread.IsValid()
2736+
? queue_backtrace_thread.GetNumFrames() + 1
2737+
: 0)) {
2738+
stackFrames.emplace_back(
2739+
llvm::json::Object{{"id", thread.GetThreadID() + 2},
2740+
{"name", "Original Exception Backtrace"},
2741+
{"presentationHint", "label"}});
2742+
continue;
2743+
}
2744+
2745+
frame = exception_backtrace_thread.GetFrameAtIndex(
2746+
i - thread.GetNumFrames() -
2747+
(queue_backtrace_thread.IsValid()
2748+
? queue_backtrace_thread.GetNumFrames() + 1
2749+
: 0));
2750+
}
26922751
if (!frame.IsValid())
26932752
break;
26942753
stackFrames.emplace_back(CreateStackFrame(frame));
26952754
}
2696-
const auto totalFrames = thread.GetNumFrames();
2755+
26972756
body.try_emplace("totalFrames", totalFrames);
26982757
}
26992758
body.try_emplace("stackFrames", std::move(stackFrames));

0 commit comments

Comments
 (0)