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 "MachThread.h" 15 #include "MachProcess.h" 16 #include "DNBLog.h" 17 #include "DNB.h" 18 19 static uint32_t 20 GetSequenceID() 21 { 22 static uint32_t g_nextID = 0; 23 return ++g_nextID; 24 } 25 26 MachThread::MachThread (MachProcess *process, thread_t thread) : 27 m_process (process), 28 m_tid (thread), 29 m_seq_id (GetSequenceID()), 30 m_state (eStateUnloaded), 31 m_state_mutex (PTHREAD_MUTEX_RECURSIVE), 32 m_breakID (INVALID_NUB_BREAK_ID), 33 m_suspendCount (0), 34 m_arch_ap (DNBArchProtocol::Create (this)), 35 m_reg_sets (m_arch_ap->GetRegisterSetInfo (&n_num_reg_sets)) 36 { 37 // Get the thread state so we know if a thread is in a state where we can't 38 // muck with it and also so we get the suspend count correct in case it was 39 // already suspended 40 GetBasicInfo(); 41 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::MachThread ( process = %p, tid = 0x%4.4x, seq_id = %u )", &m_process, m_tid, m_seq_id); 42 } 43 44 MachThread::~MachThread() 45 { 46 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::~MachThread() for tid = 0x%4.4x (%u)", m_tid, m_seq_id); 47 } 48 49 50 51 uint32_t 52 MachThread::Suspend() 53 { 54 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); 55 if (ThreadIDIsValid(m_tid)) 56 { 57 DNBError err(::thread_suspend (m_tid), DNBError::MachKernel); 58 if (err.Success()) 59 m_suspendCount++; 60 if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 61 err.LogThreaded("::thread_suspend (%4.4x)", m_tid); 62 } 63 return SuspendCount(); 64 } 65 66 uint32_t 67 MachThread::Resume() 68 { 69 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); 70 if (ThreadIDIsValid(m_tid)) 71 { 72 RestoreSuspendCount(); 73 } 74 return SuspendCount(); 75 } 76 77 bool 78 MachThread::RestoreSuspendCount() 79 { 80 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); 81 DNBError err; 82 if (ThreadIDIsValid(m_tid) == false) 83 return false; 84 if (m_suspendCount > 0) 85 { 86 while (m_suspendCount > 0) 87 { 88 err = ::thread_resume (m_tid); 89 if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 90 err.LogThreaded("::thread_resume (%4.4x)", m_tid); 91 if (err.Success()) 92 --m_suspendCount; 93 else 94 { 95 if (GetBasicInfo()) 96 m_suspendCount = m_basicInfo.suspend_count; 97 else 98 m_suspendCount = 0; 99 return false; // ??? 100 } 101 } 102 } 103 // We don't currently really support resuming a thread that was externally 104 // suspended. If/when we do, we will need to make the code below work and 105 // m_suspendCount will need to become signed instead of unsigned. 106 // else if (m_suspendCount < 0) 107 // { 108 // while (m_suspendCount < 0) 109 // { 110 // err = ::thread_suspend (m_tid); 111 // if (err.Success()) 112 // ++m_suspendCount; 113 // if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 114 // err.LogThreaded("::thread_suspend (%4.4x)", m_tid); 115 // } 116 // } 117 return true; 118 } 119 120 121 const char * 122 MachThread::GetBasicInfoAsString () const 123 { 124 static char g_basic_info_string[1024]; 125 struct thread_basic_info basicInfo; 126 127 if (GetBasicInfo(m_tid, &basicInfo)) 128 { 129 130 // char run_state_str[32]; 131 // size_t run_state_str_size = sizeof(run_state_str); 132 // switch (basicInfo.run_state) 133 // { 134 // case TH_STATE_RUNNING: strncpy(run_state_str, "running", run_state_str_size); break; 135 // case TH_STATE_STOPPED: strncpy(run_state_str, "stopped", run_state_str_size); break; 136 // case TH_STATE_WAITING: strncpy(run_state_str, "waiting", run_state_str_size); break; 137 // case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str, "uninterruptible", run_state_str_size); break; 138 // case TH_STATE_HALTED: strncpy(run_state_str, "halted", run_state_str_size); break; 139 // default: snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break; // ??? 140 // } 141 float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f; 142 float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f; 143 snprintf(g_basic_info_string, sizeof(g_basic_info_string), "Thread 0x%4.4x: user=%f system=%f cpu=%d sleep_time=%d", 144 InferiorThreadID(), 145 user, 146 system, 147 basicInfo.cpu_usage, 148 basicInfo.sleep_time); 149 150 return g_basic_info_string; 151 } 152 return NULL; 153 } 154 155 thread_t 156 MachThread::InferiorThreadID() const 157 { 158 mach_msg_type_number_t i; 159 mach_port_name_array_t names; 160 mach_port_type_array_t types; 161 mach_msg_type_number_t ncount, tcount; 162 thread_t inferior_tid = INVALID_NUB_THREAD; 163 task_t my_task = ::mach_task_self(); 164 task_t task = m_process->Task().TaskPort(); 165 166 kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount); 167 if (kret == KERN_SUCCESS) 168 { 169 170 for (i = 0; i < ncount; i++) 171 { 172 mach_port_t my_name; 173 mach_msg_type_name_t my_type; 174 175 kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type); 176 if (kret == KERN_SUCCESS) 177 { 178 ::mach_port_deallocate (my_task, my_name); 179 if (my_name == m_tid) 180 { 181 inferior_tid = names[i]; 182 break; 183 } 184 } 185 } 186 // Free up the names and types 187 ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t)); 188 ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t)); 189 } 190 return inferior_tid; 191 } 192 193 bool 194 MachThread::IsUserReady() 195 { 196 if (m_basicInfo.run_state == 0) 197 GetBasicInfo (); 198 199 switch (m_basicInfo.run_state) 200 { 201 default: 202 case TH_STATE_UNINTERRUPTIBLE: 203 break; 204 205 case TH_STATE_RUNNING: 206 case TH_STATE_STOPPED: 207 case TH_STATE_WAITING: 208 case TH_STATE_HALTED: 209 return true; 210 } 211 return false; 212 } 213 214 struct thread_basic_info * 215 MachThread::GetBasicInfo () 216 { 217 if (MachThread::GetBasicInfo(m_tid, &m_basicInfo)) 218 return &m_basicInfo; 219 return NULL; 220 } 221 222 223 bool 224 MachThread::GetBasicInfo(thread_t thread, struct thread_basic_info *basicInfoPtr) 225 { 226 if (ThreadIDIsValid(thread)) 227 { 228 unsigned int info_count = THREAD_BASIC_INFO_COUNT; 229 kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count); 230 if (err == KERN_SUCCESS) 231 return true; 232 } 233 ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info)); 234 return false; 235 } 236 237 238 bool 239 MachThread::ThreadIDIsValid(thread_t thread) 240 { 241 return thread != THREAD_NULL; 242 } 243 244 bool 245 MachThread::GetRegisterState(int flavor, bool force) 246 { 247 return m_arch_ap->GetRegisterState(flavor, force) == KERN_SUCCESS; 248 } 249 250 bool 251 MachThread::SetRegisterState(int flavor) 252 { 253 return m_arch_ap->SetRegisterState(flavor) == KERN_SUCCESS; 254 } 255 256 uint64_t 257 MachThread::GetPC(uint64_t failValue) 258 { 259 // Get program counter 260 return m_arch_ap->GetPC(failValue); 261 } 262 263 bool 264 MachThread::SetPC(uint64_t value) 265 { 266 // Set program counter 267 return m_arch_ap->SetPC(value); 268 } 269 270 uint64_t 271 MachThread::GetSP(uint64_t failValue) 272 { 273 // Get stack pointer 274 return m_arch_ap->GetSP(failValue); 275 } 276 277 nub_process_t 278 MachThread::ProcessID() const 279 { 280 if (m_process) 281 return m_process->ProcessID(); 282 return INVALID_NUB_PROCESS; 283 } 284 285 void 286 MachThread::Dump(uint32_t index) 287 { 288 const char * thread_run_state = NULL; 289 290 switch (m_basicInfo.run_state) 291 { 292 case TH_STATE_RUNNING: thread_run_state = "running"; break; // 1 thread is running normally 293 case TH_STATE_STOPPED: thread_run_state = "stopped"; break; // 2 thread is stopped 294 case TH_STATE_WAITING: thread_run_state = "waiting"; break; // 3 thread is waiting normally 295 case TH_STATE_UNINTERRUPTIBLE: thread_run_state = "uninter"; break; // 4 thread is in an uninterruptible wait 296 case TH_STATE_HALTED: thread_run_state = "halted "; break; // 5 thread is halted at a 297 default: thread_run_state = "???"; break; 298 } 299 300 DNBLogThreaded("thread[%u] %4.4x (%u): pc: 0x%8.8llx sp: 0x%8.8llx breakID: %d user: %d.%06.6d system: %d.%06.6d cpu: %d policy: %d run_state: %d (%s) flags: %d suspend_count: %d (current %d) sleep_time: %d", 301 index, 302 m_tid, 303 m_seq_id, 304 GetPC(INVALID_NUB_ADDRESS), 305 GetSP(INVALID_NUB_ADDRESS), 306 m_breakID, 307 m_basicInfo.user_time.seconds, m_basicInfo.user_time.microseconds, 308 m_basicInfo.system_time.seconds, m_basicInfo.system_time.microseconds, 309 m_basicInfo.cpu_usage, 310 m_basicInfo.policy, 311 m_basicInfo.run_state, 312 thread_run_state, 313 m_basicInfo.flags, 314 m_basicInfo.suspend_count, m_suspendCount, 315 m_basicInfo.sleep_time); 316 //DumpRegisterState(0); 317 } 318 319 void 320 MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action) 321 { 322 if (thread_action->addr != INVALID_NUB_ADDRESS) 323 SetPC (thread_action->addr); 324 325 SetState (thread_action->state); 326 switch (thread_action->state) 327 { 328 case eStateStopped: 329 case eStateSuspended: 330 Suspend(); 331 break; 332 333 case eStateRunning: 334 case eStateStepping: 335 Resume(); 336 break; 337 } 338 m_arch_ap->ThreadWillResume(); 339 m_stop_exception.Clear(); 340 } 341 342 bool 343 MachThread::ShouldStop(bool &step_more) 344 { 345 // See if this thread is at a breakpoint? 346 nub_break_t breakID = CurrentBreakpoint(); 347 348 if (NUB_BREAK_ID_IS_VALID(breakID)) 349 { 350 // This thread is sitting at a breakpoint, ask the breakpoint 351 // if we should be stopping here. 352 if (Process()->Breakpoints().ShouldStop(ProcessID(), ThreadID(), breakID)) 353 return true; 354 else 355 { 356 // The breakpoint said we shouldn't stop, but we may have gotten 357 // a signal or the user may have requested to stop in some other 358 // way. Stop if we have a valid exception (this thread won't if 359 // another thread was the reason this process stopped) and that 360 // exception, is NOT a breakpoint exception (a common case would 361 // be a SIGINT signal). 362 if (GetStopException().IsValid() && !GetStopException().IsBreakpoint()) 363 return true; 364 } 365 } 366 else 367 { 368 if (m_arch_ap->StepNotComplete()) 369 { 370 step_more = true; 371 return false; 372 } 373 // The thread state is used to let us know what the thread was 374 // trying to do. MachThread::ThreadWillResume() will set the 375 // thread state to various values depending if the thread was 376 // the current thread and if it was to be single stepped, or 377 // resumed. 378 if (GetState() == eStateRunning) 379 { 380 // If our state is running, then we should continue as we are in 381 // the process of stepping over a breakpoint. 382 return false; 383 } 384 else 385 { 386 // Stop if we have any kind of valid exception for this 387 // thread. 388 if (GetStopException().IsValid()) 389 return true; 390 } 391 } 392 return false; 393 } 394 bool 395 MachThread::IsStepping() 396 { 397 // Return true if this thread is currently being stepped. 398 // MachThread::ThreadWillResume currently determines this by looking if we 399 // have been asked to single step, or if we are at a breakpoint instruction 400 // and have been asked to resume. In the latter case we need to disable the 401 // breakpoint we are at, single step, re-enable and continue. 402 nub_state_t state = GetState(); 403 return (state == eStateStepping) || 404 (state == eStateRunning && NUB_BREAK_ID_IS_VALID(CurrentBreakpoint())); 405 } 406 407 408 bool 409 MachThread::ThreadDidStop() 410 { 411 // This thread has existed prior to resuming under debug nub control, 412 // and has just been stopped. Do any cleanup that needs to be done 413 // after running. 414 415 // The thread state and breakpoint will still have the same values 416 // as they had prior to resuming the thread, so it makes it easy to check 417 // if we were trying to step a thread, or we tried to resume while being 418 // at a breakpoint. 419 420 // When this method gets called, the process state is still in the 421 // state it was in while running so we can act accordingly. 422 m_arch_ap->ThreadDidStop(); 423 424 425 // We may have suspended this thread so the primary thread could step 426 // without worrying about race conditions, so lets restore our suspend 427 // count. 428 RestoreSuspendCount(); 429 430 // Update the basic information for a thread 431 MachThread::GetBasicInfo(m_tid, &m_basicInfo); 432 433 // See if we were at a breakpoint when we last resumed that we disabled, 434 // re-enable it. 435 nub_break_t breakID = CurrentBreakpoint(); 436 437 if (NUB_BREAK_ID_IS_VALID(breakID)) 438 { 439 m_process->EnableBreakpoint(breakID); 440 if (m_basicInfo.suspend_count > 0) 441 { 442 SetState(eStateSuspended); 443 } 444 else 445 { 446 // If we last were at a breakpoint and we single stepped, our state 447 // will be "running" to indicate we need to continue after stepping 448 // over the breakpoint instruction. If we step over a breakpoint 449 // instruction, we need to stop. 450 if (GetState() == eStateRunning) 451 { 452 // Leave state set to running so we will continue automatically 453 // from this breakpoint 454 } 455 else 456 { 457 SetState(eStateStopped); 458 } 459 } 460 } 461 else 462 { 463 if (m_basicInfo.suspend_count > 0) 464 { 465 SetState(eStateSuspended); 466 } 467 else 468 { 469 SetState(eStateStopped); 470 } 471 } 472 473 474 SetCurrentBreakpoint(INVALID_NUB_BREAK_ID); 475 476 return true; 477 } 478 479 bool 480 MachThread::NotifyException(MachException::Data& exc) 481 { 482 if (m_stop_exception.IsValid()) 483 { 484 // We may have more than one exception for a thread, but we need to 485 // only remember the one that we will say is the reason we stopped. 486 // We may have been single stepping and also gotten a signal exception, 487 // so just remember the most pertinent one. 488 if (m_stop_exception.IsBreakpoint()) 489 m_stop_exception = exc; 490 } 491 else 492 { 493 m_stop_exception = exc; 494 } 495 bool handled = m_arch_ap->NotifyException(exc); 496 if (!handled) 497 { 498 handled = true; 499 nub_addr_t pc = GetPC(); 500 nub_break_t breakID = m_process->Breakpoints().FindIDByAddress(pc); 501 SetCurrentBreakpoint(breakID); 502 switch (exc.exc_type) 503 { 504 case EXC_BAD_ACCESS: 505 break; 506 case EXC_BAD_INSTRUCTION: 507 break; 508 case EXC_ARITHMETIC: 509 break; 510 case EXC_EMULATION: 511 break; 512 case EXC_SOFTWARE: 513 break; 514 case EXC_BREAKPOINT: 515 break; 516 case EXC_SYSCALL: 517 break; 518 case EXC_MACH_SYSCALL: 519 break; 520 case EXC_RPC_ALERT: 521 break; 522 } 523 } 524 return handled; 525 } 526 527 528 nub_state_t 529 MachThread::GetState() 530 { 531 // If any other threads access this we will need a mutex for it 532 PTHREAD_MUTEX_LOCKER (locker, m_state_mutex); 533 return m_state; 534 } 535 536 void 537 MachThread::SetState(nub_state_t state) 538 { 539 PTHREAD_MUTEX_LOCKER (locker, m_state_mutex); 540 m_state = state; 541 DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%4.4x", DNBStateAsString(state), m_tid); 542 } 543 544 uint32_t 545 MachThread::GetNumRegistersInSet(int regSet) const 546 { 547 if (regSet < n_num_reg_sets) 548 return m_reg_sets[regSet].num_registers; 549 return 0; 550 } 551 552 const char * 553 MachThread::GetRegisterSetName(int regSet) const 554 { 555 if (regSet < n_num_reg_sets) 556 return m_reg_sets[regSet].name; 557 return NULL; 558 } 559 560 const DNBRegisterInfo * 561 MachThread::GetRegisterInfo(int regSet, int regIndex) const 562 { 563 if (regSet < n_num_reg_sets) 564 if (regIndex < m_reg_sets[regSet].num_registers) 565 return &m_reg_sets[regSet].registers[regIndex]; 566 return NULL; 567 } 568 void 569 MachThread::DumpRegisterState(int regSet) 570 { 571 if (regSet == REGISTER_SET_ALL) 572 { 573 for (regSet = 1; regSet < n_num_reg_sets; regSet++) 574 DumpRegisterState(regSet); 575 } 576 else 577 { 578 if (m_arch_ap->RegisterSetStateIsValid(regSet)) 579 { 580 const size_t numRegisters = GetNumRegistersInSet(regSet); 581 size_t regIndex = 0; 582 DNBRegisterValueClass reg; 583 for (regIndex = 0; regIndex < numRegisters; ++regIndex) 584 { 585 if (m_arch_ap->GetRegisterValue(regSet, regIndex, ®)) 586 { 587 reg.Dump(NULL, NULL); 588 } 589 } 590 } 591 else 592 { 593 DNBLog("%s: registers are not currently valid.", GetRegisterSetName(regSet)); 594 } 595 } 596 } 597 598 const DNBRegisterSetInfo * 599 MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const 600 { 601 *num_reg_sets = n_num_reg_sets; 602 return &m_reg_sets[0]; 603 } 604 605 bool 606 MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value ) 607 { 608 return m_arch_ap->GetRegisterValue(set, reg, value); 609 } 610 611 bool 612 MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value ) 613 { 614 return m_arch_ap->SetRegisterValue(set, reg, value); 615 } 616 617 nub_size_t 618 MachThread::GetRegisterContext (void *buf, nub_size_t buf_len) 619 { 620 return m_arch_ap->GetRegisterContext(buf, buf_len); 621 } 622 623 nub_size_t 624 MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len) 625 { 626 return m_arch_ap->SetRegisterContext(buf, buf_len); 627 } 628 629 uint32_t 630 MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp) 631 { 632 if (bp != NULL && bp->IsBreakpoint()) 633 return m_arch_ap->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize()); 634 return INVALID_NUB_HW_INDEX; 635 } 636 637 uint32_t 638 MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp) 639 { 640 if (wp != NULL && wp->IsWatchpoint()) 641 return m_arch_ap->EnableHardwareWatchpoint(wp->Address(), wp->ByteSize(), wp->WatchpointRead(), wp->WatchpointWrite()); 642 return INVALID_NUB_HW_INDEX; 643 } 644 645 bool 646 MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp) 647 { 648 if (bp != NULL && bp->IsHardware()) 649 return m_arch_ap->DisableHardwareBreakpoint(bp->GetHardwareIndex()); 650 return false; 651 } 652 653 bool 654 MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp) 655 { 656 if (wp != NULL && wp->IsHardware()) 657 return m_arch_ap->DisableHardwareWatchpoint(wp->GetHardwareIndex()); 658 return false; 659 } 660 661 662 void 663 MachThread::NotifyBreakpointChanged (const DNBBreakpoint *bp) 664 { 665 nub_break_t breakID = bp->GetID(); 666 if (bp->IsEnabled()) 667 { 668 if (bp->Address() == GetPC()) 669 { 670 SetCurrentBreakpoint(breakID); 671 } 672 } 673 else 674 { 675 if (CurrentBreakpoint() == breakID) 676 { 677 SetCurrentBreakpoint(INVALID_NUB_BREAK_ID); 678 } 679 } 680 } 681 682 bool 683 MachThread::GetIdentifierInfo () 684 { 685 #ifdef THREAD_IDENTIFIER_INFO_COUNT 686 if (m_ident_info.thread_id == 0) 687 { 688 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; 689 return ::thread_info (ThreadID(), THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count) == KERN_SUCCESS; 690 } 691 #endif 692 693 return false; 694 } 695 696 697 const char * 698 MachThread::GetName () 699 { 700 if (GetIdentifierInfo ()) 701 { 702 int len = ::proc_pidinfo (m_process->ProcessID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo)); 703 704 if (len && m_proc_threadinfo.pth_name[0]) 705 return m_proc_threadinfo.pth_name; 706 } 707 return NULL; 708 } 709 710 711 // 712 //const char * 713 //MachThread::GetDispatchQueueName() 714 //{ 715 // if (GetIdentifierInfo ()) 716 // { 717 // if (m_ident_info.dispatch_qaddr == 0) 718 // return NULL; 719 // 720 // uint8_t memory_buffer[8]; 721 // DNBDataRef data(memory_buffer, sizeof(memory_buffer), false); 722 // ModuleSP module_sp(GetProcess()->GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libSystem.B.dylib"))); 723 // if (module_sp.get() == NULL) 724 // return NULL; 725 // 726 // lldb::addr_t dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS; 727 // const Symbol *dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (ConstString("dispatch_queue_offsets"), eSymbolTypeData); 728 // if (dispatch_queue_offsets_symbol) 729 // dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetValue().GetLoadAddress(GetProcess()); 730 // 731 // if (dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS) 732 // return NULL; 733 // 734 // // Excerpt from src/queue_private.h 735 // struct dispatch_queue_offsets_s 736 // { 737 // uint16_t dqo_version; 738 // uint16_t dqo_label; 739 // uint16_t dqo_label_size; 740 // } dispatch_queue_offsets; 741 // 742 // 743 // if (GetProcess()->ReadMemory (dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets)) == sizeof(dispatch_queue_offsets)) 744 // { 745 // uint32_t data_offset = 0; 746 // if (data.GetU16(&data_offset, &dispatch_queue_offsets.dqo_version, sizeof(dispatch_queue_offsets)/sizeof(uint16_t))) 747 // { 748 // if (GetProcess()->ReadMemory (m_ident_info.dispatch_qaddr, &memory_buffer, data.GetAddressByteSize()) == data.GetAddressByteSize()) 749 // { 750 // data_offset = 0; 751 // lldb::addr_t queue_addr = data.GetAddress(&data_offset); 752 // lldb::addr_t label_addr = queue_addr + dispatch_queue_offsets.dqo_label; 753 // const size_t chunk_size = 32; 754 // uint32_t label_pos = 0; 755 // m_dispatch_queue_name.resize(chunk_size, '\0'); 756 // while (1) 757 // { 758 // size_t bytes_read = GetProcess()->ReadMemory (label_addr + label_pos, &m_dispatch_queue_name[label_pos], chunk_size); 759 // 760 // if (bytes_read <= 0) 761 // break; 762 // 763 // if (m_dispatch_queue_name.find('\0', label_pos) != std::string::npos) 764 // break; 765 // label_pos += bytes_read; 766 // } 767 // m_dispatch_queue_name.erase(m_dispatch_queue_name.find('\0')); 768 // } 769 // } 770 // } 771 // } 772 // 773 // if (m_dispatch_queue_name.empty()) 774 // return NULL; 775 // return m_dispatch_queue_name.c_str(); 776 //} 777