130fdc8d8SChris Lattner //===-- MachThread.cpp ------------------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 330fdc8d8SChris Lattner // The LLVM Compiler Infrastructure 430fdc8d8SChris Lattner // 530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source 630fdc8d8SChris Lattner // License. See LICENSE.TXT for details. 730fdc8d8SChris Lattner // 830fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 930fdc8d8SChris Lattner // 1030fdc8d8SChris Lattner // Created by Greg Clayton on 6/19/07. 1130fdc8d8SChris Lattner // 1230fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 1330fdc8d8SChris Lattner 141c73911dSJason Molenda #include <inttypes.h> 1530fdc8d8SChris Lattner #include "MachThread.h" 1630fdc8d8SChris Lattner #include "MachProcess.h" 1730fdc8d8SChris Lattner #include "DNBLog.h" 1830fdc8d8SChris Lattner #include "DNB.h" 1930fdc8d8SChris Lattner 2030fdc8d8SChris Lattner static uint32_t 2130fdc8d8SChris Lattner GetSequenceID() 2230fdc8d8SChris Lattner { 2330fdc8d8SChris Lattner static uint32_t g_nextID = 0; 2430fdc8d8SChris Lattner return ++g_nextID; 2530fdc8d8SChris Lattner } 2630fdc8d8SChris Lattner 271c73911dSJason Molenda MachThread::MachThread (MachProcess *process, uint64_t unique_thread_id, thread_t mach_port_num) : 2830fdc8d8SChris Lattner m_process (process), 291c73911dSJason Molenda m_unique_id (unique_thread_id), 301c73911dSJason Molenda m_mach_port_number (mach_port_num), 3130fdc8d8SChris Lattner m_seq_id (GetSequenceID()), 3230fdc8d8SChris Lattner m_state (eStateUnloaded), 3330fdc8d8SChris Lattner m_state_mutex (PTHREAD_MUTEX_RECURSIVE), 34c235ac76SGreg Clayton m_suspend_count (0), 35c235ac76SGreg Clayton m_stop_exception (), 363af9ea56SGreg Clayton m_arch_ap (DNBArchProtocol::Create (this)), 37c235ac76SGreg Clayton m_reg_sets (NULL), 381c73911dSJason Molenda m_num_reg_sets (0), 391c73911dSJason Molenda m_ident_info(), 40c235ac76SGreg Clayton m_proc_threadinfo(), 41c235ac76SGreg Clayton m_dispatch_queue_name() 4230fdc8d8SChris Lattner { 43c235ac76SGreg Clayton nub_size_t num_reg_sets = 0; 44c235ac76SGreg Clayton m_reg_sets = m_arch_ap->GetRegisterSetInfo (&num_reg_sets); 45c235ac76SGreg Clayton m_num_reg_sets = num_reg_sets; 46c235ac76SGreg Clayton 471b946bf6SGreg Clayton // Get the thread state so we know if a thread is in a state where we can't 481b946bf6SGreg Clayton // muck with it and also so we get the suspend count correct in case it was 491b946bf6SGreg Clayton // already suspended 50cdc7322bSGreg Clayton GetBasicInfo(); 511c73911dSJason Molenda 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); 5230fdc8d8SChris Lattner } 5330fdc8d8SChris Lattner 5430fdc8d8SChris Lattner MachThread::~MachThread() 5530fdc8d8SChris Lattner { 561c73911dSJason Molenda DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::~MachThread() for tid = 0x%8.8" PRIx64 " (%u)", m_unique_id, m_seq_id); 5730fdc8d8SChris Lattner } 5830fdc8d8SChris Lattner 5930fdc8d8SChris Lattner 6030fdc8d8SChris Lattner 619411ddb6SJim Ingham void 6230fdc8d8SChris Lattner MachThread::Suspend() 6330fdc8d8SChris Lattner { 6430fdc8d8SChris Lattner DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); 651c73911dSJason Molenda if (MachPortNumberIsValid(m_mach_port_number)) 6630fdc8d8SChris Lattner { 671c73911dSJason Molenda DNBError err(::thread_suspend (m_mach_port_number), DNBError::MachKernel); 6830fdc8d8SChris Lattner if (err.Success()) 69c235ac76SGreg Clayton m_suspend_count++; 7030fdc8d8SChris Lattner if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 711c73911dSJason Molenda err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number); 7230fdc8d8SChris Lattner } 7330fdc8d8SChris Lattner } 7430fdc8d8SChris Lattner 759411ddb6SJim Ingham void 769411ddb6SJim Ingham MachThread::Resume(bool others_stopped) 7730fdc8d8SChris Lattner { 7830fdc8d8SChris Lattner DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); 791c73911dSJason Molenda if (MachPortNumberIsValid(m_mach_port_number)) 8030fdc8d8SChris Lattner { 819411ddb6SJim Ingham SetSuspendCountBeforeResume(others_stopped); 8230fdc8d8SChris Lattner } 8330fdc8d8SChris Lattner } 8430fdc8d8SChris Lattner 8530fdc8d8SChris Lattner bool 869411ddb6SJim Ingham MachThread::SetSuspendCountBeforeResume(bool others_stopped) 8730fdc8d8SChris Lattner { 88cdc7322bSGreg Clayton DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); 8930fdc8d8SChris Lattner DNBError err; 901c73911dSJason Molenda if (MachPortNumberIsValid(m_mach_port_number) == false) 9130fdc8d8SChris Lattner return false; 929411ddb6SJim Ingham 939411ddb6SJim Ingham size_t times_to_resume; 949411ddb6SJim Ingham 959411ddb6SJim Ingham if (others_stopped) 969411ddb6SJim Ingham { 9782283e8eSJim Ingham if (GetBasicInfo()) 9882283e8eSJim Ingham { 9982283e8eSJim Ingham times_to_resume = m_basic_info.suspend_count; 100c235ac76SGreg Clayton m_suspend_count = - (times_to_resume - m_suspend_count); 1019411ddb6SJim Ingham } 1029411ddb6SJim Ingham else 10382283e8eSJim Ingham times_to_resume = 0; 10482283e8eSJim Ingham } 10582283e8eSJim Ingham else 1069411ddb6SJim Ingham { 107c235ac76SGreg Clayton times_to_resume = m_suspend_count; 108c235ac76SGreg Clayton m_suspend_count = 0; 1099411ddb6SJim Ingham } 1109411ddb6SJim Ingham 1119411ddb6SJim Ingham if (times_to_resume > 0) 1129411ddb6SJim Ingham { 1139411ddb6SJim Ingham while (times_to_resume > 0) 1149411ddb6SJim Ingham { 1151c73911dSJason Molenda err = ::thread_resume (m_mach_port_number); 1169411ddb6SJim Ingham if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 1171c73911dSJason Molenda err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number); 1189411ddb6SJim Ingham if (err.Success()) 1199411ddb6SJim Ingham --times_to_resume; 1209411ddb6SJim Ingham else 1219411ddb6SJim Ingham { 1229411ddb6SJim Ingham if (GetBasicInfo()) 123c235ac76SGreg Clayton times_to_resume = m_basic_info.suspend_count; 1249411ddb6SJim Ingham else 1259411ddb6SJim Ingham times_to_resume = 0; 1269411ddb6SJim Ingham } 1279411ddb6SJim Ingham } 1289411ddb6SJim Ingham } 1299411ddb6SJim Ingham return true; 1309411ddb6SJim Ingham } 1319411ddb6SJim Ingham 1329411ddb6SJim Ingham bool 1339411ddb6SJim Ingham MachThread::RestoreSuspendCountAfterStop () 1349411ddb6SJim Ingham { 1359411ddb6SJim Ingham DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); 1369411ddb6SJim Ingham DNBError err; 1371c73911dSJason Molenda if (MachPortNumberIsValid(m_mach_port_number) == false) 1389411ddb6SJim Ingham return false; 1399411ddb6SJim Ingham 140c235ac76SGreg Clayton if (m_suspend_count > 0) 14130fdc8d8SChris Lattner { 142c235ac76SGreg Clayton while (m_suspend_count > 0) 14330fdc8d8SChris Lattner { 1441c73911dSJason Molenda err = ::thread_resume (m_mach_port_number); 14530fdc8d8SChris Lattner if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 1461c73911dSJason Molenda err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number); 14730fdc8d8SChris Lattner if (err.Success()) 148c235ac76SGreg Clayton --m_suspend_count; 1490dd2c627SGreg Clayton else 1500dd2c627SGreg Clayton { 151cdc7322bSGreg Clayton if (GetBasicInfo()) 152c235ac76SGreg Clayton m_suspend_count = m_basic_info.suspend_count; 1530dd2c627SGreg Clayton else 154c235ac76SGreg Clayton m_suspend_count = 0; 1550dd2c627SGreg Clayton return false; // ??? 15630fdc8d8SChris Lattner } 15730fdc8d8SChris Lattner } 1580dd2c627SGreg Clayton } 159c235ac76SGreg Clayton else if (m_suspend_count < 0) 1609411ddb6SJim Ingham { 161c235ac76SGreg Clayton while (m_suspend_count < 0) 1629411ddb6SJim Ingham { 1631c73911dSJason Molenda err = ::thread_suspend (m_mach_port_number); 1649411ddb6SJim Ingham if (err.Success()) 165c235ac76SGreg Clayton ++m_suspend_count; 1669411ddb6SJim Ingham if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 167478235d8SJim Ingham { 1681c73911dSJason Molenda err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number); 169478235d8SJim Ingham return false; 170478235d8SJim Ingham } 1719411ddb6SJim Ingham } 1729411ddb6SJim Ingham } 1730dd2c627SGreg Clayton return true; 17430fdc8d8SChris Lattner } 17530fdc8d8SChris Lattner 17630fdc8d8SChris Lattner 17730fdc8d8SChris Lattner const char * 17830fdc8d8SChris Lattner MachThread::GetBasicInfoAsString () const 17930fdc8d8SChris Lattner { 18030fdc8d8SChris Lattner static char g_basic_info_string[1024]; 18130fdc8d8SChris Lattner struct thread_basic_info basicInfo; 18230fdc8d8SChris Lattner 1831c73911dSJason Molenda if (GetBasicInfo(m_mach_port_number, &basicInfo)) 18430fdc8d8SChris Lattner { 18530fdc8d8SChris Lattner 18630fdc8d8SChris Lattner // char run_state_str[32]; 18730fdc8d8SChris Lattner // size_t run_state_str_size = sizeof(run_state_str); 18830fdc8d8SChris Lattner // switch (basicInfo.run_state) 18930fdc8d8SChris Lattner // { 19030fdc8d8SChris Lattner // case TH_STATE_RUNNING: strncpy(run_state_str, "running", run_state_str_size); break; 19130fdc8d8SChris Lattner // case TH_STATE_STOPPED: strncpy(run_state_str, "stopped", run_state_str_size); break; 19230fdc8d8SChris Lattner // case TH_STATE_WAITING: strncpy(run_state_str, "waiting", run_state_str_size); break; 19330fdc8d8SChris Lattner // case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str, "uninterruptible", run_state_str_size); break; 19430fdc8d8SChris Lattner // case TH_STATE_HALTED: strncpy(run_state_str, "halted", run_state_str_size); break; 19530fdc8d8SChris Lattner // default: snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break; // ??? 19630fdc8d8SChris Lattner // } 19730fdc8d8SChris Lattner float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f; 19830fdc8d8SChris Lattner float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f; 1991c73911dSJason Molenda snprintf(g_basic_info_string, sizeof(g_basic_info_string), "Thread 0x%8.8" PRIx64 ": user=%f system=%f cpu=%d sleep_time=%d", 2001c73911dSJason Molenda m_unique_id, 20130fdc8d8SChris Lattner user, 20230fdc8d8SChris Lattner system, 20330fdc8d8SChris Lattner basicInfo.cpu_usage, 20430fdc8d8SChris Lattner basicInfo.sleep_time); 20530fdc8d8SChris Lattner 20630fdc8d8SChris Lattner return g_basic_info_string; 20730fdc8d8SChris Lattner } 20830fdc8d8SChris Lattner return NULL; 20930fdc8d8SChris Lattner } 21030fdc8d8SChris Lattner 2111c73911dSJason Molenda // Finds the Mach port number for a given thread in the inferior process' port namespace. 21230fdc8d8SChris Lattner thread_t 21330fdc8d8SChris Lattner MachThread::InferiorThreadID() const 21430fdc8d8SChris Lattner { 21530fdc8d8SChris Lattner mach_msg_type_number_t i; 21630fdc8d8SChris Lattner mach_port_name_array_t names; 21730fdc8d8SChris Lattner mach_port_type_array_t types; 21830fdc8d8SChris Lattner mach_msg_type_number_t ncount, tcount; 21930fdc8d8SChris Lattner thread_t inferior_tid = INVALID_NUB_THREAD; 22030fdc8d8SChris Lattner task_t my_task = ::mach_task_self(); 22130fdc8d8SChris Lattner task_t task = m_process->Task().TaskPort(); 22230fdc8d8SChris Lattner 22330fdc8d8SChris Lattner kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount); 22430fdc8d8SChris Lattner if (kret == KERN_SUCCESS) 22530fdc8d8SChris Lattner { 22630fdc8d8SChris Lattner 22730fdc8d8SChris Lattner for (i = 0; i < ncount; i++) 22830fdc8d8SChris Lattner { 22930fdc8d8SChris Lattner mach_port_t my_name; 23030fdc8d8SChris Lattner mach_msg_type_name_t my_type; 23130fdc8d8SChris Lattner 23230fdc8d8SChris Lattner kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type); 23330fdc8d8SChris Lattner if (kret == KERN_SUCCESS) 23430fdc8d8SChris Lattner { 23530fdc8d8SChris Lattner ::mach_port_deallocate (my_task, my_name); 2361c73911dSJason Molenda if (my_name == m_mach_port_number) 23730fdc8d8SChris Lattner { 23830fdc8d8SChris Lattner inferior_tid = names[i]; 23930fdc8d8SChris Lattner break; 24030fdc8d8SChris Lattner } 24130fdc8d8SChris Lattner } 24230fdc8d8SChris Lattner } 24330fdc8d8SChris Lattner // Free up the names and types 24430fdc8d8SChris Lattner ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t)); 24530fdc8d8SChris Lattner ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t)); 24630fdc8d8SChris Lattner } 24730fdc8d8SChris Lattner return inferior_tid; 24830fdc8d8SChris Lattner } 24930fdc8d8SChris Lattner 25030fdc8d8SChris Lattner bool 2511b946bf6SGreg Clayton MachThread::IsUserReady() 2521b946bf6SGreg Clayton { 253c235ac76SGreg Clayton if (m_basic_info.run_state == 0) 254cdc7322bSGreg Clayton GetBasicInfo (); 2551b946bf6SGreg Clayton 256c235ac76SGreg Clayton switch (m_basic_info.run_state) 2571b946bf6SGreg Clayton { 2581b946bf6SGreg Clayton default: 2591b946bf6SGreg Clayton case TH_STATE_UNINTERRUPTIBLE: 2601b946bf6SGreg Clayton break; 2611b946bf6SGreg Clayton 2621b946bf6SGreg Clayton case TH_STATE_RUNNING: 2631b946bf6SGreg Clayton case TH_STATE_STOPPED: 2641b946bf6SGreg Clayton case TH_STATE_WAITING: 2651b946bf6SGreg Clayton case TH_STATE_HALTED: 2661b946bf6SGreg Clayton return true; 2671b946bf6SGreg Clayton } 2681b946bf6SGreg Clayton return false; 2691b946bf6SGreg Clayton } 2701b946bf6SGreg Clayton 2711b946bf6SGreg Clayton struct thread_basic_info * 272cdc7322bSGreg Clayton MachThread::GetBasicInfo () 2731b946bf6SGreg Clayton { 2741c73911dSJason Molenda if (MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info)) 275c235ac76SGreg Clayton return &m_basic_info; 2761b946bf6SGreg Clayton return NULL; 2771b946bf6SGreg Clayton } 2781b946bf6SGreg Clayton 2791b946bf6SGreg Clayton 2801b946bf6SGreg Clayton bool 28130fdc8d8SChris Lattner MachThread::GetBasicInfo(thread_t thread, struct thread_basic_info *basicInfoPtr) 28230fdc8d8SChris Lattner { 2831c73911dSJason Molenda if (MachPortNumberIsValid(thread)) 28430fdc8d8SChris Lattner { 28530fdc8d8SChris Lattner unsigned int info_count = THREAD_BASIC_INFO_COUNT; 28630fdc8d8SChris Lattner kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count); 28730fdc8d8SChris Lattner if (err == KERN_SUCCESS) 28830fdc8d8SChris Lattner return true; 28930fdc8d8SChris Lattner } 29030fdc8d8SChris Lattner ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info)); 29130fdc8d8SChris Lattner return false; 29230fdc8d8SChris Lattner } 29330fdc8d8SChris Lattner 29430fdc8d8SChris Lattner 29530fdc8d8SChris Lattner bool 2961c73911dSJason Molenda MachThread::ThreadIDIsValid(uint64_t thread) 2971c73911dSJason Molenda { 2981c73911dSJason Molenda return thread != 0; 2991c73911dSJason Molenda } 3001c73911dSJason Molenda 3011c73911dSJason Molenda bool 3021c73911dSJason Molenda MachThread::MachPortNumberIsValid(thread_t thread) 30330fdc8d8SChris Lattner { 30430fdc8d8SChris Lattner return thread != THREAD_NULL; 30530fdc8d8SChris Lattner } 30630fdc8d8SChris Lattner 30730fdc8d8SChris Lattner bool 30830fdc8d8SChris Lattner MachThread::GetRegisterState(int flavor, bool force) 30930fdc8d8SChris Lattner { 3103af9ea56SGreg Clayton return m_arch_ap->GetRegisterState(flavor, force) == KERN_SUCCESS; 31130fdc8d8SChris Lattner } 31230fdc8d8SChris Lattner 31330fdc8d8SChris Lattner bool 31430fdc8d8SChris Lattner MachThread::SetRegisterState(int flavor) 31530fdc8d8SChris Lattner { 3163af9ea56SGreg Clayton return m_arch_ap->SetRegisterState(flavor) == KERN_SUCCESS; 31730fdc8d8SChris Lattner } 31830fdc8d8SChris Lattner 31930fdc8d8SChris Lattner uint64_t 32030fdc8d8SChris Lattner MachThread::GetPC(uint64_t failValue) 32130fdc8d8SChris Lattner { 32230fdc8d8SChris Lattner // Get program counter 3233af9ea56SGreg Clayton return m_arch_ap->GetPC(failValue); 32430fdc8d8SChris Lattner } 32530fdc8d8SChris Lattner 32630fdc8d8SChris Lattner bool 32730fdc8d8SChris Lattner MachThread::SetPC(uint64_t value) 32830fdc8d8SChris Lattner { 32930fdc8d8SChris Lattner // Set program counter 3303af9ea56SGreg Clayton return m_arch_ap->SetPC(value); 33130fdc8d8SChris Lattner } 33230fdc8d8SChris Lattner 33330fdc8d8SChris Lattner uint64_t 33430fdc8d8SChris Lattner MachThread::GetSP(uint64_t failValue) 33530fdc8d8SChris Lattner { 33630fdc8d8SChris Lattner // Get stack pointer 3373af9ea56SGreg Clayton return m_arch_ap->GetSP(failValue); 33830fdc8d8SChris Lattner } 33930fdc8d8SChris Lattner 34030fdc8d8SChris Lattner nub_process_t 34130fdc8d8SChris Lattner MachThread::ProcessID() const 34230fdc8d8SChris Lattner { 34330fdc8d8SChris Lattner if (m_process) 34430fdc8d8SChris Lattner return m_process->ProcessID(); 34530fdc8d8SChris Lattner return INVALID_NUB_PROCESS; 34630fdc8d8SChris Lattner } 34730fdc8d8SChris Lattner 34830fdc8d8SChris Lattner void 34930fdc8d8SChris Lattner MachThread::Dump(uint32_t index) 35030fdc8d8SChris Lattner { 35130fdc8d8SChris Lattner const char * thread_run_state = NULL; 35230fdc8d8SChris Lattner 353c235ac76SGreg Clayton switch (m_basic_info.run_state) 35430fdc8d8SChris Lattner { 35530fdc8d8SChris Lattner case TH_STATE_RUNNING: thread_run_state = "running"; break; // 1 thread is running normally 35630fdc8d8SChris Lattner case TH_STATE_STOPPED: thread_run_state = "stopped"; break; // 2 thread is stopped 35730fdc8d8SChris Lattner case TH_STATE_WAITING: thread_run_state = "waiting"; break; // 3 thread is waiting normally 35830fdc8d8SChris Lattner case TH_STATE_UNINTERRUPTIBLE: thread_run_state = "uninter"; break; // 4 thread is in an uninterruptible wait 35930fdc8d8SChris Lattner case TH_STATE_HALTED: thread_run_state = "halted "; break; // 5 thread is halted at a 36030fdc8d8SChris Lattner default: thread_run_state = "???"; break; 36130fdc8d8SChris Lattner } 36230fdc8d8SChris Lattner 363*d8cf1a11SGreg Clayton 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", 36430fdc8d8SChris Lattner index, 36530fdc8d8SChris Lattner m_seq_id, 3661c73911dSJason Molenda m_unique_id, 36730fdc8d8SChris Lattner GetPC(INVALID_NUB_ADDRESS), 36830fdc8d8SChris Lattner GetSP(INVALID_NUB_ADDRESS), 369c235ac76SGreg Clayton m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds, 370c235ac76SGreg Clayton m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds, 371c235ac76SGreg Clayton m_basic_info.cpu_usage, 372c235ac76SGreg Clayton m_basic_info.policy, 373c235ac76SGreg Clayton m_basic_info.run_state, 37430fdc8d8SChris Lattner thread_run_state, 375c235ac76SGreg Clayton m_basic_info.flags, 376c235ac76SGreg Clayton m_basic_info.suspend_count, m_suspend_count, 377c235ac76SGreg Clayton m_basic_info.sleep_time); 37830fdc8d8SChris Lattner //DumpRegisterState(0); 37930fdc8d8SChris Lattner } 38030fdc8d8SChris Lattner 38130fdc8d8SChris Lattner void 3829411ddb6SJim Ingham MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action, bool others_stopped) 38330fdc8d8SChris Lattner { 38430fdc8d8SChris Lattner if (thread_action->addr != INVALID_NUB_ADDRESS) 38530fdc8d8SChris Lattner SetPC (thread_action->addr); 386cdc7322bSGreg Clayton 38730fdc8d8SChris Lattner SetState (thread_action->state); 38830fdc8d8SChris Lattner switch (thread_action->state) 38930fdc8d8SChris Lattner { 39030fdc8d8SChris Lattner case eStateStopped: 39130fdc8d8SChris Lattner case eStateSuspended: 3929411ddb6SJim Ingham assert (others_stopped == false); 39330fdc8d8SChris Lattner Suspend(); 39430fdc8d8SChris Lattner break; 39530fdc8d8SChris Lattner 39630fdc8d8SChris Lattner case eStateRunning: 397b1e11121SJim Ingham case eStateStepping: 3989411ddb6SJim Ingham Resume(others_stopped); 399b1e11121SJim Ingham break; 400effe5c95SGreg Clayton default: 401effe5c95SGreg Clayton break; 40230fdc8d8SChris Lattner } 4033af9ea56SGreg Clayton m_arch_ap->ThreadWillResume(); 40430fdc8d8SChris Lattner m_stop_exception.Clear(); 40530fdc8d8SChris Lattner } 40630fdc8d8SChris Lattner 407*d8cf1a11SGreg Clayton DNBBreakpoint * 408c4e411ffSGreg Clayton MachThread::CurrentBreakpoint() 409c4e411ffSGreg Clayton { 410*d8cf1a11SGreg Clayton return m_process->Breakpoints().FindByAddress(GetPC()); 411c4e411ffSGreg Clayton } 412c4e411ffSGreg Clayton 41330fdc8d8SChris Lattner bool 41430fdc8d8SChris Lattner MachThread::ShouldStop(bool &step_more) 41530fdc8d8SChris Lattner { 41630fdc8d8SChris Lattner // See if this thread is at a breakpoint? 417*d8cf1a11SGreg Clayton DNBBreakpoint *bp = CurrentBreakpoint(); 41830fdc8d8SChris Lattner 419*d8cf1a11SGreg Clayton if (bp) 42030fdc8d8SChris Lattner { 42130fdc8d8SChris Lattner // This thread is sitting at a breakpoint, ask the breakpoint 42230fdc8d8SChris Lattner // if we should be stopping here. 42330fdc8d8SChris Lattner return true; 42430fdc8d8SChris Lattner } 42530fdc8d8SChris Lattner else 42630fdc8d8SChris Lattner { 4273af9ea56SGreg Clayton if (m_arch_ap->StepNotComplete()) 42830fdc8d8SChris Lattner { 42930fdc8d8SChris Lattner step_more = true; 43030fdc8d8SChris Lattner return false; 43130fdc8d8SChris Lattner } 43230fdc8d8SChris Lattner // The thread state is used to let us know what the thread was 43330fdc8d8SChris Lattner // trying to do. MachThread::ThreadWillResume() will set the 43430fdc8d8SChris Lattner // thread state to various values depending if the thread was 43530fdc8d8SChris Lattner // the current thread and if it was to be single stepped, or 43630fdc8d8SChris Lattner // resumed. 43730fdc8d8SChris Lattner if (GetState() == eStateRunning) 43830fdc8d8SChris Lattner { 43930fdc8d8SChris Lattner // If our state is running, then we should continue as we are in 44030fdc8d8SChris Lattner // the process of stepping over a breakpoint. 44130fdc8d8SChris Lattner return false; 44230fdc8d8SChris Lattner } 44330fdc8d8SChris Lattner else 44430fdc8d8SChris Lattner { 44530fdc8d8SChris Lattner // Stop if we have any kind of valid exception for this 44630fdc8d8SChris Lattner // thread. 44730fdc8d8SChris Lattner if (GetStopException().IsValid()) 44830fdc8d8SChris Lattner return true; 44930fdc8d8SChris Lattner } 45030fdc8d8SChris Lattner } 45130fdc8d8SChris Lattner return false; 45230fdc8d8SChris Lattner } 45330fdc8d8SChris Lattner bool 45430fdc8d8SChris Lattner MachThread::IsStepping() 45530fdc8d8SChris Lattner { 456c4e411ffSGreg Clayton #if ENABLE_AUTO_STEPPING_OVER_BP 45730fdc8d8SChris Lattner // Return true if this thread is currently being stepped. 45830fdc8d8SChris Lattner // MachThread::ThreadWillResume currently determines this by looking if we 45930fdc8d8SChris Lattner // have been asked to single step, or if we are at a breakpoint instruction 46030fdc8d8SChris Lattner // and have been asked to resume. In the latter case we need to disable the 46130fdc8d8SChris Lattner // breakpoint we are at, single step, re-enable and continue. 46230fdc8d8SChris Lattner nub_state_t state = GetState(); 463c4e411ffSGreg Clayton return ((state == eStateStepping) || 464c4e411ffSGreg Clayton (state == eStateRunning && NUB_BREAK_ID_IS_VALID(CurrentBreakpoint()))); 465c4e411ffSGreg Clayton #else 466c4e411ffSGreg Clayton return GetState() == eStateStepping; 467c4e411ffSGreg Clayton #endif 46830fdc8d8SChris Lattner } 46930fdc8d8SChris Lattner 47030fdc8d8SChris Lattner 47130fdc8d8SChris Lattner bool 47230fdc8d8SChris Lattner MachThread::ThreadDidStop() 47330fdc8d8SChris Lattner { 47430fdc8d8SChris Lattner // This thread has existed prior to resuming under debug nub control, 47530fdc8d8SChris Lattner // and has just been stopped. Do any cleanup that needs to be done 47630fdc8d8SChris Lattner // after running. 47730fdc8d8SChris Lattner 47830fdc8d8SChris Lattner // The thread state and breakpoint will still have the same values 47930fdc8d8SChris Lattner // as they had prior to resuming the thread, so it makes it easy to check 48030fdc8d8SChris Lattner // if we were trying to step a thread, or we tried to resume while being 48130fdc8d8SChris Lattner // at a breakpoint. 48230fdc8d8SChris Lattner 48330fdc8d8SChris Lattner // When this method gets called, the process state is still in the 48430fdc8d8SChris Lattner // state it was in while running so we can act accordingly. 4853af9ea56SGreg Clayton m_arch_ap->ThreadDidStop(); 48630fdc8d8SChris Lattner 48730fdc8d8SChris Lattner 48830fdc8d8SChris Lattner // We may have suspended this thread so the primary thread could step 48930fdc8d8SChris Lattner // without worrying about race conditions, so lets restore our suspend 49030fdc8d8SChris Lattner // count. 4919411ddb6SJim Ingham RestoreSuspendCountAfterStop(); 49230fdc8d8SChris Lattner 49330fdc8d8SChris Lattner // Update the basic information for a thread 4941c73911dSJason Molenda MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info); 49530fdc8d8SChris Lattner 496c4e411ffSGreg Clayton #if ENABLE_AUTO_STEPPING_OVER_BP 49730fdc8d8SChris Lattner // See if we were at a breakpoint when we last resumed that we disabled, 49830fdc8d8SChris Lattner // re-enable it. 49930fdc8d8SChris Lattner nub_break_t breakID = CurrentBreakpoint(); 50030fdc8d8SChris Lattner 50130fdc8d8SChris Lattner if (NUB_BREAK_ID_IS_VALID(breakID)) 50230fdc8d8SChris Lattner { 50330fdc8d8SChris Lattner m_process->EnableBreakpoint(breakID); 504c235ac76SGreg Clayton if (m_basic_info.suspend_count > 0) 50530fdc8d8SChris Lattner { 50630fdc8d8SChris Lattner SetState(eStateSuspended); 50730fdc8d8SChris Lattner } 50830fdc8d8SChris Lattner else 50930fdc8d8SChris Lattner { 51030fdc8d8SChris Lattner // If we last were at a breakpoint and we single stepped, our state 51130fdc8d8SChris Lattner // will be "running" to indicate we need to continue after stepping 51230fdc8d8SChris Lattner // over the breakpoint instruction. If we step over a breakpoint 51330fdc8d8SChris Lattner // instruction, we need to stop. 51430fdc8d8SChris Lattner if (GetState() == eStateRunning) 51530fdc8d8SChris Lattner { 51630fdc8d8SChris Lattner // Leave state set to running so we will continue automatically 51730fdc8d8SChris Lattner // from this breakpoint 51830fdc8d8SChris Lattner } 51930fdc8d8SChris Lattner else 52030fdc8d8SChris Lattner { 52130fdc8d8SChris Lattner SetState(eStateStopped); 52230fdc8d8SChris Lattner } 52330fdc8d8SChris Lattner } 52430fdc8d8SChris Lattner } 52530fdc8d8SChris Lattner else 52630fdc8d8SChris Lattner { 527c235ac76SGreg Clayton if (m_basic_info.suspend_count > 0) 52830fdc8d8SChris Lattner { 52930fdc8d8SChris Lattner SetState(eStateSuspended); 53030fdc8d8SChris Lattner } 53130fdc8d8SChris Lattner else 53230fdc8d8SChris Lattner { 53330fdc8d8SChris Lattner SetState(eStateStopped); 53430fdc8d8SChris Lattner } 53530fdc8d8SChris Lattner } 536c4e411ffSGreg Clayton #else 537c235ac76SGreg Clayton if (m_basic_info.suspend_count > 0) 538c4e411ffSGreg Clayton SetState(eStateSuspended); 539c4e411ffSGreg Clayton else 540c4e411ffSGreg Clayton SetState(eStateStopped); 541c4e411ffSGreg Clayton #endif 54230fdc8d8SChris Lattner return true; 54330fdc8d8SChris Lattner } 54430fdc8d8SChris Lattner 54530fdc8d8SChris Lattner bool 54630fdc8d8SChris Lattner MachThread::NotifyException(MachException::Data& exc) 54730fdc8d8SChris Lattner { 54888c1b77fSJohnny Chen // Allow the arch specific protocol to process (MachException::Data &)exc 54988c1b77fSJohnny Chen // first before possible reassignment of m_stop_exception with exc. 55076abb3b5SJohnny Chen // See also MachThread::GetStopException(). 55188c1b77fSJohnny Chen bool handled = m_arch_ap->NotifyException(exc); 55288c1b77fSJohnny Chen 55330fdc8d8SChris Lattner if (m_stop_exception.IsValid()) 55430fdc8d8SChris Lattner { 55530fdc8d8SChris Lattner // We may have more than one exception for a thread, but we need to 55630fdc8d8SChris Lattner // only remember the one that we will say is the reason we stopped. 55730fdc8d8SChris Lattner // We may have been single stepping and also gotten a signal exception, 55830fdc8d8SChris Lattner // so just remember the most pertinent one. 55930fdc8d8SChris Lattner if (m_stop_exception.IsBreakpoint()) 56030fdc8d8SChris Lattner m_stop_exception = exc; 56130fdc8d8SChris Lattner } 56230fdc8d8SChris Lattner else 56330fdc8d8SChris Lattner { 56430fdc8d8SChris Lattner m_stop_exception = exc; 56530fdc8d8SChris Lattner } 56688c1b77fSJohnny Chen 56730fdc8d8SChris Lattner return handled; 56830fdc8d8SChris Lattner } 56930fdc8d8SChris Lattner 57030fdc8d8SChris Lattner 57130fdc8d8SChris Lattner nub_state_t 57230fdc8d8SChris Lattner MachThread::GetState() 57330fdc8d8SChris Lattner { 57430fdc8d8SChris Lattner // If any other threads access this we will need a mutex for it 57530fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_state_mutex); 57630fdc8d8SChris Lattner return m_state; 57730fdc8d8SChris Lattner } 57830fdc8d8SChris Lattner 57930fdc8d8SChris Lattner void 58030fdc8d8SChris Lattner MachThread::SetState(nub_state_t state) 58130fdc8d8SChris Lattner { 58230fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_state_mutex); 58330fdc8d8SChris Lattner m_state = state; 5841c73911dSJason Molenda DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%8.8" PRIx64 "", DNBStateAsString(state), m_unique_id); 58530fdc8d8SChris Lattner } 58630fdc8d8SChris Lattner 58730fdc8d8SChris Lattner uint32_t 58830fdc8d8SChris Lattner MachThread::GetNumRegistersInSet(int regSet) const 58930fdc8d8SChris Lattner { 590c235ac76SGreg Clayton if (regSet < m_num_reg_sets) 5913af9ea56SGreg Clayton return m_reg_sets[regSet].num_registers; 59230fdc8d8SChris Lattner return 0; 59330fdc8d8SChris Lattner } 59430fdc8d8SChris Lattner 59530fdc8d8SChris Lattner const char * 59630fdc8d8SChris Lattner MachThread::GetRegisterSetName(int regSet) const 59730fdc8d8SChris Lattner { 598c235ac76SGreg Clayton if (regSet < m_num_reg_sets) 5993af9ea56SGreg Clayton return m_reg_sets[regSet].name; 60030fdc8d8SChris Lattner return NULL; 60130fdc8d8SChris Lattner } 60230fdc8d8SChris Lattner 60330fdc8d8SChris Lattner const DNBRegisterInfo * 60430fdc8d8SChris Lattner MachThread::GetRegisterInfo(int regSet, int regIndex) const 60530fdc8d8SChris Lattner { 606c235ac76SGreg Clayton if (regSet < m_num_reg_sets) 6073af9ea56SGreg Clayton if (regIndex < m_reg_sets[regSet].num_registers) 6083af9ea56SGreg Clayton return &m_reg_sets[regSet].registers[regIndex]; 60930fdc8d8SChris Lattner return NULL; 61030fdc8d8SChris Lattner } 61130fdc8d8SChris Lattner void 61230fdc8d8SChris Lattner MachThread::DumpRegisterState(int regSet) 61330fdc8d8SChris Lattner { 61430fdc8d8SChris Lattner if (regSet == REGISTER_SET_ALL) 61530fdc8d8SChris Lattner { 616c235ac76SGreg Clayton for (regSet = 1; regSet < m_num_reg_sets; regSet++) 61730fdc8d8SChris Lattner DumpRegisterState(regSet); 61830fdc8d8SChris Lattner } 61930fdc8d8SChris Lattner else 62030fdc8d8SChris Lattner { 6213af9ea56SGreg Clayton if (m_arch_ap->RegisterSetStateIsValid(regSet)) 62230fdc8d8SChris Lattner { 62330fdc8d8SChris Lattner const size_t numRegisters = GetNumRegistersInSet(regSet); 62430fdc8d8SChris Lattner size_t regIndex = 0; 62530fdc8d8SChris Lattner DNBRegisterValueClass reg; 62630fdc8d8SChris Lattner for (regIndex = 0; regIndex < numRegisters; ++regIndex) 62730fdc8d8SChris Lattner { 6283af9ea56SGreg Clayton if (m_arch_ap->GetRegisterValue(regSet, regIndex, ®)) 62930fdc8d8SChris Lattner { 63030fdc8d8SChris Lattner reg.Dump(NULL, NULL); 63130fdc8d8SChris Lattner } 63230fdc8d8SChris Lattner } 63330fdc8d8SChris Lattner } 63430fdc8d8SChris Lattner else 63530fdc8d8SChris Lattner { 63630fdc8d8SChris Lattner DNBLog("%s: registers are not currently valid.", GetRegisterSetName(regSet)); 63730fdc8d8SChris Lattner } 63830fdc8d8SChris Lattner } 63930fdc8d8SChris Lattner } 64030fdc8d8SChris Lattner 64130fdc8d8SChris Lattner const DNBRegisterSetInfo * 64230fdc8d8SChris Lattner MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const 64330fdc8d8SChris Lattner { 644c235ac76SGreg Clayton *num_reg_sets = m_num_reg_sets; 6453af9ea56SGreg Clayton return &m_reg_sets[0]; 64630fdc8d8SChris Lattner } 64730fdc8d8SChris Lattner 64830fdc8d8SChris Lattner bool 64930fdc8d8SChris Lattner MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value ) 65030fdc8d8SChris Lattner { 6513af9ea56SGreg Clayton return m_arch_ap->GetRegisterValue(set, reg, value); 65230fdc8d8SChris Lattner } 65330fdc8d8SChris Lattner 65430fdc8d8SChris Lattner bool 65530fdc8d8SChris Lattner MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value ) 65630fdc8d8SChris Lattner { 6573af9ea56SGreg Clayton return m_arch_ap->SetRegisterValue(set, reg, value); 65830fdc8d8SChris Lattner } 65930fdc8d8SChris Lattner 66030fdc8d8SChris Lattner nub_size_t 66130fdc8d8SChris Lattner MachThread::GetRegisterContext (void *buf, nub_size_t buf_len) 66230fdc8d8SChris Lattner { 6633af9ea56SGreg Clayton return m_arch_ap->GetRegisterContext(buf, buf_len); 66430fdc8d8SChris Lattner } 66530fdc8d8SChris Lattner 66630fdc8d8SChris Lattner nub_size_t 66730fdc8d8SChris Lattner MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len) 66830fdc8d8SChris Lattner { 6693af9ea56SGreg Clayton return m_arch_ap->SetRegisterContext(buf, buf_len); 67030fdc8d8SChris Lattner } 67130fdc8d8SChris Lattner 67230fdc8d8SChris Lattner uint32_t 67330fdc8d8SChris Lattner MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp) 67430fdc8d8SChris Lattner { 67530fdc8d8SChris Lattner if (bp != NULL && bp->IsBreakpoint()) 6763af9ea56SGreg Clayton return m_arch_ap->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize()); 67730fdc8d8SChris Lattner return INVALID_NUB_HW_INDEX; 67830fdc8d8SChris Lattner } 67930fdc8d8SChris Lattner 68030fdc8d8SChris Lattner uint32_t 68130fdc8d8SChris Lattner MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp) 68230fdc8d8SChris Lattner { 68330fdc8d8SChris Lattner if (wp != NULL && wp->IsWatchpoint()) 6843af9ea56SGreg Clayton return m_arch_ap->EnableHardwareWatchpoint(wp->Address(), wp->ByteSize(), wp->WatchpointRead(), wp->WatchpointWrite()); 68530fdc8d8SChris Lattner return INVALID_NUB_HW_INDEX; 68630fdc8d8SChris Lattner } 68730fdc8d8SChris Lattner 688a9b68f4dSJohnny Chen // Provide a chance to update the global view of the hardware watchpoint state. 689a9b68f4dSJohnny Chen void 690a9b68f4dSJohnny Chen MachThread::HardwareWatchpointStateChanged () 691a9b68f4dSJohnny Chen { 692a9b68f4dSJohnny Chen m_arch_ap->HardwareWatchpointStateChanged(); 693a9b68f4dSJohnny Chen } 694a9b68f4dSJohnny Chen 69530fdc8d8SChris Lattner bool 69684707560SJohnny Chen MachThread::RollbackTransForHWP() 69784707560SJohnny Chen { 69884707560SJohnny Chen return m_arch_ap->RollbackTransForHWP(); 69984707560SJohnny Chen } 70084707560SJohnny Chen 70184707560SJohnny Chen bool 70284707560SJohnny Chen MachThread::FinishTransForHWP() 70384707560SJohnny Chen { 70484707560SJohnny Chen return m_arch_ap->FinishTransForHWP(); 70584707560SJohnny Chen } 70684707560SJohnny Chen 70784707560SJohnny Chen bool 70830fdc8d8SChris Lattner MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp) 70930fdc8d8SChris Lattner { 71030fdc8d8SChris Lattner if (bp != NULL && bp->IsHardware()) 7113af9ea56SGreg Clayton return m_arch_ap->DisableHardwareBreakpoint(bp->GetHardwareIndex()); 71230fdc8d8SChris Lattner return false; 71330fdc8d8SChris Lattner } 71430fdc8d8SChris Lattner 71530fdc8d8SChris Lattner bool 71630fdc8d8SChris Lattner MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp) 71730fdc8d8SChris Lattner { 71830fdc8d8SChris Lattner if (wp != NULL && wp->IsHardware()) 7193af9ea56SGreg Clayton return m_arch_ap->DisableHardwareWatchpoint(wp->GetHardwareIndex()); 72030fdc8d8SChris Lattner return false; 72130fdc8d8SChris Lattner } 72230fdc8d8SChris Lattner 72364637205SJohnny Chen uint32_t 72464637205SJohnny Chen MachThread::NumSupportedHardwareWatchpoints () const 72564637205SJohnny Chen { 72664637205SJohnny Chen return m_arch_ap->NumSupportedHardwareWatchpoints(); 72764637205SJohnny Chen } 72864637205SJohnny Chen 72930fdc8d8SChris Lattner bool 73030fdc8d8SChris Lattner MachThread::GetIdentifierInfo () 73130fdc8d8SChris Lattner { 732f2c6ccf0SJim Ingham // Don't try to get the thread info once and cache it for the life of the thread. It changes over time, for instance 733f2c6ccf0SJim Ingham // if the thread name changes, then the thread_handle also changes... So you have to refetch it every time. 73430fdc8d8SChris Lattner mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; 7351c73911dSJason Molenda kern_return_t kret = ::thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count); 736f2c6ccf0SJim Ingham return kret == KERN_SUCCESS; 73730fdc8d8SChris Lattner 73830fdc8d8SChris Lattner return false; 73930fdc8d8SChris Lattner } 74030fdc8d8SChris Lattner 74130fdc8d8SChris Lattner 74230fdc8d8SChris Lattner const char * 74330fdc8d8SChris Lattner MachThread::GetName () 74430fdc8d8SChris Lattner { 74530fdc8d8SChris Lattner if (GetIdentifierInfo ()) 74630fdc8d8SChris Lattner { 74730fdc8d8SChris Lattner int len = ::proc_pidinfo (m_process->ProcessID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo)); 74830fdc8d8SChris Lattner 74930fdc8d8SChris Lattner if (len && m_proc_threadinfo.pth_name[0]) 75030fdc8d8SChris Lattner return m_proc_threadinfo.pth_name; 75130fdc8d8SChris Lattner } 75230fdc8d8SChris Lattner return NULL; 75330fdc8d8SChris Lattner } 75430fdc8d8SChris Lattner 7551c73911dSJason Molenda 7561c73911dSJason Molenda uint64_t 7571c73911dSJason Molenda MachThread::GetGloballyUniqueThreadIDForMachPortID (thread_t mach_port_id) 7581c73911dSJason Molenda { 7591c73911dSJason Molenda kern_return_t kr; 7601c73911dSJason Molenda thread_identifier_info_data_t tident; 7611c73911dSJason Molenda mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; 7621c73911dSJason Molenda kr = thread_info (mach_port_id, THREAD_IDENTIFIER_INFO, 7631c73911dSJason Molenda (thread_info_t) &tident, &tident_count); 7641c73911dSJason Molenda if (kr != KERN_SUCCESS) 7651c73911dSJason Molenda { 7661c73911dSJason Molenda return mach_port_id; 7671c73911dSJason Molenda } 7681c73911dSJason Molenda return tident.thread_id; 7691c73911dSJason Molenda } 770