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> 15705b1809SJason Molenda #include <mach/thread_policy.h> 16705b1809SJason Molenda #include <dlfcn.h> 1730fdc8d8SChris Lattner #include "MachThread.h" 1830fdc8d8SChris Lattner #include "MachProcess.h" 1930fdc8d8SChris Lattner #include "DNBLog.h" 2030fdc8d8SChris Lattner #include "DNB.h" 21705b1809SJason Molenda #include "ThreadInfo.h" 2230fdc8d8SChris Lattner 2330fdc8d8SChris Lattner static uint32_t 2430fdc8d8SChris Lattner GetSequenceID() 2530fdc8d8SChris Lattner { 2630fdc8d8SChris Lattner static uint32_t g_nextID = 0; 2730fdc8d8SChris Lattner return ++g_nextID; 2830fdc8d8SChris Lattner } 2930fdc8d8SChris Lattner 30705b1809SJason Molenda MachThread::MachThread (MachProcess *process, bool is_64_bit, uint64_t unique_thread_id, thread_t mach_port_num) : 3130fdc8d8SChris Lattner m_process (process), 321c73911dSJason Molenda m_unique_id (unique_thread_id), 331c73911dSJason Molenda m_mach_port_number (mach_port_num), 3430fdc8d8SChris Lattner m_seq_id (GetSequenceID()), 3530fdc8d8SChris Lattner m_state (eStateUnloaded), 3630fdc8d8SChris Lattner m_state_mutex (PTHREAD_MUTEX_RECURSIVE), 37c235ac76SGreg Clayton m_suspend_count (0), 38c235ac76SGreg Clayton m_stop_exception (), 393af9ea56SGreg Clayton m_arch_ap (DNBArchProtocol::Create (this)), 40c235ac76SGreg Clayton m_reg_sets (NULL), 411c73911dSJason Molenda m_num_reg_sets (0), 421c73911dSJason Molenda m_ident_info(), 43c235ac76SGreg Clayton m_proc_threadinfo(), 44705b1809SJason Molenda m_dispatch_queue_name(), 45705b1809SJason Molenda m_is_64_bit(is_64_bit), 46705b1809SJason Molenda m_pthread_qos_class_decode (nullptr) 4730fdc8d8SChris Lattner { 48c235ac76SGreg Clayton nub_size_t num_reg_sets = 0; 49c235ac76SGreg Clayton m_reg_sets = m_arch_ap->GetRegisterSetInfo (&num_reg_sets); 50c235ac76SGreg Clayton m_num_reg_sets = num_reg_sets; 51c235ac76SGreg Clayton 52705b1809SJason Molenda m_pthread_qos_class_decode = (unsigned int (*)(unsigned long, int*, unsigned long*)) dlsym (RTLD_DEFAULT, "_pthread_qos_class_decode"); 53705b1809SJason Molenda 541b946bf6SGreg Clayton // Get the thread state so we know if a thread is in a state where we can't 551b946bf6SGreg Clayton // muck with it and also so we get the suspend count correct in case it was 561b946bf6SGreg Clayton // already suspended 57cdc7322bSGreg Clayton GetBasicInfo(); 581c73911dSJason 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); 5930fdc8d8SChris Lattner } 6030fdc8d8SChris Lattner 6130fdc8d8SChris Lattner MachThread::~MachThread() 6230fdc8d8SChris Lattner { 631c73911dSJason Molenda DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::~MachThread() for tid = 0x%8.8" PRIx64 " (%u)", m_unique_id, m_seq_id); 6430fdc8d8SChris Lattner } 6530fdc8d8SChris Lattner 6630fdc8d8SChris Lattner 6730fdc8d8SChris Lattner 689411ddb6SJim Ingham void 6930fdc8d8SChris Lattner MachThread::Suspend() 7030fdc8d8SChris Lattner { 7130fdc8d8SChris Lattner DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); 721c73911dSJason Molenda if (MachPortNumberIsValid(m_mach_port_number)) 7330fdc8d8SChris Lattner { 741c73911dSJason Molenda DNBError err(::thread_suspend (m_mach_port_number), DNBError::MachKernel); 7530fdc8d8SChris Lattner if (err.Success()) 76c235ac76SGreg Clayton m_suspend_count++; 7730fdc8d8SChris Lattner if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 781c73911dSJason Molenda err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number); 7930fdc8d8SChris Lattner } 8030fdc8d8SChris Lattner } 8130fdc8d8SChris Lattner 829411ddb6SJim Ingham void 839411ddb6SJim Ingham MachThread::Resume(bool others_stopped) 8430fdc8d8SChris Lattner { 8530fdc8d8SChris Lattner DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); 861c73911dSJason Molenda if (MachPortNumberIsValid(m_mach_port_number)) 8730fdc8d8SChris Lattner { 889411ddb6SJim Ingham SetSuspendCountBeforeResume(others_stopped); 8930fdc8d8SChris Lattner } 9030fdc8d8SChris Lattner } 9130fdc8d8SChris Lattner 9230fdc8d8SChris Lattner bool 939411ddb6SJim Ingham MachThread::SetSuspendCountBeforeResume(bool others_stopped) 9430fdc8d8SChris Lattner { 95cdc7322bSGreg Clayton DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); 9630fdc8d8SChris Lattner DNBError err; 971c73911dSJason Molenda if (MachPortNumberIsValid(m_mach_port_number) == false) 9830fdc8d8SChris Lattner return false; 999411ddb6SJim Ingham 100*ee2ed525SGreg Clayton integer_t times_to_resume; 1019411ddb6SJim Ingham 1029411ddb6SJim Ingham if (others_stopped) 1039411ddb6SJim Ingham { 10482283e8eSJim Ingham if (GetBasicInfo()) 10582283e8eSJim Ingham { 10682283e8eSJim Ingham times_to_resume = m_basic_info.suspend_count; 107c235ac76SGreg Clayton m_suspend_count = - (times_to_resume - m_suspend_count); 1089411ddb6SJim Ingham } 1099411ddb6SJim Ingham else 11082283e8eSJim Ingham times_to_resume = 0; 11182283e8eSJim Ingham } 11282283e8eSJim Ingham else 1139411ddb6SJim Ingham { 114c235ac76SGreg Clayton times_to_resume = m_suspend_count; 115c235ac76SGreg Clayton m_suspend_count = 0; 1169411ddb6SJim Ingham } 1179411ddb6SJim Ingham 1189411ddb6SJim Ingham if (times_to_resume > 0) 1199411ddb6SJim Ingham { 1209411ddb6SJim Ingham while (times_to_resume > 0) 1219411ddb6SJim Ingham { 1221c73911dSJason Molenda err = ::thread_resume (m_mach_port_number); 1239411ddb6SJim Ingham if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 1241c73911dSJason Molenda err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number); 1259411ddb6SJim Ingham if (err.Success()) 1269411ddb6SJim Ingham --times_to_resume; 1279411ddb6SJim Ingham else 1289411ddb6SJim Ingham { 1299411ddb6SJim Ingham if (GetBasicInfo()) 130c235ac76SGreg Clayton times_to_resume = m_basic_info.suspend_count; 1319411ddb6SJim Ingham else 1329411ddb6SJim Ingham times_to_resume = 0; 1339411ddb6SJim Ingham } 1349411ddb6SJim Ingham } 1359411ddb6SJim Ingham } 1369411ddb6SJim Ingham return true; 1379411ddb6SJim Ingham } 1389411ddb6SJim Ingham 1399411ddb6SJim Ingham bool 1409411ddb6SJim Ingham MachThread::RestoreSuspendCountAfterStop () 1419411ddb6SJim Ingham { 1429411ddb6SJim Ingham DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); 1439411ddb6SJim Ingham DNBError err; 1441c73911dSJason Molenda if (MachPortNumberIsValid(m_mach_port_number) == false) 1459411ddb6SJim Ingham return false; 1469411ddb6SJim Ingham 147c235ac76SGreg Clayton if (m_suspend_count > 0) 14830fdc8d8SChris Lattner { 149c235ac76SGreg Clayton while (m_suspend_count > 0) 15030fdc8d8SChris Lattner { 1511c73911dSJason Molenda err = ::thread_resume (m_mach_port_number); 15230fdc8d8SChris Lattner if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 1531c73911dSJason Molenda err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number); 15430fdc8d8SChris Lattner if (err.Success()) 155c235ac76SGreg Clayton --m_suspend_count; 1560dd2c627SGreg Clayton else 1570dd2c627SGreg Clayton { 158cdc7322bSGreg Clayton if (GetBasicInfo()) 159c235ac76SGreg Clayton m_suspend_count = m_basic_info.suspend_count; 1600dd2c627SGreg Clayton else 161c235ac76SGreg Clayton m_suspend_count = 0; 1620dd2c627SGreg Clayton return false; // ??? 16330fdc8d8SChris Lattner } 16430fdc8d8SChris Lattner } 1650dd2c627SGreg Clayton } 166c235ac76SGreg Clayton else if (m_suspend_count < 0) 1679411ddb6SJim Ingham { 168c235ac76SGreg Clayton while (m_suspend_count < 0) 1699411ddb6SJim Ingham { 1701c73911dSJason Molenda err = ::thread_suspend (m_mach_port_number); 1719411ddb6SJim Ingham if (err.Success()) 172c235ac76SGreg Clayton ++m_suspend_count; 1739411ddb6SJim Ingham if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 174478235d8SJim Ingham { 1751c73911dSJason Molenda err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number); 176478235d8SJim Ingham return false; 177478235d8SJim Ingham } 1789411ddb6SJim Ingham } 1799411ddb6SJim Ingham } 1800dd2c627SGreg Clayton return true; 18130fdc8d8SChris Lattner } 18230fdc8d8SChris Lattner 18330fdc8d8SChris Lattner 18430fdc8d8SChris Lattner const char * 18530fdc8d8SChris Lattner MachThread::GetBasicInfoAsString () const 18630fdc8d8SChris Lattner { 18730fdc8d8SChris Lattner static char g_basic_info_string[1024]; 18830fdc8d8SChris Lattner struct thread_basic_info basicInfo; 18930fdc8d8SChris Lattner 1901c73911dSJason Molenda if (GetBasicInfo(m_mach_port_number, &basicInfo)) 19130fdc8d8SChris Lattner { 19230fdc8d8SChris Lattner 19330fdc8d8SChris Lattner // char run_state_str[32]; 19430fdc8d8SChris Lattner // size_t run_state_str_size = sizeof(run_state_str); 19530fdc8d8SChris Lattner // switch (basicInfo.run_state) 19630fdc8d8SChris Lattner // { 19730fdc8d8SChris Lattner // case TH_STATE_RUNNING: strncpy(run_state_str, "running", run_state_str_size); break; 19830fdc8d8SChris Lattner // case TH_STATE_STOPPED: strncpy(run_state_str, "stopped", run_state_str_size); break; 19930fdc8d8SChris Lattner // case TH_STATE_WAITING: strncpy(run_state_str, "waiting", run_state_str_size); break; 20030fdc8d8SChris Lattner // case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str, "uninterruptible", run_state_str_size); break; 20130fdc8d8SChris Lattner // case TH_STATE_HALTED: strncpy(run_state_str, "halted", run_state_str_size); break; 20230fdc8d8SChris Lattner // default: snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break; // ??? 20330fdc8d8SChris Lattner // } 20430fdc8d8SChris Lattner float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f; 20530fdc8d8SChris Lattner float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f; 2061c73911dSJason 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", 2071c73911dSJason Molenda m_unique_id, 20830fdc8d8SChris Lattner user, 20930fdc8d8SChris Lattner system, 21030fdc8d8SChris Lattner basicInfo.cpu_usage, 21130fdc8d8SChris Lattner basicInfo.sleep_time); 21230fdc8d8SChris Lattner 21330fdc8d8SChris Lattner return g_basic_info_string; 21430fdc8d8SChris Lattner } 21530fdc8d8SChris Lattner return NULL; 21630fdc8d8SChris Lattner } 21730fdc8d8SChris Lattner 2181c73911dSJason Molenda // Finds the Mach port number for a given thread in the inferior process' port namespace. 21930fdc8d8SChris Lattner thread_t 22030fdc8d8SChris Lattner MachThread::InferiorThreadID() const 22130fdc8d8SChris Lattner { 22230fdc8d8SChris Lattner mach_msg_type_number_t i; 22330fdc8d8SChris Lattner mach_port_name_array_t names; 22430fdc8d8SChris Lattner mach_port_type_array_t types; 22530fdc8d8SChris Lattner mach_msg_type_number_t ncount, tcount; 22630fdc8d8SChris Lattner thread_t inferior_tid = INVALID_NUB_THREAD; 22730fdc8d8SChris Lattner task_t my_task = ::mach_task_self(); 22830fdc8d8SChris Lattner task_t task = m_process->Task().TaskPort(); 22930fdc8d8SChris Lattner 23030fdc8d8SChris Lattner kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount); 23130fdc8d8SChris Lattner if (kret == KERN_SUCCESS) 23230fdc8d8SChris Lattner { 23330fdc8d8SChris Lattner 23430fdc8d8SChris Lattner for (i = 0; i < ncount; i++) 23530fdc8d8SChris Lattner { 23630fdc8d8SChris Lattner mach_port_t my_name; 23730fdc8d8SChris Lattner mach_msg_type_name_t my_type; 23830fdc8d8SChris Lattner 23930fdc8d8SChris Lattner kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type); 24030fdc8d8SChris Lattner if (kret == KERN_SUCCESS) 24130fdc8d8SChris Lattner { 24230fdc8d8SChris Lattner ::mach_port_deallocate (my_task, my_name); 2431c73911dSJason Molenda if (my_name == m_mach_port_number) 24430fdc8d8SChris Lattner { 24530fdc8d8SChris Lattner inferior_tid = names[i]; 24630fdc8d8SChris Lattner break; 24730fdc8d8SChris Lattner } 24830fdc8d8SChris Lattner } 24930fdc8d8SChris Lattner } 25030fdc8d8SChris Lattner // Free up the names and types 25130fdc8d8SChris Lattner ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t)); 25230fdc8d8SChris Lattner ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t)); 25330fdc8d8SChris Lattner } 25430fdc8d8SChris Lattner return inferior_tid; 25530fdc8d8SChris Lattner } 25630fdc8d8SChris Lattner 25730fdc8d8SChris Lattner bool 2581b946bf6SGreg Clayton MachThread::IsUserReady() 2591b946bf6SGreg Clayton { 260c235ac76SGreg Clayton if (m_basic_info.run_state == 0) 261cdc7322bSGreg Clayton GetBasicInfo (); 2621b946bf6SGreg Clayton 263c235ac76SGreg Clayton switch (m_basic_info.run_state) 2641b946bf6SGreg Clayton { 2651b946bf6SGreg Clayton default: 2661b946bf6SGreg Clayton case TH_STATE_UNINTERRUPTIBLE: 2671b946bf6SGreg Clayton break; 2681b946bf6SGreg Clayton 2691b946bf6SGreg Clayton case TH_STATE_RUNNING: 2701b946bf6SGreg Clayton case TH_STATE_STOPPED: 2711b946bf6SGreg Clayton case TH_STATE_WAITING: 2721b946bf6SGreg Clayton case TH_STATE_HALTED: 2731b946bf6SGreg Clayton return true; 2741b946bf6SGreg Clayton } 2751b946bf6SGreg Clayton return false; 2761b946bf6SGreg Clayton } 2771b946bf6SGreg Clayton 2781b946bf6SGreg Clayton struct thread_basic_info * 279cdc7322bSGreg Clayton MachThread::GetBasicInfo () 2801b946bf6SGreg Clayton { 2811c73911dSJason Molenda if (MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info)) 282c235ac76SGreg Clayton return &m_basic_info; 2831b946bf6SGreg Clayton return NULL; 2841b946bf6SGreg Clayton } 2851b946bf6SGreg Clayton 2861b946bf6SGreg Clayton 2871b946bf6SGreg Clayton bool 28830fdc8d8SChris Lattner MachThread::GetBasicInfo(thread_t thread, struct thread_basic_info *basicInfoPtr) 28930fdc8d8SChris Lattner { 2901c73911dSJason Molenda if (MachPortNumberIsValid(thread)) 29130fdc8d8SChris Lattner { 29230fdc8d8SChris Lattner unsigned int info_count = THREAD_BASIC_INFO_COUNT; 29330fdc8d8SChris Lattner kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count); 29430fdc8d8SChris Lattner if (err == KERN_SUCCESS) 29530fdc8d8SChris Lattner return true; 29630fdc8d8SChris Lattner } 29730fdc8d8SChris Lattner ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info)); 29830fdc8d8SChris Lattner return false; 29930fdc8d8SChris Lattner } 30030fdc8d8SChris Lattner 30130fdc8d8SChris Lattner 30230fdc8d8SChris Lattner bool 3031c73911dSJason Molenda MachThread::ThreadIDIsValid(uint64_t thread) 3041c73911dSJason Molenda { 3051c73911dSJason Molenda return thread != 0; 3061c73911dSJason Molenda } 3071c73911dSJason Molenda 3081c73911dSJason Molenda bool 3091c73911dSJason Molenda MachThread::MachPortNumberIsValid(thread_t thread) 31030fdc8d8SChris Lattner { 31130fdc8d8SChris Lattner return thread != THREAD_NULL; 31230fdc8d8SChris Lattner } 31330fdc8d8SChris Lattner 31430fdc8d8SChris Lattner bool 31530fdc8d8SChris Lattner MachThread::GetRegisterState(int flavor, bool force) 31630fdc8d8SChris Lattner { 3173af9ea56SGreg Clayton return m_arch_ap->GetRegisterState(flavor, force) == KERN_SUCCESS; 31830fdc8d8SChris Lattner } 31930fdc8d8SChris Lattner 32030fdc8d8SChris Lattner bool 32130fdc8d8SChris Lattner MachThread::SetRegisterState(int flavor) 32230fdc8d8SChris Lattner { 3233af9ea56SGreg Clayton return m_arch_ap->SetRegisterState(flavor) == KERN_SUCCESS; 32430fdc8d8SChris Lattner } 32530fdc8d8SChris Lattner 32630fdc8d8SChris Lattner uint64_t 32730fdc8d8SChris Lattner MachThread::GetPC(uint64_t failValue) 32830fdc8d8SChris Lattner { 32930fdc8d8SChris Lattner // Get program counter 3303af9ea56SGreg Clayton return m_arch_ap->GetPC(failValue); 33130fdc8d8SChris Lattner } 33230fdc8d8SChris Lattner 33330fdc8d8SChris Lattner bool 33430fdc8d8SChris Lattner MachThread::SetPC(uint64_t value) 33530fdc8d8SChris Lattner { 33630fdc8d8SChris Lattner // Set program counter 3373af9ea56SGreg Clayton return m_arch_ap->SetPC(value); 33830fdc8d8SChris Lattner } 33930fdc8d8SChris Lattner 34030fdc8d8SChris Lattner uint64_t 34130fdc8d8SChris Lattner MachThread::GetSP(uint64_t failValue) 34230fdc8d8SChris Lattner { 34330fdc8d8SChris Lattner // Get stack pointer 3443af9ea56SGreg Clayton return m_arch_ap->GetSP(failValue); 34530fdc8d8SChris Lattner } 34630fdc8d8SChris Lattner 34730fdc8d8SChris Lattner nub_process_t 34830fdc8d8SChris Lattner MachThread::ProcessID() const 34930fdc8d8SChris Lattner { 35030fdc8d8SChris Lattner if (m_process) 35130fdc8d8SChris Lattner return m_process->ProcessID(); 35230fdc8d8SChris Lattner return INVALID_NUB_PROCESS; 35330fdc8d8SChris Lattner } 35430fdc8d8SChris Lattner 35530fdc8d8SChris Lattner void 35630fdc8d8SChris Lattner MachThread::Dump(uint32_t index) 35730fdc8d8SChris Lattner { 35830fdc8d8SChris Lattner const char * thread_run_state = NULL; 35930fdc8d8SChris Lattner 360c235ac76SGreg Clayton switch (m_basic_info.run_state) 36130fdc8d8SChris Lattner { 36230fdc8d8SChris Lattner case TH_STATE_RUNNING: thread_run_state = "running"; break; // 1 thread is running normally 36330fdc8d8SChris Lattner case TH_STATE_STOPPED: thread_run_state = "stopped"; break; // 2 thread is stopped 36430fdc8d8SChris Lattner case TH_STATE_WAITING: thread_run_state = "waiting"; break; // 3 thread is waiting normally 36530fdc8d8SChris Lattner case TH_STATE_UNINTERRUPTIBLE: thread_run_state = "uninter"; break; // 4 thread is in an uninterruptible wait 36630fdc8d8SChris Lattner case TH_STATE_HALTED: thread_run_state = "halted "; break; // 5 thread is halted at a 36730fdc8d8SChris Lattner default: thread_run_state = "???"; break; 36830fdc8d8SChris Lattner } 36930fdc8d8SChris Lattner 370d8cf1a11SGreg 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", 37130fdc8d8SChris Lattner index, 37230fdc8d8SChris Lattner m_seq_id, 3731c73911dSJason Molenda m_unique_id, 37430fdc8d8SChris Lattner GetPC(INVALID_NUB_ADDRESS), 37530fdc8d8SChris Lattner GetSP(INVALID_NUB_ADDRESS), 376c235ac76SGreg Clayton m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds, 377c235ac76SGreg Clayton m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds, 378c235ac76SGreg Clayton m_basic_info.cpu_usage, 379c235ac76SGreg Clayton m_basic_info.policy, 380c235ac76SGreg Clayton m_basic_info.run_state, 38130fdc8d8SChris Lattner thread_run_state, 382c235ac76SGreg Clayton m_basic_info.flags, 383c235ac76SGreg Clayton m_basic_info.suspend_count, m_suspend_count, 384c235ac76SGreg Clayton m_basic_info.sleep_time); 38530fdc8d8SChris Lattner //DumpRegisterState(0); 38630fdc8d8SChris Lattner } 38730fdc8d8SChris Lattner 38830fdc8d8SChris Lattner void 3899411ddb6SJim Ingham MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action, bool others_stopped) 39030fdc8d8SChris Lattner { 39130fdc8d8SChris Lattner if (thread_action->addr != INVALID_NUB_ADDRESS) 39230fdc8d8SChris Lattner SetPC (thread_action->addr); 393cdc7322bSGreg Clayton 39430fdc8d8SChris Lattner SetState (thread_action->state); 39530fdc8d8SChris Lattner switch (thread_action->state) 39630fdc8d8SChris Lattner { 39730fdc8d8SChris Lattner case eStateStopped: 39830fdc8d8SChris Lattner case eStateSuspended: 3999411ddb6SJim Ingham assert (others_stopped == false); 40030fdc8d8SChris Lattner Suspend(); 40130fdc8d8SChris Lattner break; 40230fdc8d8SChris Lattner 40330fdc8d8SChris Lattner case eStateRunning: 404b1e11121SJim Ingham case eStateStepping: 4059411ddb6SJim Ingham Resume(others_stopped); 406b1e11121SJim Ingham break; 407effe5c95SGreg Clayton default: 408effe5c95SGreg Clayton break; 40930fdc8d8SChris Lattner } 4103af9ea56SGreg Clayton m_arch_ap->ThreadWillResume(); 41130fdc8d8SChris Lattner m_stop_exception.Clear(); 41230fdc8d8SChris Lattner } 41330fdc8d8SChris Lattner 414d8cf1a11SGreg Clayton DNBBreakpoint * 415c4e411ffSGreg Clayton MachThread::CurrentBreakpoint() 416c4e411ffSGreg Clayton { 417d8cf1a11SGreg Clayton return m_process->Breakpoints().FindByAddress(GetPC()); 418c4e411ffSGreg Clayton } 419c4e411ffSGreg Clayton 42030fdc8d8SChris Lattner bool 42130fdc8d8SChris Lattner MachThread::ShouldStop(bool &step_more) 42230fdc8d8SChris Lattner { 42330fdc8d8SChris Lattner // See if this thread is at a breakpoint? 424d8cf1a11SGreg Clayton DNBBreakpoint *bp = CurrentBreakpoint(); 42530fdc8d8SChris Lattner 426d8cf1a11SGreg Clayton if (bp) 42730fdc8d8SChris Lattner { 42830fdc8d8SChris Lattner // This thread is sitting at a breakpoint, ask the breakpoint 42930fdc8d8SChris Lattner // if we should be stopping here. 43030fdc8d8SChris Lattner return true; 43130fdc8d8SChris Lattner } 43230fdc8d8SChris Lattner else 43330fdc8d8SChris Lattner { 4343af9ea56SGreg Clayton if (m_arch_ap->StepNotComplete()) 43530fdc8d8SChris Lattner { 43630fdc8d8SChris Lattner step_more = true; 43730fdc8d8SChris Lattner return false; 43830fdc8d8SChris Lattner } 43930fdc8d8SChris Lattner // The thread state is used to let us know what the thread was 44030fdc8d8SChris Lattner // trying to do. MachThread::ThreadWillResume() will set the 44130fdc8d8SChris Lattner // thread state to various values depending if the thread was 44230fdc8d8SChris Lattner // the current thread and if it was to be single stepped, or 44330fdc8d8SChris Lattner // resumed. 44430fdc8d8SChris Lattner if (GetState() == eStateRunning) 44530fdc8d8SChris Lattner { 44630fdc8d8SChris Lattner // If our state is running, then we should continue as we are in 44730fdc8d8SChris Lattner // the process of stepping over a breakpoint. 44830fdc8d8SChris Lattner return false; 44930fdc8d8SChris Lattner } 45030fdc8d8SChris Lattner else 45130fdc8d8SChris Lattner { 45230fdc8d8SChris Lattner // Stop if we have any kind of valid exception for this 45330fdc8d8SChris Lattner // thread. 45430fdc8d8SChris Lattner if (GetStopException().IsValid()) 45530fdc8d8SChris Lattner return true; 45630fdc8d8SChris Lattner } 45730fdc8d8SChris Lattner } 45830fdc8d8SChris Lattner return false; 45930fdc8d8SChris Lattner } 46030fdc8d8SChris Lattner bool 46130fdc8d8SChris Lattner MachThread::IsStepping() 46230fdc8d8SChris Lattner { 463c4e411ffSGreg Clayton return GetState() == eStateStepping; 46430fdc8d8SChris Lattner } 46530fdc8d8SChris Lattner 46630fdc8d8SChris Lattner 46730fdc8d8SChris Lattner bool 46830fdc8d8SChris Lattner MachThread::ThreadDidStop() 46930fdc8d8SChris Lattner { 47030fdc8d8SChris Lattner // This thread has existed prior to resuming under debug nub control, 47130fdc8d8SChris Lattner // and has just been stopped. Do any cleanup that needs to be done 47230fdc8d8SChris Lattner // after running. 47330fdc8d8SChris Lattner 47430fdc8d8SChris Lattner // The thread state and breakpoint will still have the same values 47530fdc8d8SChris Lattner // as they had prior to resuming the thread, so it makes it easy to check 47630fdc8d8SChris Lattner // if we were trying to step a thread, or we tried to resume while being 47730fdc8d8SChris Lattner // at a breakpoint. 47830fdc8d8SChris Lattner 47930fdc8d8SChris Lattner // When this method gets called, the process state is still in the 48030fdc8d8SChris Lattner // state it was in while running so we can act accordingly. 4813af9ea56SGreg Clayton m_arch_ap->ThreadDidStop(); 48230fdc8d8SChris Lattner 48330fdc8d8SChris Lattner 48430fdc8d8SChris Lattner // We may have suspended this thread so the primary thread could step 48530fdc8d8SChris Lattner // without worrying about race conditions, so lets restore our suspend 48630fdc8d8SChris Lattner // count. 4879411ddb6SJim Ingham RestoreSuspendCountAfterStop(); 48830fdc8d8SChris Lattner 48930fdc8d8SChris Lattner // Update the basic information for a thread 4901c73911dSJason Molenda MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info); 49130fdc8d8SChris Lattner 492c235ac76SGreg Clayton if (m_basic_info.suspend_count > 0) 493c4e411ffSGreg Clayton SetState(eStateSuspended); 494c4e411ffSGreg Clayton else 495c4e411ffSGreg Clayton SetState(eStateStopped); 49630fdc8d8SChris Lattner return true; 49730fdc8d8SChris Lattner } 49830fdc8d8SChris Lattner 49930fdc8d8SChris Lattner bool 50030fdc8d8SChris Lattner MachThread::NotifyException(MachException::Data& exc) 50130fdc8d8SChris Lattner { 50288c1b77fSJohnny Chen // Allow the arch specific protocol to process (MachException::Data &)exc 50388c1b77fSJohnny Chen // first before possible reassignment of m_stop_exception with exc. 50476abb3b5SJohnny Chen // See also MachThread::GetStopException(). 50588c1b77fSJohnny Chen bool handled = m_arch_ap->NotifyException(exc); 50688c1b77fSJohnny Chen 50730fdc8d8SChris Lattner if (m_stop_exception.IsValid()) 50830fdc8d8SChris Lattner { 50930fdc8d8SChris Lattner // We may have more than one exception for a thread, but we need to 51030fdc8d8SChris Lattner // only remember the one that we will say is the reason we stopped. 51130fdc8d8SChris Lattner // We may have been single stepping and also gotten a signal exception, 51230fdc8d8SChris Lattner // so just remember the most pertinent one. 51330fdc8d8SChris Lattner if (m_stop_exception.IsBreakpoint()) 51430fdc8d8SChris Lattner m_stop_exception = exc; 51530fdc8d8SChris Lattner } 51630fdc8d8SChris Lattner else 51730fdc8d8SChris Lattner { 51830fdc8d8SChris Lattner m_stop_exception = exc; 51930fdc8d8SChris Lattner } 52088c1b77fSJohnny Chen 52130fdc8d8SChris Lattner return handled; 52230fdc8d8SChris Lattner } 52330fdc8d8SChris Lattner 52430fdc8d8SChris Lattner 52530fdc8d8SChris Lattner nub_state_t 52630fdc8d8SChris Lattner MachThread::GetState() 52730fdc8d8SChris Lattner { 52830fdc8d8SChris Lattner // If any other threads access this we will need a mutex for it 52930fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_state_mutex); 53030fdc8d8SChris Lattner return m_state; 53130fdc8d8SChris Lattner } 53230fdc8d8SChris Lattner 53330fdc8d8SChris Lattner void 53430fdc8d8SChris Lattner MachThread::SetState(nub_state_t state) 53530fdc8d8SChris Lattner { 53630fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_state_mutex); 53730fdc8d8SChris Lattner m_state = state; 5381c73911dSJason Molenda DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%8.8" PRIx64 "", DNBStateAsString(state), m_unique_id); 53930fdc8d8SChris Lattner } 54030fdc8d8SChris Lattner 541*ee2ed525SGreg Clayton nub_size_t 54230fdc8d8SChris Lattner MachThread::GetNumRegistersInSet(int regSet) const 54330fdc8d8SChris Lattner { 544c235ac76SGreg Clayton if (regSet < m_num_reg_sets) 5453af9ea56SGreg Clayton return m_reg_sets[regSet].num_registers; 54630fdc8d8SChris Lattner return 0; 54730fdc8d8SChris Lattner } 54830fdc8d8SChris Lattner 54930fdc8d8SChris Lattner const char * 55030fdc8d8SChris Lattner MachThread::GetRegisterSetName(int regSet) const 55130fdc8d8SChris Lattner { 552c235ac76SGreg Clayton if (regSet < m_num_reg_sets) 5533af9ea56SGreg Clayton return m_reg_sets[regSet].name; 55430fdc8d8SChris Lattner return NULL; 55530fdc8d8SChris Lattner } 55630fdc8d8SChris Lattner 55730fdc8d8SChris Lattner const DNBRegisterInfo * 55830fdc8d8SChris Lattner MachThread::GetRegisterInfo(int regSet, int regIndex) const 55930fdc8d8SChris Lattner { 560c235ac76SGreg Clayton if (regSet < m_num_reg_sets) 5613af9ea56SGreg Clayton if (regIndex < m_reg_sets[regSet].num_registers) 5623af9ea56SGreg Clayton return &m_reg_sets[regSet].registers[regIndex]; 56330fdc8d8SChris Lattner return NULL; 56430fdc8d8SChris Lattner } 56530fdc8d8SChris Lattner void 56630fdc8d8SChris Lattner MachThread::DumpRegisterState(int regSet) 56730fdc8d8SChris Lattner { 56830fdc8d8SChris Lattner if (regSet == REGISTER_SET_ALL) 56930fdc8d8SChris Lattner { 570c235ac76SGreg Clayton for (regSet = 1; regSet < m_num_reg_sets; regSet++) 57130fdc8d8SChris Lattner DumpRegisterState(regSet); 57230fdc8d8SChris Lattner } 57330fdc8d8SChris Lattner else 57430fdc8d8SChris Lattner { 5753af9ea56SGreg Clayton if (m_arch_ap->RegisterSetStateIsValid(regSet)) 57630fdc8d8SChris Lattner { 57730fdc8d8SChris Lattner const size_t numRegisters = GetNumRegistersInSet(regSet); 578*ee2ed525SGreg Clayton uint32_t regIndex = 0; 57930fdc8d8SChris Lattner DNBRegisterValueClass reg; 58030fdc8d8SChris Lattner for (regIndex = 0; regIndex < numRegisters; ++regIndex) 58130fdc8d8SChris Lattner { 5823af9ea56SGreg Clayton if (m_arch_ap->GetRegisterValue(regSet, regIndex, ®)) 58330fdc8d8SChris Lattner { 58430fdc8d8SChris Lattner reg.Dump(NULL, NULL); 58530fdc8d8SChris Lattner } 58630fdc8d8SChris Lattner } 58730fdc8d8SChris Lattner } 58830fdc8d8SChris Lattner else 58930fdc8d8SChris Lattner { 59030fdc8d8SChris Lattner DNBLog("%s: registers are not currently valid.", GetRegisterSetName(regSet)); 59130fdc8d8SChris Lattner } 59230fdc8d8SChris Lattner } 59330fdc8d8SChris Lattner } 59430fdc8d8SChris Lattner 59530fdc8d8SChris Lattner const DNBRegisterSetInfo * 59630fdc8d8SChris Lattner MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const 59730fdc8d8SChris Lattner { 598c235ac76SGreg Clayton *num_reg_sets = m_num_reg_sets; 5993af9ea56SGreg Clayton return &m_reg_sets[0]; 60030fdc8d8SChris Lattner } 60130fdc8d8SChris Lattner 60230fdc8d8SChris Lattner bool 60330fdc8d8SChris Lattner MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value ) 60430fdc8d8SChris Lattner { 6053af9ea56SGreg Clayton return m_arch_ap->GetRegisterValue(set, reg, value); 60630fdc8d8SChris Lattner } 60730fdc8d8SChris Lattner 60830fdc8d8SChris Lattner bool 60930fdc8d8SChris Lattner MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value ) 61030fdc8d8SChris Lattner { 6113af9ea56SGreg Clayton return m_arch_ap->SetRegisterValue(set, reg, value); 61230fdc8d8SChris Lattner } 61330fdc8d8SChris Lattner 61430fdc8d8SChris Lattner nub_size_t 61530fdc8d8SChris Lattner MachThread::GetRegisterContext (void *buf, nub_size_t buf_len) 61630fdc8d8SChris Lattner { 6173af9ea56SGreg Clayton return m_arch_ap->GetRegisterContext(buf, buf_len); 61830fdc8d8SChris Lattner } 61930fdc8d8SChris Lattner 62030fdc8d8SChris Lattner nub_size_t 62130fdc8d8SChris Lattner MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len) 62230fdc8d8SChris Lattner { 6233af9ea56SGreg Clayton return m_arch_ap->SetRegisterContext(buf, buf_len); 62430fdc8d8SChris Lattner } 62530fdc8d8SChris Lattner 62630fdc8d8SChris Lattner uint32_t 627f74cf86bSGreg Clayton MachThread::SaveRegisterState () 628f74cf86bSGreg Clayton { 629f74cf86bSGreg Clayton return m_arch_ap->SaveRegisterState(); 630f74cf86bSGreg Clayton 631f74cf86bSGreg Clayton } 632f74cf86bSGreg Clayton bool 633f74cf86bSGreg Clayton MachThread::RestoreRegisterState (uint32_t save_id) 634f74cf86bSGreg Clayton { 635f74cf86bSGreg Clayton return m_arch_ap->RestoreRegisterState(save_id); 636f74cf86bSGreg Clayton } 637f74cf86bSGreg Clayton 638f74cf86bSGreg Clayton uint32_t 63930fdc8d8SChris Lattner MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp) 64030fdc8d8SChris Lattner { 64130fdc8d8SChris Lattner if (bp != NULL && bp->IsBreakpoint()) 6423af9ea56SGreg Clayton return m_arch_ap->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize()); 64330fdc8d8SChris Lattner return INVALID_NUB_HW_INDEX; 64430fdc8d8SChris Lattner } 64530fdc8d8SChris Lattner 64630fdc8d8SChris Lattner uint32_t 647f1715ab2SJim Ingham MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp, bool also_set_on_task) 64830fdc8d8SChris Lattner { 64930fdc8d8SChris Lattner if (wp != NULL && wp->IsWatchpoint()) 650f1715ab2SJim Ingham return m_arch_ap->EnableHardwareWatchpoint(wp->Address(), wp->ByteSize(), wp->WatchpointRead(), wp->WatchpointWrite(), also_set_on_task); 65130fdc8d8SChris Lattner return INVALID_NUB_HW_INDEX; 65230fdc8d8SChris Lattner } 65330fdc8d8SChris Lattner 65430fdc8d8SChris Lattner bool 65584707560SJohnny Chen MachThread::RollbackTransForHWP() 65684707560SJohnny Chen { 65784707560SJohnny Chen return m_arch_ap->RollbackTransForHWP(); 65884707560SJohnny Chen } 65984707560SJohnny Chen 66084707560SJohnny Chen bool 66184707560SJohnny Chen MachThread::FinishTransForHWP() 66284707560SJohnny Chen { 66384707560SJohnny Chen return m_arch_ap->FinishTransForHWP(); 66484707560SJohnny Chen } 66584707560SJohnny Chen 66684707560SJohnny Chen bool 66730fdc8d8SChris Lattner MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp) 66830fdc8d8SChris Lattner { 66930fdc8d8SChris Lattner if (bp != NULL && bp->IsHardware()) 6703af9ea56SGreg Clayton return m_arch_ap->DisableHardwareBreakpoint(bp->GetHardwareIndex()); 67130fdc8d8SChris Lattner return false; 67230fdc8d8SChris Lattner } 67330fdc8d8SChris Lattner 67430fdc8d8SChris Lattner bool 675f1715ab2SJim Ingham MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp, bool also_set_on_task) 67630fdc8d8SChris Lattner { 67730fdc8d8SChris Lattner if (wp != NULL && wp->IsHardware()) 678f1715ab2SJim Ingham return m_arch_ap->DisableHardwareWatchpoint(wp->GetHardwareIndex(), also_set_on_task); 67930fdc8d8SChris Lattner return false; 68030fdc8d8SChris Lattner } 68130fdc8d8SChris Lattner 68264637205SJohnny Chen uint32_t 68364637205SJohnny Chen MachThread::NumSupportedHardwareWatchpoints () const 68464637205SJohnny Chen { 68564637205SJohnny Chen return m_arch_ap->NumSupportedHardwareWatchpoints(); 68664637205SJohnny Chen } 68764637205SJohnny Chen 68830fdc8d8SChris Lattner bool 68930fdc8d8SChris Lattner MachThread::GetIdentifierInfo () 69030fdc8d8SChris Lattner { 691f2c6ccf0SJim 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 692f2c6ccf0SJim Ingham // if the thread name changes, then the thread_handle also changes... So you have to refetch it every time. 69330fdc8d8SChris Lattner mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; 6941c73911dSJason Molenda kern_return_t kret = ::thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count); 695f2c6ccf0SJim Ingham return kret == KERN_SUCCESS; 69630fdc8d8SChris Lattner 69730fdc8d8SChris Lattner return false; 69830fdc8d8SChris Lattner } 69930fdc8d8SChris Lattner 70030fdc8d8SChris Lattner 70130fdc8d8SChris Lattner const char * 70230fdc8d8SChris Lattner MachThread::GetName () 70330fdc8d8SChris Lattner { 70430fdc8d8SChris Lattner if (GetIdentifierInfo ()) 70530fdc8d8SChris Lattner { 70630fdc8d8SChris Lattner int len = ::proc_pidinfo (m_process->ProcessID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo)); 70730fdc8d8SChris Lattner 70830fdc8d8SChris Lattner if (len && m_proc_threadinfo.pth_name[0]) 70930fdc8d8SChris Lattner return m_proc_threadinfo.pth_name; 71030fdc8d8SChris Lattner } 71130fdc8d8SChris Lattner return NULL; 71230fdc8d8SChris Lattner } 71330fdc8d8SChris Lattner 7141c73911dSJason Molenda 7151c73911dSJason Molenda uint64_t 7161c73911dSJason Molenda MachThread::GetGloballyUniqueThreadIDForMachPortID (thread_t mach_port_id) 7171c73911dSJason Molenda { 7181c73911dSJason Molenda kern_return_t kr; 7191c73911dSJason Molenda thread_identifier_info_data_t tident; 7201c73911dSJason Molenda mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; 7211c73911dSJason Molenda kr = thread_info (mach_port_id, THREAD_IDENTIFIER_INFO, 7221c73911dSJason Molenda (thread_info_t) &tident, &tident_count); 7231c73911dSJason Molenda if (kr != KERN_SUCCESS) 7241c73911dSJason Molenda { 7251c73911dSJason Molenda return mach_port_id; 7261c73911dSJason Molenda } 7271c73911dSJason Molenda return tident.thread_id; 7281c73911dSJason Molenda } 729705b1809SJason Molenda 730705b1809SJason Molenda nub_addr_t 731705b1809SJason Molenda MachThread::GetPThreadT () 732705b1809SJason Molenda { 733705b1809SJason Molenda nub_addr_t pthread_t_value = INVALID_NUB_ADDRESS; 734705b1809SJason Molenda if (MachPortNumberIsValid (m_mach_port_number)) 735705b1809SJason Molenda { 736705b1809SJason Molenda kern_return_t kr; 737705b1809SJason Molenda thread_identifier_info_data_t tident; 738705b1809SJason Molenda mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; 739705b1809SJason Molenda kr = thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO, 740705b1809SJason Molenda (thread_info_t) &tident, &tident_count); 741705b1809SJason Molenda if (kr == KERN_SUCCESS) 742705b1809SJason Molenda { 743705b1809SJason Molenda // Dereference thread_handle to get the pthread_t value for this thread. 744705b1809SJason Molenda if (m_is_64_bit) 745705b1809SJason Molenda { 746705b1809SJason Molenda uint64_t addr; 747705b1809SJason Molenda if (m_process->ReadMemory (tident.thread_handle, 8, &addr) == 8) 748705b1809SJason Molenda { 749705b1809SJason Molenda if (addr != 0) 750705b1809SJason Molenda { 751705b1809SJason Molenda pthread_t_value = addr; 752705b1809SJason Molenda } 753705b1809SJason Molenda } 754705b1809SJason Molenda } 755705b1809SJason Molenda else 756705b1809SJason Molenda { 757705b1809SJason Molenda uint32_t addr; 758705b1809SJason Molenda if (m_process->ReadMemory (tident.thread_handle, 4, &addr) == 4) 759705b1809SJason Molenda { 760705b1809SJason Molenda if (addr != 0) 761705b1809SJason Molenda { 762705b1809SJason Molenda pthread_t_value = addr; 763705b1809SJason Molenda } 764705b1809SJason Molenda } 765705b1809SJason Molenda } 766705b1809SJason Molenda } 767705b1809SJason Molenda } 768705b1809SJason Molenda return pthread_t_value; 769705b1809SJason Molenda } 770705b1809SJason Molenda 771705b1809SJason Molenda // Return this thread's TSD (Thread Specific Data) address. 772705b1809SJason Molenda // This is computed based on this thread's pthread_t value. 773705b1809SJason Molenda // 774705b1809SJason Molenda // We compute the TSD from the pthread_t by one of two methods. 775705b1809SJason Molenda // 776705b1809SJason Molenda // If plo_pthread_tsd_base_offset is non-zero, this is a simple offset that we add to 777705b1809SJason Molenda // the pthread_t to get the TSD base address. 778705b1809SJason Molenda // 779705b1809SJason Molenda // Else we read a pointer from memory at pthread_t + plo_pthread_tsd_base_address_offset and 780705b1809SJason Molenda // that gives us the TSD address. 781705b1809SJason Molenda // 782705b1809SJason Molenda // These plo_pthread_tsd_base values must be read out of libpthread by lldb & provided to debugserver. 783705b1809SJason Molenda 784705b1809SJason Molenda nub_addr_t 785705b1809SJason Molenda MachThread::GetTSDAddressForThread (uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size) 786705b1809SJason Molenda { 787705b1809SJason Molenda nub_addr_t tsd_addr = INVALID_NUB_ADDRESS; 788705b1809SJason Molenda nub_addr_t pthread_t_value = GetPThreadT(); 789705b1809SJason Molenda if (plo_pthread_tsd_base_offset != 0 && plo_pthread_tsd_base_offset != INVALID_NUB_ADDRESS) 790705b1809SJason Molenda { 791705b1809SJason Molenda tsd_addr = pthread_t_value + plo_pthread_tsd_base_offset; 792705b1809SJason Molenda } 793705b1809SJason Molenda else 794705b1809SJason Molenda { 795705b1809SJason Molenda if (plo_pthread_tsd_entry_size == 4) 796705b1809SJason Molenda { 797705b1809SJason Molenda uint32_t addr = 0; 798705b1809SJason Molenda if (m_process->ReadMemory (pthread_t_value + plo_pthread_tsd_base_address_offset, 4, &addr) == 4) 799705b1809SJason Molenda { 800705b1809SJason Molenda if (addr != 0) 801705b1809SJason Molenda { 802705b1809SJason Molenda tsd_addr = addr; 803705b1809SJason Molenda } 804705b1809SJason Molenda } 805705b1809SJason Molenda } 806705b1809SJason Molenda if (plo_pthread_tsd_entry_size == 4) 807705b1809SJason Molenda { 808705b1809SJason Molenda uint64_t addr = 0; 809705b1809SJason Molenda if (m_process->ReadMemory (pthread_t_value + plo_pthread_tsd_base_address_offset, 8, &addr) == 8) 810705b1809SJason Molenda { 811705b1809SJason Molenda if (addr != 0) 812705b1809SJason Molenda { 813705b1809SJason Molenda tsd_addr = addr; 814705b1809SJason Molenda } 815705b1809SJason Molenda } 816705b1809SJason Molenda } 817705b1809SJason Molenda } 818705b1809SJason Molenda return tsd_addr; 819705b1809SJason Molenda } 820705b1809SJason Molenda 821705b1809SJason Molenda 822705b1809SJason Molenda nub_addr_t 823705b1809SJason Molenda MachThread::GetDispatchQueueT () 824705b1809SJason Molenda { 825705b1809SJason Molenda nub_addr_t dispatch_queue_t_value = INVALID_NUB_ADDRESS; 826705b1809SJason Molenda if (MachPortNumberIsValid (m_mach_port_number)) 827705b1809SJason Molenda { 828705b1809SJason Molenda kern_return_t kr; 829705b1809SJason Molenda thread_identifier_info_data_t tident; 830705b1809SJason Molenda mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; 831705b1809SJason Molenda kr = thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO, 832705b1809SJason Molenda (thread_info_t) &tident, &tident_count); 833705b1809SJason Molenda if (kr == KERN_SUCCESS && tident.dispatch_qaddr != 0 && tident.dispatch_qaddr != INVALID_NUB_ADDRESS) 834705b1809SJason Molenda { 835705b1809SJason Molenda // Dereference dispatch_qaddr to get the dispatch_queue_t value for this thread's queue, if any. 836705b1809SJason Molenda if (m_is_64_bit) 837705b1809SJason Molenda { 838705b1809SJason Molenda uint64_t addr; 839705b1809SJason Molenda if (m_process->ReadMemory (tident.dispatch_qaddr, 8, &addr) == 8) 840705b1809SJason Molenda { 841705b1809SJason Molenda if (addr != 0) 842705b1809SJason Molenda dispatch_queue_t_value = addr; 843705b1809SJason Molenda } 844705b1809SJason Molenda } 845705b1809SJason Molenda else 846705b1809SJason Molenda { 847705b1809SJason Molenda uint32_t addr; 848705b1809SJason Molenda if (m_process->ReadMemory (tident.dispatch_qaddr, 4, &addr) == 4) 849705b1809SJason Molenda { 850705b1809SJason Molenda if (addr != 0) 851705b1809SJason Molenda dispatch_queue_t_value = addr; 852705b1809SJason Molenda } 853705b1809SJason Molenda } 854705b1809SJason Molenda } 855705b1809SJason Molenda } 856705b1809SJason Molenda return dispatch_queue_t_value; 857705b1809SJason Molenda } 858705b1809SJason Molenda 859705b1809SJason Molenda 860705b1809SJason Molenda ThreadInfo::QoS 861705b1809SJason Molenda MachThread::GetRequestedQoS (nub_addr_t tsd, uint64_t dti_qos_class_index) 862705b1809SJason Molenda { 863705b1809SJason Molenda ThreadInfo::QoS qos_value; 864705b1809SJason Molenda if (MachPortNumberIsValid (m_mach_port_number) && m_pthread_qos_class_decode != nullptr) 865705b1809SJason Molenda { 866705b1809SJason Molenda uint64_t pthread_priority_value = 0; 867705b1809SJason Molenda if (m_is_64_bit) 868705b1809SJason Molenda { 869705b1809SJason Molenda uint64_t pri; 870705b1809SJason Molenda if (m_process->ReadMemory (tsd + (dti_qos_class_index * 8), 8, &pri) == 8) 871705b1809SJason Molenda { 872705b1809SJason Molenda pthread_priority_value = pri; 873705b1809SJason Molenda } 874705b1809SJason Molenda } 875705b1809SJason Molenda else 876705b1809SJason Molenda { 877705b1809SJason Molenda uint32_t pri; 878705b1809SJason Molenda if (m_process->ReadMemory (tsd + (dti_qos_class_index * 4), 4, &pri) == 4) 879705b1809SJason Molenda { 880705b1809SJason Molenda pthread_priority_value = pri; 881705b1809SJason Molenda } 882705b1809SJason Molenda } 883705b1809SJason Molenda 884705b1809SJason Molenda uint32_t requested_qos = m_pthread_qos_class_decode (pthread_priority_value, NULL, NULL); 885705b1809SJason Molenda 886705b1809SJason Molenda switch (requested_qos) 887705b1809SJason Molenda { 888705b1809SJason Molenda // These constants from <pthread/qos.h> 889705b1809SJason Molenda case 0x21: 890705b1809SJason Molenda qos_value.enum_value = requested_qos; 891705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_USER_INTERACTIVE"; 892705b1809SJason Molenda qos_value.printable_name = "User Interactive"; 893705b1809SJason Molenda break; 894705b1809SJason Molenda case 0x19: 895705b1809SJason Molenda qos_value.enum_value = requested_qos; 896705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_USER_INITIATED"; 897705b1809SJason Molenda qos_value.printable_name = "User Initiated"; 898705b1809SJason Molenda break; 899705b1809SJason Molenda case 0x15: 900705b1809SJason Molenda qos_value.enum_value = requested_qos; 901705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_DEFAULT"; 902705b1809SJason Molenda qos_value.printable_name = "Default"; 903705b1809SJason Molenda break; 904705b1809SJason Molenda case 0x11: 905705b1809SJason Molenda qos_value.enum_value = requested_qos; 906705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_UTILITY"; 907705b1809SJason Molenda qos_value.printable_name = "Utility"; 908705b1809SJason Molenda break; 909705b1809SJason Molenda case 0x09: 910705b1809SJason Molenda qos_value.enum_value = requested_qos; 911705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_BACKGROUND"; 912705b1809SJason Molenda qos_value.printable_name = "Background"; 913705b1809SJason Molenda break; 914705b1809SJason Molenda case 0x00: 915705b1809SJason Molenda qos_value.enum_value = requested_qos; 916705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_UNSPECIFIED"; 917705b1809SJason Molenda qos_value.printable_name = "Unspecified"; 918705b1809SJason Molenda break; 919705b1809SJason Molenda } 920705b1809SJason Molenda } 921705b1809SJason Molenda return qos_value; 922705b1809SJason Molenda } 923