MachThread.cpp revision 24943d2ee8bfaa7cf5893e4709143924157a5c1e
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 19static uint32_t 20GetSequenceID() 21{ 22 static uint32_t g_nextID = 0; 23 return ++g_nextID; 24} 25 26MachThread::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 46MachThread::~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 53uint32_t 54MachThread::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 68uint32_t 69MachThread::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 86bool 87MachThread::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 119const char * 120MachThread::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 153thread_t 154MachThread::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 191bool 192MachThread::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 206bool 207MachThread::ThreadIDIsValid(thread_t thread) 208{ 209 return thread != THREAD_NULL; 210} 211 212bool 213MachThread::GetRegisterState(int flavor, bool force) 214{ 215 return m_arch.GetRegisterState(flavor, force) == KERN_SUCCESS; 216} 217 218bool 219MachThread::SetRegisterState(int flavor) 220{ 221 return m_arch.SetRegisterState(flavor) == KERN_SUCCESS; 222} 223 224uint64_t 225MachThread::GetPC(uint64_t failValue) 226{ 227 // Get program counter 228 return m_arch.GetPC(failValue); 229} 230 231bool 232MachThread::SetPC(uint64_t value) 233{ 234 // Set program counter 235 return m_arch.SetPC(value); 236} 237 238uint64_t 239MachThread::GetSP(uint64_t failValue) 240{ 241 // Get stack pointer 242 return m_arch.GetSP(failValue); 243} 244 245nub_process_t 246MachThread::ProcessID() const 247{ 248 if (m_process) 249 return m_process->ProcessID(); 250 return INVALID_NUB_PROCESS; 251} 252 253void 254MachThread::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 287void 288MachThread::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 310bool 311MachThread::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} 362bool 363MachThread::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 376bool 377MachThread::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 448bool 449MachThread::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 497nub_state_t 498MachThread::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 505void 506MachThread::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 513uint32_t 514MachThread::GetNumRegistersInSet(int regSet) const 515{ 516 if (regSet < m_regSets.size()) 517 return m_regSets[regSet].num_registers; 518 return 0; 519} 520 521const char * 522MachThread::GetRegisterSetName(int regSet) const 523{ 524 if (regSet < m_regSets.size()) 525 return m_regSets[regSet].name; 526 return NULL; 527} 528 529const DNBRegisterInfo * 530MachThread::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} 537void 538MachThread::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 567const DNBRegisterSetInfo * 568MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const 569{ 570 *num_reg_sets = m_regSets.size(); 571 return &m_regSets[0]; 572} 573 574bool 575MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value ) 576{ 577 return m_arch.GetRegisterValue(set, reg, value); 578} 579 580bool 581MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value ) 582{ 583 return m_arch.SetRegisterValue(set, reg, value); 584} 585 586nub_size_t 587MachThread::GetRegisterContext (void *buf, nub_size_t buf_len) 588{ 589 return m_arch.GetRegisterContext(buf, buf_len); 590} 591 592nub_size_t 593MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len) 594{ 595 return m_arch.SetRegisterContext(buf, buf_len); 596} 597 598uint32_t 599MachThread::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 606uint32_t 607MachThread::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 614bool 615MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp) 616{ 617 if (bp != NULL && bp->IsHardware()) 618 return m_arch.DisableHardwareBreakpoint(bp->GetHardwareIndex()); 619 return false; 620} 621 622bool 623MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp) 624{ 625 if (wp != NULL && wp->IsHardware()) 626 return m_arch.DisableHardwareWatchpoint(wp->GetHardwareIndex()); 627 return false; 628} 629 630 631void 632MachThread::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 651bool 652MachThread::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 666const char * 667MachThread::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