Home | History | Annotate | Download | only in MacOSX
      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 
     20 static uint32_t
     21 GetSequenceID()
     22 {
     23     static uint32_t g_nextID = 0;
     24     return ++g_nextID;
     25 }
     26 
     27 MachThread::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 
     54 MachThread::~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 
     61 void
     62 MachThread::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 
     75 void
     76 MachThread::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 
     85 bool
     86 MachThread::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 
    132 bool
    133 MachThread::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 
    177 const char *
    178 MachThread::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.
    212 thread_t
    213 MachThread::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 
    250 bool
    251 MachThread::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 
    271 struct thread_basic_info *
    272 MachThread::GetBasicInfo ()
    273 {
    274     if (MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info))
    275         return &m_basic_info;
    276     return NULL;
    277 }
    278 
    279 
    280 bool
    281 MachThread::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 
    295 bool
    296 MachThread::ThreadIDIsValid(uint64_t thread)
    297 {
    298     return thread != 0;
    299 }
    300 
    301 bool
    302 MachThread::MachPortNumberIsValid(thread_t thread)
    303 {
    304     return thread != THREAD_NULL;
    305 }
    306 
    307 bool
    308 MachThread::GetRegisterState(int flavor, bool force)
    309 {
    310     return m_arch_ap->GetRegisterState(flavor, force) == KERN_SUCCESS;
    311 }
    312 
    313 bool
    314 MachThread::SetRegisterState(int flavor)
    315 {
    316     return m_arch_ap->SetRegisterState(flavor) == KERN_SUCCESS;
    317 }
    318 
    319 uint64_t
    320 MachThread::GetPC(uint64_t failValue)
    321 {
    322     // Get program counter
    323     return m_arch_ap->GetPC(failValue);
    324 }
    325 
    326 bool
    327 MachThread::SetPC(uint64_t value)
    328 {
    329     // Set program counter
    330     return m_arch_ap->SetPC(value);
    331 }
    332 
    333 uint64_t
    334 MachThread::GetSP(uint64_t failValue)
    335 {
    336     // Get stack pointer
    337     return m_arch_ap->GetSP(failValue);
    338 }
    339 
    340 nub_process_t
    341 MachThread::ProcessID() const
    342 {
    343     if (m_process)
    344         return m_process->ProcessID();
    345     return INVALID_NUB_PROCESS;
    346 }
    347 
    348 void
    349 MachThread::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 
    381 void
    382 MachThread::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 
    407 DNBBreakpoint *
    408 MachThread::CurrentBreakpoint()
    409 {
    410     return m_process->Breakpoints().FindByAddress(GetPC());
    411 }
    412 
    413 bool
    414 MachThread::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 }
    453 bool
    454 MachThread::IsStepping()
    455 {
    456     return GetState() == eStateStepping;
    457 }
    458 
    459 
    460 bool
    461 MachThread::ThreadDidStop()
    462 {
    463     // This thread has existed prior to resuming under debug nub control,
    464     // and has just been stopped. Do any cleanup that needs to be done
    465     // after running.
    466 
    467     // The thread state and breakpoint will still have the same values
    468     // as they had prior to resuming the thread, so it makes it easy to check
    469     // if we were trying to step a thread, or we tried to resume while being
    470     // at a breakpoint.
    471 
    472     // When this method gets called, the process state is still in the
    473     // state it was in while running so we can act accordingly.
    474     m_arch_ap->ThreadDidStop();
    475 
    476 
    477     // We may have suspended this thread so the primary thread could step
    478     // without worrying about race conditions, so lets restore our suspend
    479     // count.
    480     RestoreSuspendCountAfterStop();
    481 
    482     // Update the basic information for a thread
    483     MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info);
    484 
    485     if (m_basic_info.suspend_count > 0)
    486         SetState(eStateSuspended);
    487     else
    488         SetState(eStateStopped);
    489     return true;
    490 }
    491 
    492 bool
    493 MachThread::NotifyException(MachException::Data& exc)
    494 {
    495     // Allow the arch specific protocol to process (MachException::Data &)exc
    496     // first before possible reassignment of m_stop_exception with exc.
    497     // See also MachThread::GetStopException().
    498     bool handled = m_arch_ap->NotifyException(exc);
    499 
    500     if (m_stop_exception.IsValid())
    501     {
    502         // We may have more than one exception for a thread, but we need to
    503         // only remember the one that we will say is the reason we stopped.
    504         // We may have been single stepping and also gotten a signal exception,
    505         // so just remember the most pertinent one.
    506         if (m_stop_exception.IsBreakpoint())
    507             m_stop_exception = exc;
    508     }
    509     else
    510     {
    511         m_stop_exception = exc;
    512     }
    513 
    514     return handled;
    515 }
    516 
    517 
    518 nub_state_t
    519 MachThread::GetState()
    520 {
    521     // If any other threads access this we will need a mutex for it
    522     PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
    523     return m_state;
    524 }
    525 
    526 void
    527 MachThread::SetState(nub_state_t state)
    528 {
    529     PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
    530     m_state = state;
    531     DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%8.8" PRIx64 "", DNBStateAsString(state), m_unique_id);
    532 }
    533 
    534 uint32_t
    535 MachThread::GetNumRegistersInSet(int regSet) const
    536 {
    537     if (regSet < m_num_reg_sets)
    538         return m_reg_sets[regSet].num_registers;
    539     return 0;
    540 }
    541 
    542 const char *
    543 MachThread::GetRegisterSetName(int regSet) const
    544 {
    545     if (regSet < m_num_reg_sets)
    546         return m_reg_sets[regSet].name;
    547     return NULL;
    548 }
    549 
    550 const DNBRegisterInfo *
    551 MachThread::GetRegisterInfo(int regSet, int regIndex) const
    552 {
    553     if (regSet < m_num_reg_sets)
    554         if (regIndex < m_reg_sets[regSet].num_registers)
    555             return &m_reg_sets[regSet].registers[regIndex];
    556     return NULL;
    557 }
    558 void
    559 MachThread::DumpRegisterState(int regSet)
    560 {
    561     if (regSet == REGISTER_SET_ALL)
    562     {
    563         for (regSet = 1; regSet < m_num_reg_sets; regSet++)
    564             DumpRegisterState(regSet);
    565     }
    566     else
    567     {
    568         if (m_arch_ap->RegisterSetStateIsValid(regSet))
    569         {
    570             const size_t numRegisters = GetNumRegistersInSet(regSet);
    571             size_t regIndex = 0;
    572             DNBRegisterValueClass reg;
    573             for (regIndex = 0; regIndex < numRegisters; ++regIndex)
    574             {
    575                 if (m_arch_ap->GetRegisterValue(regSet, regIndex, &reg))
    576                 {
    577                     reg.Dump(NULL, NULL);
    578                 }
    579             }
    580         }
    581         else
    582         {
    583             DNBLog("%s: registers are not currently valid.", GetRegisterSetName(regSet));
    584         }
    585     }
    586 }
    587 
    588 const DNBRegisterSetInfo *
    589 MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const
    590 {
    591     *num_reg_sets = m_num_reg_sets;
    592     return &m_reg_sets[0];
    593 }
    594 
    595 bool
    596 MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value )
    597 {
    598     return m_arch_ap->GetRegisterValue(set, reg, value);
    599 }
    600 
    601 bool
    602 MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value )
    603 {
    604     return m_arch_ap->SetRegisterValue(set, reg, value);
    605 }
    606 
    607 nub_size_t
    608 MachThread::GetRegisterContext (void *buf, nub_size_t buf_len)
    609 {
    610     return m_arch_ap->GetRegisterContext(buf, buf_len);
    611 }
    612 
    613 nub_size_t
    614 MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len)
    615 {
    616     return m_arch_ap->SetRegisterContext(buf, buf_len);
    617 }
    618 
    619 uint32_t
    620 MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp)
    621 {
    622     if (bp != NULL && bp->IsBreakpoint())
    623         return m_arch_ap->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize());
    624     return INVALID_NUB_HW_INDEX;
    625 }
    626 
    627 uint32_t
    628 MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp, bool also_set_on_task)
    629 {
    630     if (wp != NULL && wp->IsWatchpoint())
    631         return m_arch_ap->EnableHardwareWatchpoint(wp->Address(), wp->ByteSize(), wp->WatchpointRead(), wp->WatchpointWrite(), also_set_on_task);
    632     return INVALID_NUB_HW_INDEX;
    633 }
    634 
    635 bool
    636 MachThread::RollbackTransForHWP()
    637 {
    638     return m_arch_ap->RollbackTransForHWP();
    639 }
    640 
    641 bool
    642 MachThread::FinishTransForHWP()
    643 {
    644     return m_arch_ap->FinishTransForHWP();
    645 }
    646 
    647 bool
    648 MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp)
    649 {
    650     if (bp != NULL && bp->IsHardware())
    651         return m_arch_ap->DisableHardwareBreakpoint(bp->GetHardwareIndex());
    652     return false;
    653 }
    654 
    655 bool
    656 MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp, bool also_set_on_task)
    657 {
    658     if (wp != NULL && wp->IsHardware())
    659         return m_arch_ap->DisableHardwareWatchpoint(wp->GetHardwareIndex(), also_set_on_task);
    660     return false;
    661 }
    662 
    663 uint32_t
    664 MachThread::NumSupportedHardwareWatchpoints () const
    665 {
    666     return m_arch_ap->NumSupportedHardwareWatchpoints();
    667 }
    668 
    669 bool
    670 MachThread::GetIdentifierInfo ()
    671 {
    672         // Don't try to get the thread info once and cache it for the life of the thread.  It changes over time, for instance
    673         // if the thread name changes, then the thread_handle also changes...  So you have to refetch it every time.
    674         mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
    675         kern_return_t kret = ::thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);
    676         return kret == KERN_SUCCESS;
    677 
    678     return false;
    679 }
    680 
    681 
    682 const char *
    683 MachThread::GetName ()
    684 {
    685     if (GetIdentifierInfo ())
    686     {
    687         int len = ::proc_pidinfo (m_process->ProcessID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo));
    688 
    689         if (len && m_proc_threadinfo.pth_name[0])
    690             return m_proc_threadinfo.pth_name;
    691     }
    692     return NULL;
    693 }
    694 
    695 
    696 uint64_t
    697 MachThread::GetGloballyUniqueThreadIDForMachPortID (thread_t mach_port_id)
    698 {
    699     kern_return_t kr;
    700     thread_identifier_info_data_t tident;
    701     mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
    702     kr = thread_info (mach_port_id, THREAD_IDENTIFIER_INFO,
    703                       (thread_info_t) &tident, &tident_count);
    704     if (kr != KERN_SUCCESS)
    705     {
    706         return mach_port_id;
    707     }
    708     return tident.thread_id;
    709 }
    710