[Lldb-commits] [lldb] [lldb-dap] Improve `stackTrace` and `exceptionInfo` DAP request handlers (PR #105905)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Aug 29 14:46:38 PDT 2024
================
@@ -3106,80 +3235,109 @@ void request_stackTrace(const llvm::json::Object &request) {
llvm::json::Array stackFrames;
llvm::json::Object body;
+ // Threads stacks may contain runtime specific extended backtraces, when
+ // constructing a stack trace first report the full thread stack trace then
+ // perform a breadth first traversal of any extended backtrace frames.
+ //
+ // For example:
+ //
+ // Thread (id=th0) stack=[s0, s1, s2, s3]
+ // \ Extended backtrace "libdispatch" Thread (id=th1) stack=[s0, s1]
+ // \ Extended backtrace "libdispatch" Thread (id=th2) stack=[s0, s1]
+ // \ Extended backtrace "Application Specific Backtrace" Thread (id=th3)
+ // stack=[s0, s1, s2]
+ //
+ // Which will flatten into:
+ //
+ // 0. th0->s0
+ // 1. th0->s1
+ // 2. th0->s2
+ // 3. th0->s3
+ // 4. label - Enqueued from th1
+ // 5. th1->s0
+ // 6. th1->s1
+ // 7. label - Enqueued from th2
+ // 8. th2->s0
+ // 9. th2->s1
+ // 10. label - Application Specific Backtrace
+ // 11. th3->s0
+ // 12. th3->s1
+ // 13. th3->s2
+
if (thread.IsValid()) {
const auto startFrame = GetUnsigned(arguments, "startFrame", 0);
const auto levels = GetUnsigned(arguments, "levels", 0);
const auto endFrame = (levels == 0) ? INT64_MAX : (startFrame + levels);
- auto totalFrames = thread.GetNumFrames();
-
- // This will always return an invalid thread when
- // libBacktraceRecording.dylib is not loaded or if there is no extended
- // backtrace.
- lldb::SBThread queue_backtrace_thread;
- if (g_dap.enable_display_extended_backtrace)
- queue_backtrace_thread = thread.GetExtendedBacktraceThread("libdispatch");
- if (queue_backtrace_thread.IsValid()) {
- // One extra frame as a label to mark the enqueued thread.
- totalFrames += queue_backtrace_thread.GetNumFrames() + 1;
- }
-
- // This will always return an invalid thread when there is no exception in
- // the current thread.
- lldb::SBThread exception_backtrace_thread;
- if (g_dap.enable_display_extended_backtrace)
- exception_backtrace_thread = thread.GetCurrentExceptionBacktrace();
-
- if (exception_backtrace_thread.IsValid()) {
- // One extra frame as a label to mark the exception thread.
- totalFrames += exception_backtrace_thread.GetNumFrames() + 1;
- }
-
- for (uint32_t i = startFrame; i < endFrame; ++i) {
- lldb::SBFrame frame;
- std::string prefix;
- if (i < thread.GetNumFrames()) {
- frame = thread.GetFrameAtIndex(i);
- } else if (queue_backtrace_thread.IsValid() &&
- i < (thread.GetNumFrames() +
- queue_backtrace_thread.GetNumFrames() + 1)) {
- if (i == thread.GetNumFrames()) {
- const uint32_t thread_idx =
- queue_backtrace_thread.GetExtendedBacktraceOriginatingIndexID();
- const char *queue_name = queue_backtrace_thread.GetQueueName();
- auto name = llvm::formatv("Enqueued from {0} (Thread {1})",
- queue_name, thread_idx);
- stackFrames.emplace_back(
- llvm::json::Object{{"id", thread.GetThreadID() + 1},
- {"name", name},
- {"presentationHint", "label"}});
- continue;
+ bool done = false;
+ int64_t offset = 0;
+ lldb::SBProcess process = thread.GetProcess();
+ llvm::SmallVector<lldb::SBThread> threadCluster{{thread}};
+
+ for (uint32_t i = startFrame; i < endFrame && !threadCluster.empty(); ++i) {
+ lldb::SBThread current = threadCluster.front();
+ lldb::SBFrame frame = current.GetFrameAtIndex(i - offset);
+
+ // If we don't have a valid frame, check if we have any extended frames to
+ // report.
+ // *NOTE*: Threads can be chained across mutliple backtraces, so we
+ // need to keep track of each backtrace we've traversed fully in the
+ // offset.
+ while (!frame.IsValid() && current.IsValid() && !threadCluster.empty()) {
----------------
jeffreytan81 wrote:
Nit: it may worth moving extended back trace specific code into a dedicated helper function to improve readability.
https://github.com/llvm/llvm-project/pull/105905
More information about the lldb-commits
mailing list