1 //===-- MachThread.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 <inttypes.h>
15 #include "MachThread.h"
16 #include "MachProcess.h"
17 #include "DNBLog.h"
18 #include "DNB.h"
19
20 static uint32_t
GetSequenceID()21 GetSequenceID()
22 {
23 static uint32_t g_nextID = 0;
24 return ++g_nextID;
25 }
26
MachThread(MachProcess * process,uint64_t unique_thread_id,thread_t mach_port_num)27 MachThread::MachThread (MachProcess *process, uint64_t unique_thread_id, thread_t mach_port_num) :
28 m_process (process),
29 m_unique_id (unique_thread_id),
30 m_mach_port_number (mach_port_num),
31 m_seq_id (GetSequenceID()),
32 m_state (eStateUnloaded),
33 m_state_mutex (PTHREAD_MUTEX_RECURSIVE),
34 m_suspend_count (0),
35 m_stop_exception (),
36 m_arch_ap (DNBArchProtocol::Create (this)),
37 m_reg_sets (NULL),
38 m_num_reg_sets (0),
39 m_ident_info(),
40 m_proc_threadinfo(),
41 m_dispatch_queue_name()
42 {
43 nub_size_t num_reg_sets = 0;
44 m_reg_sets = m_arch_ap->GetRegisterSetInfo (&num_reg_sets);
45 m_num_reg_sets = num_reg_sets;
46
47 // Get the thread state so we know if a thread is in a state where we can't
48 // muck with it and also so we get the suspend count correct in case it was
49 // already suspended
50 GetBasicInfo();
51 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::MachThread ( process = %p, tid = 0x%8.8" PRIx64 ", seq_id = %u )", &m_process, m_unique_id, m_seq_id);
52 }
53
~MachThread()54 MachThread::~MachThread()
55 {
56 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::~MachThread() for tid = 0x%8.8" PRIx64 " (%u)", m_unique_id, m_seq_id);
57 }
58
59
60
61 void
Suspend()62 MachThread::Suspend()
63 {
64 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
65 if (MachPortNumberIsValid(m_mach_port_number))
66 {
67 DNBError err(::thread_suspend (m_mach_port_number), DNBError::MachKernel);
68 if (err.Success())
69 m_suspend_count++;
70 if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
71 err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number);
72 }
73 }
74
75 void
Resume(bool others_stopped)76 MachThread::Resume(bool others_stopped)
77 {
78 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
79 if (MachPortNumberIsValid(m_mach_port_number))
80 {
81 SetSuspendCountBeforeResume(others_stopped);
82 }
83 }
84
85 bool
SetSuspendCountBeforeResume(bool others_stopped)86 MachThread::SetSuspendCountBeforeResume(bool others_stopped)
87 {
88 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
89 DNBError err;
90 if (MachPortNumberIsValid(m_mach_port_number) == false)
91 return false;
92
93 size_t times_to_resume;
94
95 if (others_stopped)
96 {
97 if (GetBasicInfo())
98 {
99 times_to_resume = m_basic_info.suspend_count;
100 m_suspend_count = - (times_to_resume - m_suspend_count);
101 }
102 else
103 times_to_resume = 0;
104 }
105 else
106 {
107 times_to_resume = m_suspend_count;
108 m_suspend_count = 0;
109 }
110
111 if (times_to_resume > 0)
112 {
113 while (times_to_resume > 0)
114 {
115 err = ::thread_resume (m_mach_port_number);
116 if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
117 err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number);
118 if (err.Success())
119 --times_to_resume;
120 else
121 {
122 if (GetBasicInfo())
123 times_to_resume = m_basic_info.suspend_count;
124 else
125 times_to_resume = 0;
126 }
127 }
128 }
129 return true;
130 }
131
132 bool
RestoreSuspendCountAfterStop()133 MachThread::RestoreSuspendCountAfterStop ()
134 {
135 DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
136 DNBError err;
137 if (MachPortNumberIsValid(m_mach_port_number) == false)
138 return false;
139
140 if (m_suspend_count > 0)
141 {
142 while (m_suspend_count > 0)
143 {
144 err = ::thread_resume (m_mach_port_number);
145 if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
146 err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number);
147 if (err.Success())
148 --m_suspend_count;
149 else
150 {
151 if (GetBasicInfo())
152 m_suspend_count = m_basic_info.suspend_count;
153 else
154 m_suspend_count = 0;
155 return false; // ???
156 }
157 }
158 }
159 else if (m_suspend_count < 0)
160 {
161 while (m_suspend_count < 0)
162 {
163 err = ::thread_suspend (m_mach_port_number);
164 if (err.Success())
165 ++m_suspend_count;
166 if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
167 {
168 err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number);
169 return false;
170 }
171 }
172 }
173 return true;
174 }
175
176
177 const char *
GetBasicInfoAsString() const178 MachThread::GetBasicInfoAsString () const
179 {
180 static char g_basic_info_string[1024];
181 struct thread_basic_info basicInfo;
182
183 if (GetBasicInfo(m_mach_port_number, &basicInfo))
184 {
185
186 // char run_state_str[32];
187 // size_t run_state_str_size = sizeof(run_state_str);
188 // switch (basicInfo.run_state)
189 // {
190 // case TH_STATE_RUNNING: strncpy(run_state_str, "running", run_state_str_size); break;
191 // case TH_STATE_STOPPED: strncpy(run_state_str, "stopped", run_state_str_size); break;
192 // case TH_STATE_WAITING: strncpy(run_state_str, "waiting", run_state_str_size); break;
193 // case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str, "uninterruptible", run_state_str_size); break;
194 // case TH_STATE_HALTED: strncpy(run_state_str, "halted", run_state_str_size); break;
195 // default: snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break; // ???
196 // }
197 float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
198 float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
199 snprintf(g_basic_info_string, sizeof(g_basic_info_string), "Thread 0x%8.8" PRIx64 ": user=%f system=%f cpu=%d sleep_time=%d",
200 m_unique_id,
201 user,
202 system,
203 basicInfo.cpu_usage,
204 basicInfo.sleep_time);
205
206 return g_basic_info_string;
207 }
208 return NULL;
209 }
210
211 // Finds the Mach port number for a given thread in the inferior process' port namespace.
212 thread_t
InferiorThreadID() const213 MachThread::InferiorThreadID() const
214 {
215 mach_msg_type_number_t i;
216 mach_port_name_array_t names;
217 mach_port_type_array_t types;
218 mach_msg_type_number_t ncount, tcount;
219 thread_t inferior_tid = INVALID_NUB_THREAD;
220 task_t my_task = ::mach_task_self();
221 task_t task = m_process->Task().TaskPort();
222
223 kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount);
224 if (kret == KERN_SUCCESS)
225 {
226
227 for (i = 0; i < ncount; i++)
228 {
229 mach_port_t my_name;
230 mach_msg_type_name_t my_type;
231
232 kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type);
233 if (kret == KERN_SUCCESS)
234 {
235 ::mach_port_deallocate (my_task, my_name);
236 if (my_name == m_mach_port_number)
237 {
238 inferior_tid = names[i];
239 break;
240 }
241 }
242 }
243 // Free up the names and types
244 ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t));
245 ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t));
246 }
247 return inferior_tid;
248 }
249
250 bool
IsUserReady()251 MachThread::IsUserReady()
252 {
253 if (m_basic_info.run_state == 0)
254 GetBasicInfo ();
255
256 switch (m_basic_info.run_state)
257 {
258 default:
259 case TH_STATE_UNINTERRUPTIBLE:
260 break;
261
262 case TH_STATE_RUNNING:
263 case TH_STATE_STOPPED:
264 case TH_STATE_WAITING:
265 case TH_STATE_HALTED:
266 return true;
267 }
268 return false;
269 }
270
271 struct thread_basic_info *
GetBasicInfo()272 MachThread::GetBasicInfo ()
273 {
274 if (MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info))
275 return &m_basic_info;
276 return NULL;
277 }
278
279
280 bool
GetBasicInfo(thread_t thread,struct thread_basic_info * basicInfoPtr)281 MachThread::GetBasicInfo(thread_t thread, struct thread_basic_info *basicInfoPtr)
282 {
283 if (MachPortNumberIsValid(thread))
284 {
285 unsigned int info_count = THREAD_BASIC_INFO_COUNT;
286 kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count);
287 if (err == KERN_SUCCESS)
288 return true;
289 }
290 ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info));
291 return false;
292 }
293
294
295 bool
ThreadIDIsValid(uint64_t thread)296 MachThread::ThreadIDIsValid(uint64_t thread)
297 {
298 return thread != 0;
299 }
300
301 bool
MachPortNumberIsValid(thread_t thread)302 MachThread::MachPortNumberIsValid(thread_t thread)
303 {
304 return thread != THREAD_NULL;
305 }
306
307 bool
GetRegisterState(int flavor,bool force)308 MachThread::GetRegisterState(int flavor, bool force)
309 {
310 return m_arch_ap->GetRegisterState(flavor, force) == KERN_SUCCESS;
311 }
312
313 bool
SetRegisterState(int flavor)314 MachThread::SetRegisterState(int flavor)
315 {
316 return m_arch_ap->SetRegisterState(flavor) == KERN_SUCCESS;
317 }
318
319 uint64_t
GetPC(uint64_t failValue)320 MachThread::GetPC(uint64_t failValue)
321 {
322 // Get program counter
323 return m_arch_ap->GetPC(failValue);
324 }
325
326 bool
SetPC(uint64_t value)327 MachThread::SetPC(uint64_t value)
328 {
329 // Set program counter
330 return m_arch_ap->SetPC(value);
331 }
332
333 uint64_t
GetSP(uint64_t failValue)334 MachThread::GetSP(uint64_t failValue)
335 {
336 // Get stack pointer
337 return m_arch_ap->GetSP(failValue);
338 }
339
340 nub_process_t
ProcessID() const341 MachThread::ProcessID() const
342 {
343 if (m_process)
344 return m_process->ProcessID();
345 return INVALID_NUB_PROCESS;
346 }
347
348 void
Dump(uint32_t index)349 MachThread::Dump(uint32_t index)
350 {
351 const char * thread_run_state = NULL;
352
353 switch (m_basic_info.run_state)
354 {
355 case TH_STATE_RUNNING: thread_run_state = "running"; break; // 1 thread is running normally
356 case TH_STATE_STOPPED: thread_run_state = "stopped"; break; // 2 thread is stopped
357 case TH_STATE_WAITING: thread_run_state = "waiting"; break; // 3 thread is waiting normally
358 case TH_STATE_UNINTERRUPTIBLE: thread_run_state = "uninter"; break; // 4 thread is in an uninterruptible wait
359 case TH_STATE_HALTED: thread_run_state = "halted "; break; // 5 thread is halted at a
360 default: thread_run_state = "???"; break;
361 }
362
363 DNBLogThreaded("[%3u] #%3u tid: 0x%8.8" PRIx64 ", pc: 0x%16.16" PRIx64 ", sp: 0x%16.16" PRIx64 ", user: %d.%6.6d, system: %d.%6.6d, cpu: %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d",
364 index,
365 m_seq_id,
366 m_unique_id,
367 GetPC(INVALID_NUB_ADDRESS),
368 GetSP(INVALID_NUB_ADDRESS),
369 m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds,
370 m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds,
371 m_basic_info.cpu_usage,
372 m_basic_info.policy,
373 m_basic_info.run_state,
374 thread_run_state,
375 m_basic_info.flags,
376 m_basic_info.suspend_count, m_suspend_count,
377 m_basic_info.sleep_time);
378 //DumpRegisterState(0);
379 }
380
381 void
ThreadWillResume(const DNBThreadResumeAction * thread_action,bool others_stopped)382 MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action, bool others_stopped)
383 {
384 if (thread_action->addr != INVALID_NUB_ADDRESS)
385 SetPC (thread_action->addr);
386
387 SetState (thread_action->state);
388 switch (thread_action->state)
389 {
390 case eStateStopped:
391 case eStateSuspended:
392 assert (others_stopped == false);
393 Suspend();
394 break;
395
396 case eStateRunning:
397 case eStateStepping:
398 Resume(others_stopped);
399 break;
400 default:
401 break;
402 }
403 m_arch_ap->ThreadWillResume();
404 m_stop_exception.Clear();
405 }
406
407 DNBBreakpoint *
CurrentBreakpoint()408 MachThread::CurrentBreakpoint()
409 {
410 return m_process->Breakpoints().FindByAddress(GetPC());
411 }
412
413 bool
ShouldStop(bool & step_more)414 MachThread::ShouldStop(bool &step_more)
415 {
416 // See if this thread is at a breakpoint?
417 DNBBreakpoint *bp = CurrentBreakpoint();
418
419 if (bp)
420 {
421 // This thread is sitting at a breakpoint, ask the breakpoint
422 // if we should be stopping here.
423 return true;
424 }
425 else
426 {
427 if (m_arch_ap->StepNotComplete())
428 {
429 step_more = true;
430 return false;
431 }
432 // The thread state is used to let us know what the thread was
433 // trying to do. MachThread::ThreadWillResume() will set the
434 // thread state to various values depending if the thread was
435 // the current thread and if it was to be single stepped, or
436 // resumed.
437 if (GetState() == eStateRunning)
438 {
439 // If our state is running, then we should continue as we are in
440 // the process of stepping over a breakpoint.
441 return false;
442 }
443 else
444 {
445 // Stop if we have any kind of valid exception for this
446 // thread.
447 if (GetStopException().IsValid())
448 return true;
449 }
450 }
451 return false;
452 }
453 bool
IsStepping()454 MachThread::IsStepping()
455 {
456 return GetState() == eStateStepping;
457 }
458
459
460 bool
ThreadDidStop()461 MachThread::ThreadDidStop()
462 {
463 // This thread has existed prior to resuming under debug nub control,
464 // and has just been stopped. Do any cleanup that needs to be done
465 // after running.
466
467 // The thread state and breakpoint will still have the same values
468 // as they had prior to resuming the thread, so it makes it easy to check
469 // if we were trying to step a thread, or we tried to resume while being
470 // at a breakpoint.
471
472 // When this method gets called, the process state is still in the
473 // state it was in while running so we can act accordingly.
474 m_arch_ap->ThreadDidStop();
475
476
477 // We may have suspended this thread so the primary thread could step
478 // without worrying about race conditions, so lets restore our suspend
479 // count.
480 RestoreSuspendCountAfterStop();
481
482 // Update the basic information for a thread
483 MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info);
484
485 if (m_basic_info.suspend_count > 0)
486 SetState(eStateSuspended);
487 else
488 SetState(eStateStopped);
489 return true;
490 }
491
492 bool
NotifyException(MachException::Data & exc)493 MachThread::NotifyException(MachException::Data& exc)
494 {
495 // Allow the arch specific protocol to process (MachException::Data &)exc
496 // first before possible reassignment of m_stop_exception with exc.
497 // See also MachThread::GetStopException().
498 bool handled = m_arch_ap->NotifyException(exc);
499
500 if (m_stop_exception.IsValid())
501 {
502 // We may have more than one exception for a thread, but we need to
503 // only remember the one that we will say is the reason we stopped.
504 // We may have been single stepping and also gotten a signal exception,
505 // so just remember the most pertinent one.
506 if (m_stop_exception.IsBreakpoint())
507 m_stop_exception = exc;
508 }
509 else
510 {
511 m_stop_exception = exc;
512 }
513
514 return handled;
515 }
516
517
518 nub_state_t
GetState()519 MachThread::GetState()
520 {
521 // If any other threads access this we will need a mutex for it
522 PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
523 return m_state;
524 }
525
526 void
SetState(nub_state_t state)527 MachThread::SetState(nub_state_t state)
528 {
529 PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
530 m_state = state;
531 DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%8.8" PRIx64 "", DNBStateAsString(state), m_unique_id);
532 }
533
534 uint32_t
GetNumRegistersInSet(int regSet) const535 MachThread::GetNumRegistersInSet(int regSet) const
536 {
537 if (regSet < m_num_reg_sets)
538 return m_reg_sets[regSet].num_registers;
539 return 0;
540 }
541
542 const char *
GetRegisterSetName(int regSet) const543 MachThread::GetRegisterSetName(int regSet) const
544 {
545 if (regSet < m_num_reg_sets)
546 return m_reg_sets[regSet].name;
547 return NULL;
548 }
549
550 const DNBRegisterInfo *
GetRegisterInfo(int regSet,int regIndex) const551 MachThread::GetRegisterInfo(int regSet, int regIndex) const
552 {
553 if (regSet < m_num_reg_sets)
554 if (regIndex < m_reg_sets[regSet].num_registers)
555 return &m_reg_sets[regSet].registers[regIndex];
556 return NULL;
557 }
558 void
DumpRegisterState(int regSet)559 MachThread::DumpRegisterState(int regSet)
560 {
561 if (regSet == REGISTER_SET_ALL)
562 {
563 for (regSet = 1; regSet < m_num_reg_sets; regSet++)
564 DumpRegisterState(regSet);
565 }
566 else
567 {
568 if (m_arch_ap->RegisterSetStateIsValid(regSet))
569 {
570 const size_t numRegisters = GetNumRegistersInSet(regSet);
571 size_t regIndex = 0;
572 DNBRegisterValueClass reg;
573 for (regIndex = 0; regIndex < numRegisters; ++regIndex)
574 {
575 if (m_arch_ap->GetRegisterValue(regSet, regIndex, ®))
576 {
577 reg.Dump(NULL, NULL);
578 }
579 }
580 }
581 else
582 {
583 DNBLog("%s: registers are not currently valid.", GetRegisterSetName(regSet));
584 }
585 }
586 }
587
588 const DNBRegisterSetInfo *
GetRegisterSetInfo(nub_size_t * num_reg_sets) const589 MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const
590 {
591 *num_reg_sets = m_num_reg_sets;
592 return &m_reg_sets[0];
593 }
594
595 bool
GetRegisterValue(uint32_t set,uint32_t reg,DNBRegisterValue * value)596 MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value )
597 {
598 return m_arch_ap->GetRegisterValue(set, reg, value);
599 }
600
601 bool
SetRegisterValue(uint32_t set,uint32_t reg,const DNBRegisterValue * value)602 MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value )
603 {
604 return m_arch_ap->SetRegisterValue(set, reg, value);
605 }
606
607 nub_size_t
GetRegisterContext(void * buf,nub_size_t buf_len)608 MachThread::GetRegisterContext (void *buf, nub_size_t buf_len)
609 {
610 return m_arch_ap->GetRegisterContext(buf, buf_len);
611 }
612
613 nub_size_t
SetRegisterContext(const void * buf,nub_size_t buf_len)614 MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len)
615 {
616 return m_arch_ap->SetRegisterContext(buf, buf_len);
617 }
618
619 uint32_t
EnableHardwareBreakpoint(const DNBBreakpoint * bp)620 MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp)
621 {
622 if (bp != NULL && bp->IsBreakpoint())
623 return m_arch_ap->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize());
624 return INVALID_NUB_HW_INDEX;
625 }
626
627 uint32_t
EnableHardwareWatchpoint(const DNBBreakpoint * wp,bool also_set_on_task)628 MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp, bool also_set_on_task)
629 {
630 if (wp != NULL && wp->IsWatchpoint())
631 return m_arch_ap->EnableHardwareWatchpoint(wp->Address(), wp->ByteSize(), wp->WatchpointRead(), wp->WatchpointWrite(), also_set_on_task);
632 return INVALID_NUB_HW_INDEX;
633 }
634
635 bool
RollbackTransForHWP()636 MachThread::RollbackTransForHWP()
637 {
638 return m_arch_ap->RollbackTransForHWP();
639 }
640
641 bool
FinishTransForHWP()642 MachThread::FinishTransForHWP()
643 {
644 return m_arch_ap->FinishTransForHWP();
645 }
646
647 bool
DisableHardwareBreakpoint(const DNBBreakpoint * bp)648 MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp)
649 {
650 if (bp != NULL && bp->IsHardware())
651 return m_arch_ap->DisableHardwareBreakpoint(bp->GetHardwareIndex());
652 return false;
653 }
654
655 bool
DisableHardwareWatchpoint(const DNBBreakpoint * wp,bool also_set_on_task)656 MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp, bool also_set_on_task)
657 {
658 if (wp != NULL && wp->IsHardware())
659 return m_arch_ap->DisableHardwareWatchpoint(wp->GetHardwareIndex(), also_set_on_task);
660 return false;
661 }
662
663 uint32_t
NumSupportedHardwareWatchpoints() const664 MachThread::NumSupportedHardwareWatchpoints () const
665 {
666 return m_arch_ap->NumSupportedHardwareWatchpoints();
667 }
668
669 bool
GetIdentifierInfo()670 MachThread::GetIdentifierInfo ()
671 {
672 // Don't try to get the thread info once and cache it for the life of the thread. It changes over time, for instance
673 // if the thread name changes, then the thread_handle also changes... So you have to refetch it every time.
674 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
675 kern_return_t kret = ::thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);
676 return kret == KERN_SUCCESS;
677
678 return false;
679 }
680
681
682 const char *
GetName()683 MachThread::GetName ()
684 {
685 if (GetIdentifierInfo ())
686 {
687 int len = ::proc_pidinfo (m_process->ProcessID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo));
688
689 if (len && m_proc_threadinfo.pth_name[0])
690 return m_proc_threadinfo.pth_name;
691 }
692 return NULL;
693 }
694
695
696 uint64_t
GetGloballyUniqueThreadIDForMachPortID(thread_t mach_port_id)697 MachThread::GetGloballyUniqueThreadIDForMachPortID (thread_t mach_port_id)
698 {
699 kern_return_t kr;
700 thread_identifier_info_data_t tident;
701 mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
702 kr = thread_info (mach_port_id, THREAD_IDENTIFIER_INFO,
703 (thread_info_t) &tident, &tident_count);
704 if (kr != KERN_SUCCESS)
705 {
706 return mach_port_id;
707 }
708 return tident.thread_id;
709 }
710