LLDB  mainline
CommandObjectThreadUtil.cpp
Go to the documentation of this file.
1 //===-- CommandObjectThreadUtil.cpp -----------------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
10 
12 #include "lldb/Target/Process.h"
13 #include "lldb/Target/Thread.h"
14 
15 using namespace lldb;
16 using namespace lldb_private;
17 using namespace llvm;
18 
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.
25  m_arguments.push_back({thread_arg});
26 }
27 
29  CommandInterpreter &interpreter, const char *name, const char *help,
30  const char *syntax, uint32_t flags)
31  : CommandObjectParsed(interpreter, name, help, syntax, flags) {
32  // These commands all take thread ID's as arguments.
34  m_arguments.push_back({thread_arg});
35 }
36 
38  CommandReturnObject &result) {
40 
41  bool all_threads = false;
42  if (command.GetArgumentCount() == 0) {
43  Thread *thread = m_exe_ctx.GetThreadPtr();
44  if (!thread || !HandleOneThread(thread->GetID(), result))
45  return false;
46  return result.Succeeded();
47  } else if (command.GetArgumentCount() == 1) {
48  all_threads = ::strcmp(command.GetArgumentAtIndex(0), "all") == 0;
49  m_unique_stacks = ::strcmp(command.GetArgumentAtIndex(0), "unique") == 0;
50  }
51 
52  // Use tids instead of ThreadSPs to prevent deadlocking problems which
53  // result from JIT-ing code while iterating over the (locked) ThreadSP
54  // list.
55  std::vector<lldb::tid_t> tids;
56 
57  if (all_threads || m_unique_stacks) {
58  Process *process = m_exe_ctx.GetProcessPtr();
59 
60  for (ThreadSP thread_sp : process->Threads())
61  tids.push_back(thread_sp->GetID());
62  } else {
63  const size_t num_args = command.GetArgumentCount();
64  Process *process = m_exe_ctx.GetProcessPtr();
65 
66  std::lock_guard<std::recursive_mutex> guard(
67  process->GetThreadList().GetMutex());
68 
69  for (size_t i = 0; i < num_args; i++) {
70  uint32_t thread_idx;
71  if (!llvm::to_integer(command.GetArgumentAtIndex(i), thread_idx)) {
72  result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
73  command.GetArgumentAtIndex(i));
74  return false;
75  }
76 
77  ThreadSP thread =
78  process->GetThreadList().FindThreadByIndexID(thread_idx);
79 
80  if (!thread) {
81  result.AppendErrorWithFormat("no thread with index: \"%s\"\n",
82  command.GetArgumentAtIndex(i));
83  return false;
84  }
85 
86  tids.push_back(thread->GetID());
87  }
88  }
89 
90  if (m_unique_stacks) {
91  // Iterate over threads, finding unique stack buckets.
92  std::set<UniqueStack> unique_stacks;
93  for (const lldb::tid_t &tid : tids) {
94  if (!BucketThread(tid, unique_stacks, result)) {
95  return false;
96  }
97  }
98 
99  // Write the thread id's and unique call stacks to the output stream
100  Stream &strm = result.GetOutputStream();
101  Process *process = m_exe_ctx.GetProcessPtr();
102  for (const UniqueStack &stack : unique_stacks) {
103  // List the common thread ID's
104  const std::vector<uint32_t> &thread_index_ids =
105  stack.GetUniqueThreadIndexIDs();
106  strm.Format("{0} thread(s) ", thread_index_ids.size());
107  for (const uint32_t &thread_index_id : thread_index_ids) {
108  strm.Format("#{0} ", thread_index_id);
109  }
110  strm.EOL();
111 
112  // List the shared call stack for this set of threads
113  uint32_t representative_thread_id = stack.GetRepresentativeThread();
114  ThreadSP thread = process->GetThreadList().FindThreadByIndexID(
115  representative_thread_id);
116  if (!HandleOneThread(thread->GetID(), result)) {
117  return false;
118  }
119  }
120  } else {
121  uint32_t idx = 0;
122  for (const lldb::tid_t &tid : tids) {
123  if (idx != 0 && m_add_return)
124  result.AppendMessage("");
125 
126  if (!HandleOneThread(tid, result))
127  return false;
128 
129  ++idx;
130  }
131  }
132  return result.Succeeded();
133 }
134 
136  lldb::tid_t tid, std::set<UniqueStack> &unique_stacks,
137  CommandReturnObject &result) {
138  // Grab the corresponding thread for the given thread id.
139  Process *process = m_exe_ctx.GetProcessPtr();
140  Thread *thread = process->GetThreadList().FindThreadByID(tid).get();
141  if (thread == nullptr) {
142  result.AppendErrorWithFormatv("Failed to process thread #{0}.\n", tid);
143  return false;
144  }
145 
146  // Collect the each frame's address for this call-stack
147  std::stack<lldb::addr_t> stack_frames;
148  const uint32_t frame_count = thread->GetStackFrameCount();
149  for (uint32_t frame_index = 0; frame_index < frame_count; frame_index++) {
150  const lldb::StackFrameSP frame_sp =
151  thread->GetStackFrameAtIndex(frame_index);
152  const lldb::addr_t pc = frame_sp->GetStackID().GetPC();
153  stack_frames.push(pc);
154  }
155 
156  uint32_t thread_index_id = thread->GetIndexID();
157  UniqueStack new_unique_stack(stack_frames, thread_index_id);
158 
159  // Try to match the threads stack to and existing entry.
160  std::set<UniqueStack>::iterator matching_stack =
161  unique_stacks.find(new_unique_stack);
162  if (matching_stack != unique_stacks.end()) {
163  matching_stack->AddThread(thread_index_id);
164  } else {
165  unique_stacks.insert(new_unique_stack);
166  }
167  return true;
168 }
169 
171  CommandReturnObject &result) {
172  Process &process = m_exe_ctx.GetProcessRef();
173 
174  std::vector<lldb::tid_t> tids;
175  const size_t num_args = command.GetArgumentCount();
176 
177  std::lock_guard<std::recursive_mutex> guard(
178  process.GetThreadList().GetMutex());
179 
180  if (num_args > 0 && ::strcmp(command.GetArgumentAtIndex(0), "all") == 0) {
181  for (ThreadSP thread_sp : process.Threads())
182  tids.push_back(thread_sp->GetID());
183  } else {
184  if (num_args == 0) {
185  Thread &thread = m_exe_ctx.GetThreadRef();
186  tids.push_back(thread.GetID());
187  }
188 
189  for (size_t i = 0; i < num_args; i++) {
190  uint32_t thread_idx;
191  if (!llvm::to_integer(command.GetArgumentAtIndex(i), thread_idx)) {
192  result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
193  command.GetArgumentAtIndex(i));
194  return false;
195  }
196 
197  ThreadSP thread = process.GetThreadList().FindThreadByIndexID(thread_idx);
198 
199  if (!thread) {
200  result.AppendErrorWithFormat("no thread with index: \"%s\"\n",
201  command.GetArgumentAtIndex(i));
202  return false;
203  }
204 
205  tids.push_back(thread->GetID());
206  }
207  }
208 
209  return DoExecuteOnThreads(command, result, tids);
210 }
lldb::eArgTypeThreadIndex
@ eArgTypeThreadIndex
Definition: lldb-enumerations.h:587
lldb_private::Stream::Format
void Format(const char *format, Args &&... args)
Definition: Stream.h:309
lldb_private::CommandObjectParsed
Definition: CommandObject.h:393
lldb_private::CommandObjectIterateOverThreads::m_unique_stacks
bool m_unique_stacks
Definition: CommandObjectThreadUtil.h:75
llvm
Definition: Debugger.h:50
lldb_private::CommandObjectIterateOverThreads::m_success_return
lldb::ReturnStatus m_success_return
Definition: CommandObjectThreadUtil.h:74
lldb_private::Thread::GetIndexID
uint32_t GetIndexID() const
Definition: Thread.cpp:1381
lldb_private::ExecutionContext::GetProcessPtr
Process * GetProcessPtr() const
Returns a pointer to the process object.
Definition: ExecutionContext.cpp:206
lldb_private::CommandObject::m_exe_ctx
ExecutionContext m_exe_ctx
Definition: CommandObject.h:373
lldb_private::CommandObjectIterateOverThreads::DoExecute
bool DoExecute(Args &command, CommandReturnObject &result) override
Definition: CommandObjectThreadUtil.cpp:37
lldb_private::Process
Definition: Process.h:338
lldb_private::CommandObjectMultipleThreads::DoExecute
bool DoExecute(Args &command, CommandReturnObject &result) override
Definition: CommandObjectThreadUtil.cpp:170
lldb_private::Process::GetThreadList
ThreadList & GetThreadList()
Definition: Process.h:2073
lldb_private::CommandObject::CommandArgumentData
Definition: CommandObject.h:89
lldb_private::Stream
Definition: Stream.h:28
lldb_private::Args
Definition: Args.h:33
lldb::addr_t
uint64_t addr_t
Definition: lldb-types.h:83
pc
@ pc
Definition: CompactUnwindInfo.cpp:1251
lldb_private::CommandReturnObject::Succeeded
bool Succeeded() const
Definition: CommandReturnObject.cpp:131
CommandReturnObject.h
lldb_private::CommandReturnObject::AppendErrorWithFormatv
void AppendErrorWithFormatv(const char *format, Args &&... args)
Definition: CommandReturnObject.h:130
lldb_private::ExecutionContext::GetThreadPtr
Thread * GetThreadPtr() const
Returns a pointer to the thread object.
Definition: ExecutionContext.h:399
lldb_private::ExecutionContext::GetProcessRef
Process & GetProcessRef() const
Returns a reference to the process object.
Definition: ExecutionContext.cpp:229
Process.h
lldb_private::CommandObject::m_arguments
std::vector< CommandArgumentEntry > m_arguments
Definition: CommandObject.h:380
lldb_private::ThreadList::FindThreadByID
lldb::ThreadSP FindThreadByID(lldb::tid_t tid, bool can_update=true)
Definition: ThreadList.cpp:103
lldb_private::Process::Threads
ThreadList::ThreadIterable Threads()
Definition: Process.h:2081
lldb_private::CommandObjectMultipleThreads::DoExecuteOnThreads
virtual bool DoExecuteOnThreads(Args &command, CommandReturnObject &result, llvm::ArrayRef< lldb::tid_t > tids)=0
Method that handles the command after the main arguments have been parsed.
lldb_private::Thread
Definition: Thread.h:61
lldb_private::CommandReturnObject::SetStatus
void SetStatus(lldb::ReturnStatus status)
Definition: CommandReturnObject.cpp:127
lldb_private::CommandReturnObject::GetOutputStream
Stream & GetOutputStream()
Definition: CommandReturnObject.h:46
lldb_private::ThreadList::GetMutex
std::recursive_mutex & GetMutex() const override
Definition: ThreadList.cpp:749
lldb_private::Thread::GetStackFrameCount
virtual uint32_t GetStackFrameCount()
Definition: Thread.h:394
lldb_private::CommandInterpreter
Definition: CommandInterpreter.h:214
lldb_private::eArgRepeatStar
@ eArgRepeatStar
Definition: lldb-private-enumerations.h:98
Thread.h
lldb_private::CommandObjectIterateOverThreads::m_add_return
bool m_add_return
Definition: CommandObjectThreadUtil.h:76
lldb_private::UserID::GetID
lldb::user_id_t GetID() const
Get accessor for the user ID.
Definition: UserID.h:47
lldb_private::CommandObjectMultipleThreads::CommandObjectMultipleThreads
CommandObjectMultipleThreads(CommandInterpreter &interpreter, const char *name, const char *help, const char *syntax, uint32_t flags)
Definition: CommandObjectThreadUtil.cpp:28
lldb_private::ExecutionContext::GetThreadRef
Thread & GetThreadRef() const
Returns a reference to the thread object.
Definition: ExecutionContext.cpp:234
lldb_private::Args::GetArgumentAtIndex
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
Definition: Args.cpp:259
lldb_private::CommandReturnObject
Definition: CommandReturnObject.h:26
uint32_t
lldb_private::Stream::EOL
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:128
lldb_private::CommandObjectIterateOverThreads::UniqueStack
Definition: CommandObjectThreadUtil.h:18
lldb_private::CommandReturnObject::AppendErrorWithFormat
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
Definition: CommandReturnObject.cpp:46
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
CommandObjectThreadUtil.h
lldb_private::ThreadList::FindThreadByIndexID
lldb::ThreadSP FindThreadByIndexID(uint32_t index_id, bool can_update=true)
Definition: ThreadList.cpp:209
lldb_private::CommandObjectIterateOverThreads::HandleOneThread
virtual bool HandleOneThread(lldb::tid_t, CommandReturnObject &result)=0
lldb_private::Thread::GetStackFrameAtIndex
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:398
lldb_private::CommandObjectIterateOverThreads::BucketThread
bool BucketThread(lldb::tid_t tid, std::set< UniqueStack > &unique_stacks, CommandReturnObject &result)
Definition: CommandObjectThreadUtil.cpp:135
lldb_private::Args::GetArgumentCount
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.h:118
lldb
Definition: SBAddress.h:15
lldb_private::CommandReturnObject::AppendMessage
void AppendMessage(llvm::StringRef in_string)
Definition: CommandReturnObject.cpp:88
lldb::tid_t
uint64_t tid_t
Definition: lldb-types.h:86