MachThreadList.cpp revision 24943d2ee8bfaa7cf5893e4709143924157a5c1e
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 currThreads.push_back(threadSP); 241 } 242 } 243 244 m_threads.swap(currThreads); 245 m_current_thread.reset(); 246 247 // Free the vm memory given to us by ::task_threads() 248 vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t)); 249 ::vm_deallocate (::mach_task_self(), 250 (vm_address_t)thread_list, 251 thread_list_size); 252 } 253 } 254 return m_threads.size(); 255} 256 257 258void 259MachThreadList::CurrentThread(MachThreadSP& threadSP) 260{ 261 // locker will keep a mutex locked until it goes out of scope 262 PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); 263 if (m_current_thread.get() == NULL) 264 { 265 // Figure out which thread is going to be our current thread. 266 // This is currently done by finding the first thread in the list 267 // that has a valid exception. 268 const size_t num_threads = m_threads.size(); 269 size_t idx; 270 for (idx = 0; idx < num_threads; ++idx) 271 { 272 MachThread *thread = m_threads[idx].get(); 273 if (thread->GetStopException().IsValid()) 274 { 275 m_current_thread = m_threads[idx]; 276 break; 277 } 278 } 279 } 280 threadSP = m_current_thread; 281} 282 283void 284MachThreadList::GetRegisterState(int flavor, bool force) 285{ 286 uint32_t idx = 0; 287 const uint32_t num_threads = m_threads.size(); 288 for (idx = 0; idx < num_threads; ++idx) 289 { 290 m_threads[idx]->GetRegisterState(flavor, force); 291 } 292} 293 294void 295MachThreadList::SetRegisterState(int flavor) 296{ 297 uint32_t idx = 0; 298 const uint32_t num_threads = m_threads.size(); 299 for (idx = 0; idx < num_threads; ++idx) 300 { 301 m_threads[idx]->SetRegisterState(flavor); 302 } 303} 304 305void 306MachThreadList::Dump() const 307{ 308 uint32_t idx = 0; 309 const uint32_t num_threads = m_threads.size(); 310 for (idx = 0; idx < num_threads; ++idx) 311 { 312 m_threads[idx]->Dump(idx); 313 } 314} 315 316 317void 318MachThreadList::ProcessWillResume(MachProcess *process, const DNBThreadResumeActions &thread_actions) 319{ 320 uint32_t idx = 0; 321 const uint32_t num_threads = m_threads.size(); 322 323 for (idx = 0; idx < num_threads; ++idx) 324 { 325 MachThread *thread = m_threads[idx].get(); 326 327 const DNBThreadResumeAction *thread_action = thread_actions.GetActionForThread (thread->ThreadID(), true); 328 // There must always be a thread action for every thread. 329 assert (thread_action); 330 thread->ThreadWillResume (thread_action); 331 } 332} 333 334uint32_t 335MachThreadList::ProcessDidStop(MachProcess *process) 336{ 337 // Update our thread list 338 const uint32_t num_threads = UpdateThreadList(process, true); 339 uint32_t idx = 0; 340 for (idx = 0; idx < num_threads; ++idx) 341 { 342 m_threads[idx]->ThreadDidStop(); 343 } 344 return num_threads; 345} 346 347//---------------------------------------------------------------------- 348// Check each thread in our thread list to see if we should notify our 349// client of the current halt in execution. 350// 351// Breakpoints can have callback functions associated with them than 352// can return true to stop, or false to continue executing the inferior. 353// 354// RETURNS 355// true if we should stop and notify our clients 356// false if we should resume our child process and skip notification 357//---------------------------------------------------------------------- 358bool 359MachThreadList::ShouldStop(bool &step_more) 360{ 361 uint32_t should_stop = false; 362 const uint32_t num_threads = m_threads.size(); 363 uint32_t idx = 0; 364 for (idx = 0; !should_stop && idx < num_threads; ++idx) 365 { 366 should_stop = m_threads[idx]->ShouldStop(step_more); 367 } 368 return should_stop; 369} 370 371 372void 373MachThreadList::NotifyBreakpointChanged (const DNBBreakpoint *bp) 374{ 375 uint32_t idx = 0; 376 const uint32_t num_threads = m_threads.size(); 377 for (idx = 0; idx < num_threads; ++idx) 378 { 379 m_threads[idx]->NotifyBreakpointChanged(bp); 380 } 381} 382 383 384uint32_t 385MachThreadList::EnableHardwareBreakpoint (const DNBBreakpoint* bp) const 386{ 387 if (bp != NULL) 388 { 389 uint32_t idx = GetThreadIndexByID(bp->ThreadID()); 390 if (idx < m_threads.size()) 391 return m_threads[idx]->EnableHardwareBreakpoint(bp); 392 } 393 return INVALID_NUB_HW_INDEX; 394} 395 396bool 397MachThreadList::DisableHardwareBreakpoint (const DNBBreakpoint* bp) const 398{ 399 if (bp != NULL) 400 { 401 uint32_t idx = GetThreadIndexByID(bp->ThreadID()); 402 if (idx < m_threads.size()) 403 return m_threads[idx]->DisableHardwareBreakpoint(bp); 404 } 405 return false; 406} 407 408uint32_t 409MachThreadList::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const 410{ 411 if (wp != NULL) 412 { 413 uint32_t idx = GetThreadIndexByID(wp->ThreadID()); 414 if (idx < m_threads.size()) 415 return m_threads[idx]->EnableHardwareWatchpoint(wp); 416 } 417 return INVALID_NUB_HW_INDEX; 418} 419 420bool 421MachThreadList::DisableHardwareWatchpoint (const DNBBreakpoint* wp) const 422{ 423 if (wp != NULL) 424 { 425 uint32_t idx = GetThreadIndexByID(wp->ThreadID()); 426 if (idx < m_threads.size()) 427 return m_threads[idx]->DisableHardwareWatchpoint(wp); 428 } 429 return false; 430} 431 432 433