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