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 19 MachThreadList::MachThreadList() : 20 m_threads(), 21 m_threads_mutex(PTHREAD_MUTEX_RECURSIVE) 22 { 23 } 24 25 MachThreadList::~MachThreadList() 26 { 27 } 28 29 // Not thread safe, must lock m_threads_mutex prior to using this function. 30 uint32_t 31 MachThreadList::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 43 nub_state_t 44 MachThreadList::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 52 const char * 53 MachThreadList::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 61 nub_thread_t 62 MachThreadList::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 74 bool 75 MachThreadList::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 83 bool 84 MachThreadList::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 90 void 91 MachThreadList::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 98 const char * 99 MachThreadList::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 107 bool 108 MachThreadList::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 117 bool 118 MachThreadList::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 127 nub_size_t 128 MachThreadList::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 136 nub_size_t 137 MachThreadList::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 145 nub_size_t 146 MachThreadList::NumThreads() const 147 { 148 return m_threads.size(); 149 } 150 151 nub_thread_t 152 MachThreadList::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 159 nub_thread_t 160 MachThreadList::CurrentThreadID ( ) 161 { 162 MachThreadSP threadSP; 163 CurrentThread(threadSP); 164 if (threadSP.get()) 165 return threadSP->ThreadID(); 166 return INVALID_NUB_THREAD; 167 } 168 169 bool 170 MachThreadList::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 /* 182 MachThreadList::const_iterator 183 MachThreadList::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 */ 195 void 196 MachThreadList::Clear() 197 { 198 m_threads.clear(); 199 } 200 201 uint32_t 202 MachThreadList::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 258 void 259 MachThreadList::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 283 void 284 MachThreadList::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 294 void 295 MachThreadList::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 305 void 306 MachThreadList::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 317 void 318 MachThreadList::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 334 uint32_t 335 MachThreadList::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 //---------------------------------------------------------------------- 358 bool 359 MachThreadList::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 372 void 373 MachThreadList::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 384 uint32_t 385 MachThreadList::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 396 bool 397 MachThreadList::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 408 uint32_t 409 MachThreadList::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 420 bool 421 MachThreadList::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