1 //===-- MachThreadList.cpp --------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  Created by Greg Clayton on 6/19/07.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "MachThreadList.h"
15 
16 #include <inttypes.h>
17 #include <sys/sysctl.h>
18 
19 #include "DNBLog.h"
20 #include "DNBThreadResumeActions.h"
21 #include "MachProcess.h"
22 
23 MachThreadList::MachThreadList() :
24     m_threads(),
25     m_threads_mutex(PTHREAD_MUTEX_RECURSIVE)
26 {
27 }
28 
29 MachThreadList::~MachThreadList()
30 {
31 }
32 
33 nub_state_t
34 MachThreadList::GetState(nub_thread_t tid)
35 {
36     MachThreadSP thread_sp (GetThreadByID (tid));
37     if (thread_sp)
38         return thread_sp->GetState();
39     return eStateInvalid;
40 }
41 
42 const char *
43 MachThreadList::GetName (nub_thread_t tid)
44 {
45     MachThreadSP thread_sp (GetThreadByID (tid));
46     if (thread_sp)
47         return thread_sp->GetName();
48     return NULL;
49 }
50 
51 nub_thread_t
52 MachThreadList::SetCurrentThread(nub_thread_t tid)
53 {
54     MachThreadSP thread_sp (GetThreadByID (tid));
55     if (thread_sp)
56     {
57         m_current_thread = thread_sp;
58         return tid;
59     }
60     return INVALID_NUB_THREAD;
61 }
62 
63 
64 bool
65 MachThreadList::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const
66 {
67     MachThreadSP thread_sp (GetThreadByID (tid));
68     if (thread_sp)
69         return thread_sp->GetStopException().GetStopInfo(stop_info);
70     return false;
71 }
72 
73 bool
74 MachThreadList::GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info)
75 {
76     mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
77     return ::thread_info (tid, THREAD_IDENTIFIER_INFO, (thread_info_t)ident_info, &count) == KERN_SUCCESS;
78 }
79 
80 void
81 MachThreadList::DumpThreadStoppedReason (nub_thread_t tid) const
82 {
83     MachThreadSP thread_sp (GetThreadByID (tid));
84     if (thread_sp)
85         thread_sp->GetStopException().DumpStopReason();
86 }
87 
88 const char *
89 MachThreadList::GetThreadInfo (nub_thread_t tid) const
90 {
91     MachThreadSP thread_sp (GetThreadByID (tid));
92     if (thread_sp)
93         return thread_sp->GetBasicInfoAsString();
94     return NULL;
95 }
96 
97 MachThreadSP
98 MachThreadList::GetThreadByID (nub_thread_t tid) const
99 {
100     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
101     MachThreadSP thread_sp;
102     const size_t num_threads = m_threads.size();
103     for (size_t idx = 0; idx < num_threads; ++idx)
104     {
105         if (m_threads[idx]->ThreadID() == tid)
106         {
107             thread_sp = m_threads[idx];
108             break;
109         }
110     }
111     return thread_sp;
112 }
113 
114 MachThreadSP
115 MachThreadList::GetThreadByMachPortNumber (thread_t mach_port_number) const
116 {
117     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
118     MachThreadSP thread_sp;
119     const size_t num_threads = m_threads.size();
120     for (size_t idx = 0; idx < num_threads; ++idx)
121     {
122         if (m_threads[idx]->MachPortNumber() == mach_port_number)
123         {
124             thread_sp = m_threads[idx];
125             break;
126         }
127     }
128     return thread_sp;
129 }
130 
131 nub_thread_t
132 MachThreadList::GetThreadIDByMachPortNumber (thread_t mach_port_number) const
133 {
134     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
135     MachThreadSP thread_sp;
136     const size_t num_threads = m_threads.size();
137     for (size_t idx = 0; idx < num_threads; ++idx)
138     {
139         if (m_threads[idx]->MachPortNumber() == mach_port_number)
140         {
141             return m_threads[idx]->ThreadID();
142         }
143     }
144     return INVALID_NUB_THREAD;
145 }
146 
147 bool
148 MachThreadList::GetRegisterValue (nub_thread_t tid, uint32_t reg_set_idx, uint32_t reg_idx, DNBRegisterValue *reg_value ) const
149 {
150     MachThreadSP thread_sp (GetThreadByID (tid));
151     if (thread_sp)
152         return thread_sp->GetRegisterValue(reg_set_idx, reg_idx, reg_value);
153 
154     return false;
155 }
156 
157 bool
158 MachThreadList::SetRegisterValue (nub_thread_t tid, uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value ) const
159 {
160     MachThreadSP thread_sp (GetThreadByID (tid));
161     if (thread_sp)
162         return thread_sp->SetRegisterValue(reg_set_idx, reg_idx, reg_value);
163 
164     return false;
165 }
166 
167 nub_size_t
168 MachThreadList::GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len)
169 {
170     MachThreadSP thread_sp (GetThreadByID (tid));
171     if (thread_sp)
172         return thread_sp->GetRegisterContext (buf, buf_len);
173     return 0;
174 }
175 
176 nub_size_t
177 MachThreadList::SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len)
178 {
179     MachThreadSP thread_sp (GetThreadByID (tid));
180     if (thread_sp)
181         return thread_sp->SetRegisterContext (buf, buf_len);
182     return 0;
183 }
184 
185 nub_size_t
186 MachThreadList::NumThreads () const
187 {
188     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
189     return m_threads.size();
190 }
191 
192 nub_thread_t
193 MachThreadList::ThreadIDAtIndex (nub_size_t idx) const
194 {
195     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
196     if (idx < m_threads.size())
197         return m_threads[idx]->ThreadID();
198     return INVALID_NUB_THREAD;
199 }
200 
201 nub_thread_t
202 MachThreadList::CurrentThreadID ( )
203 {
204     MachThreadSP thread_sp;
205     CurrentThread(thread_sp);
206     if (thread_sp.get())
207         return thread_sp->ThreadID();
208     return INVALID_NUB_THREAD;
209 }
210 
211 bool
212 MachThreadList::NotifyException(MachException::Data& exc)
213 {
214     MachThreadSP thread_sp (GetThreadByMachPortNumber (exc.thread_port));
215     if (thread_sp)
216     {
217         thread_sp->NotifyException(exc);
218         return true;
219     }
220     return false;
221 }
222 
223 void
224 MachThreadList::Clear()
225 {
226     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
227     m_threads.clear();
228 }
229 
230 uint32_t
231 MachThreadList::UpdateThreadList(MachProcess *process, bool update, MachThreadList::collection *new_threads)
232 {
233     // locker will keep a mutex locked until it goes out of scope
234     DNBLogThreadedIf (LOG_THREAD, "MachThreadList::UpdateThreadList (pid = %4.4x, update = %u) process stop count = %u", process->ProcessID(), update, process->StopCount());
235     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
236 
237 #if defined (__i386__) || defined (__x86_64__)
238     if (process->StopCount() == 0)
239     {
240         int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process->ProcessID() };
241         struct kinfo_proc processInfo;
242         size_t bufsize = sizeof(processInfo);
243         bool is_64_bit = false;
244         if (sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &processInfo, &bufsize, NULL, 0) == 0 && bufsize > 0)
245         {
246             if (processInfo.kp_proc.p_flag & P_LP64)
247                 is_64_bit = true;
248         }
249         if (is_64_bit)
250             DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64);
251         else
252             DNBArchProtocol::SetArchitecture(CPU_TYPE_I386);
253     }
254 #endif
255 
256     if (m_threads.empty() || update)
257     {
258         thread_array_t thread_list = NULL;
259         mach_msg_type_number_t thread_list_count = 0;
260         task_t task = process->Task().TaskPort();
261         DNBError err(::task_threads (task, &thread_list, &thread_list_count), DNBError::MachKernel);
262 
263         if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
264             err.LogThreaded("::task_threads ( task = 0x%4.4x, thread_list => %p, thread_list_count => %u )", task, thread_list, thread_list_count);
265 
266         if (err.Error() == KERN_SUCCESS && thread_list_count > 0)
267         {
268             MachThreadList::collection currThreads;
269             size_t idx;
270             // Iterator through the current thread list and see which threads
271             // we already have in our list (keep them), which ones we don't
272             // (add them), and which ones are not around anymore (remove them).
273             for (idx = 0; idx < thread_list_count; ++idx)
274             {
275                 const thread_t mach_port_num = thread_list[idx];
276 
277                 uint64_t unique_thread_id = MachThread::GetGloballyUniqueThreadIDForMachPortID (mach_port_num);
278                 MachThreadSP thread_sp (GetThreadByID (unique_thread_id));
279                 if (thread_sp)
280                 {
281                     // Keep the existing thread class
282                     currThreads.push_back(thread_sp);
283                 }
284                 else
285                 {
286                     // We don't have this thread, lets add it.
287                     thread_sp.reset(new MachThread(process, unique_thread_id, mach_port_num));
288 
289                     // Add the new thread regardless of its is user ready state...
290                     // Make sure the thread is ready to be displayed and shown to users
291                     // before we add this thread to our list...
292                     if (thread_sp->IsUserReady())
293                     {
294                         if (new_threads)
295                             new_threads->push_back(thread_sp);
296 
297                         currThreads.push_back(thread_sp);
298                     }
299                 }
300             }
301 
302             m_threads.swap(currThreads);
303             m_current_thread.reset();
304 
305             // Free the vm memory given to us by ::task_threads()
306             vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t));
307             ::vm_deallocate (::mach_task_self(),
308                              (vm_address_t)thread_list,
309                              thread_list_size);
310         }
311     }
312     return m_threads.size();
313 }
314 
315 
316 void
317 MachThreadList::CurrentThread (MachThreadSP& thread_sp)
318 {
319     // locker will keep a mutex locked until it goes out of scope
320     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
321     if (m_current_thread.get() == NULL)
322     {
323         // Figure out which thread is going to be our current thread.
324         // This is currently done by finding the first thread in the list
325         // that has a valid exception.
326         const uint32_t num_threads = m_threads.size();
327         for (uint32_t idx = 0; idx < num_threads; ++idx)
328         {
329             if (m_threads[idx]->GetStopException().IsValid())
330             {
331                 m_current_thread = m_threads[idx];
332                 break;
333             }
334         }
335     }
336     thread_sp = m_current_thread;
337 }
338 
339 void
340 MachThreadList::Dump() const
341 {
342     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
343     const uint32_t num_threads = m_threads.size();
344     for (uint32_t idx = 0; idx < num_threads; ++idx)
345     {
346         m_threads[idx]->Dump(idx);
347     }
348 }
349 
350 
351 void
352 MachThreadList::ProcessWillResume(MachProcess *process, const DNBThreadResumeActions &thread_actions)
353 {
354     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
355 
356     // Update our thread list, because sometimes libdispatch or the kernel
357     // will spawn threads while a task is suspended.
358     MachThreadList::collection new_threads;
359 
360     // First figure out if we were planning on running only one thread, and if so force that thread to resume.
361     bool run_one_thread;
362     nub_thread_t solo_thread = INVALID_NUB_THREAD;
363     if (thread_actions.GetSize() > 0
364         && thread_actions.NumActionsWithState(eStateStepping) + thread_actions.NumActionsWithState (eStateRunning) == 1)
365     {
366         run_one_thread = true;
367         const DNBThreadResumeAction *action_ptr = thread_actions.GetFirst();
368         size_t num_actions = thread_actions.GetSize();
369         for (size_t i = 0; i < num_actions; i++, action_ptr++)
370         {
371             if (action_ptr->state == eStateStepping || action_ptr->state == eStateRunning)
372             {
373                 solo_thread = action_ptr->tid;
374                 break;
375             }
376         }
377     }
378     else
379         run_one_thread = false;
380 
381     UpdateThreadList(process, true, &new_threads);
382 
383     DNBThreadResumeAction resume_new_threads = { -1U, eStateRunning, 0, INVALID_NUB_ADDRESS };
384     // If we are planning to run only one thread, any new threads should be suspended.
385     if (run_one_thread)
386         resume_new_threads.state = eStateSuspended;
387 
388     const uint32_t num_new_threads = new_threads.size();
389     const uint32_t num_threads = m_threads.size();
390     for (uint32_t idx = 0; idx < num_threads; ++idx)
391     {
392         MachThread *thread = m_threads[idx].get();
393         bool handled = false;
394         for (uint32_t new_idx = 0; new_idx < num_new_threads; ++new_idx)
395         {
396             if (thread == new_threads[new_idx].get())
397             {
398                 thread->ThreadWillResume(&resume_new_threads);
399                 handled = true;
400                 break;
401             }
402         }
403 
404         if (!handled)
405         {
406             const DNBThreadResumeAction *thread_action = thread_actions.GetActionForThread (thread->ThreadID(), true);
407             // There must always be a thread action for every thread.
408             assert (thread_action);
409             bool others_stopped = false;
410             if (solo_thread == thread->ThreadID())
411                 others_stopped = true;
412             thread->ThreadWillResume (thread_action, others_stopped);
413         }
414     }
415 
416     if (new_threads.size())
417     {
418         for (uint32_t idx = 0; idx < num_new_threads; ++idx)
419         {
420             DNBLogThreadedIf (LOG_THREAD, "MachThreadList::ProcessWillResume (pid = %4.4x) stop-id=%u, resuming newly discovered thread: 0x%8.8" PRIx64 ", thread-is-user-ready=%i)",
421                               process->ProcessID(),
422                               process->StopCount(),
423                               new_threads[idx]->ThreadID(),
424                               new_threads[idx]->IsUserReady());
425         }
426     }
427 }
428 
429 uint32_t
430 MachThreadList::ProcessDidStop(MachProcess *process)
431 {
432     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
433     // Update our thread list
434     const uint32_t num_threads = UpdateThreadList(process, true);
435     for (uint32_t idx = 0; idx < num_threads; ++idx)
436     {
437         m_threads[idx]->ThreadDidStop();
438     }
439     return num_threads;
440 }
441 
442 //----------------------------------------------------------------------
443 // Check each thread in our thread list to see if we should notify our
444 // client of the current halt in execution.
445 //
446 // Breakpoints can have callback functions associated with them than
447 // can return true to stop, or false to continue executing the inferior.
448 //
449 // RETURNS
450 //    true if we should stop and notify our clients
451 //    false if we should resume our child process and skip notification
452 //----------------------------------------------------------------------
453 bool
454 MachThreadList::ShouldStop(bool &step_more)
455 {
456     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
457     uint32_t should_stop = false;
458     const uint32_t num_threads = m_threads.size();
459     for (uint32_t idx = 0; !should_stop && idx < num_threads; ++idx)
460     {
461         should_stop = m_threads[idx]->ShouldStop(step_more);
462     }
463     return should_stop;
464 }
465 
466 
467 void
468 MachThreadList::NotifyBreakpointChanged (const DNBBreakpoint *bp)
469 {
470     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
471     const uint32_t num_threads = m_threads.size();
472     for (uint32_t idx = 0; idx < num_threads; ++idx)
473     {
474         m_threads[idx]->NotifyBreakpointChanged(bp);
475     }
476 }
477 
478 
479 uint32_t
480 MachThreadList::EnableHardwareBreakpoint (const DNBBreakpoint* bp) const
481 {
482     if (bp != NULL)
483     {
484         MachThreadSP thread_sp (GetThreadByID (bp->ThreadID()));
485         if (thread_sp)
486             return thread_sp->EnableHardwareBreakpoint(bp);
487     }
488     return INVALID_NUB_HW_INDEX;
489 }
490 
491 bool
492 MachThreadList::DisableHardwareBreakpoint (const DNBBreakpoint* bp) const
493 {
494     if (bp != NULL)
495     {
496         MachThreadSP thread_sp (GetThreadByID (bp->ThreadID()));
497         if (thread_sp)
498             return thread_sp->DisableHardwareBreakpoint(bp);
499     }
500     return false;
501 }
502 
503 // DNBWatchpointSet() -> MachProcess::CreateWatchpoint() -> MachProcess::EnableWatchpoint()
504 // -> MachThreadList::EnableHardwareWatchpoint().
505 uint32_t
506 MachThreadList::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const
507 {
508     uint32_t hw_index = INVALID_NUB_HW_INDEX;
509     if (wp != NULL)
510     {
511         PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
512         const uint32_t num_threads = m_threads.size();
513         for (uint32_t idx = 0; idx < num_threads; ++idx)
514         {
515             if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint(wp)) == INVALID_NUB_HW_INDEX)
516             {
517                 // We know that idx failed for some reason.  Let's rollback the transaction for [0, idx).
518                 for (uint32_t i = 0; i < idx; ++i)
519                     m_threads[i]->RollbackTransForHWP();
520                 return INVALID_NUB_HW_INDEX;
521             }
522         }
523         // Notify each thread to commit the pending transaction.
524         for (uint32_t idx = 0; idx < num_threads; ++idx)
525             m_threads[idx]->FinishTransForHWP();
526 
527         // Use an arbitrary thread to signal the completion of our transaction.
528         if (num_threads)
529             m_threads[0]->HardwareWatchpointStateChanged();
530     }
531     return hw_index;
532 }
533 
534 bool
535 MachThreadList::DisableHardwareWatchpoint (const DNBBreakpoint* wp) const
536 {
537     if (wp != NULL)
538     {
539         PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
540         const uint32_t num_threads = m_threads.size();
541         for (uint32_t idx = 0; idx < num_threads; ++idx)
542         {
543             if (!m_threads[idx]->DisableHardwareWatchpoint(wp))
544             {
545                 // We know that idx failed for some reason.  Let's rollback the transaction for [0, idx).
546                 for (uint32_t i = 0; i < idx; ++i)
547                     m_threads[i]->RollbackTransForHWP();
548                 return false;
549             }
550         }
551         // Notify each thread to commit the pending transaction.
552         for (uint32_t idx = 0; idx < num_threads; ++idx)
553             m_threads[idx]->FinishTransForHWP();
554 
555         // Use an arbitrary thread to signal the completion of our transaction.
556         if (num_threads)
557             m_threads[0]->HardwareWatchpointStateChanged();
558         return true;
559     }
560     return false;
561 }
562 
563 uint32_t
564 MachThreadList::NumSupportedHardwareWatchpoints () const
565 {
566     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
567     const uint32_t num_threads = m_threads.size();
568     // Use an arbitrary thread to retrieve the number of supported hardware watchpoints.
569     if (num_threads)
570         return m_threads[0]->NumSupportedHardwareWatchpoints();
571     return 0;
572 }
573 
574 uint32_t
575 MachThreadList::GetThreadIndexForThreadStoppedWithSignal (const int signo) const
576 {
577     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
578     uint32_t should_stop = false;
579     const uint32_t num_threads = m_threads.size();
580     for (uint32_t idx = 0; !should_stop && idx < num_threads; ++idx)
581     {
582         if (m_threads[idx]->GetStopException().SoftSignal () == signo)
583             return idx;
584     }
585     return UINT32_MAX;
586 }
587 
588