130fdc8d8SChris Lattner //===-- MachThread.cpp ------------------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 830fdc8d8SChris Lattner // 930fdc8d8SChris Lattner // Created by Greg Clayton on 6/19/07. 1030fdc8d8SChris Lattner // 1130fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 1230fdc8d8SChris Lattner 13b9c1b51eSKate Stone #include "MachThread.h" 14b9c1b51eSKate Stone #include "DNB.h" 15b9c1b51eSKate Stone #include "DNBLog.h" 16b9c1b51eSKate Stone #include "MachProcess.h" 17b9c1b51eSKate Stone #include "ThreadInfo.h" 18b9c1b51eSKate Stone #include <dlfcn.h> 191c73911dSJason Molenda #include <inttypes.h> 20705b1809SJason Molenda #include <mach/thread_policy.h> 2130fdc8d8SChris Lattner 22b9c1b51eSKate Stone static uint32_t GetSequenceID() { 2330fdc8d8SChris Lattner static uint32_t g_nextID = 0; 2430fdc8d8SChris Lattner return ++g_nextID; 2530fdc8d8SChris Lattner } 2630fdc8d8SChris Lattner 27b9c1b51eSKate Stone MachThread::MachThread(MachProcess *process, bool is_64_bit, 28b9c1b51eSKate Stone uint64_t unique_thread_id, thread_t mach_port_num) 29b9c1b51eSKate Stone : m_process(process), m_unique_id(unique_thread_id), 30b9c1b51eSKate Stone m_mach_port_number(mach_port_num), m_seq_id(GetSequenceID()), 31b9c1b51eSKate Stone m_state(eStateUnloaded), m_state_mutex(PTHREAD_MUTEX_RECURSIVE), 32b9c1b51eSKate Stone m_suspend_count(0), m_stop_exception(), 33d5b44036SJonas Devlieghere m_arch_up(DNBArchProtocol::Create(this)), m_reg_sets(NULL), 34b9c1b51eSKate Stone m_num_reg_sets(0), m_ident_info(), m_proc_threadinfo(), 35b9c1b51eSKate Stone m_dispatch_queue_name(), m_is_64_bit(is_64_bit), 36b9c1b51eSKate Stone m_pthread_qos_class_decode(nullptr) { 37c235ac76SGreg Clayton nub_size_t num_reg_sets = 0; 38d5b44036SJonas Devlieghere m_reg_sets = m_arch_up->GetRegisterSetInfo(&num_reg_sets); 39c235ac76SGreg Clayton m_num_reg_sets = num_reg_sets; 40c235ac76SGreg Clayton 41b9c1b51eSKate Stone m_pthread_qos_class_decode = 42b9c1b51eSKate Stone (unsigned int (*)(unsigned long, int *, unsigned long *))dlsym( 43b9c1b51eSKate Stone RTLD_DEFAULT, "_pthread_qos_class_decode"); 44705b1809SJason Molenda 451b946bf6SGreg Clayton // Get the thread state so we know if a thread is in a state where we can't 461b946bf6SGreg Clayton // muck with it and also so we get the suspend count correct in case it was 471b946bf6SGreg Clayton // already suspended 48cdc7322bSGreg Clayton GetBasicInfo(); 49b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, 50b9c1b51eSKate Stone "MachThread::MachThread ( process = %p, tid = 0x%8.8" PRIx64 51b9c1b51eSKate Stone ", seq_id = %u )", 52a64fafc7STim Hammerquist reinterpret_cast<void *>(&m_process), m_unique_id, m_seq_id); 5330fdc8d8SChris Lattner } 5430fdc8d8SChris Lattner 55b9c1b51eSKate Stone MachThread::~MachThread() { 56b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, 57b9c1b51eSKate Stone "MachThread::~MachThread() for tid = 0x%8.8" PRIx64 " (%u)", 58b9c1b51eSKate Stone m_unique_id, m_seq_id); 5930fdc8d8SChris Lattner } 6030fdc8d8SChris Lattner 61b9c1b51eSKate Stone void MachThread::Suspend() { 62b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", 63b9c1b51eSKate Stone __FUNCTION__); 64b9c1b51eSKate Stone if (MachPortNumberIsValid(m_mach_port_number)) { 651c73911dSJason Molenda DNBError err(::thread_suspend(m_mach_port_number), DNBError::MachKernel); 6630fdc8d8SChris Lattner if (err.Success()) 67c235ac76SGreg Clayton m_suspend_count++; 6830fdc8d8SChris Lattner if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 691c73911dSJason Molenda err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number); 7030fdc8d8SChris Lattner } 7130fdc8d8SChris Lattner } 7230fdc8d8SChris Lattner 73b9c1b51eSKate Stone void MachThread::Resume(bool others_stopped) { 74b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", 75b9c1b51eSKate Stone __FUNCTION__); 76b9c1b51eSKate Stone if (MachPortNumberIsValid(m_mach_port_number)) { 779411ddb6SJim Ingham SetSuspendCountBeforeResume(others_stopped); 7830fdc8d8SChris Lattner } 7930fdc8d8SChris Lattner } 8030fdc8d8SChris Lattner 81b9c1b51eSKate Stone bool MachThread::SetSuspendCountBeforeResume(bool others_stopped) { 82b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", 83b9c1b51eSKate Stone __FUNCTION__); 8430fdc8d8SChris Lattner DNBError err; 85a6682a41SJonas Devlieghere if (!MachPortNumberIsValid(m_mach_port_number)) 8630fdc8d8SChris Lattner return false; 879411ddb6SJim Ingham 88ee2ed525SGreg Clayton integer_t times_to_resume; 899411ddb6SJim Ingham 90b9c1b51eSKate Stone if (others_stopped) { 91b9c1b51eSKate Stone if (GetBasicInfo()) { 9282283e8eSJim Ingham times_to_resume = m_basic_info.suspend_count; 93c235ac76SGreg Clayton m_suspend_count = -(times_to_resume - m_suspend_count); 94b9c1b51eSKate Stone } else 9582283e8eSJim Ingham times_to_resume = 0; 96b9c1b51eSKate Stone } else { 97c235ac76SGreg Clayton times_to_resume = m_suspend_count; 98c235ac76SGreg Clayton m_suspend_count = 0; 999411ddb6SJim Ingham } 1009411ddb6SJim Ingham 101b9c1b51eSKate Stone if (times_to_resume > 0) { 102b9c1b51eSKate Stone while (times_to_resume > 0) { 1031c73911dSJason Molenda err = ::thread_resume(m_mach_port_number); 1049411ddb6SJim Ingham if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 1051c73911dSJason Molenda err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number); 1069411ddb6SJim Ingham if (err.Success()) 1079411ddb6SJim Ingham --times_to_resume; 108b9c1b51eSKate Stone else { 1099411ddb6SJim Ingham if (GetBasicInfo()) 110c235ac76SGreg Clayton times_to_resume = m_basic_info.suspend_count; 1119411ddb6SJim Ingham else 1129411ddb6SJim Ingham times_to_resume = 0; 1139411ddb6SJim Ingham } 1149411ddb6SJim Ingham } 1159411ddb6SJim Ingham } 1169411ddb6SJim Ingham return true; 1179411ddb6SJim Ingham } 1189411ddb6SJim Ingham 119b9c1b51eSKate Stone bool MachThread::RestoreSuspendCountAfterStop() { 120b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", 121b9c1b51eSKate Stone __FUNCTION__); 1229411ddb6SJim Ingham DNBError err; 123a6682a41SJonas Devlieghere if (!MachPortNumberIsValid(m_mach_port_number)) 1249411ddb6SJim Ingham return false; 1259411ddb6SJim Ingham 126b9c1b51eSKate Stone if (m_suspend_count > 0) { 127b9c1b51eSKate Stone while (m_suspend_count > 0) { 1281c73911dSJason Molenda err = ::thread_resume(m_mach_port_number); 12930fdc8d8SChris Lattner if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 1301c73911dSJason Molenda err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number); 13130fdc8d8SChris Lattner if (err.Success()) 132c235ac76SGreg Clayton --m_suspend_count; 133b9c1b51eSKate Stone else { 134cdc7322bSGreg Clayton if (GetBasicInfo()) 135c235ac76SGreg Clayton m_suspend_count = m_basic_info.suspend_count; 1360dd2c627SGreg Clayton else 137c235ac76SGreg Clayton m_suspend_count = 0; 1380dd2c627SGreg Clayton return false; // ??? 13930fdc8d8SChris Lattner } 14030fdc8d8SChris Lattner } 141b9c1b51eSKate Stone } else if (m_suspend_count < 0) { 142b9c1b51eSKate Stone while (m_suspend_count < 0) { 1431c73911dSJason Molenda err = ::thread_suspend(m_mach_port_number); 1449411ddb6SJim Ingham if (err.Success()) 145c235ac76SGreg Clayton ++m_suspend_count; 146b9c1b51eSKate Stone if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) { 147b9c1b51eSKate Stone err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", 148b9c1b51eSKate Stone m_mach_port_number); 149478235d8SJim Ingham return false; 150478235d8SJim Ingham } 1519411ddb6SJim Ingham } 1529411ddb6SJim Ingham } 1530dd2c627SGreg Clayton return true; 15430fdc8d8SChris Lattner } 15530fdc8d8SChris Lattner 156b9c1b51eSKate Stone const char *MachThread::GetBasicInfoAsString() const { 15730fdc8d8SChris Lattner static char g_basic_info_string[1024]; 15830fdc8d8SChris Lattner struct thread_basic_info basicInfo; 15930fdc8d8SChris Lattner 160b9c1b51eSKate Stone if (GetBasicInfo(m_mach_port_number, &basicInfo)) { 16130fdc8d8SChris Lattner 16230fdc8d8SChris Lattner // char run_state_str[32]; 16330fdc8d8SChris Lattner // size_t run_state_str_size = sizeof(run_state_str); 16430fdc8d8SChris Lattner // switch (basicInfo.run_state) 16530fdc8d8SChris Lattner // { 166aae5b690SJason Molenda // case TH_STATE_RUNNING: strlcpy(run_state_str, "running", 167b9c1b51eSKate Stone // run_state_str_size); break; 168aae5b690SJason Molenda // case TH_STATE_STOPPED: strlcpy(run_state_str, "stopped", 169b9c1b51eSKate Stone // run_state_str_size); break; 170aae5b690SJason Molenda // case TH_STATE_WAITING: strlcpy(run_state_str, "waiting", 171b9c1b51eSKate Stone // run_state_str_size); break; 172aae5b690SJason Molenda // case TH_STATE_UNINTERRUPTIBLE: strlcpy(run_state_str, 173b9c1b51eSKate Stone // "uninterruptible", run_state_str_size); break; 174aae5b690SJason Molenda // case TH_STATE_HALTED: strlcpy(run_state_str, "halted", 175b9c1b51eSKate Stone // run_state_str_size); break; 176b9c1b51eSKate Stone // default: snprintf(run_state_str, 177b9c1b51eSKate Stone // run_state_str_size, "%d", basicInfo.run_state); break; // ??? 17830fdc8d8SChris Lattner // } 179b9c1b51eSKate Stone float user = (float)basicInfo.user_time.seconds + 180b9c1b51eSKate Stone (float)basicInfo.user_time.microseconds / 1000000.0f; 181b9c1b51eSKate Stone float system = (float)basicInfo.user_time.seconds + 182b9c1b51eSKate Stone (float)basicInfo.user_time.microseconds / 1000000.0f; 183b9c1b51eSKate Stone snprintf(g_basic_info_string, sizeof(g_basic_info_string), 184b9c1b51eSKate Stone "Thread 0x%8.8" PRIx64 ": user=%f system=%f cpu=%d sleep_time=%d", 185b9c1b51eSKate Stone m_unique_id, user, system, basicInfo.cpu_usage, 18630fdc8d8SChris Lattner basicInfo.sleep_time); 18730fdc8d8SChris Lattner 18830fdc8d8SChris Lattner return g_basic_info_string; 18930fdc8d8SChris Lattner } 19030fdc8d8SChris Lattner return NULL; 19130fdc8d8SChris Lattner } 19230fdc8d8SChris Lattner 193b9c1b51eSKate Stone // Finds the Mach port number for a given thread in the inferior process' port 194b9c1b51eSKate Stone // namespace. 195b9c1b51eSKate Stone thread_t MachThread::InferiorThreadID() const { 19630fdc8d8SChris Lattner mach_msg_type_number_t i; 19730fdc8d8SChris Lattner mach_port_name_array_t names; 19830fdc8d8SChris Lattner mach_port_type_array_t types; 19930fdc8d8SChris Lattner mach_msg_type_number_t ncount, tcount; 20030fdc8d8SChris Lattner thread_t inferior_tid = INVALID_NUB_THREAD; 20130fdc8d8SChris Lattner task_t my_task = ::mach_task_self(); 20230fdc8d8SChris Lattner task_t task = m_process->Task().TaskPort(); 20330fdc8d8SChris Lattner 204b9c1b51eSKate Stone kern_return_t kret = 205b9c1b51eSKate Stone ::mach_port_names(task, &names, &ncount, &types, &tcount); 206b9c1b51eSKate Stone if (kret == KERN_SUCCESS) { 20730fdc8d8SChris Lattner 208b9c1b51eSKate Stone for (i = 0; i < ncount; i++) { 20930fdc8d8SChris Lattner mach_port_t my_name; 21030fdc8d8SChris Lattner mach_msg_type_name_t my_type; 21130fdc8d8SChris Lattner 212b9c1b51eSKate Stone kret = ::mach_port_extract_right(task, names[i], MACH_MSG_TYPE_COPY_SEND, 213b9c1b51eSKate Stone &my_name, &my_type); 214b9c1b51eSKate Stone if (kret == KERN_SUCCESS) { 21530fdc8d8SChris Lattner ::mach_port_deallocate(my_task, my_name); 216b9c1b51eSKate Stone if (my_name == m_mach_port_number) { 21730fdc8d8SChris Lattner inferior_tid = names[i]; 21830fdc8d8SChris Lattner break; 21930fdc8d8SChris Lattner } 22030fdc8d8SChris Lattner } 22130fdc8d8SChris Lattner } 22230fdc8d8SChris Lattner // Free up the names and types 223b9c1b51eSKate Stone ::vm_deallocate(my_task, (vm_address_t)names, 224b9c1b51eSKate Stone ncount * sizeof(mach_port_name_t)); 225b9c1b51eSKate Stone ::vm_deallocate(my_task, (vm_address_t)types, 226b9c1b51eSKate Stone tcount * sizeof(mach_port_type_t)); 22730fdc8d8SChris Lattner } 22830fdc8d8SChris Lattner return inferior_tid; 22930fdc8d8SChris Lattner } 23030fdc8d8SChris Lattner 231b9c1b51eSKate Stone bool MachThread::IsUserReady() { 232c235ac76SGreg Clayton if (m_basic_info.run_state == 0) 233cdc7322bSGreg Clayton GetBasicInfo(); 2341b946bf6SGreg Clayton 235b9c1b51eSKate Stone switch (m_basic_info.run_state) { 2361b946bf6SGreg Clayton default: 2371b946bf6SGreg Clayton case TH_STATE_UNINTERRUPTIBLE: 2381b946bf6SGreg Clayton break; 2391b946bf6SGreg Clayton 2401b946bf6SGreg Clayton case TH_STATE_RUNNING: 2411b946bf6SGreg Clayton case TH_STATE_STOPPED: 2421b946bf6SGreg Clayton case TH_STATE_WAITING: 2431b946bf6SGreg Clayton case TH_STATE_HALTED: 2441b946bf6SGreg Clayton return true; 2451b946bf6SGreg Clayton } 246*fcda044dSFrederic Riss return GetPC(0) != 0; 2471b946bf6SGreg Clayton } 2481b946bf6SGreg Clayton 249b9c1b51eSKate Stone struct thread_basic_info *MachThread::GetBasicInfo() { 2501c73911dSJason Molenda if (MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info)) 251c235ac76SGreg Clayton return &m_basic_info; 2521b946bf6SGreg Clayton return NULL; 2531b946bf6SGreg Clayton } 2541b946bf6SGreg Clayton 255b9c1b51eSKate Stone bool MachThread::GetBasicInfo(thread_t thread, 256b9c1b51eSKate Stone struct thread_basic_info *basicInfoPtr) { 257b9c1b51eSKate Stone if (MachPortNumberIsValid(thread)) { 25830fdc8d8SChris Lattner unsigned int info_count = THREAD_BASIC_INFO_COUNT; 259b9c1b51eSKate Stone kern_return_t err = ::thread_info(thread, THREAD_BASIC_INFO, 260b9c1b51eSKate Stone (thread_info_t)basicInfoPtr, &info_count); 26130fdc8d8SChris Lattner if (err == KERN_SUCCESS) 26230fdc8d8SChris Lattner return true; 26330fdc8d8SChris Lattner } 26430fdc8d8SChris Lattner ::memset(basicInfoPtr, 0, sizeof(struct thread_basic_info)); 26530fdc8d8SChris Lattner return false; 26630fdc8d8SChris Lattner } 26730fdc8d8SChris Lattner 268b9c1b51eSKate Stone bool MachThread::ThreadIDIsValid(uint64_t thread) { return thread != 0; } 26930fdc8d8SChris Lattner 270b9c1b51eSKate Stone bool MachThread::MachPortNumberIsValid(thread_t thread) { 27130fdc8d8SChris Lattner return thread != THREAD_NULL; 27230fdc8d8SChris Lattner } 27330fdc8d8SChris Lattner 274b9c1b51eSKate Stone bool MachThread::GetRegisterState(int flavor, bool force) { 275d5b44036SJonas Devlieghere return m_arch_up->GetRegisterState(flavor, force) == KERN_SUCCESS; 27630fdc8d8SChris Lattner } 27730fdc8d8SChris Lattner 278b9c1b51eSKate Stone bool MachThread::SetRegisterState(int flavor) { 279d5b44036SJonas Devlieghere return m_arch_up->SetRegisterState(flavor) == KERN_SUCCESS; 28030fdc8d8SChris Lattner } 28130fdc8d8SChris Lattner 282b9c1b51eSKate Stone uint64_t MachThread::GetPC(uint64_t failValue) { 28330fdc8d8SChris Lattner // Get program counter 284d5b44036SJonas Devlieghere return m_arch_up->GetPC(failValue); 28530fdc8d8SChris Lattner } 28630fdc8d8SChris Lattner 287b9c1b51eSKate Stone bool MachThread::SetPC(uint64_t value) { 28830fdc8d8SChris Lattner // Set program counter 289d5b44036SJonas Devlieghere return m_arch_up->SetPC(value); 29030fdc8d8SChris Lattner } 29130fdc8d8SChris Lattner 292b9c1b51eSKate Stone uint64_t MachThread::GetSP(uint64_t failValue) { 29330fdc8d8SChris Lattner // Get stack pointer 294d5b44036SJonas Devlieghere return m_arch_up->GetSP(failValue); 29530fdc8d8SChris Lattner } 29630fdc8d8SChris Lattner 297b9c1b51eSKate Stone nub_process_t MachThread::ProcessID() const { 29830fdc8d8SChris Lattner if (m_process) 29930fdc8d8SChris Lattner return m_process->ProcessID(); 30030fdc8d8SChris Lattner return INVALID_NUB_PROCESS; 30130fdc8d8SChris Lattner } 30230fdc8d8SChris Lattner 303b9c1b51eSKate Stone void MachThread::Dump(uint32_t index) { 30430fdc8d8SChris Lattner const char *thread_run_state = NULL; 30530fdc8d8SChris Lattner 306b9c1b51eSKate Stone switch (m_basic_info.run_state) { 307b9c1b51eSKate Stone case TH_STATE_RUNNING: 308b9c1b51eSKate Stone thread_run_state = "running"; 309b9c1b51eSKate Stone break; // 1 thread is running normally 310b9c1b51eSKate Stone case TH_STATE_STOPPED: 311b9c1b51eSKate Stone thread_run_state = "stopped"; 312b9c1b51eSKate Stone break; // 2 thread is stopped 313b9c1b51eSKate Stone case TH_STATE_WAITING: 314b9c1b51eSKate Stone thread_run_state = "waiting"; 315b9c1b51eSKate Stone break; // 3 thread is waiting normally 316b9c1b51eSKate Stone case TH_STATE_UNINTERRUPTIBLE: 317b9c1b51eSKate Stone thread_run_state = "uninter"; 318b9c1b51eSKate Stone break; // 4 thread is in an uninterruptible wait 319b9c1b51eSKate Stone case TH_STATE_HALTED: 320b9c1b51eSKate Stone thread_run_state = "halted "; 321b9c1b51eSKate Stone break; // 5 thread is halted at a 322b9c1b51eSKate Stone default: 323b9c1b51eSKate Stone thread_run_state = "???"; 324b9c1b51eSKate Stone break; 32530fdc8d8SChris Lattner } 32630fdc8d8SChris Lattner 327b9c1b51eSKate Stone DNBLogThreaded( 328b9c1b51eSKate Stone "[%3u] #%3u tid: 0x%8.8" PRIx64 ", pc: 0x%16.16" PRIx64 329b9c1b51eSKate Stone ", sp: 0x%16.16" PRIx64 330b9c1b51eSKate Stone ", user: %d.%6.6d, system: %d.%6.6d, cpu: %2d, policy: %2d, run_state: " 331b9c1b51eSKate Stone "%2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d", 332b9c1b51eSKate Stone index, m_seq_id, m_unique_id, GetPC(INVALID_NUB_ADDRESS), 333b9c1b51eSKate Stone GetSP(INVALID_NUB_ADDRESS), m_basic_info.user_time.seconds, 334b9c1b51eSKate Stone m_basic_info.user_time.microseconds, m_basic_info.system_time.seconds, 335b9c1b51eSKate Stone m_basic_info.system_time.microseconds, m_basic_info.cpu_usage, 336b9c1b51eSKate Stone m_basic_info.policy, m_basic_info.run_state, thread_run_state, 337b9c1b51eSKate Stone m_basic_info.flags, m_basic_info.suspend_count, m_suspend_count, 338c235ac76SGreg Clayton m_basic_info.sleep_time); 33930fdc8d8SChris Lattner // DumpRegisterState(0); 34030fdc8d8SChris Lattner } 34130fdc8d8SChris Lattner 342b9c1b51eSKate Stone void MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action, 343b9c1b51eSKate Stone bool others_stopped) { 34430fdc8d8SChris Lattner if (thread_action->addr != INVALID_NUB_ADDRESS) 34530fdc8d8SChris Lattner SetPC(thread_action->addr); 346cdc7322bSGreg Clayton 34730fdc8d8SChris Lattner SetState(thread_action->state); 348b9c1b51eSKate Stone switch (thread_action->state) { 34930fdc8d8SChris Lattner case eStateStopped: 35030fdc8d8SChris Lattner case eStateSuspended: 3519411ddb6SJim Ingham assert(others_stopped == false); 35230fdc8d8SChris Lattner Suspend(); 35330fdc8d8SChris Lattner break; 35430fdc8d8SChris Lattner 35530fdc8d8SChris Lattner case eStateRunning: 356b1e11121SJim Ingham case eStateStepping: 3579411ddb6SJim Ingham Resume(others_stopped); 358b1e11121SJim Ingham break; 359effe5c95SGreg Clayton default: 360effe5c95SGreg Clayton break; 36130fdc8d8SChris Lattner } 362d5b44036SJonas Devlieghere m_arch_up->ThreadWillResume(); 36330fdc8d8SChris Lattner m_stop_exception.Clear(); 36430fdc8d8SChris Lattner } 36530fdc8d8SChris Lattner 366b9c1b51eSKate Stone DNBBreakpoint *MachThread::CurrentBreakpoint() { 367d8cf1a11SGreg Clayton return m_process->Breakpoints().FindByAddress(GetPC()); 368c4e411ffSGreg Clayton } 369c4e411ffSGreg Clayton 370b9c1b51eSKate Stone bool MachThread::ShouldStop(bool &step_more) { 37130fdc8d8SChris Lattner // See if this thread is at a breakpoint? 372d8cf1a11SGreg Clayton DNBBreakpoint *bp = CurrentBreakpoint(); 37330fdc8d8SChris Lattner 374b9c1b51eSKate Stone if (bp) { 37530fdc8d8SChris Lattner // This thread is sitting at a breakpoint, ask the breakpoint 37630fdc8d8SChris Lattner // if we should be stopping here. 37730fdc8d8SChris Lattner return true; 378b9c1b51eSKate Stone } else { 379d5b44036SJonas Devlieghere if (m_arch_up->StepNotComplete()) { 38030fdc8d8SChris Lattner step_more = true; 38130fdc8d8SChris Lattner return false; 38230fdc8d8SChris Lattner } 38330fdc8d8SChris Lattner // The thread state is used to let us know what the thread was 38430fdc8d8SChris Lattner // trying to do. MachThread::ThreadWillResume() will set the 38530fdc8d8SChris Lattner // thread state to various values depending if the thread was 38630fdc8d8SChris Lattner // the current thread and if it was to be single stepped, or 38730fdc8d8SChris Lattner // resumed. 388b9c1b51eSKate Stone if (GetState() == eStateRunning) { 38930fdc8d8SChris Lattner // If our state is running, then we should continue as we are in 39030fdc8d8SChris Lattner // the process of stepping over a breakpoint. 39130fdc8d8SChris Lattner return false; 392b9c1b51eSKate Stone } else { 39330fdc8d8SChris Lattner // Stop if we have any kind of valid exception for this 39430fdc8d8SChris Lattner // thread. 39530fdc8d8SChris Lattner if (GetStopException().IsValid()) 39630fdc8d8SChris Lattner return true; 39730fdc8d8SChris Lattner } 39830fdc8d8SChris Lattner } 39930fdc8d8SChris Lattner return false; 40030fdc8d8SChris Lattner } 401b9c1b51eSKate Stone bool MachThread::IsStepping() { return GetState() == eStateStepping; } 40230fdc8d8SChris Lattner 403b9c1b51eSKate Stone bool MachThread::ThreadDidStop() { 40430fdc8d8SChris Lattner // This thread has existed prior to resuming under debug nub control, 40530fdc8d8SChris Lattner // and has just been stopped. Do any cleanup that needs to be done 40630fdc8d8SChris Lattner // after running. 40730fdc8d8SChris Lattner 40830fdc8d8SChris Lattner // The thread state and breakpoint will still have the same values 40930fdc8d8SChris Lattner // as they had prior to resuming the thread, so it makes it easy to check 41030fdc8d8SChris Lattner // if we were trying to step a thread, or we tried to resume while being 41130fdc8d8SChris Lattner // at a breakpoint. 41230fdc8d8SChris Lattner 41330fdc8d8SChris Lattner // When this method gets called, the process state is still in the 41430fdc8d8SChris Lattner // state it was in while running so we can act accordingly. 415d5b44036SJonas Devlieghere m_arch_up->ThreadDidStop(); 41630fdc8d8SChris Lattner 41730fdc8d8SChris Lattner // We may have suspended this thread so the primary thread could step 41830fdc8d8SChris Lattner // without worrying about race conditions, so lets restore our suspend 41930fdc8d8SChris Lattner // count. 4209411ddb6SJim Ingham RestoreSuspendCountAfterStop(); 42130fdc8d8SChris Lattner 42230fdc8d8SChris Lattner // Update the basic information for a thread 4231c73911dSJason Molenda MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info); 42430fdc8d8SChris Lattner 425c235ac76SGreg Clayton if (m_basic_info.suspend_count > 0) 426c4e411ffSGreg Clayton SetState(eStateSuspended); 427c4e411ffSGreg Clayton else 428c4e411ffSGreg Clayton SetState(eStateStopped); 42930fdc8d8SChris Lattner return true; 43030fdc8d8SChris Lattner } 43130fdc8d8SChris Lattner 432b9c1b51eSKate Stone bool MachThread::NotifyException(MachException::Data &exc) { 43388c1b77fSJohnny Chen // Allow the arch specific protocol to process (MachException::Data &)exc 43488c1b77fSJohnny Chen // first before possible reassignment of m_stop_exception with exc. 43576abb3b5SJohnny Chen // See also MachThread::GetStopException(). 436d5b44036SJonas Devlieghere bool handled = m_arch_up->NotifyException(exc); 43788c1b77fSJohnny Chen 438b9c1b51eSKate Stone if (m_stop_exception.IsValid()) { 43930fdc8d8SChris Lattner // We may have more than one exception for a thread, but we need to 44030fdc8d8SChris Lattner // only remember the one that we will say is the reason we stopped. 44130fdc8d8SChris Lattner // We may have been single stepping and also gotten a signal exception, 44230fdc8d8SChris Lattner // so just remember the most pertinent one. 44330fdc8d8SChris Lattner if (m_stop_exception.IsBreakpoint()) 44430fdc8d8SChris Lattner m_stop_exception = exc; 445b9c1b51eSKate Stone } else { 44630fdc8d8SChris Lattner m_stop_exception = exc; 44730fdc8d8SChris Lattner } 44888c1b77fSJohnny Chen 44930fdc8d8SChris Lattner return handled; 45030fdc8d8SChris Lattner } 45130fdc8d8SChris Lattner 452b9c1b51eSKate Stone nub_state_t MachThread::GetState() { 45330fdc8d8SChris Lattner // If any other threads access this we will need a mutex for it 45430fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_state_mutex); 45530fdc8d8SChris Lattner return m_state; 45630fdc8d8SChris Lattner } 45730fdc8d8SChris Lattner 458b9c1b51eSKate Stone void MachThread::SetState(nub_state_t state) { 45930fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_state_mutex); 46030fdc8d8SChris Lattner m_state = state; 461b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD, 462b9c1b51eSKate Stone "MachThread::SetState ( %s ) for tid = 0x%8.8" PRIx64 "", 463b9c1b51eSKate Stone DNBStateAsString(state), m_unique_id); 46430fdc8d8SChris Lattner } 46530fdc8d8SChris Lattner 466b9c1b51eSKate Stone nub_size_t MachThread::GetNumRegistersInSet(nub_size_t regSet) const { 467c235ac76SGreg Clayton if (regSet < m_num_reg_sets) 4683af9ea56SGreg Clayton return m_reg_sets[regSet].num_registers; 46930fdc8d8SChris Lattner return 0; 47030fdc8d8SChris Lattner } 47130fdc8d8SChris Lattner 472b9c1b51eSKate Stone const char *MachThread::GetRegisterSetName(nub_size_t regSet) const { 473c235ac76SGreg Clayton if (regSet < m_num_reg_sets) 4743af9ea56SGreg Clayton return m_reg_sets[regSet].name; 47530fdc8d8SChris Lattner return NULL; 47630fdc8d8SChris Lattner } 47730fdc8d8SChris Lattner 478b9c1b51eSKate Stone const DNBRegisterInfo *MachThread::GetRegisterInfo(nub_size_t regSet, 479b9c1b51eSKate Stone nub_size_t regIndex) const { 480c235ac76SGreg Clayton if (regSet < m_num_reg_sets) 4813af9ea56SGreg Clayton if (regIndex < m_reg_sets[regSet].num_registers) 4823af9ea56SGreg Clayton return &m_reg_sets[regSet].registers[regIndex]; 48330fdc8d8SChris Lattner return NULL; 48430fdc8d8SChris Lattner } 485b9c1b51eSKate Stone void MachThread::DumpRegisterState(nub_size_t regSet) { 486b9c1b51eSKate Stone if (regSet == REGISTER_SET_ALL) { 487c235ac76SGreg Clayton for (regSet = 1; regSet < m_num_reg_sets; regSet++) 48830fdc8d8SChris Lattner DumpRegisterState(regSet); 489b9c1b51eSKate Stone } else { 490d5b44036SJonas Devlieghere if (m_arch_up->RegisterSetStateIsValid((int)regSet)) { 49130fdc8d8SChris Lattner const size_t numRegisters = GetNumRegistersInSet(regSet); 492ee2ed525SGreg Clayton uint32_t regIndex = 0; 49330fdc8d8SChris Lattner DNBRegisterValueClass reg; 494b9c1b51eSKate Stone for (regIndex = 0; regIndex < numRegisters; ++regIndex) { 495d5b44036SJonas Devlieghere if (m_arch_up->GetRegisterValue((uint32_t)regSet, regIndex, ®)) { 49630fdc8d8SChris Lattner reg.Dump(NULL, NULL); 49730fdc8d8SChris Lattner } 49830fdc8d8SChris Lattner } 499b9c1b51eSKate Stone } else { 500b9c1b51eSKate Stone DNBLog("%s: registers are not currently valid.", 501b9c1b51eSKate Stone GetRegisterSetName(regSet)); 50230fdc8d8SChris Lattner } 50330fdc8d8SChris Lattner } 50430fdc8d8SChris Lattner } 50530fdc8d8SChris Lattner 50630fdc8d8SChris Lattner const DNBRegisterSetInfo * 507b9c1b51eSKate Stone MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets) const { 508c235ac76SGreg Clayton *num_reg_sets = m_num_reg_sets; 5093af9ea56SGreg Clayton return &m_reg_sets[0]; 51030fdc8d8SChris Lattner } 51130fdc8d8SChris Lattner 512b9c1b51eSKate Stone bool MachThread::GetRegisterValue(uint32_t set, uint32_t reg, 513b9c1b51eSKate Stone DNBRegisterValue *value) { 514d5b44036SJonas Devlieghere return m_arch_up->GetRegisterValue(set, reg, value); 51530fdc8d8SChris Lattner } 51630fdc8d8SChris Lattner 517b9c1b51eSKate Stone bool MachThread::SetRegisterValue(uint32_t set, uint32_t reg, 518b9c1b51eSKate Stone const DNBRegisterValue *value) { 519d5b44036SJonas Devlieghere return m_arch_up->SetRegisterValue(set, reg, value); 52030fdc8d8SChris Lattner } 52130fdc8d8SChris Lattner 522b9c1b51eSKate Stone nub_size_t MachThread::GetRegisterContext(void *buf, nub_size_t buf_len) { 523d5b44036SJonas Devlieghere return m_arch_up->GetRegisterContext(buf, buf_len); 52430fdc8d8SChris Lattner } 52530fdc8d8SChris Lattner 526b9c1b51eSKate Stone nub_size_t MachThread::SetRegisterContext(const void *buf, nub_size_t buf_len) { 527d5b44036SJonas Devlieghere return m_arch_up->SetRegisterContext(buf, buf_len); 52830fdc8d8SChris Lattner } 52930fdc8d8SChris Lattner 530b9c1b51eSKate Stone uint32_t MachThread::SaveRegisterState() { 531d5b44036SJonas Devlieghere return m_arch_up->SaveRegisterState(); 532f74cf86bSGreg Clayton } 533b9c1b51eSKate Stone bool MachThread::RestoreRegisterState(uint32_t save_id) { 534d5b44036SJonas Devlieghere return m_arch_up->RestoreRegisterState(save_id); 535f74cf86bSGreg Clayton } 536f74cf86bSGreg Clayton 537b9c1b51eSKate Stone uint32_t MachThread::EnableHardwareBreakpoint(const DNBBreakpoint *bp) { 53830fdc8d8SChris Lattner if (bp != NULL && bp->IsBreakpoint()) 539d5b44036SJonas Devlieghere return m_arch_up->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize()); 54030fdc8d8SChris Lattner return INVALID_NUB_HW_INDEX; 54130fdc8d8SChris Lattner } 54230fdc8d8SChris Lattner 543b9c1b51eSKate Stone uint32_t MachThread::EnableHardwareWatchpoint(const DNBBreakpoint *wp, 544b9c1b51eSKate Stone bool also_set_on_task) { 54530fdc8d8SChris Lattner if (wp != NULL && wp->IsWatchpoint()) 546d5b44036SJonas Devlieghere return m_arch_up->EnableHardwareWatchpoint( 547b9c1b51eSKate Stone wp->Address(), wp->ByteSize(), wp->WatchpointRead(), 548b9c1b51eSKate Stone wp->WatchpointWrite(), also_set_on_task); 54930fdc8d8SChris Lattner return INVALID_NUB_HW_INDEX; 55030fdc8d8SChris Lattner } 55130fdc8d8SChris Lattner 552b9c1b51eSKate Stone bool MachThread::RollbackTransForHWP() { 553d5b44036SJonas Devlieghere return m_arch_up->RollbackTransForHWP(); 55484707560SJohnny Chen } 55584707560SJohnny Chen 556d5b44036SJonas Devlieghere bool MachThread::FinishTransForHWP() { return m_arch_up->FinishTransForHWP(); } 55784707560SJohnny Chen 558b9c1b51eSKate Stone bool MachThread::DisableHardwareBreakpoint(const DNBBreakpoint *bp) { 55930fdc8d8SChris Lattner if (bp != NULL && bp->IsHardware()) 560d5b44036SJonas Devlieghere return m_arch_up->DisableHardwareBreakpoint(bp->GetHardwareIndex()); 56130fdc8d8SChris Lattner return false; 56230fdc8d8SChris Lattner } 56330fdc8d8SChris Lattner 564b9c1b51eSKate Stone bool MachThread::DisableHardwareWatchpoint(const DNBBreakpoint *wp, 565b9c1b51eSKate Stone bool also_set_on_task) { 56630fdc8d8SChris Lattner if (wp != NULL && wp->IsHardware()) 567d5b44036SJonas Devlieghere return m_arch_up->DisableHardwareWatchpoint(wp->GetHardwareIndex(), 568b9c1b51eSKate Stone also_set_on_task); 56930fdc8d8SChris Lattner return false; 57030fdc8d8SChris Lattner } 57130fdc8d8SChris Lattner 572b9c1b51eSKate Stone uint32_t MachThread::NumSupportedHardwareWatchpoints() const { 573d5b44036SJonas Devlieghere return m_arch_up->NumSupportedHardwareWatchpoints(); 57464637205SJohnny Chen } 57564637205SJohnny Chen 576b9c1b51eSKate Stone bool MachThread::GetIdentifierInfo() { 577b9c1b51eSKate Stone // Don't try to get the thread info once and cache it for the life of the 578b9c1b51eSKate Stone // thread. It changes over time, for instance 579b9c1b51eSKate Stone // if the thread name changes, then the thread_handle also changes... So you 580b9c1b51eSKate Stone // have to refetch it every time. 58130fdc8d8SChris Lattner mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; 582b9c1b51eSKate Stone kern_return_t kret = ::thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO, 583b9c1b51eSKate Stone (thread_info_t)&m_ident_info, &count); 584f2c6ccf0SJim Ingham return kret == KERN_SUCCESS; 58530fdc8d8SChris Lattner 58630fdc8d8SChris Lattner return false; 58730fdc8d8SChris Lattner } 58830fdc8d8SChris Lattner 589b9c1b51eSKate Stone const char *MachThread::GetName() { 590b9c1b51eSKate Stone if (GetIdentifierInfo()) { 591b9c1b51eSKate Stone int len = ::proc_pidinfo(m_process->ProcessID(), PROC_PIDTHREADINFO, 592b9c1b51eSKate Stone m_ident_info.thread_handle, &m_proc_threadinfo, 593b9c1b51eSKate Stone sizeof(m_proc_threadinfo)); 59430fdc8d8SChris Lattner 59530fdc8d8SChris Lattner if (len && m_proc_threadinfo.pth_name[0]) 59630fdc8d8SChris Lattner return m_proc_threadinfo.pth_name; 59730fdc8d8SChris Lattner } 59830fdc8d8SChris Lattner return NULL; 59930fdc8d8SChris Lattner } 60030fdc8d8SChris Lattner 6011c73911dSJason Molenda uint64_t 602b9c1b51eSKate Stone MachThread::GetGloballyUniqueThreadIDForMachPortID(thread_t mach_port_id) { 6031c73911dSJason Molenda kern_return_t kr; 6041c73911dSJason Molenda thread_identifier_info_data_t tident; 6051c73911dSJason Molenda mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; 606b9c1b51eSKate Stone kr = thread_info(mach_port_id, THREAD_IDENTIFIER_INFO, (thread_info_t)&tident, 607b9c1b51eSKate Stone &tident_count); 608b9c1b51eSKate Stone if (kr != KERN_SUCCESS) { 6091c73911dSJason Molenda return mach_port_id; 6101c73911dSJason Molenda } 6111c73911dSJason Molenda return tident.thread_id; 6121c73911dSJason Molenda } 613705b1809SJason Molenda 614b9c1b51eSKate Stone nub_addr_t MachThread::GetPThreadT() { 615705b1809SJason Molenda nub_addr_t pthread_t_value = INVALID_NUB_ADDRESS; 616b9c1b51eSKate Stone if (MachPortNumberIsValid(m_mach_port_number)) { 617705b1809SJason Molenda kern_return_t kr; 618705b1809SJason Molenda thread_identifier_info_data_t tident; 619705b1809SJason Molenda mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; 620705b1809SJason Molenda kr = thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO, 621705b1809SJason Molenda (thread_info_t)&tident, &tident_count); 622b9c1b51eSKate Stone if (kr == KERN_SUCCESS) { 623705b1809SJason Molenda // Dereference thread_handle to get the pthread_t value for this thread. 624b9c1b51eSKate Stone if (m_is_64_bit) { 625705b1809SJason Molenda uint64_t addr; 626b9c1b51eSKate Stone if (m_process->ReadMemory(tident.thread_handle, 8, &addr) == 8) { 627b9c1b51eSKate Stone if (addr != 0) { 628705b1809SJason Molenda pthread_t_value = addr; 629705b1809SJason Molenda } 630705b1809SJason Molenda } 631b9c1b51eSKate Stone } else { 632705b1809SJason Molenda uint32_t addr; 633b9c1b51eSKate Stone if (m_process->ReadMemory(tident.thread_handle, 4, &addr) == 4) { 634b9c1b51eSKate Stone if (addr != 0) { 635705b1809SJason Molenda pthread_t_value = addr; 636705b1809SJason Molenda } 637705b1809SJason Molenda } 638705b1809SJason Molenda } 639705b1809SJason Molenda } 640705b1809SJason Molenda } 641705b1809SJason Molenda return pthread_t_value; 642705b1809SJason Molenda } 643705b1809SJason Molenda 644705b1809SJason Molenda // Return this thread's TSD (Thread Specific Data) address. 645705b1809SJason Molenda // This is computed based on this thread's pthread_t value. 646705b1809SJason Molenda // 647705b1809SJason Molenda // We compute the TSD from the pthread_t by one of two methods. 648705b1809SJason Molenda // 649b9c1b51eSKate Stone // If plo_pthread_tsd_base_offset is non-zero, this is a simple offset that we 650b9c1b51eSKate Stone // add to 651705b1809SJason Molenda // the pthread_t to get the TSD base address. 652705b1809SJason Molenda // 653b9c1b51eSKate Stone // Else we read a pointer from memory at pthread_t + 654b9c1b51eSKate Stone // plo_pthread_tsd_base_address_offset and 655705b1809SJason Molenda // that gives us the TSD address. 656705b1809SJason Molenda // 657b9c1b51eSKate Stone // These plo_pthread_tsd_base values must be read out of libpthread by lldb & 658b9c1b51eSKate Stone // provided to debugserver. 659705b1809SJason Molenda 660705b1809SJason Molenda nub_addr_t 661b9c1b51eSKate Stone MachThread::GetTSDAddressForThread(uint64_t plo_pthread_tsd_base_address_offset, 662b9c1b51eSKate Stone uint64_t plo_pthread_tsd_base_offset, 663b9c1b51eSKate Stone uint64_t plo_pthread_tsd_entry_size) { 664705b1809SJason Molenda nub_addr_t tsd_addr = INVALID_NUB_ADDRESS; 665705b1809SJason Molenda nub_addr_t pthread_t_value = GetPThreadT(); 666b9c1b51eSKate Stone if (plo_pthread_tsd_base_offset != 0 && 667b9c1b51eSKate Stone plo_pthread_tsd_base_offset != INVALID_NUB_ADDRESS) { 668705b1809SJason Molenda tsd_addr = pthread_t_value + plo_pthread_tsd_base_offset; 669b9c1b51eSKate Stone } else { 670b9c1b51eSKate Stone if (plo_pthread_tsd_entry_size == 4) { 671705b1809SJason Molenda uint32_t addr = 0; 672b9c1b51eSKate Stone if (m_process->ReadMemory(pthread_t_value + 673b9c1b51eSKate Stone plo_pthread_tsd_base_address_offset, 674b9c1b51eSKate Stone 4, &addr) == 4) { 675b9c1b51eSKate Stone if (addr != 0) { 676705b1809SJason Molenda tsd_addr = addr; 677705b1809SJason Molenda } 678705b1809SJason Molenda } 679705b1809SJason Molenda } 680b9c1b51eSKate Stone if (plo_pthread_tsd_entry_size == 4) { 681705b1809SJason Molenda uint64_t addr = 0; 682b9c1b51eSKate Stone if (m_process->ReadMemory(pthread_t_value + 683b9c1b51eSKate Stone plo_pthread_tsd_base_address_offset, 684b9c1b51eSKate Stone 8, &addr) == 8) { 685b9c1b51eSKate Stone if (addr != 0) { 686705b1809SJason Molenda tsd_addr = addr; 687705b1809SJason Molenda } 688705b1809SJason Molenda } 689705b1809SJason Molenda } 690705b1809SJason Molenda } 691705b1809SJason Molenda return tsd_addr; 692705b1809SJason Molenda } 693705b1809SJason Molenda 694b9c1b51eSKate Stone nub_addr_t MachThread::GetDispatchQueueT() { 695705b1809SJason Molenda nub_addr_t dispatch_queue_t_value = INVALID_NUB_ADDRESS; 696b9c1b51eSKate Stone if (MachPortNumberIsValid(m_mach_port_number)) { 697705b1809SJason Molenda kern_return_t kr; 698705b1809SJason Molenda thread_identifier_info_data_t tident; 699705b1809SJason Molenda mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; 700705b1809SJason Molenda kr = thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO, 701705b1809SJason Molenda (thread_info_t)&tident, &tident_count); 702b9c1b51eSKate Stone if (kr == KERN_SUCCESS && tident.dispatch_qaddr != 0 && 703b9c1b51eSKate Stone tident.dispatch_qaddr != INVALID_NUB_ADDRESS) { 704b9c1b51eSKate Stone // Dereference dispatch_qaddr to get the dispatch_queue_t value for this 705b9c1b51eSKate Stone // thread's queue, if any. 706b9c1b51eSKate Stone if (m_is_64_bit) { 707705b1809SJason Molenda uint64_t addr; 708b9c1b51eSKate Stone if (m_process->ReadMemory(tident.dispatch_qaddr, 8, &addr) == 8) { 709705b1809SJason Molenda if (addr != 0) 710705b1809SJason Molenda dispatch_queue_t_value = addr; 711705b1809SJason Molenda } 712b9c1b51eSKate Stone } else { 713705b1809SJason Molenda uint32_t addr; 714b9c1b51eSKate Stone if (m_process->ReadMemory(tident.dispatch_qaddr, 4, &addr) == 4) { 715705b1809SJason Molenda if (addr != 0) 716705b1809SJason Molenda dispatch_queue_t_value = addr; 717705b1809SJason Molenda } 718705b1809SJason Molenda } 719705b1809SJason Molenda } 720705b1809SJason Molenda } 721705b1809SJason Molenda return dispatch_queue_t_value; 722705b1809SJason Molenda } 723705b1809SJason Molenda 724b9c1b51eSKate Stone ThreadInfo::QoS MachThread::GetRequestedQoS(nub_addr_t tsd, 725b9c1b51eSKate Stone uint64_t dti_qos_class_index) { 726705b1809SJason Molenda ThreadInfo::QoS qos_value; 727b9c1b51eSKate Stone if (MachPortNumberIsValid(m_mach_port_number) && 728b9c1b51eSKate Stone m_pthread_qos_class_decode != nullptr) { 729705b1809SJason Molenda uint64_t pthread_priority_value = 0; 730b9c1b51eSKate Stone if (m_is_64_bit) { 731705b1809SJason Molenda uint64_t pri; 732b9c1b51eSKate Stone if (m_process->ReadMemory(tsd + (dti_qos_class_index * 8), 8, &pri) == 733b9c1b51eSKate Stone 8) { 734705b1809SJason Molenda pthread_priority_value = pri; 735705b1809SJason Molenda } 736b9c1b51eSKate Stone } else { 737705b1809SJason Molenda uint32_t pri; 738b9c1b51eSKate Stone if (m_process->ReadMemory(tsd + (dti_qos_class_index * 4), 4, &pri) == 739b9c1b51eSKate Stone 4) { 740705b1809SJason Molenda pthread_priority_value = pri; 741705b1809SJason Molenda } 742705b1809SJason Molenda } 743705b1809SJason Molenda 744b9c1b51eSKate Stone uint32_t requested_qos = 745b9c1b51eSKate Stone m_pthread_qos_class_decode(pthread_priority_value, NULL, NULL); 746705b1809SJason Molenda 747b9c1b51eSKate Stone switch (requested_qos) { 748705b1809SJason Molenda // These constants from <pthread/qos.h> 749705b1809SJason Molenda case 0x21: 750705b1809SJason Molenda qos_value.enum_value = requested_qos; 751705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_USER_INTERACTIVE"; 752705b1809SJason Molenda qos_value.printable_name = "User Interactive"; 753705b1809SJason Molenda break; 754705b1809SJason Molenda case 0x19: 755705b1809SJason Molenda qos_value.enum_value = requested_qos; 756705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_USER_INITIATED"; 757705b1809SJason Molenda qos_value.printable_name = "User Initiated"; 758705b1809SJason Molenda break; 759705b1809SJason Molenda case 0x15: 760705b1809SJason Molenda qos_value.enum_value = requested_qos; 761705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_DEFAULT"; 762705b1809SJason Molenda qos_value.printable_name = "Default"; 763705b1809SJason Molenda break; 764705b1809SJason Molenda case 0x11: 765705b1809SJason Molenda qos_value.enum_value = requested_qos; 766705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_UTILITY"; 767705b1809SJason Molenda qos_value.printable_name = "Utility"; 768705b1809SJason Molenda break; 769705b1809SJason Molenda case 0x09: 770705b1809SJason Molenda qos_value.enum_value = requested_qos; 771705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_BACKGROUND"; 772705b1809SJason Molenda qos_value.printable_name = "Background"; 773705b1809SJason Molenda break; 774705b1809SJason Molenda case 0x00: 775705b1809SJason Molenda qos_value.enum_value = requested_qos; 776705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_UNSPECIFIED"; 777705b1809SJason Molenda qos_value.printable_name = "Unspecified"; 778705b1809SJason Molenda break; 779705b1809SJason Molenda } 780705b1809SJason Molenda } 781705b1809SJason Molenda return qos_value; 782705b1809SJason Molenda } 783