1 //===-- CommandObjectThreadUtil.cpp -----------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "CommandObjectThreadUtil.h"
11 #include "lldb/Interpreter/CommandReturnObject.h"
12 #include "lldb/Target/Process.h"
13 #include "lldb/Target/Thread.h"
16 using namespace lldb_private
;
19 CommandObjectIterateOverThreads::CommandObjectIterateOverThreads(
20 CommandInterpreter
&interpreter
, const char *name
, const char *help
,
21 const char *syntax
, uint32_t flags
)
22 : CommandObjectParsed(interpreter
, name
, help
, syntax
, flags
) {
23 // These commands all take thread ID's as arguments.
24 AddSimpleArgumentList(eArgTypeThreadIndex
, eArgRepeatStar
);
27 CommandObjectMultipleThreads::CommandObjectMultipleThreads(
28 CommandInterpreter
&interpreter
, const char *name
, const char *help
,
29 const char *syntax
, uint32_t flags
)
30 : CommandObjectParsed(interpreter
, name
, help
, syntax
, flags
) {
31 // These commands all take thread ID's as arguments.
32 AddSimpleArgumentList(eArgTypeThreadIndex
, eArgRepeatStar
);
35 void CommandObjectIterateOverThreads::DoExecute(Args
&command
,
36 CommandReturnObject
&result
) {
37 result
.SetStatus(m_success_return
);
39 bool all_threads
= false;
40 if (command
.GetArgumentCount() == 0) {
41 Thread
*thread
= m_exe_ctx
.GetThreadPtr();
43 HandleOneThread(thread
->GetID(), result
);
45 } else if (command
.GetArgumentCount() == 1) {
46 all_threads
= ::strcmp(command
.GetArgumentAtIndex(0), "all") == 0;
47 m_unique_stacks
= ::strcmp(command
.GetArgumentAtIndex(0), "unique") == 0;
50 // Use tids instead of ThreadSPs to prevent deadlocking problems which
51 // result from JIT-ing code while iterating over the (locked) ThreadSP
53 std::vector
<lldb::tid_t
> tids
;
55 if (all_threads
|| m_unique_stacks
) {
56 Process
*process
= m_exe_ctx
.GetProcessPtr();
58 for (ThreadSP thread_sp
: process
->Threads())
59 tids
.push_back(thread_sp
->GetID());
61 const size_t num_args
= command
.GetArgumentCount();
62 Process
*process
= m_exe_ctx
.GetProcessPtr();
64 std::lock_guard
<std::recursive_mutex
> guard(
65 process
->GetThreadList().GetMutex());
67 for (size_t i
= 0; i
< num_args
; i
++) {
69 if (!llvm::to_integer(command
.GetArgumentAtIndex(i
), thread_idx
)) {
70 result
.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
71 command
.GetArgumentAtIndex(i
));
76 process
->GetThreadList().FindThreadByIndexID(thread_idx
);
79 result
.AppendErrorWithFormat("no thread with index: \"%s\"\n",
80 command
.GetArgumentAtIndex(i
));
84 tids
.push_back(thread
->GetID());
88 if (m_unique_stacks
) {
89 // Iterate over threads, finding unique stack buckets.
90 std::set
<UniqueStack
> unique_stacks
;
91 for (const lldb::tid_t
&tid
: tids
) {
92 if (!BucketThread(tid
, unique_stacks
, result
)) {
97 // Write the thread id's and unique call stacks to the output stream
98 Stream
&strm
= result
.GetOutputStream();
99 Process
*process
= m_exe_ctx
.GetProcessPtr();
100 for (const UniqueStack
&stack
: unique_stacks
) {
101 // List the common thread ID's
102 const std::vector
<uint32_t> &thread_index_ids
=
103 stack
.GetUniqueThreadIndexIDs();
104 strm
.Format("{0} thread(s) ", thread_index_ids
.size());
105 for (const uint32_t &thread_index_id
: thread_index_ids
) {
106 strm
.Format("#{0} ", thread_index_id
);
110 // List the shared call stack for this set of threads
111 uint32_t representative_thread_id
= stack
.GetRepresentativeThread();
112 ThreadSP thread
= process
->GetThreadList().FindThreadByIndexID(
113 representative_thread_id
);
114 if (!HandleOneThread(thread
->GetID(), result
)) {
120 for (const lldb::tid_t
&tid
: tids
) {
121 if (idx
!= 0 && m_add_return
)
122 result
.AppendMessage("");
124 if (!HandleOneThread(tid
, result
))
132 bool CommandObjectIterateOverThreads::BucketThread(
133 lldb::tid_t tid
, std::set
<UniqueStack
> &unique_stacks
,
134 CommandReturnObject
&result
) {
135 // Grab the corresponding thread for the given thread id.
136 Process
*process
= m_exe_ctx
.GetProcessPtr();
137 Thread
*thread
= process
->GetThreadList().FindThreadByID(tid
).get();
138 if (thread
== nullptr) {
139 result
.AppendErrorWithFormatv("Failed to process thread #{0}.\n", tid
);
143 // Collect the each frame's address for this call-stack
144 std::stack
<lldb::addr_t
> stack_frames
;
145 const uint32_t frame_count
= thread
->GetStackFrameCount();
146 for (uint32_t frame_index
= 0; frame_index
< frame_count
; frame_index
++) {
147 const lldb::StackFrameSP frame_sp
=
148 thread
->GetStackFrameAtIndex(frame_index
);
149 const lldb::addr_t pc
= frame_sp
->GetStackID().GetPC();
150 stack_frames
.push(pc
);
153 uint32_t thread_index_id
= thread
->GetIndexID();
154 UniqueStack
new_unique_stack(stack_frames
, thread_index_id
);
156 // Try to match the threads stack to and existing entry.
157 std::set
<UniqueStack
>::iterator matching_stack
=
158 unique_stacks
.find(new_unique_stack
);
159 if (matching_stack
!= unique_stacks
.end()) {
160 matching_stack
->AddThread(thread_index_id
);
162 unique_stacks
.insert(new_unique_stack
);
167 void CommandObjectMultipleThreads::DoExecute(Args
&command
,
168 CommandReturnObject
&result
) {
169 Process
&process
= m_exe_ctx
.GetProcessRef();
171 std::vector
<lldb::tid_t
> tids
;
172 const size_t num_args
= command
.GetArgumentCount();
174 std::lock_guard
<std::recursive_mutex
> guard(
175 process
.GetThreadList().GetMutex());
177 if (num_args
> 0 && ::strcmp(command
.GetArgumentAtIndex(0), "all") == 0) {
178 for (ThreadSP thread_sp
: process
.Threads())
179 tids
.push_back(thread_sp
->GetID());
182 Thread
&thread
= m_exe_ctx
.GetThreadRef();
183 tids
.push_back(thread
.GetID());
186 for (size_t i
= 0; i
< num_args
; i
++) {
188 if (!llvm::to_integer(command
.GetArgumentAtIndex(i
), thread_idx
)) {
189 result
.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
190 command
.GetArgumentAtIndex(i
));
194 ThreadSP thread
= process
.GetThreadList().FindThreadByIndexID(thread_idx
);
197 result
.AppendErrorWithFormat("no thread with index: \"%s\"\n",
198 command
.GetArgumentAtIndex(i
));
202 tids
.push_back(thread
->GetID());
206 DoExecuteOnThreads(command
, result
, tids
);