130fdc8d8SChris Lattner //===-- MachThread.cpp ------------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner //
1030fdc8d8SChris Lattner //  Created by Greg Clayton on 6/19/07.
1130fdc8d8SChris Lattner //
1230fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1330fdc8d8SChris Lattner 
141c73911dSJason Molenda #include <inttypes.h>
15705b1809SJason Molenda #include <mach/thread_policy.h>
16705b1809SJason Molenda #include <dlfcn.h>
1730fdc8d8SChris Lattner #include "MachThread.h"
1830fdc8d8SChris Lattner #include "MachProcess.h"
1930fdc8d8SChris Lattner #include "DNBLog.h"
2030fdc8d8SChris Lattner #include "DNB.h"
21705b1809SJason Molenda #include "ThreadInfo.h"
2230fdc8d8SChris Lattner 
2330fdc8d8SChris Lattner static uint32_t
2430fdc8d8SChris Lattner GetSequenceID()
2530fdc8d8SChris Lattner {
2630fdc8d8SChris Lattner     static uint32_t g_nextID = 0;
2730fdc8d8SChris Lattner     return ++g_nextID;
2830fdc8d8SChris Lattner }
2930fdc8d8SChris Lattner 
30705b1809SJason Molenda MachThread::MachThread (MachProcess *process, bool is_64_bit, uint64_t unique_thread_id, thread_t mach_port_num) :
3130fdc8d8SChris Lattner     m_process (process),
321c73911dSJason Molenda     m_unique_id (unique_thread_id),
331c73911dSJason Molenda     m_mach_port_number (mach_port_num),
3430fdc8d8SChris Lattner     m_seq_id (GetSequenceID()),
3530fdc8d8SChris Lattner     m_state (eStateUnloaded),
3630fdc8d8SChris Lattner     m_state_mutex (PTHREAD_MUTEX_RECURSIVE),
37c235ac76SGreg Clayton     m_suspend_count (0),
38c235ac76SGreg Clayton     m_stop_exception (),
393af9ea56SGreg Clayton     m_arch_ap (DNBArchProtocol::Create (this)),
40c235ac76SGreg Clayton     m_reg_sets (NULL),
411c73911dSJason Molenda     m_num_reg_sets (0),
421c73911dSJason Molenda     m_ident_info(),
43c235ac76SGreg Clayton     m_proc_threadinfo(),
44705b1809SJason Molenda     m_dispatch_queue_name(),
45705b1809SJason Molenda     m_is_64_bit(is_64_bit),
46705b1809SJason Molenda     m_pthread_qos_class_decode (nullptr)
4730fdc8d8SChris Lattner {
48c235ac76SGreg Clayton     nub_size_t num_reg_sets = 0;
49c235ac76SGreg Clayton     m_reg_sets = m_arch_ap->GetRegisterSetInfo (&num_reg_sets);
50c235ac76SGreg Clayton     m_num_reg_sets = num_reg_sets;
51c235ac76SGreg Clayton 
52705b1809SJason Molenda     m_pthread_qos_class_decode = (unsigned int (*)(unsigned long, int*, unsigned long*)) dlsym (RTLD_DEFAULT, "_pthread_qos_class_decode");
53705b1809SJason Molenda 
541b946bf6SGreg Clayton     // Get the thread state so we know if a thread is in a state where we can't
551b946bf6SGreg Clayton     // muck with it and also so we get the suspend count correct in case it was
561b946bf6SGreg Clayton     // already suspended
57cdc7322bSGreg Clayton     GetBasicInfo();
581c73911dSJason Molenda     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);
5930fdc8d8SChris Lattner }
6030fdc8d8SChris Lattner 
6130fdc8d8SChris Lattner MachThread::~MachThread()
6230fdc8d8SChris Lattner {
631c73911dSJason Molenda     DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::~MachThread() for tid = 0x%8.8" PRIx64 " (%u)", m_unique_id, m_seq_id);
6430fdc8d8SChris Lattner }
6530fdc8d8SChris Lattner 
6630fdc8d8SChris Lattner 
6730fdc8d8SChris Lattner 
689411ddb6SJim Ingham void
6930fdc8d8SChris Lattner MachThread::Suspend()
7030fdc8d8SChris Lattner {
7130fdc8d8SChris Lattner     DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
721c73911dSJason Molenda     if (MachPortNumberIsValid(m_mach_port_number))
7330fdc8d8SChris Lattner     {
741c73911dSJason Molenda         DNBError err(::thread_suspend (m_mach_port_number), DNBError::MachKernel);
7530fdc8d8SChris Lattner         if (err.Success())
76c235ac76SGreg Clayton             m_suspend_count++;
7730fdc8d8SChris Lattner         if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
781c73911dSJason Molenda             err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number);
7930fdc8d8SChris Lattner     }
8030fdc8d8SChris Lattner }
8130fdc8d8SChris Lattner 
829411ddb6SJim Ingham void
839411ddb6SJim Ingham MachThread::Resume(bool others_stopped)
8430fdc8d8SChris Lattner {
8530fdc8d8SChris Lattner     DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
861c73911dSJason Molenda     if (MachPortNumberIsValid(m_mach_port_number))
8730fdc8d8SChris Lattner     {
889411ddb6SJim Ingham         SetSuspendCountBeforeResume(others_stopped);
8930fdc8d8SChris Lattner     }
9030fdc8d8SChris Lattner }
9130fdc8d8SChris Lattner 
9230fdc8d8SChris Lattner bool
939411ddb6SJim Ingham MachThread::SetSuspendCountBeforeResume(bool others_stopped)
9430fdc8d8SChris Lattner {
95cdc7322bSGreg Clayton     DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
9630fdc8d8SChris Lattner     DNBError err;
971c73911dSJason Molenda     if (MachPortNumberIsValid(m_mach_port_number) == false)
9830fdc8d8SChris Lattner         return false;
999411ddb6SJim Ingham 
100*ee2ed525SGreg Clayton     integer_t times_to_resume;
1019411ddb6SJim Ingham 
1029411ddb6SJim Ingham     if (others_stopped)
1039411ddb6SJim Ingham     {
10482283e8eSJim Ingham         if (GetBasicInfo())
10582283e8eSJim Ingham         {
10682283e8eSJim Ingham             times_to_resume = m_basic_info.suspend_count;
107c235ac76SGreg Clayton             m_suspend_count = - (times_to_resume - m_suspend_count);
1089411ddb6SJim Ingham         }
1099411ddb6SJim Ingham         else
11082283e8eSJim Ingham             times_to_resume = 0;
11182283e8eSJim Ingham     }
11282283e8eSJim Ingham     else
1139411ddb6SJim Ingham     {
114c235ac76SGreg Clayton         times_to_resume = m_suspend_count;
115c235ac76SGreg Clayton         m_suspend_count = 0;
1169411ddb6SJim Ingham     }
1179411ddb6SJim Ingham 
1189411ddb6SJim Ingham     if (times_to_resume > 0)
1199411ddb6SJim Ingham     {
1209411ddb6SJim Ingham         while (times_to_resume > 0)
1219411ddb6SJim Ingham         {
1221c73911dSJason Molenda             err = ::thread_resume (m_mach_port_number);
1239411ddb6SJim Ingham             if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
1241c73911dSJason Molenda                 err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number);
1259411ddb6SJim Ingham             if (err.Success())
1269411ddb6SJim Ingham                 --times_to_resume;
1279411ddb6SJim Ingham             else
1289411ddb6SJim Ingham             {
1299411ddb6SJim Ingham                 if (GetBasicInfo())
130c235ac76SGreg Clayton                     times_to_resume = m_basic_info.suspend_count;
1319411ddb6SJim Ingham                 else
1329411ddb6SJim Ingham                     times_to_resume = 0;
1339411ddb6SJim Ingham             }
1349411ddb6SJim Ingham         }
1359411ddb6SJim Ingham     }
1369411ddb6SJim Ingham     return true;
1379411ddb6SJim Ingham }
1389411ddb6SJim Ingham 
1399411ddb6SJim Ingham bool
1409411ddb6SJim Ingham MachThread::RestoreSuspendCountAfterStop ()
1419411ddb6SJim Ingham {
1429411ddb6SJim Ingham     DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__);
1439411ddb6SJim Ingham     DNBError err;
1441c73911dSJason Molenda     if (MachPortNumberIsValid(m_mach_port_number) == false)
1459411ddb6SJim Ingham         return false;
1469411ddb6SJim Ingham 
147c235ac76SGreg Clayton     if (m_suspend_count > 0)
14830fdc8d8SChris Lattner     {
149c235ac76SGreg Clayton         while (m_suspend_count > 0)
15030fdc8d8SChris Lattner         {
1511c73911dSJason Molenda             err = ::thread_resume (m_mach_port_number);
15230fdc8d8SChris Lattner             if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
1531c73911dSJason Molenda                 err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number);
15430fdc8d8SChris Lattner             if (err.Success())
155c235ac76SGreg Clayton                 --m_suspend_count;
1560dd2c627SGreg Clayton             else
1570dd2c627SGreg Clayton             {
158cdc7322bSGreg Clayton                 if (GetBasicInfo())
159c235ac76SGreg Clayton                     m_suspend_count = m_basic_info.suspend_count;
1600dd2c627SGreg Clayton                 else
161c235ac76SGreg Clayton                     m_suspend_count = 0;
1620dd2c627SGreg Clayton                 return false; // ???
16330fdc8d8SChris Lattner             }
16430fdc8d8SChris Lattner         }
1650dd2c627SGreg Clayton     }
166c235ac76SGreg Clayton     else if (m_suspend_count < 0)
1679411ddb6SJim Ingham     {
168c235ac76SGreg Clayton         while (m_suspend_count < 0)
1699411ddb6SJim Ingham         {
1701c73911dSJason Molenda             err = ::thread_suspend (m_mach_port_number);
1719411ddb6SJim Ingham             if (err.Success())
172c235ac76SGreg Clayton                 ++m_suspend_count;
1739411ddb6SJim Ingham             if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
174478235d8SJim Ingham             {
1751c73911dSJason Molenda                 err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number);
176478235d8SJim Ingham                 return false;
177478235d8SJim Ingham             }
1789411ddb6SJim Ingham         }
1799411ddb6SJim Ingham     }
1800dd2c627SGreg Clayton     return true;
18130fdc8d8SChris Lattner }
18230fdc8d8SChris Lattner 
18330fdc8d8SChris Lattner 
18430fdc8d8SChris Lattner const char *
18530fdc8d8SChris Lattner MachThread::GetBasicInfoAsString () const
18630fdc8d8SChris Lattner {
18730fdc8d8SChris Lattner     static char g_basic_info_string[1024];
18830fdc8d8SChris Lattner     struct thread_basic_info basicInfo;
18930fdc8d8SChris Lattner 
1901c73911dSJason Molenda     if (GetBasicInfo(m_mach_port_number, &basicInfo))
19130fdc8d8SChris Lattner     {
19230fdc8d8SChris Lattner 
19330fdc8d8SChris Lattner //        char run_state_str[32];
19430fdc8d8SChris Lattner //        size_t run_state_str_size = sizeof(run_state_str);
19530fdc8d8SChris Lattner //        switch (basicInfo.run_state)
19630fdc8d8SChris Lattner //        {
19730fdc8d8SChris Lattner //        case TH_STATE_RUNNING:          strncpy(run_state_str, "running", run_state_str_size); break;
19830fdc8d8SChris Lattner //        case TH_STATE_STOPPED:          strncpy(run_state_str, "stopped", run_state_str_size); break;
19930fdc8d8SChris Lattner //        case TH_STATE_WAITING:          strncpy(run_state_str, "waiting", run_state_str_size); break;
20030fdc8d8SChris Lattner //        case TH_STATE_UNINTERRUPTIBLE:  strncpy(run_state_str, "uninterruptible", run_state_str_size); break;
20130fdc8d8SChris Lattner //        case TH_STATE_HALTED:           strncpy(run_state_str, "halted", run_state_str_size); break;
20230fdc8d8SChris Lattner //        default:                        snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break;    // ???
20330fdc8d8SChris Lattner //        }
20430fdc8d8SChris Lattner         float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
20530fdc8d8SChris Lattner         float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
2061c73911dSJason Molenda         snprintf(g_basic_info_string, sizeof(g_basic_info_string), "Thread 0x%8.8" PRIx64 ": user=%f system=%f cpu=%d sleep_time=%d",
2071c73911dSJason Molenda             m_unique_id,
20830fdc8d8SChris Lattner             user,
20930fdc8d8SChris Lattner             system,
21030fdc8d8SChris Lattner             basicInfo.cpu_usage,
21130fdc8d8SChris Lattner             basicInfo.sleep_time);
21230fdc8d8SChris Lattner 
21330fdc8d8SChris Lattner         return g_basic_info_string;
21430fdc8d8SChris Lattner     }
21530fdc8d8SChris Lattner     return NULL;
21630fdc8d8SChris Lattner }
21730fdc8d8SChris Lattner 
2181c73911dSJason Molenda // Finds the Mach port number for a given thread in the inferior process' port namespace.
21930fdc8d8SChris Lattner thread_t
22030fdc8d8SChris Lattner MachThread::InferiorThreadID() const
22130fdc8d8SChris Lattner {
22230fdc8d8SChris Lattner     mach_msg_type_number_t i;
22330fdc8d8SChris Lattner     mach_port_name_array_t names;
22430fdc8d8SChris Lattner     mach_port_type_array_t types;
22530fdc8d8SChris Lattner     mach_msg_type_number_t ncount, tcount;
22630fdc8d8SChris Lattner     thread_t inferior_tid = INVALID_NUB_THREAD;
22730fdc8d8SChris Lattner     task_t my_task = ::mach_task_self();
22830fdc8d8SChris Lattner     task_t task = m_process->Task().TaskPort();
22930fdc8d8SChris Lattner 
23030fdc8d8SChris Lattner     kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount);
23130fdc8d8SChris Lattner     if (kret == KERN_SUCCESS)
23230fdc8d8SChris Lattner     {
23330fdc8d8SChris Lattner 
23430fdc8d8SChris Lattner         for (i = 0; i < ncount; i++)
23530fdc8d8SChris Lattner         {
23630fdc8d8SChris Lattner             mach_port_t my_name;
23730fdc8d8SChris Lattner             mach_msg_type_name_t my_type;
23830fdc8d8SChris Lattner 
23930fdc8d8SChris Lattner             kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type);
24030fdc8d8SChris Lattner             if (kret == KERN_SUCCESS)
24130fdc8d8SChris Lattner             {
24230fdc8d8SChris Lattner                 ::mach_port_deallocate (my_task, my_name);
2431c73911dSJason Molenda                 if (my_name == m_mach_port_number)
24430fdc8d8SChris Lattner                 {
24530fdc8d8SChris Lattner                     inferior_tid = names[i];
24630fdc8d8SChris Lattner                     break;
24730fdc8d8SChris Lattner                 }
24830fdc8d8SChris Lattner             }
24930fdc8d8SChris Lattner         }
25030fdc8d8SChris Lattner         // Free up the names and types
25130fdc8d8SChris Lattner         ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t));
25230fdc8d8SChris Lattner         ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t));
25330fdc8d8SChris Lattner     }
25430fdc8d8SChris Lattner     return inferior_tid;
25530fdc8d8SChris Lattner }
25630fdc8d8SChris Lattner 
25730fdc8d8SChris Lattner bool
2581b946bf6SGreg Clayton MachThread::IsUserReady()
2591b946bf6SGreg Clayton {
260c235ac76SGreg Clayton     if (m_basic_info.run_state == 0)
261cdc7322bSGreg Clayton         GetBasicInfo ();
2621b946bf6SGreg Clayton 
263c235ac76SGreg Clayton     switch (m_basic_info.run_state)
2641b946bf6SGreg Clayton     {
2651b946bf6SGreg Clayton     default:
2661b946bf6SGreg Clayton     case TH_STATE_UNINTERRUPTIBLE:
2671b946bf6SGreg Clayton         break;
2681b946bf6SGreg Clayton 
2691b946bf6SGreg Clayton     case TH_STATE_RUNNING:
2701b946bf6SGreg Clayton     case TH_STATE_STOPPED:
2711b946bf6SGreg Clayton     case TH_STATE_WAITING:
2721b946bf6SGreg Clayton     case TH_STATE_HALTED:
2731b946bf6SGreg Clayton         return true;
2741b946bf6SGreg Clayton     }
2751b946bf6SGreg Clayton     return false;
2761b946bf6SGreg Clayton }
2771b946bf6SGreg Clayton 
2781b946bf6SGreg Clayton struct thread_basic_info *
279cdc7322bSGreg Clayton MachThread::GetBasicInfo ()
2801b946bf6SGreg Clayton {
2811c73911dSJason Molenda     if (MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info))
282c235ac76SGreg Clayton         return &m_basic_info;
2831b946bf6SGreg Clayton     return NULL;
2841b946bf6SGreg Clayton }
2851b946bf6SGreg Clayton 
2861b946bf6SGreg Clayton 
2871b946bf6SGreg Clayton bool
28830fdc8d8SChris Lattner MachThread::GetBasicInfo(thread_t thread, struct thread_basic_info *basicInfoPtr)
28930fdc8d8SChris Lattner {
2901c73911dSJason Molenda     if (MachPortNumberIsValid(thread))
29130fdc8d8SChris Lattner     {
29230fdc8d8SChris Lattner         unsigned int info_count = THREAD_BASIC_INFO_COUNT;
29330fdc8d8SChris Lattner         kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count);
29430fdc8d8SChris Lattner         if (err == KERN_SUCCESS)
29530fdc8d8SChris Lattner             return true;
29630fdc8d8SChris Lattner     }
29730fdc8d8SChris Lattner     ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info));
29830fdc8d8SChris Lattner     return false;
29930fdc8d8SChris Lattner }
30030fdc8d8SChris Lattner 
30130fdc8d8SChris Lattner 
30230fdc8d8SChris Lattner bool
3031c73911dSJason Molenda MachThread::ThreadIDIsValid(uint64_t thread)
3041c73911dSJason Molenda {
3051c73911dSJason Molenda     return thread != 0;
3061c73911dSJason Molenda }
3071c73911dSJason Molenda 
3081c73911dSJason Molenda bool
3091c73911dSJason Molenda MachThread::MachPortNumberIsValid(thread_t thread)
31030fdc8d8SChris Lattner {
31130fdc8d8SChris Lattner     return thread != THREAD_NULL;
31230fdc8d8SChris Lattner }
31330fdc8d8SChris Lattner 
31430fdc8d8SChris Lattner bool
31530fdc8d8SChris Lattner MachThread::GetRegisterState(int flavor, bool force)
31630fdc8d8SChris Lattner {
3173af9ea56SGreg Clayton     return m_arch_ap->GetRegisterState(flavor, force) == KERN_SUCCESS;
31830fdc8d8SChris Lattner }
31930fdc8d8SChris Lattner 
32030fdc8d8SChris Lattner bool
32130fdc8d8SChris Lattner MachThread::SetRegisterState(int flavor)
32230fdc8d8SChris Lattner {
3233af9ea56SGreg Clayton     return m_arch_ap->SetRegisterState(flavor) == KERN_SUCCESS;
32430fdc8d8SChris Lattner }
32530fdc8d8SChris Lattner 
32630fdc8d8SChris Lattner uint64_t
32730fdc8d8SChris Lattner MachThread::GetPC(uint64_t failValue)
32830fdc8d8SChris Lattner {
32930fdc8d8SChris Lattner     // Get program counter
3303af9ea56SGreg Clayton     return m_arch_ap->GetPC(failValue);
33130fdc8d8SChris Lattner }
33230fdc8d8SChris Lattner 
33330fdc8d8SChris Lattner bool
33430fdc8d8SChris Lattner MachThread::SetPC(uint64_t value)
33530fdc8d8SChris Lattner {
33630fdc8d8SChris Lattner     // Set program counter
3373af9ea56SGreg Clayton     return m_arch_ap->SetPC(value);
33830fdc8d8SChris Lattner }
33930fdc8d8SChris Lattner 
34030fdc8d8SChris Lattner uint64_t
34130fdc8d8SChris Lattner MachThread::GetSP(uint64_t failValue)
34230fdc8d8SChris Lattner {
34330fdc8d8SChris Lattner     // Get stack pointer
3443af9ea56SGreg Clayton     return m_arch_ap->GetSP(failValue);
34530fdc8d8SChris Lattner }
34630fdc8d8SChris Lattner 
34730fdc8d8SChris Lattner nub_process_t
34830fdc8d8SChris Lattner MachThread::ProcessID() const
34930fdc8d8SChris Lattner {
35030fdc8d8SChris Lattner     if (m_process)
35130fdc8d8SChris Lattner         return m_process->ProcessID();
35230fdc8d8SChris Lattner     return INVALID_NUB_PROCESS;
35330fdc8d8SChris Lattner }
35430fdc8d8SChris Lattner 
35530fdc8d8SChris Lattner void
35630fdc8d8SChris Lattner MachThread::Dump(uint32_t index)
35730fdc8d8SChris Lattner {
35830fdc8d8SChris Lattner     const char * thread_run_state = NULL;
35930fdc8d8SChris Lattner 
360c235ac76SGreg Clayton     switch (m_basic_info.run_state)
36130fdc8d8SChris Lattner     {
36230fdc8d8SChris Lattner     case TH_STATE_RUNNING:          thread_run_state = "running"; break;    // 1 thread is running normally
36330fdc8d8SChris Lattner     case TH_STATE_STOPPED:          thread_run_state = "stopped"; break;    // 2 thread is stopped
36430fdc8d8SChris Lattner     case TH_STATE_WAITING:          thread_run_state = "waiting"; break;    // 3 thread is waiting normally
36530fdc8d8SChris Lattner     case TH_STATE_UNINTERRUPTIBLE:  thread_run_state = "uninter"; break;    // 4 thread is in an uninterruptible wait
36630fdc8d8SChris Lattner     case TH_STATE_HALTED:           thread_run_state = "halted "; break;     // 5 thread is halted at a
36730fdc8d8SChris Lattner     default:                        thread_run_state = "???"; break;
36830fdc8d8SChris Lattner     }
36930fdc8d8SChris Lattner 
370d8cf1a11SGreg Clayton     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",
37130fdc8d8SChris Lattner         index,
37230fdc8d8SChris Lattner         m_seq_id,
3731c73911dSJason Molenda         m_unique_id,
37430fdc8d8SChris Lattner         GetPC(INVALID_NUB_ADDRESS),
37530fdc8d8SChris Lattner         GetSP(INVALID_NUB_ADDRESS),
376c235ac76SGreg Clayton         m_basic_info.user_time.seconds,      m_basic_info.user_time.microseconds,
377c235ac76SGreg Clayton         m_basic_info.system_time.seconds,    m_basic_info.system_time.microseconds,
378c235ac76SGreg Clayton         m_basic_info.cpu_usage,
379c235ac76SGreg Clayton         m_basic_info.policy,
380c235ac76SGreg Clayton         m_basic_info.run_state,
38130fdc8d8SChris Lattner         thread_run_state,
382c235ac76SGreg Clayton         m_basic_info.flags,
383c235ac76SGreg Clayton         m_basic_info.suspend_count, m_suspend_count,
384c235ac76SGreg Clayton         m_basic_info.sleep_time);
38530fdc8d8SChris Lattner     //DumpRegisterState(0);
38630fdc8d8SChris Lattner }
38730fdc8d8SChris Lattner 
38830fdc8d8SChris Lattner void
3899411ddb6SJim Ingham MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action, bool others_stopped)
39030fdc8d8SChris Lattner {
39130fdc8d8SChris Lattner     if (thread_action->addr != INVALID_NUB_ADDRESS)
39230fdc8d8SChris Lattner         SetPC (thread_action->addr);
393cdc7322bSGreg Clayton 
39430fdc8d8SChris Lattner     SetState (thread_action->state);
39530fdc8d8SChris Lattner     switch (thread_action->state)
39630fdc8d8SChris Lattner     {
39730fdc8d8SChris Lattner     case eStateStopped:
39830fdc8d8SChris Lattner     case eStateSuspended:
3999411ddb6SJim Ingham         assert (others_stopped == false);
40030fdc8d8SChris Lattner         Suspend();
40130fdc8d8SChris Lattner         break;
40230fdc8d8SChris Lattner 
40330fdc8d8SChris Lattner     case eStateRunning:
404b1e11121SJim Ingham     case eStateStepping:
4059411ddb6SJim Ingham         Resume(others_stopped);
406b1e11121SJim Ingham         break;
407effe5c95SGreg Clayton     default:
408effe5c95SGreg Clayton         break;
40930fdc8d8SChris Lattner     }
4103af9ea56SGreg Clayton     m_arch_ap->ThreadWillResume();
41130fdc8d8SChris Lattner     m_stop_exception.Clear();
41230fdc8d8SChris Lattner }
41330fdc8d8SChris Lattner 
414d8cf1a11SGreg Clayton DNBBreakpoint *
415c4e411ffSGreg Clayton MachThread::CurrentBreakpoint()
416c4e411ffSGreg Clayton {
417d8cf1a11SGreg Clayton     return m_process->Breakpoints().FindByAddress(GetPC());
418c4e411ffSGreg Clayton }
419c4e411ffSGreg Clayton 
42030fdc8d8SChris Lattner bool
42130fdc8d8SChris Lattner MachThread::ShouldStop(bool &step_more)
42230fdc8d8SChris Lattner {
42330fdc8d8SChris Lattner     // See if this thread is at a breakpoint?
424d8cf1a11SGreg Clayton     DNBBreakpoint *bp = CurrentBreakpoint();
42530fdc8d8SChris Lattner 
426d8cf1a11SGreg Clayton     if (bp)
42730fdc8d8SChris Lattner     {
42830fdc8d8SChris Lattner         // This thread is sitting at a breakpoint, ask the breakpoint
42930fdc8d8SChris Lattner         // if we should be stopping here.
43030fdc8d8SChris Lattner         return true;
43130fdc8d8SChris Lattner     }
43230fdc8d8SChris Lattner     else
43330fdc8d8SChris Lattner     {
4343af9ea56SGreg Clayton         if (m_arch_ap->StepNotComplete())
43530fdc8d8SChris Lattner         {
43630fdc8d8SChris Lattner             step_more = true;
43730fdc8d8SChris Lattner             return false;
43830fdc8d8SChris Lattner         }
43930fdc8d8SChris Lattner         // The thread state is used to let us know what the thread was
44030fdc8d8SChris Lattner         // trying to do. MachThread::ThreadWillResume() will set the
44130fdc8d8SChris Lattner         // thread state to various values depending if the thread was
44230fdc8d8SChris Lattner         // the current thread and if it was to be single stepped, or
44330fdc8d8SChris Lattner         // resumed.
44430fdc8d8SChris Lattner         if (GetState() == eStateRunning)
44530fdc8d8SChris Lattner         {
44630fdc8d8SChris Lattner             // If our state is running, then we should continue as we are in
44730fdc8d8SChris Lattner             // the process of stepping over a breakpoint.
44830fdc8d8SChris Lattner             return false;
44930fdc8d8SChris Lattner         }
45030fdc8d8SChris Lattner         else
45130fdc8d8SChris Lattner         {
45230fdc8d8SChris Lattner             // Stop if we have any kind of valid exception for this
45330fdc8d8SChris Lattner             // thread.
45430fdc8d8SChris Lattner             if (GetStopException().IsValid())
45530fdc8d8SChris Lattner                 return true;
45630fdc8d8SChris Lattner         }
45730fdc8d8SChris Lattner     }
45830fdc8d8SChris Lattner     return false;
45930fdc8d8SChris Lattner }
46030fdc8d8SChris Lattner bool
46130fdc8d8SChris Lattner MachThread::IsStepping()
46230fdc8d8SChris Lattner {
463c4e411ffSGreg Clayton     return GetState() == eStateStepping;
46430fdc8d8SChris Lattner }
46530fdc8d8SChris Lattner 
46630fdc8d8SChris Lattner 
46730fdc8d8SChris Lattner bool
46830fdc8d8SChris Lattner MachThread::ThreadDidStop()
46930fdc8d8SChris Lattner {
47030fdc8d8SChris Lattner     // This thread has existed prior to resuming under debug nub control,
47130fdc8d8SChris Lattner     // and has just been stopped. Do any cleanup that needs to be done
47230fdc8d8SChris Lattner     // after running.
47330fdc8d8SChris Lattner 
47430fdc8d8SChris Lattner     // The thread state and breakpoint will still have the same values
47530fdc8d8SChris Lattner     // as they had prior to resuming the thread, so it makes it easy to check
47630fdc8d8SChris Lattner     // if we were trying to step a thread, or we tried to resume while being
47730fdc8d8SChris Lattner     // at a breakpoint.
47830fdc8d8SChris Lattner 
47930fdc8d8SChris Lattner     // When this method gets called, the process state is still in the
48030fdc8d8SChris Lattner     // state it was in while running so we can act accordingly.
4813af9ea56SGreg Clayton     m_arch_ap->ThreadDidStop();
48230fdc8d8SChris Lattner 
48330fdc8d8SChris Lattner 
48430fdc8d8SChris Lattner     // We may have suspended this thread so the primary thread could step
48530fdc8d8SChris Lattner     // without worrying about race conditions, so lets restore our suspend
48630fdc8d8SChris Lattner     // count.
4879411ddb6SJim Ingham     RestoreSuspendCountAfterStop();
48830fdc8d8SChris Lattner 
48930fdc8d8SChris Lattner     // Update the basic information for a thread
4901c73911dSJason Molenda     MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info);
49130fdc8d8SChris Lattner 
492c235ac76SGreg Clayton     if (m_basic_info.suspend_count > 0)
493c4e411ffSGreg Clayton         SetState(eStateSuspended);
494c4e411ffSGreg Clayton     else
495c4e411ffSGreg Clayton         SetState(eStateStopped);
49630fdc8d8SChris Lattner     return true;
49730fdc8d8SChris Lattner }
49830fdc8d8SChris Lattner 
49930fdc8d8SChris Lattner bool
50030fdc8d8SChris Lattner MachThread::NotifyException(MachException::Data& exc)
50130fdc8d8SChris Lattner {
50288c1b77fSJohnny Chen     // Allow the arch specific protocol to process (MachException::Data &)exc
50388c1b77fSJohnny Chen     // first before possible reassignment of m_stop_exception with exc.
50476abb3b5SJohnny Chen     // See also MachThread::GetStopException().
50588c1b77fSJohnny Chen     bool handled = m_arch_ap->NotifyException(exc);
50688c1b77fSJohnny Chen 
50730fdc8d8SChris Lattner     if (m_stop_exception.IsValid())
50830fdc8d8SChris Lattner     {
50930fdc8d8SChris Lattner         // We may have more than one exception for a thread, but we need to
51030fdc8d8SChris Lattner         // only remember the one that we will say is the reason we stopped.
51130fdc8d8SChris Lattner         // We may have been single stepping and also gotten a signal exception,
51230fdc8d8SChris Lattner         // so just remember the most pertinent one.
51330fdc8d8SChris Lattner         if (m_stop_exception.IsBreakpoint())
51430fdc8d8SChris Lattner             m_stop_exception = exc;
51530fdc8d8SChris Lattner     }
51630fdc8d8SChris Lattner     else
51730fdc8d8SChris Lattner     {
51830fdc8d8SChris Lattner         m_stop_exception = exc;
51930fdc8d8SChris Lattner     }
52088c1b77fSJohnny Chen 
52130fdc8d8SChris Lattner     return handled;
52230fdc8d8SChris Lattner }
52330fdc8d8SChris Lattner 
52430fdc8d8SChris Lattner 
52530fdc8d8SChris Lattner nub_state_t
52630fdc8d8SChris Lattner MachThread::GetState()
52730fdc8d8SChris Lattner {
52830fdc8d8SChris Lattner     // If any other threads access this we will need a mutex for it
52930fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
53030fdc8d8SChris Lattner     return m_state;
53130fdc8d8SChris Lattner }
53230fdc8d8SChris Lattner 
53330fdc8d8SChris Lattner void
53430fdc8d8SChris Lattner MachThread::SetState(nub_state_t state)
53530fdc8d8SChris Lattner {
53630fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER (locker, m_state_mutex);
53730fdc8d8SChris Lattner     m_state = state;
5381c73911dSJason Molenda     DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%8.8" PRIx64 "", DNBStateAsString(state), m_unique_id);
53930fdc8d8SChris Lattner }
54030fdc8d8SChris Lattner 
541*ee2ed525SGreg Clayton nub_size_t
54230fdc8d8SChris Lattner MachThread::GetNumRegistersInSet(int regSet) const
54330fdc8d8SChris Lattner {
544c235ac76SGreg Clayton     if (regSet < m_num_reg_sets)
5453af9ea56SGreg Clayton         return m_reg_sets[regSet].num_registers;
54630fdc8d8SChris Lattner     return 0;
54730fdc8d8SChris Lattner }
54830fdc8d8SChris Lattner 
54930fdc8d8SChris Lattner const char *
55030fdc8d8SChris Lattner MachThread::GetRegisterSetName(int regSet) const
55130fdc8d8SChris Lattner {
552c235ac76SGreg Clayton     if (regSet < m_num_reg_sets)
5533af9ea56SGreg Clayton         return m_reg_sets[regSet].name;
55430fdc8d8SChris Lattner     return NULL;
55530fdc8d8SChris Lattner }
55630fdc8d8SChris Lattner 
55730fdc8d8SChris Lattner const DNBRegisterInfo *
55830fdc8d8SChris Lattner MachThread::GetRegisterInfo(int regSet, int regIndex) const
55930fdc8d8SChris Lattner {
560c235ac76SGreg Clayton     if (regSet < m_num_reg_sets)
5613af9ea56SGreg Clayton         if (regIndex < m_reg_sets[regSet].num_registers)
5623af9ea56SGreg Clayton             return &m_reg_sets[regSet].registers[regIndex];
56330fdc8d8SChris Lattner     return NULL;
56430fdc8d8SChris Lattner }
56530fdc8d8SChris Lattner void
56630fdc8d8SChris Lattner MachThread::DumpRegisterState(int regSet)
56730fdc8d8SChris Lattner {
56830fdc8d8SChris Lattner     if (regSet == REGISTER_SET_ALL)
56930fdc8d8SChris Lattner     {
570c235ac76SGreg Clayton         for (regSet = 1; regSet < m_num_reg_sets; regSet++)
57130fdc8d8SChris Lattner             DumpRegisterState(regSet);
57230fdc8d8SChris Lattner     }
57330fdc8d8SChris Lattner     else
57430fdc8d8SChris Lattner     {
5753af9ea56SGreg Clayton         if (m_arch_ap->RegisterSetStateIsValid(regSet))
57630fdc8d8SChris Lattner         {
57730fdc8d8SChris Lattner             const size_t numRegisters = GetNumRegistersInSet(regSet);
578*ee2ed525SGreg Clayton             uint32_t regIndex = 0;
57930fdc8d8SChris Lattner             DNBRegisterValueClass reg;
58030fdc8d8SChris Lattner             for (regIndex = 0; regIndex < numRegisters; ++regIndex)
58130fdc8d8SChris Lattner             {
5823af9ea56SGreg Clayton                 if (m_arch_ap->GetRegisterValue(regSet, regIndex, &reg))
58330fdc8d8SChris Lattner                 {
58430fdc8d8SChris Lattner                     reg.Dump(NULL, NULL);
58530fdc8d8SChris Lattner                 }
58630fdc8d8SChris Lattner             }
58730fdc8d8SChris Lattner         }
58830fdc8d8SChris Lattner         else
58930fdc8d8SChris Lattner         {
59030fdc8d8SChris Lattner             DNBLog("%s: registers are not currently valid.", GetRegisterSetName(regSet));
59130fdc8d8SChris Lattner         }
59230fdc8d8SChris Lattner     }
59330fdc8d8SChris Lattner }
59430fdc8d8SChris Lattner 
59530fdc8d8SChris Lattner const DNBRegisterSetInfo *
59630fdc8d8SChris Lattner MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const
59730fdc8d8SChris Lattner {
598c235ac76SGreg Clayton     *num_reg_sets = m_num_reg_sets;
5993af9ea56SGreg Clayton     return &m_reg_sets[0];
60030fdc8d8SChris Lattner }
60130fdc8d8SChris Lattner 
60230fdc8d8SChris Lattner bool
60330fdc8d8SChris Lattner MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value )
60430fdc8d8SChris Lattner {
6053af9ea56SGreg Clayton     return m_arch_ap->GetRegisterValue(set, reg, value);
60630fdc8d8SChris Lattner }
60730fdc8d8SChris Lattner 
60830fdc8d8SChris Lattner bool
60930fdc8d8SChris Lattner MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value )
61030fdc8d8SChris Lattner {
6113af9ea56SGreg Clayton     return m_arch_ap->SetRegisterValue(set, reg, value);
61230fdc8d8SChris Lattner }
61330fdc8d8SChris Lattner 
61430fdc8d8SChris Lattner nub_size_t
61530fdc8d8SChris Lattner MachThread::GetRegisterContext (void *buf, nub_size_t buf_len)
61630fdc8d8SChris Lattner {
6173af9ea56SGreg Clayton     return m_arch_ap->GetRegisterContext(buf, buf_len);
61830fdc8d8SChris Lattner }
61930fdc8d8SChris Lattner 
62030fdc8d8SChris Lattner nub_size_t
62130fdc8d8SChris Lattner MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len)
62230fdc8d8SChris Lattner {
6233af9ea56SGreg Clayton     return m_arch_ap->SetRegisterContext(buf, buf_len);
62430fdc8d8SChris Lattner }
62530fdc8d8SChris Lattner 
62630fdc8d8SChris Lattner uint32_t
627f74cf86bSGreg Clayton MachThread::SaveRegisterState ()
628f74cf86bSGreg Clayton {
629f74cf86bSGreg Clayton     return m_arch_ap->SaveRegisterState();
630f74cf86bSGreg Clayton 
631f74cf86bSGreg Clayton }
632f74cf86bSGreg Clayton bool
633f74cf86bSGreg Clayton MachThread::RestoreRegisterState (uint32_t save_id)
634f74cf86bSGreg Clayton {
635f74cf86bSGreg Clayton     return m_arch_ap->RestoreRegisterState(save_id);
636f74cf86bSGreg Clayton }
637f74cf86bSGreg Clayton 
638f74cf86bSGreg Clayton uint32_t
63930fdc8d8SChris Lattner MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp)
64030fdc8d8SChris Lattner {
64130fdc8d8SChris Lattner     if (bp != NULL && bp->IsBreakpoint())
6423af9ea56SGreg Clayton         return m_arch_ap->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize());
64330fdc8d8SChris Lattner     return INVALID_NUB_HW_INDEX;
64430fdc8d8SChris Lattner }
64530fdc8d8SChris Lattner 
64630fdc8d8SChris Lattner uint32_t
647f1715ab2SJim Ingham MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp, bool also_set_on_task)
64830fdc8d8SChris Lattner {
64930fdc8d8SChris Lattner     if (wp != NULL && wp->IsWatchpoint())
650f1715ab2SJim Ingham         return m_arch_ap->EnableHardwareWatchpoint(wp->Address(), wp->ByteSize(), wp->WatchpointRead(), wp->WatchpointWrite(), also_set_on_task);
65130fdc8d8SChris Lattner     return INVALID_NUB_HW_INDEX;
65230fdc8d8SChris Lattner }
65330fdc8d8SChris Lattner 
65430fdc8d8SChris Lattner bool
65584707560SJohnny Chen MachThread::RollbackTransForHWP()
65684707560SJohnny Chen {
65784707560SJohnny Chen     return m_arch_ap->RollbackTransForHWP();
65884707560SJohnny Chen }
65984707560SJohnny Chen 
66084707560SJohnny Chen bool
66184707560SJohnny Chen MachThread::FinishTransForHWP()
66284707560SJohnny Chen {
66384707560SJohnny Chen     return m_arch_ap->FinishTransForHWP();
66484707560SJohnny Chen }
66584707560SJohnny Chen 
66684707560SJohnny Chen bool
66730fdc8d8SChris Lattner MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp)
66830fdc8d8SChris Lattner {
66930fdc8d8SChris Lattner     if (bp != NULL && bp->IsHardware())
6703af9ea56SGreg Clayton         return m_arch_ap->DisableHardwareBreakpoint(bp->GetHardwareIndex());
67130fdc8d8SChris Lattner     return false;
67230fdc8d8SChris Lattner }
67330fdc8d8SChris Lattner 
67430fdc8d8SChris Lattner bool
675f1715ab2SJim Ingham MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp, bool also_set_on_task)
67630fdc8d8SChris Lattner {
67730fdc8d8SChris Lattner     if (wp != NULL && wp->IsHardware())
678f1715ab2SJim Ingham         return m_arch_ap->DisableHardwareWatchpoint(wp->GetHardwareIndex(), also_set_on_task);
67930fdc8d8SChris Lattner     return false;
68030fdc8d8SChris Lattner }
68130fdc8d8SChris Lattner 
68264637205SJohnny Chen uint32_t
68364637205SJohnny Chen MachThread::NumSupportedHardwareWatchpoints () const
68464637205SJohnny Chen {
68564637205SJohnny Chen     return m_arch_ap->NumSupportedHardwareWatchpoints();
68664637205SJohnny Chen }
68764637205SJohnny Chen 
68830fdc8d8SChris Lattner bool
68930fdc8d8SChris Lattner MachThread::GetIdentifierInfo ()
69030fdc8d8SChris Lattner {
691f2c6ccf0SJim Ingham         // Don't try to get the thread info once and cache it for the life of the thread.  It changes over time, for instance
692f2c6ccf0SJim Ingham         // if the thread name changes, then the thread_handle also changes...  So you have to refetch it every time.
69330fdc8d8SChris Lattner         mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
6941c73911dSJason Molenda         kern_return_t kret = ::thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);
695f2c6ccf0SJim Ingham         return kret == KERN_SUCCESS;
69630fdc8d8SChris Lattner 
69730fdc8d8SChris Lattner     return false;
69830fdc8d8SChris Lattner }
69930fdc8d8SChris Lattner 
70030fdc8d8SChris Lattner 
70130fdc8d8SChris Lattner const char *
70230fdc8d8SChris Lattner MachThread::GetName ()
70330fdc8d8SChris Lattner {
70430fdc8d8SChris Lattner     if (GetIdentifierInfo ())
70530fdc8d8SChris Lattner     {
70630fdc8d8SChris Lattner         int len = ::proc_pidinfo (m_process->ProcessID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo));
70730fdc8d8SChris Lattner 
70830fdc8d8SChris Lattner         if (len && m_proc_threadinfo.pth_name[0])
70930fdc8d8SChris Lattner             return m_proc_threadinfo.pth_name;
71030fdc8d8SChris Lattner     }
71130fdc8d8SChris Lattner     return NULL;
71230fdc8d8SChris Lattner }
71330fdc8d8SChris Lattner 
7141c73911dSJason Molenda 
7151c73911dSJason Molenda uint64_t
7161c73911dSJason Molenda MachThread::GetGloballyUniqueThreadIDForMachPortID (thread_t mach_port_id)
7171c73911dSJason Molenda {
7181c73911dSJason Molenda     kern_return_t kr;
7191c73911dSJason Molenda     thread_identifier_info_data_t tident;
7201c73911dSJason Molenda     mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
7211c73911dSJason Molenda     kr = thread_info (mach_port_id, THREAD_IDENTIFIER_INFO,
7221c73911dSJason Molenda                       (thread_info_t) &tident, &tident_count);
7231c73911dSJason Molenda     if (kr != KERN_SUCCESS)
7241c73911dSJason Molenda     {
7251c73911dSJason Molenda         return mach_port_id;
7261c73911dSJason Molenda     }
7271c73911dSJason Molenda     return tident.thread_id;
7281c73911dSJason Molenda }
729705b1809SJason Molenda 
730705b1809SJason Molenda nub_addr_t
731705b1809SJason Molenda MachThread::GetPThreadT ()
732705b1809SJason Molenda {
733705b1809SJason Molenda     nub_addr_t pthread_t_value = INVALID_NUB_ADDRESS;
734705b1809SJason Molenda     if (MachPortNumberIsValid (m_mach_port_number))
735705b1809SJason Molenda     {
736705b1809SJason Molenda         kern_return_t kr;
737705b1809SJason Molenda         thread_identifier_info_data_t tident;
738705b1809SJason Molenda         mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
739705b1809SJason Molenda         kr = thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO,
740705b1809SJason Molenda                         (thread_info_t) &tident, &tident_count);
741705b1809SJason Molenda         if (kr == KERN_SUCCESS)
742705b1809SJason Molenda         {
743705b1809SJason Molenda             // Dereference thread_handle to get the pthread_t value for this thread.
744705b1809SJason Molenda             if (m_is_64_bit)
745705b1809SJason Molenda             {
746705b1809SJason Molenda                 uint64_t addr;
747705b1809SJason Molenda                 if (m_process->ReadMemory (tident.thread_handle, 8, &addr) == 8)
748705b1809SJason Molenda                 {
749705b1809SJason Molenda                     if (addr != 0)
750705b1809SJason Molenda                     {
751705b1809SJason Molenda                         pthread_t_value = addr;
752705b1809SJason Molenda                     }
753705b1809SJason Molenda                 }
754705b1809SJason Molenda             }
755705b1809SJason Molenda             else
756705b1809SJason Molenda             {
757705b1809SJason Molenda                 uint32_t addr;
758705b1809SJason Molenda                 if (m_process->ReadMemory (tident.thread_handle, 4, &addr) == 4)
759705b1809SJason Molenda                 {
760705b1809SJason Molenda                     if (addr != 0)
761705b1809SJason Molenda                     {
762705b1809SJason Molenda                         pthread_t_value = addr;
763705b1809SJason Molenda                     }
764705b1809SJason Molenda                 }
765705b1809SJason Molenda             }
766705b1809SJason Molenda         }
767705b1809SJason Molenda     }
768705b1809SJason Molenda     return pthread_t_value;
769705b1809SJason Molenda }
770705b1809SJason Molenda 
771705b1809SJason Molenda // Return this thread's TSD (Thread Specific Data) address.
772705b1809SJason Molenda // This is computed based on this thread's pthread_t value.
773705b1809SJason Molenda //
774705b1809SJason Molenda // We compute the TSD from the pthread_t by one of two methods.
775705b1809SJason Molenda //
776705b1809SJason Molenda // If plo_pthread_tsd_base_offset is non-zero, this is a simple offset that we add to
777705b1809SJason Molenda // the pthread_t to get the TSD base address.
778705b1809SJason Molenda //
779705b1809SJason Molenda // Else we read a pointer from memory at pthread_t + plo_pthread_tsd_base_address_offset and
780705b1809SJason Molenda // that gives us the TSD address.
781705b1809SJason Molenda //
782705b1809SJason Molenda // These plo_pthread_tsd_base values must be read out of libpthread by lldb & provided to debugserver.
783705b1809SJason Molenda 
784705b1809SJason Molenda nub_addr_t
785705b1809SJason Molenda MachThread::GetTSDAddressForThread (uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size)
786705b1809SJason Molenda {
787705b1809SJason Molenda     nub_addr_t tsd_addr = INVALID_NUB_ADDRESS;
788705b1809SJason Molenda     nub_addr_t pthread_t_value = GetPThreadT();
789705b1809SJason Molenda     if (plo_pthread_tsd_base_offset != 0 && plo_pthread_tsd_base_offset != INVALID_NUB_ADDRESS)
790705b1809SJason Molenda     {
791705b1809SJason Molenda         tsd_addr = pthread_t_value + plo_pthread_tsd_base_offset;
792705b1809SJason Molenda     }
793705b1809SJason Molenda     else
794705b1809SJason Molenda     {
795705b1809SJason Molenda         if (plo_pthread_tsd_entry_size == 4)
796705b1809SJason Molenda         {
797705b1809SJason Molenda             uint32_t addr = 0;
798705b1809SJason Molenda             if (m_process->ReadMemory (pthread_t_value + plo_pthread_tsd_base_address_offset, 4, &addr) == 4)
799705b1809SJason Molenda             {
800705b1809SJason Molenda                 if (addr != 0)
801705b1809SJason Molenda                 {
802705b1809SJason Molenda                     tsd_addr = addr;
803705b1809SJason Molenda                 }
804705b1809SJason Molenda             }
805705b1809SJason Molenda         }
806705b1809SJason Molenda         if (plo_pthread_tsd_entry_size == 4)
807705b1809SJason Molenda         {
808705b1809SJason Molenda             uint64_t addr = 0;
809705b1809SJason Molenda             if (m_process->ReadMemory (pthread_t_value + plo_pthread_tsd_base_address_offset, 8, &addr) == 8)
810705b1809SJason Molenda             {
811705b1809SJason Molenda                 if (addr != 0)
812705b1809SJason Molenda                 {
813705b1809SJason Molenda                     tsd_addr = addr;
814705b1809SJason Molenda                 }
815705b1809SJason Molenda             }
816705b1809SJason Molenda         }
817705b1809SJason Molenda     }
818705b1809SJason Molenda     return tsd_addr;
819705b1809SJason Molenda }
820705b1809SJason Molenda 
821705b1809SJason Molenda 
822705b1809SJason Molenda nub_addr_t
823705b1809SJason Molenda MachThread::GetDispatchQueueT ()
824705b1809SJason Molenda {
825705b1809SJason Molenda     nub_addr_t dispatch_queue_t_value = INVALID_NUB_ADDRESS;
826705b1809SJason Molenda     if (MachPortNumberIsValid (m_mach_port_number))
827705b1809SJason Molenda     {
828705b1809SJason Molenda         kern_return_t kr;
829705b1809SJason Molenda         thread_identifier_info_data_t tident;
830705b1809SJason Molenda         mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
831705b1809SJason Molenda         kr = thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO,
832705b1809SJason Molenda                         (thread_info_t) &tident, &tident_count);
833705b1809SJason Molenda         if (kr == KERN_SUCCESS && tident.dispatch_qaddr != 0 && tident.dispatch_qaddr != INVALID_NUB_ADDRESS)
834705b1809SJason Molenda         {
835705b1809SJason Molenda             // Dereference dispatch_qaddr to get the dispatch_queue_t value for this thread's queue, if any.
836705b1809SJason Molenda             if (m_is_64_bit)
837705b1809SJason Molenda             {
838705b1809SJason Molenda                 uint64_t addr;
839705b1809SJason Molenda                 if (m_process->ReadMemory (tident.dispatch_qaddr, 8, &addr) == 8)
840705b1809SJason Molenda                 {
841705b1809SJason Molenda                     if (addr != 0)
842705b1809SJason Molenda                         dispatch_queue_t_value = addr;
843705b1809SJason Molenda                 }
844705b1809SJason Molenda             }
845705b1809SJason Molenda             else
846705b1809SJason Molenda             {
847705b1809SJason Molenda                 uint32_t addr;
848705b1809SJason Molenda                 if (m_process->ReadMemory (tident.dispatch_qaddr, 4, &addr) == 4)
849705b1809SJason Molenda                 {
850705b1809SJason Molenda                     if (addr != 0)
851705b1809SJason Molenda                         dispatch_queue_t_value = addr;
852705b1809SJason Molenda                 }
853705b1809SJason Molenda             }
854705b1809SJason Molenda         }
855705b1809SJason Molenda     }
856705b1809SJason Molenda     return dispatch_queue_t_value;
857705b1809SJason Molenda }
858705b1809SJason Molenda 
859705b1809SJason Molenda 
860705b1809SJason Molenda ThreadInfo::QoS
861705b1809SJason Molenda MachThread::GetRequestedQoS (nub_addr_t tsd, uint64_t dti_qos_class_index)
862705b1809SJason Molenda {
863705b1809SJason Molenda     ThreadInfo::QoS qos_value;
864705b1809SJason Molenda     if (MachPortNumberIsValid (m_mach_port_number) && m_pthread_qos_class_decode != nullptr)
865705b1809SJason Molenda     {
866705b1809SJason Molenda         uint64_t pthread_priority_value = 0;
867705b1809SJason Molenda         if (m_is_64_bit)
868705b1809SJason Molenda         {
869705b1809SJason Molenda             uint64_t pri;
870705b1809SJason Molenda             if (m_process->ReadMemory (tsd + (dti_qos_class_index * 8), 8, &pri) == 8)
871705b1809SJason Molenda             {
872705b1809SJason Molenda                 pthread_priority_value = pri;
873705b1809SJason Molenda             }
874705b1809SJason Molenda         }
875705b1809SJason Molenda         else
876705b1809SJason Molenda         {
877705b1809SJason Molenda             uint32_t pri;
878705b1809SJason Molenda             if (m_process->ReadMemory (tsd + (dti_qos_class_index * 4), 4, &pri) == 4)
879705b1809SJason Molenda             {
880705b1809SJason Molenda                 pthread_priority_value = pri;
881705b1809SJason Molenda             }
882705b1809SJason Molenda         }
883705b1809SJason Molenda 
884705b1809SJason Molenda         uint32_t requested_qos = m_pthread_qos_class_decode (pthread_priority_value, NULL, NULL);
885705b1809SJason Molenda 
886705b1809SJason Molenda         switch (requested_qos)
887705b1809SJason Molenda         {
888705b1809SJason Molenda             // These constants from <pthread/qos.h>
889705b1809SJason Molenda             case 0x21:
890705b1809SJason Molenda                 qos_value.enum_value = requested_qos;
891705b1809SJason Molenda                 qos_value.constant_name = "QOS_CLASS_USER_INTERACTIVE";
892705b1809SJason Molenda                 qos_value.printable_name = "User Interactive";
893705b1809SJason Molenda                 break;
894705b1809SJason Molenda             case 0x19:
895705b1809SJason Molenda                 qos_value.enum_value = requested_qos;
896705b1809SJason Molenda                 qos_value.constant_name = "QOS_CLASS_USER_INITIATED";
897705b1809SJason Molenda                 qos_value.printable_name = "User Initiated";
898705b1809SJason Molenda                 break;
899705b1809SJason Molenda             case 0x15:
900705b1809SJason Molenda                 qos_value.enum_value = requested_qos;
901705b1809SJason Molenda                 qos_value.constant_name = "QOS_CLASS_DEFAULT";
902705b1809SJason Molenda                 qos_value.printable_name = "Default";
903705b1809SJason Molenda                 break;
904705b1809SJason Molenda             case 0x11:
905705b1809SJason Molenda                 qos_value.enum_value = requested_qos;
906705b1809SJason Molenda                 qos_value.constant_name = "QOS_CLASS_UTILITY";
907705b1809SJason Molenda                 qos_value.printable_name = "Utility";
908705b1809SJason Molenda                 break;
909705b1809SJason Molenda             case 0x09:
910705b1809SJason Molenda                 qos_value.enum_value = requested_qos;
911705b1809SJason Molenda                 qos_value.constant_name = "QOS_CLASS_BACKGROUND";
912705b1809SJason Molenda                 qos_value.printable_name = "Background";
913705b1809SJason Molenda                 break;
914705b1809SJason Molenda             case 0x00:
915705b1809SJason Molenda                 qos_value.enum_value = requested_qos;
916705b1809SJason Molenda                 qos_value.constant_name = "QOS_CLASS_UNSPECIFIED";
917705b1809SJason Molenda                 qos_value.printable_name = "Unspecified";
918705b1809SJason Molenda                 break;
919705b1809SJason Molenda         }
920705b1809SJason Molenda     }
921705b1809SJason Molenda     return qos_value;
922705b1809SJason Molenda }
923