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