NativeThreadListDarwin.cpp revision 341825
1292934Sdim//===-- NativeThreadListDarwin.cpp ------------------------------------*- C++ 2280461Sdim//-*-===// 3353358Sdim// 4353358Sdim// The LLVM Compiler Infrastructure 5353358Sdim// 6280461Sdim// This file is distributed under the University of Illinois Open Source 7280461Sdim// License. See LICENSE.TXT for details. 8280461Sdim// 9280461Sdim//===----------------------------------------------------------------------===// 10280461Sdim// 11280461Sdim// Created by Greg Clayton on 6/19/07. 12280461Sdim// 13280461Sdim//===----------------------------------------------------------------------===// 14280461Sdim 15280461Sdim#include "NativeThreadListDarwin.h" 16280461Sdim 17280461Sdim// C includes 18280461Sdim#include <inttypes.h> 19280461Sdim#include <mach/vm_map.h> 20280461Sdim#include <sys/sysctl.h> 21280461Sdim 22280461Sdim// LLDB includes 23280461Sdim#include "lldb/Utility/Log.h" 24280461Sdim#include "lldb/Utility/Status.h" 25280461Sdim#include "lldb/Utility/Stream.h" 26280461Sdim#include "lldb/lldb-enumerations.h" 27280461Sdim 28280461Sdim#include "NativeProcessDarwin.h" 29280461Sdim#include "NativeThreadDarwin.h" 30280461Sdim 31280461Sdimusing namespace lldb; 32280461Sdimusing namespace lldb_private; 33280461Sdimusing namespace lldb_private::process_darwin; 34280461Sdim 35280461SdimNativeThreadListDarwin::NativeThreadListDarwin() 36280461Sdim : m_threads(), m_threads_mutex(), m_is_64_bit(false) {} 37327952Sdim 38280461SdimNativeThreadListDarwin::~NativeThreadListDarwin() {} 39280461Sdim 40280461Sdim// These methods will be accessed directly from NativeThreadDarwin 41280461Sdim#if 0 42280461Sdimnub_state_t 43280461SdimNativeThreadListDarwin::GetState(nub_thread_t tid) 44280461Sdim{ 45280461Sdim MachThreadSP thread_sp (GetThreadByID (tid)); 46280461Sdim if (thread_sp) 47280461Sdim return thread_sp->GetState(); 48280461Sdim return eStateInvalid; 49280461Sdim} 50280461Sdim 51280461Sdimconst char * 52280461SdimNativeThreadListDarwin::GetName (nub_thread_t tid) 53280461Sdim{ 54280461Sdim MachThreadSP thread_sp (GetThreadByID (tid)); 55280461Sdim if (thread_sp) 56303239Sdim return thread_sp->GetName(); 57303239Sdim return NULL; 58280461Sdim} 59280461Sdim#endif 60280461Sdim 61280461Sdim// TODO: figure out if we need to add this to NativeThreadDarwin yet. 62280461Sdim#if 0 63292934SdimThreadInfo::QoS 64280461SdimNativeThreadListDarwin::GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index) 65280461Sdim{ 66280461Sdim MachThreadSP thread_sp (GetThreadByID (tid)); 67280461Sdim if (thread_sp) 68280461Sdim return thread_sp->GetRequestedQoS(tsd, dti_qos_class_index); 69280461Sdim return ThreadInfo::QoS(); 70280461Sdim} 71280461Sdim 72280461Sdimnub_addr_t 73280461SdimNativeThreadListDarwin::GetPThreadT (nub_thread_t tid) 74280461Sdim{ 75280461Sdim MachThreadSP thread_sp (GetThreadByID (tid)); 76280461Sdim if (thread_sp) 77280461Sdim return thread_sp->GetPThreadT(); 78280461Sdim return INVALID_NUB_ADDRESS; 79280461Sdim} 80280461Sdim 81280461Sdimnub_addr_t 82280461SdimNativeThreadListDarwin::GetDispatchQueueT (nub_thread_t tid) 83280461Sdim{ 84280461Sdim MachThreadSP thread_sp (GetThreadByID (tid)); 85280461Sdim if (thread_sp) 86280461Sdim return thread_sp->GetDispatchQueueT(); 87280461Sdim return INVALID_NUB_ADDRESS; 88280461Sdim} 89280461Sdim 90280461Sdimnub_addr_t 91280461SdimNativeThreadListDarwin::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) 92280461Sdim{ 93280461Sdim MachThreadSP thread_sp (GetThreadByID (tid)); 94292934Sdim if (thread_sp) 95303239Sdim return thread_sp->GetTSDAddressForThread(plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size); 96303239Sdim return INVALID_NUB_ADDRESS; 97303239Sdim} 98280461Sdim#endif 99280461Sdim 100303239Sdim// TODO implement these 101280461Sdim#if 0 102292934Sdimnub_thread_t 103280461SdimNativeThreadListDarwin::SetCurrentThread(nub_thread_t tid) 104280461Sdim{ 105280461Sdim MachThreadSP thread_sp (GetThreadByID (tid)); 106280461Sdim if (thread_sp) 107280461Sdim { 108280461Sdim m_current_thread = thread_sp; 109280461Sdim return tid; 110280461Sdim } 111280461Sdim return INVALID_NUB_THREAD; 112360784Sdim} 113280461Sdim 114280461Sdim 115280461Sdimbool 116280461SdimNativeThreadListDarwin::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const 117280461Sdim{ 118280461Sdim MachThreadSP thread_sp (GetThreadByID (tid)); 119280461Sdim if (thread_sp) 120280461Sdim return thread_sp->GetStopException().GetStopInfo(stop_info); 121280461Sdim return false; 122280461Sdim} 123280461Sdim 124280461Sdimbool 125280461SdimNativeThreadListDarwin::GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info) 126280461Sdim{ 127280461Sdim thread_t mach_port_number = GetMachPortNumberByThreadID (tid); 128280461Sdim 129280461Sdim mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; 130280461Sdim return ::thread_info (mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t)ident_info, &count) == KERN_SUCCESS; 131280461Sdim} 132280461Sdim 133280461Sdimvoid 134292934SdimNativeThreadListDarwin::DumpThreadStoppedReason (nub_thread_t tid) const 135292934Sdim{ 136314564Sdim MachThreadSP thread_sp (GetThreadByID (tid)); 137280461Sdim if (thread_sp) 138280461Sdim thread_sp->GetStopException().DumpStopReason(); 139280461Sdim} 140280461Sdim 141280461Sdimconst char * 142280461SdimNativeThreadListDarwin::GetThreadInfo (nub_thread_t tid) const 143280461Sdim{ 144280461Sdim MachThreadSP thread_sp (GetThreadByID (tid)); 145280461Sdim if (thread_sp) 146280461Sdim return thread_sp->GetBasicInfoAsString(); 147280461Sdim return NULL; 148280461Sdim} 149280461Sdim 150280461Sdim#endif 151280461Sdim 152280461SdimNativeThreadDarwinSP 153280461SdimNativeThreadListDarwin::GetThreadByID(lldb::tid_t tid) const { 154280461Sdim std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 155280461Sdim for (auto thread_sp : m_threads) { 156280461Sdim if (thread_sp && (thread_sp->GetID() == tid)) 157280461Sdim return thread_sp; 158280461Sdim } 159292934Sdim return NativeThreadDarwinSP(); 160292934Sdim} 161280461Sdim 162280461SdimNativeThreadDarwinSP NativeThreadListDarwin::GetThreadByMachPortNumber( 163280461Sdim ::thread_t mach_port_number) const { 164280461Sdim std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 165280461Sdim for (auto thread_sp : m_threads) { 166280461Sdim if (thread_sp && (thread_sp->GetMachPortNumber() == mach_port_number)) 167280461Sdim return thread_sp; 168280461Sdim } 169280461Sdim return NativeThreadDarwinSP(); 170280461Sdim} 171292934Sdim 172280461Sdimlldb::tid_t NativeThreadListDarwin::GetThreadIDByMachPortNumber( 173303239Sdim ::thread_t mach_port_number) const { 174280461Sdim std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); 175280461Sdim for (auto thread_sp : m_threads) { 176280461Sdim if (thread_sp && (thread_sp->GetMachPortNumber() == mach_port_number)) 177280461Sdim return thread_sp->GetID(); 178280461Sdim } 179360784Sdim return LLDB_INVALID_THREAD_ID; 180280461Sdim} 181280461Sdim 182280461Sdim// TODO implement 183280461Sdim#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