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