MachThreadList.cpp revision 44eb9fb021023027159df55f91c3e95384088970
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
23MachThreadList::MachThreadList() :
24    m_threads(),
25    m_threads_mutex(PTHREAD_MUTEX_RECURSIVE)
26{
27}
28
29MachThreadList::~MachThreadList()
30{
31}
32
33nub_state_t
34MachThreadList::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
42const char *
43MachThreadList::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
51nub_thread_t
52MachThreadList::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
64bool
65MachThreadList::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
73bool
74MachThreadList::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
80void
81MachThreadList::DumpThreadStoppedReason (nub_thread_t tid) const
82{
83    MachThreadSP thread_sp (GetThreadByID (tid));
84    if (thread_sp)
85        thread_sp->GetStopException().DumpStopReason();
86}
87
88const char *
89MachThreadList::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
97MachThreadSP
98MachThreadList::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
114MachThreadSP
115MachThreadList::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
131nub_thread_t
132MachThreadList::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
147bool
148MachThreadList::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
157bool
158MachThreadList::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
167nub_size_t
168MachThreadList::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
176nub_size_t
177MachThreadList::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
185nub_size_t
186MachThreadList::NumThreads () const
187{
188    PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
189    return m_threads.size();
190}
191
192nub_thread_t
193MachThreadList::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
201nub_thread_t
202MachThreadList::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
211bool
212MachThreadList::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
223void
224MachThreadList::Clear()
225{
226    PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
227    m_threads.clear();
228}
229
230uint32_t
231MachThreadList::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
316void
317MachThreadList::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
339void
340MachThreadList::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
351void
352MachThreadList::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
429uint32_t
430MachThreadList::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//----------------------------------------------------------------------
453bool
454MachThreadList::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
467void
468MachThreadList::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
479uint32_t
480MachThreadList::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
491bool
492MachThreadList::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().
505uint32_t
506MachThreadList::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
534bool
535MachThreadList::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
563uint32_t
564MachThreadList::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
574uint32_t
575MachThreadList::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