NativeThreadListDarwin.cpp revision 341825
1//===-- NativeThreadListDarwin.cpp ------------------------------------*- C++ 2//-*-===// 3// 4// The LLVM Compiler Infrastructure 5// 6// This file is distributed under the University of Illinois Open Source 7// License. See LICENSE.TXT for details. 8// 9//===----------------------------------------------------------------------===// 10// 11// Created by Greg Clayton on 6/19/07. 12// 13//===----------------------------------------------------------------------===// 14 15#include "NativeThreadListDarwin.h" 16 17// C includes 18#include <inttypes.h> 19#include <mach/vm_map.h> 20#include <sys/sysctl.h> 21 22// LLDB includes 23#include "lldb/Utility/Log.h" 24#include "lldb/Utility/Status.h" 25#include "lldb/Utility/Stream.h" 26#include "lldb/lldb-enumerations.h" 27 28#include "NativeProcessDarwin.h" 29#include "NativeThreadDarwin.h" 30 31using namespace lldb; 32using namespace lldb_private; 33using namespace lldb_private::process_darwin; 34 35NativeThreadListDarwin::NativeThreadListDarwin() 36 : m_threads(), m_threads_mutex(), m_is_64_bit(false) {} 37 38NativeThreadListDarwin::~NativeThreadListDarwin() {} 39 40// These methods will be accessed directly from NativeThreadDarwin 41#if 0 42nub_state_t 43NativeThreadListDarwin::GetState(nub_thread_t tid) 44{ 45 MachThreadSP thread_sp (GetThreadByID (tid)); 46 if (thread_sp) 47 return thread_sp->GetState(); 48 return eStateInvalid; 49} 50 51const char * 52NativeThreadListDarwin::GetName (nub_thread_t tid) 53{ 54 MachThreadSP thread_sp (GetThreadByID (tid)); 55 if (thread_sp) 56 return thread_sp->GetName(); 57 return NULL; 58} 59#endif 60 61// TODO: figure out if we need to add this to NativeThreadDarwin yet. 62#if 0 63ThreadInfo::QoS 64NativeThreadListDarwin::GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index) 65{ 66 MachThreadSP thread_sp (GetThreadByID (tid)); 67 if (thread_sp) 68 return thread_sp->GetRequestedQoS(tsd, dti_qos_class_index); 69 return ThreadInfo::QoS(); 70} 71 72nub_addr_t 73NativeThreadListDarwin::GetPThreadT (nub_thread_t tid) 74{ 75 MachThreadSP thread_sp (GetThreadByID (tid)); 76 if (thread_sp) 77 return thread_sp->GetPThreadT(); 78 return INVALID_NUB_ADDRESS; 79} 80 81nub_addr_t 82NativeThreadListDarwin::GetDispatchQueueT (nub_thread_t tid) 83{ 84 MachThreadSP thread_sp (GetThreadByID (tid)); 85 if (thread_sp) 86 return thread_sp->GetDispatchQueueT(); 87 return INVALID_NUB_ADDRESS; 88} 89 90nub_addr_t 91NativeThreadListDarwin::GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size) 92{ 93 MachThreadSP thread_sp (GetThreadByID (tid)); 94 if (thread_sp) 95 return thread_sp->GetTSDAddressForThread(plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size); 96 return INVALID_NUB_ADDRESS; 97} 98#endif 99 100// TODO implement these 101#if 0 102nub_thread_t 103NativeThreadListDarwin::SetCurrentThread(nub_thread_t tid) 104{ 105 MachThreadSP thread_sp (GetThreadByID (tid)); 106 if (thread_sp) 107 { 108 m_current_thread = thread_sp; 109 return tid; 110 } 111 return INVALID_NUB_THREAD; 112} 113 114 115bool 116NativeThreadListDarwin::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const 117{ 118 MachThreadSP thread_sp (GetThreadByID (tid)); 119 if (thread_sp) 120 return thread_sp->GetStopException().GetStopInfo(stop_info); 121 return false; 122} 123 124bool 125NativeThreadListDarwin::GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info) 126{ 127 thread_t mach_port_number = GetMachPortNumberByThreadID (tid); 128 129 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; 130 return ::thread_info (mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t)ident_info, &count) == KERN_SUCCESS; 131} 132 133void 134NativeThreadListDarwin::DumpThreadStoppedReason (nub_thread_t tid) const 135{ 136 MachThreadSP thread_sp (GetThreadByID (tid)); 137 if (thread_sp) 138 thread_sp->GetStopException().DumpStopReason(); 139} 140 141const char * 142NativeThreadListDarwin::GetThreadInfo (nub_thread_t tid) const 143{ 144 MachThreadSP thread_sp (GetThreadByID (tid)); 145 if (thread_sp) 146 return thread_sp->GetBasicInfoAsString(); 147 return NULL; 148} 149 150#endif 151 152NativeThreadDarwinSP 153NativeThreadListDarwin::GetThreadByID(lldb::tid_t tid) const { 154 std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 155 for (auto thread_sp : m_threads) { 156 if (thread_sp && (thread_sp->GetID() == tid)) 157 return thread_sp; 158 } 159 return NativeThreadDarwinSP(); 160} 161 162NativeThreadDarwinSP NativeThreadListDarwin::GetThreadByMachPortNumber( 163 ::thread_t mach_port_number) const { 164 std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 165 for (auto thread_sp : m_threads) { 166 if (thread_sp && (thread_sp->GetMachPortNumber() == mach_port_number)) 167 return thread_sp; 168 } 169 return NativeThreadDarwinSP(); 170} 171 172lldb::tid_t NativeThreadListDarwin::GetThreadIDByMachPortNumber( 173 ::thread_t mach_port_number) const { 174 std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 175 for (auto thread_sp : m_threads) { 176 if (thread_sp && (thread_sp->GetMachPortNumber() == mach_port_number)) 177 return thread_sp->GetID(); 178 } 179 return LLDB_INVALID_THREAD_ID; 180} 181 182// TODO implement 183#if 0 184thread_t 185NativeThreadListDarwin::GetMachPortNumberByThreadID (nub_thread_t globally_unique_id) const 186{ 187 PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); 188 MachThreadSP thread_sp; 189 const size_t num_threads = m_threads.size(); 190 for (size_t idx = 0; idx < num_threads; ++idx) 191 { 192 if (m_threads[idx]->ThreadID() == globally_unique_id) 193 { 194 return m_threads[idx]->MachPortNumber(); 195 } 196 } 197 return 0; 198} 199 200bool 201NativeThreadListDarwin::GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value ) const 202{ 203 MachThreadSP thread_sp (GetThreadByID (tid)); 204 if (thread_sp) 205 return thread_sp->GetRegisterValue(set, reg, reg_value); 206 207 return false; 208} 209 210bool 211NativeThreadListDarwin::SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *reg_value ) const 212{ 213 MachThreadSP thread_sp (GetThreadByID (tid)); 214 if (thread_sp) 215 return thread_sp->SetRegisterValue(set, reg, reg_value); 216 217 return false; 218} 219 220nub_size_t 221NativeThreadListDarwin::GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len) 222{ 223 MachThreadSP thread_sp (GetThreadByID (tid)); 224 if (thread_sp) 225 return thread_sp->GetRegisterContext (buf, buf_len); 226 return 0; 227} 228 229nub_size_t 230NativeThreadListDarwin::SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len) 231{ 232 MachThreadSP thread_sp (GetThreadByID (tid)); 233 if (thread_sp) 234 return thread_sp->SetRegisterContext (buf, buf_len); 235 return 0; 236} 237 238uint32_t 239NativeThreadListDarwin::SaveRegisterState (nub_thread_t tid) 240{ 241 MachThreadSP thread_sp (GetThreadByID (tid)); 242 if (thread_sp) 243 return thread_sp->SaveRegisterState (); 244 return 0; 245} 246 247bool 248NativeThreadListDarwin::RestoreRegisterState (nub_thread_t tid, uint32_t save_id) 249{ 250 MachThreadSP thread_sp (GetThreadByID (tid)); 251 if (thread_sp) 252 return thread_sp->RestoreRegisterState (save_id); 253 return 0; 254} 255#endif 256 257size_t NativeThreadListDarwin::GetNumberOfThreads() const { 258 std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 259 return static_cast<size_t>(m_threads.size()); 260} 261 262// TODO implement 263#if 0 264nub_thread_t 265NativeThreadListDarwin::ThreadIDAtIndex (nub_size_t idx) const 266{ 267 PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); 268 if (idx < m_threads.size()) 269 return m_threads[idx]->ThreadID(); 270 return INVALID_NUB_THREAD; 271} 272 273nub_thread_t 274NativeThreadListDarwin::CurrentThreadID ( ) 275{ 276 MachThreadSP thread_sp; 277 CurrentThread(thread_sp); 278 if (thread_sp.get()) 279 return thread_sp->ThreadID(); 280 return INVALID_NUB_THREAD; 281} 282 283#endif 284 285bool NativeThreadListDarwin::NotifyException(MachException::Data &exc) { 286 auto thread_sp = GetThreadByMachPortNumber(exc.thread_port); 287 if (thread_sp) { 288 thread_sp->NotifyException(exc); 289 return true; 290 } 291 return false; 292} 293 294void NativeThreadListDarwin::Clear() { 295 std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 296 m_threads.clear(); 297} 298 299uint32_t NativeThreadListDarwin::UpdateThreadList(NativeProcessDarwin &process, 300 bool update, 301 collection *new_threads) { 302 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); 303 304 std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 305 if (log) 306 log->Printf("NativeThreadListDarwin::%s() (pid = %" PRIu64 ", update = " 307 "%u) process stop count = %u", 308 __FUNCTION__, process.GetID(), update, process.GetStopID()); 309 310 if (process.GetStopID() == 0) { 311 // On our first stop, we'll record details like 32/64 bitness and select 312 // the proper architecture implementation. 313 // 314 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)process.GetID()}; 315 316 struct kinfo_proc processInfo; 317 size_t bufsize = sizeof(processInfo); 318 if ((sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, 319 &bufsize, NULL, 0) == 0) && 320 (bufsize > 0)) { 321 if (processInfo.kp_proc.p_flag & P_LP64) 322 m_is_64_bit = true; 323 } 324 325// TODO implement architecture selection and abstraction. 326#if 0 327#if defined(__i386__) || defined(__x86_64__) 328 if (m_is_64_bit) 329 DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64); 330 else 331 DNBArchProtocol::SetArchitecture(CPU_TYPE_I386); 332#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__) 333 if (m_is_64_bit) 334 DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64); 335 else 336 DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM); 337#endif 338#endif 339 } 340 341 if (m_threads.empty() || update) { 342 thread_array_t thread_list = nullptr; 343 mach_msg_type_number_t thread_list_count = 0; 344 task_t task = process.GetTask(); 345 346 Status error; 347 auto mach_err = ::task_threads(task, &thread_list, &thread_list_count); 348 error.SetError(mach_err, eErrorTypeMachKernel); 349 if (error.Fail()) { 350 if (log) 351 log->Printf("::task_threads(task = 0x%4.4x, thread_list => %p, " 352 "thread_list_count => %u) failed: %u (%s)", 353 task, thread_list, thread_list_count, error.GetError(), 354 error.AsCString()); 355 return 0; 356 } 357 358 if (thread_list_count > 0) { 359 collection currThreads; 360 size_t idx; 361 // Iterator through the current thread list and see which threads we 362 // already have in our list (keep them), which ones we don't (add them), 363 // and which ones are not around anymore (remove them). 364 for (idx = 0; idx < thread_list_count; ++idx) { 365 // Get the Mach thread port. 366 const ::thread_t mach_port_num = thread_list[idx]; 367 368 // Get the unique thread id for the mach port number. 369 uint64_t unique_thread_id = 370 NativeThreadDarwin::GetGloballyUniqueThreadIDForMachPortID( 371 mach_port_num); 372 373 // Retrieve the thread if it exists. 374 auto thread_sp = GetThreadByID(unique_thread_id); 375 if (thread_sp) { 376 // We are already tracking it. Keep the existing native thread 377 // instance. 378 currThreads.push_back(thread_sp); 379 } else { 380 // We don't have a native thread instance for this thread. Create it 381 // now. 382 thread_sp.reset(new NativeThreadDarwin( 383 &process, m_is_64_bit, unique_thread_id, mach_port_num)); 384 385 // Add the new thread regardless of its is user ready state. Make 386 // sure the thread is ready to be displayed and shown to users before 387 // we add this thread to our list... 388 if (thread_sp->IsUserReady()) { 389 if (new_threads) 390 new_threads->push_back(thread_sp); 391 392 currThreads.push_back(thread_sp); 393 } 394 } 395 } 396 397 m_threads.swap(currThreads); 398 m_current_thread.reset(); 399 400 // Free the vm memory given to us by ::task_threads() 401 vm_size_t thread_list_size = 402 (vm_size_t)(thread_list_count * sizeof(::thread_t)); 403 ::vm_deallocate(::mach_task_self(), (vm_address_t)thread_list, 404 thread_list_size); 405 } 406 } 407 return static_cast<uint32_t>(m_threads.size()); 408} 409 410// TODO implement 411#if 0 412 413void 414NativeThreadListDarwin::CurrentThread (MachThreadSP& thread_sp) 415{ 416 // locker will keep a mutex locked until it goes out of scope 417 PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); 418 if (m_current_thread.get() == NULL) 419 { 420 // Figure out which thread is going to be our current thread. This is 421 // currently done by finding the first thread in the list that has a 422 // valid exception. 423 const size_t num_threads = m_threads.size(); 424 for (uint32_t idx = 0; idx < num_threads; ++idx) 425 { 426 if (m_threads[idx]->GetStopException().IsValid()) 427 { 428 m_current_thread = m_threads[idx]; 429 break; 430 } 431 } 432 } 433 thread_sp = m_current_thread; 434} 435 436#endif 437 438void NativeThreadListDarwin::Dump(Stream &stream) const { 439 bool first = true; 440 441 std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 442 for (auto thread_sp : m_threads) { 443 if (thread_sp) { 444 // Handle newlines between thread entries. 445 if (first) 446 first = false; 447 else 448 stream.PutChar('\n'); 449 thread_sp->Dump(stream); 450 } 451 } 452} 453 454void NativeThreadListDarwin::ProcessWillResume( 455 NativeProcessDarwin &process, const ResumeActionList &thread_actions) { 456 std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 457 458 // Update our thread list, because sometimes libdispatch or the kernel will 459 // spawn threads while a task is suspended. 460 NativeThreadListDarwin::collection new_threads; 461 462// TODO implement this. 463#if 0 464 // First figure out if we were planning on running only one thread, and if 465 // so, force that thread to resume. 466 bool run_one_thread; 467 thread_t solo_thread = THREAD_NULL; 468 if ((thread_actions.GetSize() > 0) && 469 (thread_actions.NumActionsWithState(eStateStepping) + 470 thread_actions.NumActionsWithState (eStateRunning) == 1)) 471 { 472 run_one_thread = true; 473 const DNBThreadResumeAction *action_ptr = thread_actions.GetFirst(); 474 size_t num_actions = thread_actions.GetSize(); 475 for (size_t i = 0; i < num_actions; i++, action_ptr++) 476 { 477 if (action_ptr->state == eStateStepping || action_ptr->state == eStateRunning) 478 { 479 solo_thread = action_ptr->tid; 480 break; 481 } 482 } 483 } 484 else 485 run_one_thread = false; 486#endif 487 488 UpdateThreadList(process, true, &new_threads); 489 490#if 0 491 DNBThreadResumeAction resume_new_threads = { -1U, eStateRunning, 0, INVALID_NUB_ADDRESS }; 492 // If we are planning to run only one thread, any new threads should be 493 // suspended. 494 if (run_one_thread) 495 resume_new_threads.state = eStateSuspended; 496 497 const size_t num_new_threads = new_threads.size(); 498 const size_t num_threads = m_threads.size(); 499 for (uint32_t idx = 0; idx < num_threads; ++idx) 500 { 501 MachThread *thread = m_threads[idx].get(); 502 bool handled = false; 503 for (uint32_t new_idx = 0; new_idx < num_new_threads; ++new_idx) 504 { 505 if (thread == new_threads[new_idx].get()) 506 { 507 thread->ThreadWillResume(&resume_new_threads); 508 handled = true; 509 break; 510 } 511 } 512 513 if (!handled) 514 { 515 const DNBThreadResumeAction *thread_action = thread_actions.GetActionForThread (thread->ThreadID(), true); 516 // There must always be a thread action for every thread. 517 assert (thread_action); 518 bool others_stopped = false; 519 if (solo_thread == thread->ThreadID()) 520 others_stopped = true; 521 thread->ThreadWillResume (thread_action, others_stopped); 522 } 523 } 524 525 if (new_threads.size()) 526 { 527 for (uint32_t idx = 0; idx < num_new_threads; ++idx) 528 { 529 DNBLogThreadedIf (LOG_THREAD, "NativeThreadListDarwin::ProcessWillResume (pid = %4.4x) stop-id=%u, resuming newly discovered thread: 0x%8.8" PRIx64 ", thread-is-user-ready=%i)", 530 process->ProcessID(), 531 process->StopCount(), 532 new_threads[idx]->ThreadID(), 533 new_threads[idx]->IsUserReady()); 534 } 535 } 536#endif 537} 538 539uint32_t NativeThreadListDarwin::ProcessDidStop(NativeProcessDarwin &process) { 540 std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 541 542 // Update our thread list. 543 UpdateThreadList(process, true); 544 545 for (auto thread_sp : m_threads) { 546 if (thread_sp) 547 thread_sp->ThreadDidStop(); 548 } 549 return (uint32_t)m_threads.size(); 550} 551 552//---------------------------------------------------------------------- 553// Check each thread in our thread list to see if we should notify our client 554// of the current halt in execution. 555// 556// Breakpoints can have callback functions associated with them than can return 557// true to stop, or false to continue executing the inferior. 558// 559// RETURNS 560// true if we should stop and notify our clients 561// false if we should resume our child process and skip notification 562//---------------------------------------------------------------------- 563bool NativeThreadListDarwin::ShouldStop(bool &step_more) { 564 std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 565 for (auto thread_sp : m_threads) { 566 if (thread_sp && thread_sp->ShouldStop(step_more)) 567 return true; 568 } 569 return false; 570} 571 572// Implement. 573#if 0 574 575void 576NativeThreadListDarwin::NotifyBreakpointChanged (const DNBBreakpoint *bp) 577{ 578 PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); 579 const size_t num_threads = m_threads.size(); 580 for (uint32_t idx = 0; idx < num_threads; ++idx) 581 { 582 m_threads[idx]->NotifyBreakpointChanged(bp); 583 } 584} 585 586 587uint32_t 588NativeThreadListDarwin::EnableHardwareBreakpoint (const DNBBreakpoint* bp) const 589{ 590 if (bp != NULL) 591 { 592 const size_t num_threads = m_threads.size(); 593 for (uint32_t idx = 0; idx < num_threads; ++idx) 594 m_threads[idx]->EnableHardwareBreakpoint(bp); 595 } 596 return INVALID_NUB_HW_INDEX; 597} 598 599bool 600NativeThreadListDarwin::DisableHardwareBreakpoint (const DNBBreakpoint* bp) const 601{ 602 if (bp != NULL) 603 { 604 const size_t num_threads = m_threads.size(); 605 for (uint32_t idx = 0; idx < num_threads; ++idx) 606 m_threads[idx]->DisableHardwareBreakpoint(bp); 607 } 608 return false; 609} 610 611// DNBWatchpointSet() -> MachProcess::CreateWatchpoint() -> 612// MachProcess::EnableWatchpoint() -> 613// NativeThreadListDarwin::EnableHardwareWatchpoint(). 614uint32_t 615NativeThreadListDarwin::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const 616{ 617 uint32_t hw_index = INVALID_NUB_HW_INDEX; 618 if (wp != NULL) 619 { 620 PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); 621 const size_t num_threads = m_threads.size(); 622 // On Mac OS X we have to prime the control registers for new threads. 623 // We do this using the control register data for the first thread, for 624 // lack of a better way of choosing. 625 bool also_set_on_task = true; 626 for (uint32_t idx = 0; idx < num_threads; ++idx) 627 { 628 if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint(wp, also_set_on_task)) == INVALID_NUB_HW_INDEX) 629 { 630 // We know that idx failed for some reason. Let's rollback the 631 // transaction for [0, idx). 632 for (uint32_t i = 0; i < idx; ++i) 633 m_threads[i]->RollbackTransForHWP(); 634 return INVALID_NUB_HW_INDEX; 635 } 636 also_set_on_task = false; 637 } 638 // Notify each thread to commit the pending transaction. 639 for (uint32_t idx = 0; idx < num_threads; ++idx) 640 m_threads[idx]->FinishTransForHWP(); 641 642 } 643 return hw_index; 644} 645 646bool 647NativeThreadListDarwin::DisableHardwareWatchpoint (const DNBBreakpoint* wp) const 648{ 649 if (wp != NULL) 650 { 651 PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); 652 const size_t num_threads = m_threads.size(); 653 654 // On Mac OS X we have to prime the control registers for new threads. 655 // We do this using the control register data for the first thread, for 656 // lack of a better way of choosing. 657 bool also_set_on_task = true; 658 for (uint32_t idx = 0; idx < num_threads; ++idx) 659 { 660 if (!m_threads[idx]->DisableHardwareWatchpoint(wp, also_set_on_task)) 661 { 662 // We know that idx failed for some reason. Let's rollback the 663 // transaction for [0, idx). 664 for (uint32_t i = 0; i < idx; ++i) 665 m_threads[i]->RollbackTransForHWP(); 666 return false; 667 } 668 also_set_on_task = false; 669 } 670 // Notify each thread to commit the pending transaction. 671 for (uint32_t idx = 0; idx < num_threads; ++idx) 672 m_threads[idx]->FinishTransForHWP(); 673 674 return true; 675 } 676 return false; 677} 678 679uint32_t 680NativeThreadListDarwin::NumSupportedHardwareWatchpoints () const 681{ 682 PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); 683 const size_t num_threads = m_threads.size(); 684 // Use an arbitrary thread to retrieve the number of supported hardware 685 // watchpoints. 686 if (num_threads) 687 return m_threads[0]->NumSupportedHardwareWatchpoints(); 688 return 0; 689} 690 691uint32_t 692NativeThreadListDarwin::GetThreadIndexForThreadStoppedWithSignal (const int signo) const 693{ 694 PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); 695 uint32_t should_stop = false; 696 const size_t num_threads = m_threads.size(); 697 for (uint32_t idx = 0; !should_stop && idx < num_threads; ++idx) 698 { 699 if (m_threads[idx]->GetStopException().SoftSignal () == signo) 700 return idx; 701 } 702 return UINT32_MAX; 703} 704 705#endif 706