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