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