@@ -641,6 +641,79 @@ void SetSourceMapFromArguments(const llvm::json::Object &arguments) {
641641 }
642642}
643643
644+ // Fill in the stack frames of the thread.
645+ //
646+ // Threads stacks may contain runtime specific extended backtraces, when
647+ // constructing a stack trace first report the full thread stack trace then
648+ // perform a breadth first traversal of any extended backtrace frames.
649+ //
650+ // For example:
651+ //
652+ // Thread (id=th0) stack=[s0, s1, s2, s3]
653+ // \ Extended backtrace "libdispatch" Thread (id=th1) stack=[s0, s1]
654+ // \ Extended backtrace "libdispatch" Thread (id=th2) stack=[s0, s1]
655+ // \ Extended backtrace "Application Specific Backtrace" Thread (id=th3)
656+ // stack=[s0, s1, s2]
657+ //
658+ // Which will flatten into:
659+ //
660+ // 0. th0->s0
661+ // 1. th0->s1
662+ // 2. th0->s2
663+ // 3. th0->s3
664+ // 4. label - Enqueued from th1, sf=-1, i=-4
665+ // 5. th1->s0
666+ // 6. th1->s1
667+ // 7. label - Enqueued from th2
668+ // 8. th2->s0
669+ // 9. th2->s1
670+ // 10. label - Application Specific Backtrace
671+ // 11. th3->s0
672+ // 12. th3->s1
673+ // 13. th3->s2
674+ //
675+ // s=3,l=3 = [th0->s3, label1, th1->s0]
676+ bool FillStackFrames (lldb::SBThread &thread, llvm::json::Array &stack_frames,
677+ int64_t &offset, const int64_t start_frame,
678+ const int64_t levels) {
679+ bool reached_end_of_stack = false ;
680+ for (int64_t i = start_frame;
681+ static_cast <int64_t >(stack_frames.size ()) < levels; i++) {
682+ if (i == -1 ) {
683+ stack_frames.emplace_back (CreateExtendedStackFrameLabel (thread));
684+ continue ;
685+ }
686+
687+ lldb::SBFrame frame = thread.GetFrameAtIndex (i);
688+ if (!frame.IsValid ()) {
689+ offset += thread.GetNumFrames () + 1 /* label between threads */ ;
690+ reached_end_of_stack = true ;
691+ break ;
692+ }
693+
694+ stack_frames.emplace_back (CreateStackFrame (frame));
695+ }
696+
697+ if (g_dap.enable_display_extended_backtrace && reached_end_of_stack) {
698+ // Check for any extended backtraces.
699+ for (uint32_t bt = 0 ;
700+ bt < thread.GetProcess ().GetNumExtendedBacktraceTypes (); bt++) {
701+ lldb::SBThread backtrace = thread.GetExtendedBacktraceThread (
702+ thread.GetProcess ().GetExtendedBacktraceTypeAtIndex (bt));
703+ if (!backtrace.IsValid ())
704+ continue ;
705+
706+ reached_end_of_stack = FillStackFrames (
707+ backtrace, stack_frames, offset,
708+ (start_frame - offset) > 0 ? start_frame - offset : -1 , levels);
709+ if (static_cast <int64_t >(stack_frames.size ()) >= levels)
710+ break ;
711+ }
712+ }
713+
714+ return reached_end_of_stack;
715+ }
716+
644717// "AttachRequest": {
645718// "allOf": [ { "$ref": "#/definitions/Request" }, {
646719// "type": "object",
@@ -3234,114 +3307,22 @@ void request_stackTrace(const llvm::json::Object &request) {
32343307 lldb::SBError error;
32353308 auto arguments = request.getObject (" arguments" );
32363309 lldb::SBThread thread = g_dap.GetLLDBThread (*arguments);
3237- llvm::json::Array stackFrames ;
3310+ llvm::json::Array stack_frames ;
32383311 llvm::json::Object body;
32393312
3240- // Threads stacks may contain runtime specific extended backtraces, when
3241- // constructing a stack trace first report the full thread stack trace then
3242- // perform a breadth first traversal of any extended backtrace frames.
3243- //
3244- // For example:
3245- //
3246- // Thread (id=th0) stack=[s0, s1, s2, s3]
3247- // \ Extended backtrace "libdispatch" Thread (id=th1) stack=[s0, s1]
3248- // \ Extended backtrace "libdispatch" Thread (id=th2) stack=[s0, s1]
3249- // \ Extended backtrace "Application Specific Backtrace" Thread (id=th3)
3250- // stack=[s0, s1, s2]
3251- //
3252- // Which will flatten into:
3253- //
3254- // 0. th0->s0
3255- // 1. th0->s1
3256- // 2. th0->s2
3257- // 3. th0->s3
3258- // 4. label - Enqueued from th1
3259- // 5. th1->s0
3260- // 6. th1->s1
3261- // 7. label - Enqueued from th2
3262- // 8. th2->s0
3263- // 9. th2->s1
3264- // 10. label - Application Specific Backtrace
3265- // 11. th3->s0
3266- // 12. th3->s1
3267- // 13. th3->s2
3268-
32693313 if (thread.IsValid ()) {
3270- const auto startFrame = GetUnsigned (arguments, " startFrame" , 0 );
3314+ const auto start_frame = GetUnsigned (arguments, " startFrame" , 0 );
32713315 const auto levels = GetUnsigned (arguments, " levels" , 0 );
3272- const auto endFrame = (levels == 0 ) ? INT64_MAX : (startFrame + levels);
3273- bool done = false ;
32743316 int64_t offset = 0 ;
3275- lldb::SBProcess process = thread.GetProcess ();
3276- llvm::SmallVector<lldb::SBThread> threadCluster{{thread}};
3277-
3278- for (uint32_t i = startFrame; i < endFrame && !threadCluster.empty (); ++i) {
3279- lldb::SBThread current = threadCluster.front ();
3280- lldb::SBFrame frame = current.GetFrameAtIndex (i - offset);
3281-
3282- // If we don't have a valid frame, check if we have any extended frames to
3283- // report.
3284- // *NOTE*: Threads can be chained across mutliple backtraces, so we
3285- // need to keep track of each backtrace we've traversed fully in the
3286- // offset.
3287- while (!frame.IsValid () && current.IsValid () && !threadCluster.empty ()) {
3288- offset += current.GetNumFrames () +
3289- 1 /* one extra frame for a label between threads*/ ;
3290- threadCluster.pop_back ();
3291-
3292- if (!g_dap.enable_display_extended_backtrace ) {
3293- break ;
3294- }
3295-
3296- // Check for any extended backtraces.
3297- for (uint32_t i = 0 ; i < process.GetNumExtendedBacktraceTypes (); i++) {
3298- lldb::SBThread backtrace = current.GetExtendedBacktraceThread (
3299- process.GetExtendedBacktraceTypeAtIndex (i));
3300- if (backtrace.IsValid ()) {
3301- threadCluster.emplace_back (backtrace);
3302- }
3303- }
3304-
3305- if (threadCluster.empty ())
3306- break ;
3307-
3308- current = threadCluster.front ();
3309- frame = current.GetFrameAtIndex (0 );
3310- }
3311-
3312- // If we're out of extended backtraces, no more frames to load.
3313- if (!frame.IsValid () && threadCluster.empty ()) {
3314- done = true ;
3315- break ;
3316- }
3317-
3318- // Between the thread and extended backtrace add a label.
3319- if (offset != 0 && (i - offset) == 0 ) {
3320- const uint32_t thread_idx =
3321- current.GetExtendedBacktraceOriginatingIndexID ();
3322- const char *queue_name = current.GetQueueName ();
3323- std::string name;
3324- if (queue_name != nullptr ) {
3325- name = llvm::formatv (" Enqueued from {0} (Thread {1})" , queue_name,
3326- thread_idx);
3327- } else {
3328- name = llvm::formatv (" Thread {0}" , thread_idx);
3329- }
3330- stackFrames.emplace_back (
3331- llvm::json::Object{{" id" , thread.GetThreadID () + 1 },
3332- {" name" , name},
3333- {" presentationHint" , " label" }});
3334- } else {
3335- stackFrames.emplace_back (CreateStackFrame (frame));
3336- }
3337- }
3338-
3339- // If we loaded all the frames, set the total frame to the current total,
3340- // otherwise use the totalFrames to indicate more data is available.
3341- body.try_emplace (" totalFrames" , startFrame + stackFrames.size () +
3342- (done ? 0 : StackPageSize));
3317+ bool reached_end_of_stack =
3318+ FillStackFrames (thread, stack_frames, offset, start_frame,
3319+ levels == 0 ? INT64_MAX : levels);
3320+ body.try_emplace (" totalFrames" ,
3321+ start_frame + stack_frames.size () +
3322+ (reached_end_of_stack ? 0 : StackPageSize));
33433323 }
3344- body.try_emplace (" stackFrames" , std::move (stackFrames));
3324+
3325+ body.try_emplace (" stackFrames" , std::move (stack_frames));
33453326 response.try_emplace (" body" , std::move (body));
33463327 g_dap.SendJSON (llvm::json::Value (std::move (response)));
33473328}
0 commit comments