MachThread.cpp revision c72af6b67914810cafc34a83c403235de58d2051
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 thread) :
27    m_process (process),
28    m_tid (thread),
29    m_seq_id (GetSequenceID()),
30    m_state (eStateUnloaded),
31    m_state_mutex (PTHREAD_MUTEX_RECURSIVE),
32    m_breakID (INVALID_NUB_BREAK_ID),
33    m_suspend_count (0),
34    m_arch_ap (DNBArchProtocol::Create (this)),
35    m_reg_sets (m_arch_ap->GetRegisterSetInfo (&n_num_reg_sets)),
36    m_basic_info_valid (false)
37{
38    // Get the thread state so we know if a thread is in a state where we can't
39    // muck with it and also so we get the suspend count correct in case it was
40    // already suspended
41    GetBasicInfo(true);
42    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::MachThread ( process = %p, tid = 0x%4.4x, seq_id = %u )", &m_process, m_tid, m_seq_id);
43}
44
45MachThread::~MachThread()
46{
47    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::~MachThread() for tid = 0x%4.4x (%u)", m_tid, m_seq_id);
48}
49
50
51
52int32_t
53MachThread::Suspend()
54{
55    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
56    if (ThreadIDIsValid(m_tid))
57    {
58        DNBError err(::thread_suspend (m_tid), DNBError::MachKernel);
59        if (err.Success())
60            m_suspend_count++;
61        if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
62            err.LogThreaded("::thread_suspend (%4.4x)", m_tid);
63    }
64    return m_suspend_count;
65}
66
67int32_t
68MachThread::ForceResume ()
69{
70    // We need to resume this all the way to 0.
71    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
72    // Okay, now m_basic_info has the full suspend count.  So I'll just
73    // keep decrementing the suspend count till that is zero, and at the same time
74    // decrement m_suspend_count.  If that goes below zero, then the next time we
75    // call RestoreSuspendCount, we'll have to suspend it back to 0.
76    uint32_t num_suspends = m_basic_info.suspend_count + m_suspend_count;
77    DNBError err;
78    while (num_suspends > 0)
79    {
80        if (m_suspend_count < 0)
81         DNBLogThreadedIf(LOG_THREAD, "MachThread::%s ( ) (tid = %4.4x) setting suspend count negative = %d", __FUNCTION__,
82                     m_tid, m_suspend_count);
83        err = ::thread_resume (m_tid);
84        if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
85            err.LogThreaded("ForceResume ::thread_resume (%4.4x)", m_tid);
86        if (err.Success())
87        {
88            --m_suspend_count;
89            --num_suspends;
90        }
91        else
92        {
93            break;
94        }
95    }
96    return m_suspend_count;
97
98}
99
100int32_t
101MachThread::Resume()
102{
103    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
104    if (ThreadIDIsValid(m_tid))
105    {
106        RestoreSuspendCount();
107    }
108    return m_suspend_count;
109}
110
111bool
112MachThread::RestoreSuspendCount()
113{
114    DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( ) (tid = %4.4x) our suspend count = %d", __FUNCTION__,
115                     m_tid, m_suspend_count);
116    DNBError err;
117    if (ThreadIDIsValid(m_tid) == false)
118        return false;
119    if (m_suspend_count > 0)
120    {
121        while (m_suspend_count > 0)
122        {
123            err = ::thread_resume (m_tid);
124            if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
125                err.LogThreaded("RestoreSuspendCount ::thread_resume (%4.4x)", m_tid);
126            if (err.Success())
127                --m_suspend_count;
128            else
129            {
130                if (GetBasicInfo(true))
131                    m_suspend_count = m_basic_info.suspend_count;
132                else
133                    m_suspend_count = 0;
134                return false; // ???
135            }
136        }
137    }
138    else if (m_suspend_count < 0)
139    {
140         DNBLogThreadedIf(LOG_THREAD, "MachThread::%s ( ) (tid = %4.4x) negative suspend count = %d", __FUNCTION__,
141                     m_tid, m_suspend_count);
142        while (m_suspend_count < 0)
143        {
144            err = ::thread_suspend (m_tid);
145            if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
146                err.LogThreaded("RestoreSuspendCount ::thread_suspend (%4.4x)", m_tid);
147
148            if (err.Success())
149                ++m_suspend_count;
150            else
151            {
152                if (GetBasicInfo(true))
153                    m_suspend_count = m_basic_info.suspend_count;
154                else
155                    m_suspend_count = 0;
156                return false; // ???
157            }
158
159        }
160    }
161    return true;
162}
163
164
165const char *
166MachThread::GetBasicInfoAsString () const
167{
168    static char g_basic_info_string[1024];
169    struct thread_basic_info basicInfo;
170
171    if (GetBasicInfo(m_tid, &basicInfo))
172    {
173
174//        char run_state_str[32];
175//        size_t run_state_str_size = sizeof(run_state_str);
176//        switch (basicInfo.run_state)
177//        {
178//        case TH_STATE_RUNNING:          strncpy(run_state_str, "running", run_state_str_size); break;
179//        case TH_STATE_STOPPED:          strncpy(run_state_str, "stopped", run_state_str_size); break;
180//        case TH_STATE_WAITING:          strncpy(run_state_str, "waiting", run_state_str_size); break;
181//        case TH_STATE_UNINTERRUPTIBLE:  strncpy(run_state_str, "uninterruptible", run_state_str_size); break;
182//        case TH_STATE_HALTED:           strncpy(run_state_str, "halted", run_state_str_size); break;
183//        default:                        snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break;    // ???
184//        }
185        float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
186        float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
187        snprintf(g_basic_info_string, sizeof(g_basic_info_string), "Thread 0x%4.4x: user=%f system=%f cpu=%d sleep_time=%d",
188            InferiorThreadID(),
189            user,
190            system,
191            basicInfo.cpu_usage,
192            basicInfo.sleep_time);
193
194        return g_basic_info_string;
195    }
196    return NULL;
197}
198
199thread_t
200MachThread::InferiorThreadID() const
201{
202    mach_msg_type_number_t i;
203    mach_port_name_array_t names;
204    mach_port_type_array_t types;
205    mach_msg_type_number_t ncount, tcount;
206    thread_t inferior_tid = INVALID_NUB_THREAD;
207    task_t my_task = ::mach_task_self();
208    task_t task = m_process->Task().TaskPort();
209
210    kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount);
211    if (kret == KERN_SUCCESS)
212    {
213
214        for (i = 0; i < ncount; i++)
215        {
216            mach_port_t my_name;
217            mach_msg_type_name_t my_type;
218
219            kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type);
220            if (kret == KERN_SUCCESS)
221            {
222                ::mach_port_deallocate (my_task, my_name);
223                if (my_name == m_tid)
224                {
225                    inferior_tid = names[i];
226                    break;
227                }
228            }
229        }
230        // Free up the names and types
231        ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t));
232        ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t));
233    }
234    return inferior_tid;
235}
236
237bool
238MachThread::IsUserReady()
239{
240    GetBasicInfo (false);
241
242    switch (m_basic_info.run_state)
243    {
244    default:
245    case TH_STATE_UNINTERRUPTIBLE:
246        break;
247
248    case TH_STATE_RUNNING:
249    case TH_STATE_STOPPED:
250    case TH_STATE_WAITING:
251    case TH_STATE_HALTED:
252        return true;
253    }
254    return false;
255}
256
257struct thread_basic_info *
258MachThread::GetBasicInfo (bool force)
259{
260    if (!force && m_basic_info_valid)
261        return &m_basic_info;
262
263    if (MachThread::GetBasicInfo(m_tid, &m_basic_info))
264    {
265        m_basic_info_valid = true;
266        return &m_basic_info;
267    }
268    return NULL;
269}
270
271
272bool
273MachThread::GetBasicInfo(thread_t thread, struct thread_basic_info *basicInfoPtr)
274{
275    if (ThreadIDIsValid(thread))
276    {
277        unsigned int info_count = THREAD_BASIC_INFO_COUNT;
278        kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count);
279        if (err == KERN_SUCCESS)
280            return true;
281    }
282    ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info));
283    return false;
284}
285
286
287bool
288MachThread::ThreadIDIsValid(thread_t thread)
289{
290    return thread != THREAD_NULL;
291}
292
293bool
294MachThread::GetRegisterState(int flavor, bool force)
295{
296    return m_arch_ap->GetRegisterState(flavor, force) == KERN_SUCCESS;
297}
298
299bool
300MachThread::SetRegisterState(int flavor)
301{
302    return m_arch_ap->SetRegisterState(flavor) == KERN_SUCCESS;
303}
304
305uint64_t
306MachThread::GetPC(uint64_t failValue)
307{
308    // Get program counter
309    return m_arch_ap->GetPC(failValue);
310}
311
312bool
313MachThread::SetPC(uint64_t value)
314{
315    // Set program counter
316    return m_arch_ap->SetPC(value);
317}
318
319uint64_t
320MachThread::GetSP(uint64_t failValue)
321{
322    // Get stack pointer
323    return m_arch_ap->GetSP(failValue);
324}
325
326nub_process_t
327MachThread::ProcessID() const
328{
329    if (m_process)
330        return m_process->ProcessID();
331    return INVALID_NUB_PROCESS;
332}
333
334void
335MachThread::Dump(uint32_t index)
336{
337    const char * thread_run_state = NULL;
338
339    switch (m_basic_info.run_state)
340    {
341    case TH_STATE_RUNNING:          thread_run_state = "running"; break;    // 1 thread is running normally
342    case TH_STATE_STOPPED:          thread_run_state = "stopped"; break;    // 2 thread is stopped
343    case TH_STATE_WAITING:          thread_run_state = "waiting"; break;    // 3 thread is waiting normally
344    case TH_STATE_UNINTERRUPTIBLE:  thread_run_state = "uninter"; break;    // 4 thread is in an uninterruptible wait
345    case TH_STATE_HALTED:           thread_run_state = "halted "; break;     // 5 thread is halted at a
346    default:                        thread_run_state = "???"; break;
347    }
348
349    DNBLogThreaded("[%3u] #%3u tid: 0x%4.4x, pc: 0x%16.16llx, sp: 0x%16.16llx, breakID: %3d, user: %d.%06.6d, system: %d.%06.6d, cpu: %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d",
350        index,
351        m_seq_id,
352        m_tid,
353        GetPC(INVALID_NUB_ADDRESS),
354        GetSP(INVALID_NUB_ADDRESS),
355        m_breakID,
356        m_basic_info.user_time.seconds,      m_basic_info.user_time.microseconds,
357        m_basic_info.system_time.seconds,    m_basic_info.system_time.microseconds,
358        m_basic_info.cpu_usage,
359        m_basic_info.policy,
360        m_basic_info.run_state,
361        thread_run_state,
362        m_basic_info.flags,
363        m_basic_info.suspend_count, m_suspend_count,
364        m_basic_info.sleep_time);
365    //DumpRegisterState(0);
366}
367
368void
369MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action)
370{
371    if (thread_action->addr != INVALID_NUB_ADDRESS)
372        SetPC (thread_action->addr);
373    // DidStop restores the state to it's natural state, and sets
374    // m_suspend_count to 0 in the process, and then here is the only
375    // place that we should be suspending or resuming (and thus changing
376    // that state.
377    assert (m_suspend_count == 0);
378    SetState (thread_action->state);
379    switch (thread_action->state)
380    {
381    case eStateStopped:
382    case eStateSuspended:
383        Suspend();
384        break;
385
386    case eStateRunning:
387        Resume();
388        break;
389    case eStateStepping:
390        ForceResume();
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    RestoreSuspendCount();
494
495    // Update the basic information for a thread
496    GetBasicInfo (true);
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    if (m_stop_exception.IsValid())
551    {
552        // We may have more than one exception for a thread, but we need to
553        // only remember the one that we will say is the reason we stopped.
554        // We may have been single stepping and also gotten a signal exception,
555        // so just remember the most pertinent one.
556        if (m_stop_exception.IsBreakpoint())
557            m_stop_exception = exc;
558    }
559    else
560    {
561        m_stop_exception = exc;
562    }
563    bool handled = m_arch_ap->NotifyException(exc);
564    if (!handled)
565    {
566        handled = true;
567//        switch (exc.exc_type)
568//        {
569//        case EXC_BAD_ACCESS:
570//            break;
571//        case EXC_BAD_INSTRUCTION:
572//            break;
573//        case EXC_ARITHMETIC:
574//            break;
575//        case EXC_EMULATION:
576//            break;
577//        case EXC_SOFTWARE:
578//            break;
579//        case EXC_BREAKPOINT:
580//            break;
581//        case EXC_SYSCALL:
582//            break;
583//        case EXC_MACH_SYSCALL:
584//            break;
585//        case EXC_RPC_ALERT:
586//            break;
587//        }
588    }
589    return handled;
590}
591
592
593nub_state_t
594MachThread::GetState()
595{
596    // If any other threads access this we will need a mutex for it
597    PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
598    return m_state;
599}
600
601void
602MachThread::SetState(nub_state_t state)
603{
604    PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
605    m_state = state;
606    DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%4.4x", DNBStateAsString(state), m_tid);
607}
608
609uint32_t
610MachThread::GetNumRegistersInSet(int regSet) const
611{
612    if (regSet < n_num_reg_sets)
613        return m_reg_sets[regSet].num_registers;
614    return 0;
615}
616
617const char *
618MachThread::GetRegisterSetName(int regSet) const
619{
620    if (regSet < n_num_reg_sets)
621        return m_reg_sets[regSet].name;
622    return NULL;
623}
624
625const DNBRegisterInfo *
626MachThread::GetRegisterInfo(int regSet, int regIndex) const
627{
628    if (regSet < n_num_reg_sets)
629        if (regIndex < m_reg_sets[regSet].num_registers)
630            return &m_reg_sets[regSet].registers[regIndex];
631    return NULL;
632}
633void
634MachThread::DumpRegisterState(int regSet)
635{
636    if (regSet == REGISTER_SET_ALL)
637    {
638        for (regSet = 1; regSet < n_num_reg_sets; regSet++)
639            DumpRegisterState(regSet);
640    }
641    else
642    {
643        if (m_arch_ap->RegisterSetStateIsValid(regSet))
644        {
645            const size_t numRegisters = GetNumRegistersInSet(regSet);
646            size_t regIndex = 0;
647            DNBRegisterValueClass reg;
648            for (regIndex = 0; regIndex < numRegisters; ++regIndex)
649            {
650                if (m_arch_ap->GetRegisterValue(regSet, regIndex, &reg))
651                {
652                    reg.Dump(NULL, NULL);
653                }
654            }
655        }
656        else
657        {
658            DNBLog("%s: registers are not currently valid.", GetRegisterSetName(regSet));
659        }
660    }
661}
662
663const DNBRegisterSetInfo *
664MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const
665{
666    *num_reg_sets = n_num_reg_sets;
667    return &m_reg_sets[0];
668}
669
670bool
671MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value )
672{
673    return m_arch_ap->GetRegisterValue(set, reg, value);
674}
675
676bool
677MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value )
678{
679    return m_arch_ap->SetRegisterValue(set, reg, value);
680}
681
682nub_size_t
683MachThread::GetRegisterContext (void *buf, nub_size_t buf_len)
684{
685    return m_arch_ap->GetRegisterContext(buf, buf_len);
686}
687
688nub_size_t
689MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len)
690{
691    return m_arch_ap->SetRegisterContext(buf, buf_len);
692}
693
694uint32_t
695MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp)
696{
697    if (bp != NULL && bp->IsBreakpoint())
698        return m_arch_ap->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize());
699    return INVALID_NUB_HW_INDEX;
700}
701
702uint32_t
703MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp)
704{
705    if (wp != NULL && wp->IsWatchpoint())
706        return m_arch_ap->EnableHardwareWatchpoint(wp->Address(), wp->ByteSize(), wp->WatchpointRead(), wp->WatchpointWrite());
707    return INVALID_NUB_HW_INDEX;
708}
709
710bool
711MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp)
712{
713    if (bp != NULL && bp->IsHardware())
714        return m_arch_ap->DisableHardwareBreakpoint(bp->GetHardwareIndex());
715    return false;
716}
717
718bool
719MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp)
720{
721    if (wp != NULL && wp->IsHardware())
722        return m_arch_ap->DisableHardwareWatchpoint(wp->GetHardwareIndex());
723    return false;
724}
725
726bool
727MachThread::GetIdentifierInfo ()
728{
729#ifdef THREAD_IDENTIFIER_INFO_COUNT
730    if (m_ident_info.thread_id == 0)
731    {
732        mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
733        return ::thread_info (ThreadID(), THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count) == KERN_SUCCESS;
734    }
735#endif
736
737    return false;
738}
739
740
741const char *
742MachThread::GetName ()
743{
744    if (GetIdentifierInfo ())
745    {
746        int len = ::proc_pidinfo (m_process->ProcessID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo));
747
748        if (len && m_proc_threadinfo.pth_name[0])
749            return m_proc_threadinfo.pth_name;
750    }
751    return NULL;
752}
753
754
755//
756//const char *
757//MachThread::GetDispatchQueueName()
758//{
759//    if (GetIdentifierInfo ())
760//    {
761//        if (m_ident_info.dispatch_qaddr == 0)
762//            return NULL;
763//
764//        uint8_t memory_buffer[8];
765//        DNBDataRef data(memory_buffer, sizeof(memory_buffer), false);
766//        ModuleSP module_sp(GetProcess()->GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libSystem.B.dylib")));
767//        if (module_sp.get() == NULL)
768//            return NULL;
769//
770//        lldb::addr_t dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS;
771//        const Symbol *dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (ConstString("dispatch_queue_offsets"), eSymbolTypeData);
772//        if (dispatch_queue_offsets_symbol)
773//            dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetValue().GetLoadAddress(GetProcess());
774//
775//        if (dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
776//            return NULL;
777//
778//        // Excerpt from src/queue_private.h
779//        struct dispatch_queue_offsets_s
780//        {
781//            uint16_t dqo_version;
782//            uint16_t dqo_label;
783//            uint16_t dqo_label_size;
784//        } dispatch_queue_offsets;
785//
786//
787//        if (GetProcess()->ReadMemory (dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets)) == sizeof(dispatch_queue_offsets))
788//        {
789//            uint32_t data_offset = 0;
790//            if (data.GetU16(&data_offset, &dispatch_queue_offsets.dqo_version, sizeof(dispatch_queue_offsets)/sizeof(uint16_t)))
791//            {
792//                if (GetProcess()->ReadMemory (m_ident_info.dispatch_qaddr, &memory_buffer, data.GetAddressByteSize()) == data.GetAddressByteSize())
793//                {
794//                    data_offset = 0;
795//                    lldb::addr_t queue_addr = data.GetAddress(&data_offset);
796//                    lldb::addr_t label_addr = queue_addr + dispatch_queue_offsets.dqo_label;
797//                    const size_t chunk_size = 32;
798//                    uint32_t label_pos = 0;
799//                    m_dispatch_queue_name.resize(chunk_size, '\0');
800//                    while (1)
801//                    {
802//                        size_t bytes_read = GetProcess()->ReadMemory (label_addr + label_pos, &m_dispatch_queue_name[label_pos], chunk_size);
803//
804//                        if (bytes_read <= 0)
805//                            break;
806//
807//                        if (m_dispatch_queue_name.find('\0', label_pos) != std::string::npos)
808//                            break;
809//                        label_pos += bytes_read;
810//                    }
811//                    m_dispatch_queue_name.erase(m_dispatch_queue_name.find('\0'));
812//                }
813//            }
814//        }
815//    }
816//
817//    if (m_dispatch_queue_name.empty())
818//        return NULL;
819//    return m_dispatch_queue_name.c_str();
820//}
821