MachThread.cpp revision 0e8147bd867e4cdaae9400f56d02c7aacd40a9b3
1//===-- MachThread.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 "MachThread.h"
15#include "MachProcess.h"
16#include "DNBLog.h"
17#include "DNB.h"
18
19static uint32_t
20GetSequenceID()
21{
22    static uint32_t g_nextID = 0;
23    return ++g_nextID;
24}
25
26MachThread::MachThread (MachProcess *process, thread_t tid) :
27    m_process (process),
28    m_tid (tid),
29    m_seq_id (GetSequenceID()),
30    m_state (eStateUnloaded),
31    m_state_mutex (PTHREAD_MUTEX_RECURSIVE),
32    m_break_id (INVALID_NUB_BREAK_ID),
33    m_suspend_count (0),
34    m_stop_exception (),
35    m_arch_ap (DNBArchProtocol::Create (this)),
36    m_reg_sets (NULL),
37    m_num_reg_sets (0)
38#ifdef THREAD_IDENTIFIER_INFO_COUNT
39    , m_ident_info(),
40    m_proc_threadinfo(),
41    m_dispatch_queue_name()
42#endif
43{
44    nub_size_t num_reg_sets = 0;
45    m_reg_sets = m_arch_ap->GetRegisterSetInfo (&num_reg_sets);
46    m_num_reg_sets = num_reg_sets;
47
48    // Get the thread state so we know if a thread is in a state where we can't
49    // muck with it and also so we get the suspend count correct in case it was
50    // already suspended
51    GetBasicInfo();
52    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::MachThread ( process = %p, tid = 0x%4.4x, seq_id = %u )", &m_process, m_tid, m_seq_id);
53}
54
55MachThread::~MachThread()
56{
57    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::~MachThread() for tid = 0x%4.4x (%u)", m_tid, m_seq_id);
58}
59
60
61
62void
63MachThread::Suspend()
64{
65    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
66    if (ThreadIDIsValid(m_tid))
67    {
68        DNBError err(::thread_suspend (m_tid), DNBError::MachKernel);
69        if (err.Success())
70            m_suspend_count++;
71        if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
72            err.LogThreaded("::thread_suspend (%4.4x)", m_tid);
73    }
74}
75
76void
77MachThread::Resume(bool others_stopped)
78{
79    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
80    if (ThreadIDIsValid(m_tid))
81    {
82        SetSuspendCountBeforeResume(others_stopped);
83    }
84}
85
86bool
87MachThread::SetSuspendCountBeforeResume(bool others_stopped)
88{
89    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
90    DNBError err;
91    if (ThreadIDIsValid(m_tid) == false)
92        return false;
93
94    size_t times_to_resume;
95
96    if (others_stopped)
97    {
98        times_to_resume = GetBasicInfo()->suspend_count;
99        m_suspend_count = - (times_to_resume - m_suspend_count);
100    }
101    else
102    {
103        times_to_resume = m_suspend_count;
104        m_suspend_count = 0;
105    }
106
107    if (times_to_resume > 0)
108    {
109        while (times_to_resume > 0)
110        {
111            err = ::thread_resume (m_tid);
112            if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
113                err.LogThreaded("::thread_resume (%4.4x)", m_tid);
114            if (err.Success())
115                --times_to_resume;
116            else
117            {
118                if (GetBasicInfo())
119                    times_to_resume = m_basic_info.suspend_count;
120                else
121                    times_to_resume = 0;
122            }
123        }
124    }
125    return true;
126}
127
128bool
129MachThread::RestoreSuspendCountAfterStop ()
130{
131    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
132    DNBError err;
133    if (ThreadIDIsValid(m_tid) == false)
134        return false;
135
136    if (m_suspend_count > 0)
137    {
138        while (m_suspend_count > 0)
139        {
140            err = ::thread_resume (m_tid);
141            if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
142                err.LogThreaded("::thread_resume (%4.4x)", m_tid);
143            if (err.Success())
144                --m_suspend_count;
145            else
146            {
147                if (GetBasicInfo())
148                    m_suspend_count = m_basic_info.suspend_count;
149                else
150                    m_suspend_count = 0;
151                return false; // ???
152            }
153        }
154    }
155    else if (m_suspend_count < 0)
156    {
157        while (m_suspend_count < 0)
158        {
159            err = ::thread_suspend (m_tid);
160            if (err.Success())
161                ++m_suspend_count;
162            if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
163            {
164                err.LogThreaded("::thread_suspend (%4.4x)", m_tid);
165                return false;
166            }
167        }
168    }
169    return true;
170}
171
172
173const char *
174MachThread::GetBasicInfoAsString () const
175{
176    static char g_basic_info_string[1024];
177    struct thread_basic_info basicInfo;
178
179    if (GetBasicInfo(m_tid, &basicInfo))
180    {
181
182//        char run_state_str[32];
183//        size_t run_state_str_size = sizeof(run_state_str);
184//        switch (basicInfo.run_state)
185//        {
186//        case TH_STATE_RUNNING:          strncpy(run_state_str, "running", run_state_str_size); break;
187//        case TH_STATE_STOPPED:          strncpy(run_state_str, "stopped", run_state_str_size); break;
188//        case TH_STATE_WAITING:          strncpy(run_state_str, "waiting", run_state_str_size); break;
189//        case TH_STATE_UNINTERRUPTIBLE:  strncpy(run_state_str, "uninterruptible", run_state_str_size); break;
190//        case TH_STATE_HALTED:           strncpy(run_state_str, "halted", run_state_str_size); break;
191//        default:                        snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break;    // ???
192//        }
193        float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
194        float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
195        snprintf(g_basic_info_string, sizeof(g_basic_info_string), "Thread 0x%4.4x: user=%f system=%f cpu=%d sleep_time=%d",
196            InferiorThreadID(),
197            user,
198            system,
199            basicInfo.cpu_usage,
200            basicInfo.sleep_time);
201
202        return g_basic_info_string;
203    }
204    return NULL;
205}
206
207thread_t
208MachThread::InferiorThreadID() const
209{
210    mach_msg_type_number_t i;
211    mach_port_name_array_t names;
212    mach_port_type_array_t types;
213    mach_msg_type_number_t ncount, tcount;
214    thread_t inferior_tid = INVALID_NUB_THREAD;
215    task_t my_task = ::mach_task_self();
216    task_t task = m_process->Task().TaskPort();
217
218    kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount);
219    if (kret == KERN_SUCCESS)
220    {
221
222        for (i = 0; i < ncount; i++)
223        {
224            mach_port_t my_name;
225            mach_msg_type_name_t my_type;
226
227            kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type);
228            if (kret == KERN_SUCCESS)
229            {
230                ::mach_port_deallocate (my_task, my_name);
231                if (my_name == m_tid)
232                {
233                    inferior_tid = names[i];
234                    break;
235                }
236            }
237        }
238        // Free up the names and types
239        ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t));
240        ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t));
241    }
242    return inferior_tid;
243}
244
245bool
246MachThread::IsUserReady()
247{
248    if (m_basic_info.run_state == 0)
249        GetBasicInfo ();
250
251    switch (m_basic_info.run_state)
252    {
253    default:
254    case TH_STATE_UNINTERRUPTIBLE:
255        break;
256
257    case TH_STATE_RUNNING:
258    case TH_STATE_STOPPED:
259    case TH_STATE_WAITING:
260    case TH_STATE_HALTED:
261        return true;
262    }
263    return false;
264}
265
266struct thread_basic_info *
267MachThread::GetBasicInfo ()
268{
269    if (MachThread::GetBasicInfo(m_tid, &m_basic_info))
270        return &m_basic_info;
271    return NULL;
272}
273
274
275bool
276MachThread::GetBasicInfo(thread_t thread, struct thread_basic_info *basicInfoPtr)
277{
278    if (ThreadIDIsValid(thread))
279    {
280        unsigned int info_count = THREAD_BASIC_INFO_COUNT;
281        kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count);
282        if (err == KERN_SUCCESS)
283            return true;
284    }
285    ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info));
286    return false;
287}
288
289
290bool
291MachThread::ThreadIDIsValid(thread_t thread)
292{
293    return thread != THREAD_NULL;
294}
295
296bool
297MachThread::GetRegisterState(int flavor, bool force)
298{
299    return m_arch_ap->GetRegisterState(flavor, force) == KERN_SUCCESS;
300}
301
302bool
303MachThread::SetRegisterState(int flavor)
304{
305    return m_arch_ap->SetRegisterState(flavor) == KERN_SUCCESS;
306}
307
308uint64_t
309MachThread::GetPC(uint64_t failValue)
310{
311    // Get program counter
312    return m_arch_ap->GetPC(failValue);
313}
314
315bool
316MachThread::SetPC(uint64_t value)
317{
318    // Set program counter
319    return m_arch_ap->SetPC(value);
320}
321
322uint64_t
323MachThread::GetSP(uint64_t failValue)
324{
325    // Get stack pointer
326    return m_arch_ap->GetSP(failValue);
327}
328
329nub_process_t
330MachThread::ProcessID() const
331{
332    if (m_process)
333        return m_process->ProcessID();
334    return INVALID_NUB_PROCESS;
335}
336
337void
338MachThread::Dump(uint32_t index)
339{
340    const char * thread_run_state = NULL;
341
342    switch (m_basic_info.run_state)
343    {
344    case TH_STATE_RUNNING:          thread_run_state = "running"; break;    // 1 thread is running normally
345    case TH_STATE_STOPPED:          thread_run_state = "stopped"; break;    // 2 thread is stopped
346    case TH_STATE_WAITING:          thread_run_state = "waiting"; break;    // 3 thread is waiting normally
347    case TH_STATE_UNINTERRUPTIBLE:  thread_run_state = "uninter"; break;    // 4 thread is in an uninterruptible wait
348    case TH_STATE_HALTED:           thread_run_state = "halted "; break;     // 5 thread is halted at a
349    default:                        thread_run_state = "???"; break;
350    }
351
352    DNBLogThreaded("[%3u] #%3u tid: 0x%4.4x, pc: 0x%16.16llx, sp: 0x%16.16llx, breakID: %3d, user: %d.%6.6d, system: %d.%6.6d, cpu: %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d",
353        index,
354        m_seq_id,
355        m_tid,
356        GetPC(INVALID_NUB_ADDRESS),
357        GetSP(INVALID_NUB_ADDRESS),
358        m_break_id,
359        m_basic_info.user_time.seconds,      m_basic_info.user_time.microseconds,
360        m_basic_info.system_time.seconds,    m_basic_info.system_time.microseconds,
361        m_basic_info.cpu_usage,
362        m_basic_info.policy,
363        m_basic_info.run_state,
364        thread_run_state,
365        m_basic_info.flags,
366        m_basic_info.suspend_count, m_suspend_count,
367        m_basic_info.sleep_time);
368    //DumpRegisterState(0);
369}
370
371void
372MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action, bool others_stopped)
373{
374    if (thread_action->addr != INVALID_NUB_ADDRESS)
375        SetPC (thread_action->addr);
376
377    SetState (thread_action->state);
378    switch (thread_action->state)
379    {
380    case eStateStopped:
381    case eStateSuspended:
382        assert (others_stopped == false);
383        Suspend();
384        break;
385
386    case eStateRunning:
387    case eStateStepping:
388        Resume(others_stopped);
389        break;
390    default:
391        break;
392    }
393    m_arch_ap->ThreadWillResume();
394    m_stop_exception.Clear();
395}
396
397nub_break_t
398MachThread::CurrentBreakpoint()
399{
400    return m_process->Breakpoints().FindIDByAddress(GetPC());
401}
402
403bool
404MachThread::ShouldStop(bool &step_more)
405{
406    // See if this thread is at a breakpoint?
407    nub_break_t breakID = CurrentBreakpoint();
408
409    if (NUB_BREAK_ID_IS_VALID(breakID))
410    {
411        // This thread is sitting at a breakpoint, ask the breakpoint
412        // if we should be stopping here.
413        if (Process()->Breakpoints().ShouldStop(ProcessID(), ThreadID(), breakID))
414            return true;
415        else
416        {
417            // The breakpoint said we shouldn't stop, but we may have gotten
418            // a signal or the user may have requested to stop in some other
419            // way. Stop if we have a valid exception (this thread won't if
420            // another thread was the reason this process stopped) and that
421            // exception, is NOT a breakpoint exception (a common case would
422            // be a SIGINT signal).
423            if (GetStopException().IsValid() && !GetStopException().IsBreakpoint())
424                return true;
425        }
426    }
427    else
428    {
429        if (m_arch_ap->StepNotComplete())
430        {
431            step_more = true;
432            return false;
433        }
434        // The thread state is used to let us know what the thread was
435        // trying to do. MachThread::ThreadWillResume() will set the
436        // thread state to various values depending if the thread was
437        // the current thread and if it was to be single stepped, or
438        // resumed.
439        if (GetState() == eStateRunning)
440        {
441            // If our state is running, then we should continue as we are in
442            // the process of stepping over a breakpoint.
443            return false;
444        }
445        else
446        {
447            // Stop if we have any kind of valid exception for this
448            // thread.
449            if (GetStopException().IsValid())
450                return true;
451        }
452    }
453    return false;
454}
455bool
456MachThread::IsStepping()
457{
458#if ENABLE_AUTO_STEPPING_OVER_BP
459    // Return true if this thread is currently being stepped.
460    // MachThread::ThreadWillResume currently determines this by looking if we
461    // have been asked to single step, or if we are at a breakpoint instruction
462    // and have been asked to resume. In the latter case we need to disable the
463    // breakpoint we are at, single step, re-enable and continue.
464    nub_state_t state = GetState();
465    return ((state == eStateStepping) ||
466            (state == eStateRunning && NUB_BREAK_ID_IS_VALID(CurrentBreakpoint())));
467#else
468    return GetState() == eStateStepping;
469#endif
470}
471
472
473bool
474MachThread::ThreadDidStop()
475{
476    // This thread has existed prior to resuming under debug nub control,
477    // and has just been stopped. Do any cleanup that needs to be done
478    // after running.
479
480    // The thread state and breakpoint will still have the same values
481    // as they had prior to resuming the thread, so it makes it easy to check
482    // if we were trying to step a thread, or we tried to resume while being
483    // at a breakpoint.
484
485    // When this method gets called, the process state is still in the
486    // state it was in while running so we can act accordingly.
487    m_arch_ap->ThreadDidStop();
488
489
490    // We may have suspended this thread so the primary thread could step
491    // without worrying about race conditions, so lets restore our suspend
492    // count.
493    RestoreSuspendCountAfterStop();
494
495    // Update the basic information for a thread
496    MachThread::GetBasicInfo(m_tid, &m_basic_info);
497
498#if ENABLE_AUTO_STEPPING_OVER_BP
499    // See if we were at a breakpoint when we last resumed that we disabled,
500    // re-enable it.
501    nub_break_t breakID = CurrentBreakpoint();
502
503    if (NUB_BREAK_ID_IS_VALID(breakID))
504    {
505        m_process->EnableBreakpoint(breakID);
506        if (m_basic_info.suspend_count > 0)
507        {
508            SetState(eStateSuspended);
509        }
510        else
511        {
512            // If we last were at a breakpoint and we single stepped, our state
513            // will be "running" to indicate we need to continue after stepping
514            // over the breakpoint instruction. If we step over a breakpoint
515            // instruction, we need to stop.
516            if (GetState() == eStateRunning)
517            {
518                // Leave state set to running so we will continue automatically
519                // from this breakpoint
520            }
521            else
522            {
523                SetState(eStateStopped);
524            }
525        }
526    }
527    else
528    {
529        if (m_basic_info.suspend_count > 0)
530        {
531            SetState(eStateSuspended);
532        }
533        else
534        {
535            SetState(eStateStopped);
536        }
537    }
538#else
539    if (m_basic_info.suspend_count > 0)
540        SetState(eStateSuspended);
541    else
542        SetState(eStateStopped);
543#endif
544    return true;
545}
546
547bool
548MachThread::NotifyException(MachException::Data& exc)
549{
550    // Allow the arch specific protocol to process (MachException::Data &)exc
551    // first before possible reassignment of m_stop_exception with exc.
552    // See also MachThread::GetStopException().
553    bool handled = m_arch_ap->NotifyException(exc);
554
555    if (m_stop_exception.IsValid())
556    {
557        // We may have more than one exception for a thread, but we need to
558        // only remember the one that we will say is the reason we stopped.
559        // We may have been single stepping and also gotten a signal exception,
560        // so just remember the most pertinent one.
561        if (m_stop_exception.IsBreakpoint())
562            m_stop_exception = exc;
563    }
564    else
565    {
566        m_stop_exception = exc;
567    }
568
569    return handled;
570}
571
572
573nub_state_t
574MachThread::GetState()
575{
576    // If any other threads access this we will need a mutex for it
577    PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
578    return m_state;
579}
580
581void
582MachThread::SetState(nub_state_t state)
583{
584    PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
585    m_state = state;
586    DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%4.4x", DNBStateAsString(state), m_tid);
587}
588
589uint32_t
590MachThread::GetNumRegistersInSet(int regSet) const
591{
592    if (regSet < m_num_reg_sets)
593        return m_reg_sets[regSet].num_registers;
594    return 0;
595}
596
597const char *
598MachThread::GetRegisterSetName(int regSet) const
599{
600    if (regSet < m_num_reg_sets)
601        return m_reg_sets[regSet].name;
602    return NULL;
603}
604
605const DNBRegisterInfo *
606MachThread::GetRegisterInfo(int regSet, int regIndex) const
607{
608    if (regSet < m_num_reg_sets)
609        if (regIndex < m_reg_sets[regSet].num_registers)
610            return &m_reg_sets[regSet].registers[regIndex];
611    return NULL;
612}
613void
614MachThread::DumpRegisterState(int regSet)
615{
616    if (regSet == REGISTER_SET_ALL)
617    {
618        for (regSet = 1; regSet < m_num_reg_sets; regSet++)
619            DumpRegisterState(regSet);
620    }
621    else
622    {
623        if (m_arch_ap->RegisterSetStateIsValid(regSet))
624        {
625            const size_t numRegisters = GetNumRegistersInSet(regSet);
626            size_t regIndex = 0;
627            DNBRegisterValueClass reg;
628            for (regIndex = 0; regIndex < numRegisters; ++regIndex)
629            {
630                if (m_arch_ap->GetRegisterValue(regSet, regIndex, &reg))
631                {
632                    reg.Dump(NULL, NULL);
633                }
634            }
635        }
636        else
637        {
638            DNBLog("%s: registers are not currently valid.", GetRegisterSetName(regSet));
639        }
640    }
641}
642
643const DNBRegisterSetInfo *
644MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const
645{
646    *num_reg_sets = m_num_reg_sets;
647    return &m_reg_sets[0];
648}
649
650bool
651MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value )
652{
653    return m_arch_ap->GetRegisterValue(set, reg, value);
654}
655
656bool
657MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value )
658{
659    return m_arch_ap->SetRegisterValue(set, reg, value);
660}
661
662nub_size_t
663MachThread::GetRegisterContext (void *buf, nub_size_t buf_len)
664{
665    return m_arch_ap->GetRegisterContext(buf, buf_len);
666}
667
668nub_size_t
669MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len)
670{
671    return m_arch_ap->SetRegisterContext(buf, buf_len);
672}
673
674uint32_t
675MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp)
676{
677    if (bp != NULL && bp->IsBreakpoint())
678        return m_arch_ap->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize());
679    return INVALID_NUB_HW_INDEX;
680}
681
682uint32_t
683MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp)
684{
685    if (wp != NULL && wp->IsWatchpoint())
686        return m_arch_ap->EnableHardwareWatchpoint(wp->Address(), wp->ByteSize(), wp->WatchpointRead(), wp->WatchpointWrite());
687    return INVALID_NUB_HW_INDEX;
688}
689
690// Provide a chance to update the global view of the hardware watchpoint state.
691void
692MachThread::HardwareWatchpointStateChanged ()
693{
694    m_arch_ap->HardwareWatchpointStateChanged();
695}
696
697bool
698MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp)
699{
700    if (bp != NULL && bp->IsHardware())
701        return m_arch_ap->DisableHardwareBreakpoint(bp->GetHardwareIndex());
702    return false;
703}
704
705bool
706MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp)
707{
708    if (wp != NULL && wp->IsHardware())
709        return m_arch_ap->DisableHardwareWatchpoint(wp->GetHardwareIndex());
710    return false;
711}
712
713bool
714MachThread::GetIdentifierInfo ()
715{
716#ifdef THREAD_IDENTIFIER_INFO_COUNT
717        // Don't try to get the thread info once and cache it for the life of the thread.  It changes over time, for instance
718        // if the thread name changes, then the thread_handle also changes...  So you have to refetch it every time.
719        mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
720        kern_return_t kret = ::thread_info (ThreadID(), THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);
721        return kret == KERN_SUCCESS;
722#endif
723
724    return false;
725}
726
727
728const char *
729MachThread::GetName ()
730{
731    if (GetIdentifierInfo ())
732    {
733        int len = ::proc_pidinfo (m_process->ProcessID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo));
734
735        if (len && m_proc_threadinfo.pth_name[0])
736            return m_proc_threadinfo.pth_name;
737    }
738    return NULL;
739}
740
741