[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