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 
25  CommandReturnObject &result) {
27 
28  bool all_threads = false;
29  if (command.GetArgumentCount() == 0) {
30  Thread *thread = m_exe_ctx.GetThreadPtr();
31  if (!thread || !HandleOneThread(thread->GetID(), result))
32  return false;
33  return result.Succeeded();
34  } else if (command.GetArgumentCount() == 1) {
35  all_threads = ::strcmp(command.GetArgumentAtIndex(0), "all") == 0;
36  m_unique_stacks = ::strcmp(command.GetArgumentAtIndex(0), "unique") == 0;
37  }
38 
39  // Use tids instead of ThreadSPs to prevent deadlocking problems which
40  // result from JIT-ing code while iterating over the (locked) ThreadSP
41  // list.
42  std::vector<lldb::tid_t> tids;
43 
44  if (all_threads || m_unique_stacks) {
45  Process *process = m_exe_ctx.GetProcessPtr();
46 
47  for (ThreadSP thread_sp : process->Threads())
48  tids.push_back(thread_sp->GetID());
49  } else {
50  const size_t num_args = command.GetArgumentCount();
51  Process *process = m_exe_ctx.GetProcessPtr();
52 
53  std::lock_guard<std::recursive_mutex> guard(
54  process->GetThreadList().GetMutex());
55 
56  for (size_t i = 0; i < num_args; i++) {
57  uint32_t thread_idx;
58  if (!llvm::to_integer(command.GetArgumentAtIndex(i), thread_idx)) {
59  result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
60  command.GetArgumentAtIndex(i));
61  return false;
62  }
63 
64  ThreadSP thread =
65  process->GetThreadList().FindThreadByIndexID(thread_idx);
66 
67  if (!thread) {
68  result.AppendErrorWithFormat("no thread with index: \"%s\"\n",
69  command.GetArgumentAtIndex(i));
70  return false;
71  }
72 
73  tids.push_back(thread->GetID());
74  }
75  }
76 
77  if (m_unique_stacks) {
78  // Iterate over threads, finding unique stack buckets.
79  std::set<UniqueStack> unique_stacks;
80  for (const lldb::tid_t &tid : tids) {
81  if (!BucketThread(tid, unique_stacks, result)) {
82  return false;
83  }
84  }
85 
86  // Write the thread id's and unique call stacks to the output stream
87  Stream &strm = result.GetOutputStream();
88  Process *process = m_exe_ctx.GetProcessPtr();
89  for (const UniqueStack &stack : unique_stacks) {
90  // List the common thread ID's
91  const std::vector<uint32_t> &thread_index_ids =
92  stack.GetUniqueThreadIndexIDs();
93  strm.Format("{0} thread(s) ", thread_index_ids.size());
94  for (const uint32_t &thread_index_id : thread_index_ids) {
95  strm.Format("#{0} ", thread_index_id);
96  }
97  strm.EOL();
98 
99  // List the shared call stack for this set of threads
100  uint32_t representative_thread_id = stack.GetRepresentativeThread();
101  ThreadSP thread = process->GetThreadList().FindThreadByIndexID(
102  representative_thread_id);
103  if (!HandleOneThread(thread->GetID(), result)) {
104  return false;
105  }
106  }
107  } else {
108  uint32_t idx = 0;
109  for (const lldb::tid_t &tid : tids) {
110  if (idx != 0 && m_add_return)
111  result.AppendMessage("");
112 
113  if (!HandleOneThread(tid, result))
114  return false;
115 
116  ++idx;
117  }
118  }
119  return result.Succeeded();
120 }
121 
123  lldb::tid_t tid, std::set<UniqueStack> &unique_stacks,
124  CommandReturnObject &result) {
125  // Grab the corresponding thread for the given thread id.
126  Process *process = m_exe_ctx.GetProcessPtr();
127  Thread *thread = process->GetThreadList().FindThreadByID(tid).get();
128  if (thread == nullptr) {
129  result.AppendErrorWithFormatv("Failed to process thread #{0}.\n", tid);
130  return false;
131  }
132 
133  // Collect the each frame's address for this call-stack
134  std::stack<lldb::addr_t> stack_frames;
135  const uint32_t frame_count = thread->GetStackFrameCount();
136  for (uint32_t frame_index = 0; frame_index < frame_count; frame_index++) {
137  const lldb::StackFrameSP frame_sp =
138  thread->GetStackFrameAtIndex(frame_index);
139  const lldb::addr_t pc = frame_sp->GetStackID().GetPC();
140  stack_frames.push(pc);
141  }
142 
143  uint32_t thread_index_id = thread->GetIndexID();
144  UniqueStack new_unique_stack(stack_frames, thread_index_id);
145 
146  // Try to match the threads stack to and existing entry.
147  std::set<UniqueStack>::iterator matching_stack =
148  unique_stacks.find(new_unique_stack);
149  if (matching_stack != unique_stacks.end()) {
150  matching_stack->AddThread(thread_index_id);
151  } else {
152  unique_stacks.insert(new_unique_stack);
153  }
154  return true;
155 }
156 
158  CommandReturnObject &result) {
159  Process &process = m_exe_ctx.GetProcessRef();
160 
161  std::vector<lldb::tid_t> tids;
162  const size_t num_args = command.GetArgumentCount();
163 
164  std::lock_guard<std::recursive_mutex> guard(
165  process.GetThreadList().GetMutex());
166 
167  if (num_args > 0 && ::strcmp(command.GetArgumentAtIndex(0), "all") == 0) {
168  for (ThreadSP thread_sp : process.Threads())
169  tids.push_back(thread_sp->GetID());
170  } else {
171  if (num_args == 0) {
172  Thread &thread = m_exe_ctx.GetThreadRef();
173  tids.push_back(thread.GetID());
174  }
175 
176  for (size_t i = 0; i < num_args; i++) {
177  uint32_t thread_idx;
178  if (!llvm::to_integer(command.GetArgumentAtIndex(i), thread_idx)) {
179  result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
180  command.GetArgumentAtIndex(i));
181  return false;
182  }
183 
184  ThreadSP thread = process.GetThreadList().FindThreadByIndexID(thread_idx);
185 
186  if (!thread) {
187  result.AppendErrorWithFormat("no thread with index: \"%s\"\n",
188  command.GetArgumentAtIndex(i));
189  return false;
190  }
191 
192  tids.push_back(thread->GetID());
193  }
194  }
195 
196  return DoExecuteOnThreads(command, result, tids);
197 }
lldb_private::Stream::Format
void Format(const char *format, Args &&... args)
Definition: Stream.h:309
lldb_private::CommandObjectParsed
Definition: CommandObject.h:394
lldb_private::CommandObjectIterateOverThreads::m_unique_stacks
bool m_unique_stacks
Definition: CommandObjectThreadUtil.h:75
llvm
Definition: Debugger.h:49
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:1387
lldb_private::ExecutionContext::GetProcessPtr
Process * GetProcessPtr() const
Returns a pointer to the process object.
Definition: ExecutionContext.cpp:208
lldb_private::CommandObject::m_exe_ctx
ExecutionContext m_exe_ctx
Definition: CommandObject.h:374
lldb_private::CommandObjectIterateOverThreads::DoExecute
bool DoExecute(Args &command, CommandReturnObject &result) override
Definition: CommandObjectThreadUtil.cpp:24
lldb_private::Process
Definition: Process.h:341
lldb_private::CommandObjectMultipleThreads::DoExecute
bool DoExecute(Args &command, CommandReturnObject &result) override
Definition: CommandObjectThreadUtil.cpp:157
lldb_private::Process::GetThreadList
ThreadList & GetThreadList()
Definition: Process.h:2108
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:1250
CommandReturnObject.h
lldb_private::CommandReturnObject::AppendErrorWithFormatv
void AppendErrorWithFormatv(const char *format, Args &&... args)
Definition: CommandReturnObject.h:129
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:231
Process.h
lldb_private::ThreadList::FindThreadByID
lldb::ThreadSP FindThreadByID(lldb::tid_t tid, bool can_update=true)
Definition: ThreadList.cpp:102
lldb_private::Process::Threads
ThreadList::ThreadIterable Threads()
Definition: Process.h:2116
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:60
lldb_private::CommandReturnObject::SetStatus
void SetStatus(lldb::ReturnStatus status)
Definition: CommandReturnObject.cpp:121
lldb_private::CommandReturnObject::GetOutputStream
Stream & GetOutputStream()
Definition: CommandReturnObject.h:45
lldb_private::ThreadList::GetMutex
std::recursive_mutex & GetMutex() const override
Definition: ThreadList.cpp:748
lldb_private::Thread::GetStackFrameCount
virtual uint32_t GetStackFrameCount()
Definition: Thread.h:393
lldb_private::CommandInterpreter
Definition: CommandInterpreter.h:214
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::ExecutionContext::GetThreadRef
Thread & GetThreadRef() const
Returns a reference to the thread object.
Definition: ExecutionContext.cpp:236
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:25
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::Succeeded
bool Succeeded()
Definition: CommandReturnObject.cpp:125
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:208
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:397
lldb_private::CommandObjectIterateOverThreads::BucketThread
bool BucketThread(lldb::tid_t tid, std::set< UniqueStack > &unique_stacks, CommandReturnObject &result)
Definition: CommandObjectThreadUtil.cpp:122
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