MachThreadList.cpp revision 02274ed47ccff35a64870331f6e2c88c711ca0f9
1//===-- MachThreadList.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 "MachThreadList.h" 15#include "DNBLog.h" 16#include "DNBThreadResumeActions.h" 17#include "MachProcess.h" 18 19MachThreadList::MachThreadList() : 20 m_threads(), 21 m_threads_mutex(PTHREAD_MUTEX_RECURSIVE) 22{ 23} 24 25MachThreadList::~MachThreadList() 26{ 27} 28 29// Not thread safe, must lock m_threads_mutex prior to using this function. 30uint32_t 31MachThreadList::GetThreadIndexByID(thread_t tid) const 32{ 33 uint32_t idx = 0; 34 const uint32_t num_threads = m_threads.size(); 35 for (idx = 0; idx < num_threads; ++idx) 36 { 37 if (m_threads[idx]->ThreadID() == tid) 38 return idx; 39 } 40 return ~((uint32_t)0); 41} 42 43nub_state_t 44MachThreadList::GetState(thread_t tid) 45{ 46 uint32_t idx = GetThreadIndexByID(tid); 47 if (idx < m_threads.size()) 48 return m_threads[idx]->GetState(); 49 return eStateInvalid; 50} 51 52const char * 53MachThreadList::GetName (thread_t tid) 54{ 55 uint32_t idx = GetThreadIndexByID(tid); 56 if (idx < m_threads.size()) 57 return m_threads[idx]->GetName(); 58 return NULL; 59} 60 61nub_thread_t 62MachThreadList::SetCurrentThread(thread_t tid) 63{ 64 uint32_t idx = GetThreadIndexByID(tid); 65 if (idx < m_threads.size()) 66 m_current_thread = m_threads[idx]; 67 68 if (m_current_thread.get()) 69 return m_current_thread->ThreadID(); 70 return INVALID_NUB_THREAD; 71} 72 73 74bool 75MachThreadList::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const 76{ 77 uint32_t idx = GetThreadIndexByID(tid); 78 if (idx < m_threads.size()) 79 return m_threads[idx]->GetStopException().GetStopInfo(stop_info); 80 return false; 81} 82 83bool 84MachThreadList::GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info) 85{ 86 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; 87 return ::thread_info (tid, THREAD_IDENTIFIER_INFO, (thread_info_t)ident_info, &count) == KERN_SUCCESS; 88} 89 90void 91MachThreadList::DumpThreadStoppedReason(nub_thread_t tid) const 92{ 93 uint32_t idx = GetThreadIndexByID(tid); 94 if (idx < m_threads.size()) 95 m_threads[idx]->GetStopException().DumpStopReason(); 96} 97 98const char * 99MachThreadList::GetThreadInfo(nub_thread_t tid) const 100{ 101 uint32_t idx = GetThreadIndexByID(tid); 102 if (idx < m_threads.size()) 103 return m_threads[idx]->GetBasicInfoAsString(); 104 return NULL; 105} 106 107bool 108MachThreadList::GetRegisterValue ( nub_thread_t tid, uint32_t reg_set_idx, uint32_t reg_idx, DNBRegisterValue *reg_value ) const 109{ 110 uint32_t idx = GetThreadIndexByID(tid); 111 if (idx < m_threads.size()) 112 return m_threads[idx]->GetRegisterValue(reg_set_idx, reg_idx, reg_value); 113 114 return false; 115} 116 117bool 118MachThreadList::SetRegisterValue ( nub_thread_t tid, uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value ) const 119{ 120 uint32_t idx = GetThreadIndexByID(tid); 121 if (idx < m_threads.size()) 122 return m_threads[idx]->SetRegisterValue(reg_set_idx, reg_idx, reg_value); 123 124 return false; 125} 126 127nub_size_t 128MachThreadList::GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len) 129{ 130 uint32_t idx = GetThreadIndexByID(tid); 131 if (idx < m_threads.size()) 132 return m_threads[idx]->GetRegisterContext (buf, buf_len); 133 return 0; 134} 135 136nub_size_t 137MachThreadList::SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len) 138{ 139 uint32_t idx = GetThreadIndexByID(tid); 140 if (idx < m_threads.size()) 141 return m_threads[idx]->SetRegisterContext (buf, buf_len); 142 return 0; 143} 144 145nub_size_t 146MachThreadList::NumThreads() const 147{ 148 return m_threads.size(); 149} 150 151nub_thread_t 152MachThreadList::ThreadIDAtIndex(nub_size_t idx) const 153{ 154 if (idx < m_threads.size()) 155 return m_threads[idx]->ThreadID(); 156 return INVALID_NUB_THREAD; 157} 158 159nub_thread_t 160MachThreadList::CurrentThreadID ( ) 161{ 162 MachThreadSP threadSP; 163 CurrentThread(threadSP); 164 if (threadSP.get()) 165 return threadSP->ThreadID(); 166 return INVALID_NUB_THREAD; 167} 168 169bool 170MachThreadList::NotifyException(MachException::Data& exc) 171{ 172 uint32_t idx = GetThreadIndexByID(exc.thread_port); 173 if (idx < m_threads.size()) 174 { 175 m_threads[idx]->NotifyException(exc); 176 return true; 177 } 178 return false; 179} 180 181/* 182MachThreadList::const_iterator 183MachThreadList::FindThreadByID(thread_t tid) const 184{ 185 const_iterator pos; 186 const_iterator end = m_threads.end(); 187 for (pos = m_threads.begin(); pos != end; ++pos) 188 { 189 if (pos->ThreadID() == tid) 190 return pos; 191 } 192 return NULL; 193} 194*/ 195void 196MachThreadList::Clear() 197{ 198 m_threads.clear(); 199} 200 201uint32_t 202MachThreadList::UpdateThreadList(MachProcess *process, bool update) 203{ 204 // locker will keep a mutex locked until it goes out of scope 205 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThreadList::UpdateThreadList (pid = %4.4x, update = %u )", process->ProcessID(), update); 206 PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); 207 208 if (m_threads.empty() || update) 209 { 210 thread_array_t thread_list = NULL; 211 mach_msg_type_number_t thread_list_count = 0; 212 task_t task = process->Task().TaskPort(); 213 DNBError err(::task_threads (task, &thread_list, &thread_list_count), DNBError::MachKernel); 214 215 if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) 216 err.LogThreaded("::task_threads ( task = 0x%4.4x, thread_list => %p, thread_list_count => %u )", task, thread_list, thread_list_count); 217 218 if (err.Error() == KERN_SUCCESS && thread_list_count > 0) 219 { 220 MachThreadList::collection currThreads; 221 const size_t numOldThreads = m_threads.size(); 222 size_t idx; 223 // Iterator through the current thread list and see which threads 224 // we already have in our list (keep them), which ones we don't 225 // (add them), and which ones are not around anymore (remove them). 226 for (idx = 0; idx < thread_list_count; ++idx) 227 { 228 uint32_t existing_idx = 0; 229 if (numOldThreads > 0) 230 existing_idx = GetThreadIndexByID(thread_list[idx]); 231 if (existing_idx < numOldThreads) 232 { 233 // Keep the existing thread class 234 currThreads.push_back(m_threads[existing_idx]); 235 } 236 else 237 { 238 // We don't have this thread, lets add it. 239 MachThreadSP threadSP(new MachThread(process, thread_list[idx])); 240 // Make sure the thread is ready to be displayed and shown to users 241 // before we add this thread to our list... 242 if (threadSP->IsUserReady()) 243 currThreads.push_back(threadSP); 244 } 245 } 246 247 m_threads.swap(currThreads); 248 m_current_thread.reset(); 249 250 // Free the vm memory given to us by ::task_threads() 251 vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t)); 252 ::vm_deallocate (::mach_task_self(), 253 (vm_address_t)thread_list, 254 thread_list_size); 255 } 256 } 257 return m_threads.size(); 258} 259 260 261void 262MachThreadList::CurrentThread(MachThreadSP& threadSP) 263{ 264 // locker will keep a mutex locked until it goes out of scope 265 PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); 266 if (m_current_thread.get() == NULL) 267 { 268 // Figure out which thread is going to be our current thread. 269 // This is currently done by finding the first thread in the list 270 // that has a valid exception. 271 const size_t num_threads = m_threads.size(); 272 size_t idx; 273 for (idx = 0; idx < num_threads; ++idx) 274 { 275 MachThread *thread = m_threads[idx].get(); 276 if (thread->GetStopException().IsValid()) 277 { 278 m_current_thread = m_threads[idx]; 279 break; 280 } 281 } 282 } 283 threadSP = m_current_thread; 284} 285 286void 287MachThreadList::GetRegisterState(int flavor, bool force) 288{ 289 uint32_t idx = 0; 290 const uint32_t num_threads = m_threads.size(); 291 for (idx = 0; idx < num_threads; ++idx) 292 { 293 m_threads[idx]->GetRegisterState(flavor, force); 294 } 295} 296 297void 298MachThreadList::SetRegisterState(int flavor) 299{ 300 uint32_t idx = 0; 301 const uint32_t num_threads = m_threads.size(); 302 for (idx = 0; idx < num_threads; ++idx) 303 { 304 m_threads[idx]->SetRegisterState(flavor); 305 } 306} 307 308void 309MachThreadList::Dump() const 310{ 311 uint32_t idx = 0; 312 const uint32_t num_threads = m_threads.size(); 313 for (idx = 0; idx < num_threads; ++idx) 314 { 315 m_threads[idx]->Dump(idx); 316 } 317} 318 319 320void 321MachThreadList::ProcessWillResume(MachProcess *process, const DNBThreadResumeActions &thread_actions) 322{ 323 uint32_t idx = 0; 324 const uint32_t num_threads = m_threads.size(); 325 326 for (idx = 0; idx < num_threads; ++idx) 327 { 328 MachThread *thread = m_threads[idx].get(); 329 330 const DNBThreadResumeAction *thread_action = thread_actions.GetActionForThread (thread->ThreadID(), true); 331 // There must always be a thread action for every thread. 332 assert (thread_action); 333 thread->ThreadWillResume (thread_action); 334 } 335} 336 337uint32_t 338MachThreadList::ProcessDidStop(MachProcess *process) 339{ 340 // Update our thread list 341 const uint32_t num_threads = UpdateThreadList(process, true); 342 uint32_t idx = 0; 343 for (idx = 0; idx < num_threads; ++idx) 344 { 345 m_threads[idx]->ThreadDidStop(); 346 } 347 return num_threads; 348} 349 350//---------------------------------------------------------------------- 351// Check each thread in our thread list to see if we should notify our 352// client of the current halt in execution. 353// 354// Breakpoints can have callback functions associated with them than 355// can return true to stop, or false to continue executing the inferior. 356// 357// RETURNS 358// true if we should stop and notify our clients 359// false if we should resume our child process and skip notification 360//---------------------------------------------------------------------- 361bool 362MachThreadList::ShouldStop(bool &step_more) 363{ 364 uint32_t should_stop = false; 365 const uint32_t num_threads = m_threads.size(); 366 uint32_t idx = 0; 367 for (idx = 0; !should_stop && idx < num_threads; ++idx) 368 { 369 should_stop = m_threads[idx]->ShouldStop(step_more); 370 } 371 return should_stop; 372} 373 374 375void 376MachThreadList::NotifyBreakpointChanged (const DNBBreakpoint *bp) 377{ 378 uint32_t idx = 0; 379 const uint32_t num_threads = m_threads.size(); 380 for (idx = 0; idx < num_threads; ++idx) 381 { 382 m_threads[idx]->NotifyBreakpointChanged(bp); 383 } 384} 385 386 387uint32_t 388MachThreadList::EnableHardwareBreakpoint (const DNBBreakpoint* bp) const 389{ 390 if (bp != NULL) 391 { 392 uint32_t idx = GetThreadIndexByID(bp->ThreadID()); 393 if (idx < m_threads.size()) 394 return m_threads[idx]->EnableHardwareBreakpoint(bp); 395 } 396 return INVALID_NUB_HW_INDEX; 397} 398 399bool 400MachThreadList::DisableHardwareBreakpoint (const DNBBreakpoint* bp) const 401{ 402 if (bp != NULL) 403 { 404 uint32_t idx = GetThreadIndexByID(bp->ThreadID()); 405 if (idx < m_threads.size()) 406 return m_threads[idx]->DisableHardwareBreakpoint(bp); 407 } 408 return false; 409} 410 411uint32_t 412MachThreadList::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const 413{ 414 if (wp != NULL) 415 { 416 uint32_t idx = GetThreadIndexByID(wp->ThreadID()); 417 if (idx < m_threads.size()) 418 return m_threads[idx]->EnableHardwareWatchpoint(wp); 419 } 420 return INVALID_NUB_HW_INDEX; 421} 422 423bool 424MachThreadList::DisableHardwareWatchpoint (const DNBBreakpoint* wp) const 425{ 426 if (wp != NULL) 427 { 428 uint32_t idx = GetThreadIndexByID(wp->ThreadID()); 429 if (idx < m_threads.size()) 430 return m_threads[idx]->DisableHardwareWatchpoint(wp); 431 } 432 return false; 433} 434 435uint32_t 436MachThreadList::GetThreadIndexForThreadStoppedWithSignal (const int signo) const 437{ 438 uint32_t should_stop = false; 439 const uint32_t num_threads = m_threads.size(); 440 uint32_t idx = 0; 441 for (idx = 0; !should_stop && idx < num_threads; ++idx) 442 { 443 if (m_threads[idx]->GetStopException().SoftSignal () == signo) 444 return idx; 445 } 446 return UINT32_MAX; 447} 448 449