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