xref: /openbsd-src/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachThread.cpp (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1061da546Spatrick //===-- MachThread.cpp ------------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick //
9061da546Spatrick //  Created by Greg Clayton on 6/19/07.
10061da546Spatrick //
11061da546Spatrick //===----------------------------------------------------------------------===//
12061da546Spatrick 
13061da546Spatrick #include "MachThread.h"
14061da546Spatrick #include "DNB.h"
15061da546Spatrick #include "DNBLog.h"
16061da546Spatrick #include "MachProcess.h"
17061da546Spatrick #include "ThreadInfo.h"
18*be691f3bSpatrick #include <cinttypes>
19061da546Spatrick #include <dlfcn.h>
20061da546Spatrick #include <mach/thread_policy.h>
21061da546Spatrick 
GetSequenceID()22061da546Spatrick static uint32_t GetSequenceID() {
23061da546Spatrick   static uint32_t g_nextID = 0;
24061da546Spatrick   return ++g_nextID;
25061da546Spatrick }
26061da546Spatrick 
MachThread(MachProcess * process,bool is_64_bit,uint64_t unique_thread_id,thread_t mach_port_num)27061da546Spatrick MachThread::MachThread(MachProcess *process, bool is_64_bit,
28061da546Spatrick                        uint64_t unique_thread_id, thread_t mach_port_num)
29061da546Spatrick     : m_process(process), m_unique_id(unique_thread_id),
30061da546Spatrick       m_mach_port_number(mach_port_num), m_seq_id(GetSequenceID()),
31061da546Spatrick       m_state(eStateUnloaded), m_state_mutex(PTHREAD_MUTEX_RECURSIVE),
32061da546Spatrick       m_suspend_count(0), m_stop_exception(),
33061da546Spatrick       m_arch_up(DNBArchProtocol::Create(this)), m_reg_sets(NULL),
34061da546Spatrick       m_num_reg_sets(0), m_ident_info(), m_proc_threadinfo(),
35061da546Spatrick       m_dispatch_queue_name(), m_is_64_bit(is_64_bit),
36061da546Spatrick       m_pthread_qos_class_decode(nullptr) {
37061da546Spatrick   nub_size_t num_reg_sets = 0;
38061da546Spatrick   m_reg_sets = m_arch_up->GetRegisterSetInfo(&num_reg_sets);
39061da546Spatrick   m_num_reg_sets = num_reg_sets;
40061da546Spatrick 
41061da546Spatrick   m_pthread_qos_class_decode =
42061da546Spatrick       (unsigned int (*)(unsigned long, int *, unsigned long *))dlsym(
43061da546Spatrick           RTLD_DEFAULT, "_pthread_qos_class_decode");
44061da546Spatrick 
45061da546Spatrick   // Get the thread state so we know if a thread is in a state where we can't
46061da546Spatrick   // muck with it and also so we get the suspend count correct in case it was
47061da546Spatrick   // already suspended
48061da546Spatrick   GetBasicInfo();
49061da546Spatrick   DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE,
50061da546Spatrick                    "MachThread::MachThread ( process = %p, tid = 0x%8.8" PRIx64
51061da546Spatrick                    ", seq_id = %u )",
52061da546Spatrick                    static_cast<void *>(&m_process), m_unique_id, m_seq_id);
53061da546Spatrick }
54061da546Spatrick 
~MachThread()55061da546Spatrick MachThread::~MachThread() {
56061da546Spatrick   DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE,
57061da546Spatrick                    "MachThread::~MachThread() for tid = 0x%8.8" PRIx64 " (%u)",
58061da546Spatrick                    m_unique_id, m_seq_id);
59061da546Spatrick }
60061da546Spatrick 
Suspend()61061da546Spatrick void MachThread::Suspend() {
62061da546Spatrick   DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )",
63061da546Spatrick                    __FUNCTION__);
64061da546Spatrick   if (MachPortNumberIsValid(m_mach_port_number)) {
65061da546Spatrick     DNBError err(::thread_suspend(m_mach_port_number), DNBError::MachKernel);
66061da546Spatrick     if (err.Success())
67061da546Spatrick       m_suspend_count++;
68061da546Spatrick     if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
69061da546Spatrick       err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number);
70061da546Spatrick   }
71061da546Spatrick }
72061da546Spatrick 
Resume(bool others_stopped)73061da546Spatrick void MachThread::Resume(bool others_stopped) {
74061da546Spatrick   DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )",
75061da546Spatrick                    __FUNCTION__);
76061da546Spatrick   if (MachPortNumberIsValid(m_mach_port_number)) {
77061da546Spatrick     SetSuspendCountBeforeResume(others_stopped);
78061da546Spatrick   }
79061da546Spatrick }
80061da546Spatrick 
SetSuspendCountBeforeResume(bool others_stopped)81061da546Spatrick bool MachThread::SetSuspendCountBeforeResume(bool others_stopped) {
82061da546Spatrick   DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )",
83061da546Spatrick                    __FUNCTION__);
84061da546Spatrick   DNBError err;
85061da546Spatrick   if (!MachPortNumberIsValid(m_mach_port_number))
86061da546Spatrick     return false;
87061da546Spatrick 
88061da546Spatrick   integer_t times_to_resume;
89061da546Spatrick 
90061da546Spatrick   if (others_stopped) {
91061da546Spatrick     if (GetBasicInfo()) {
92061da546Spatrick       times_to_resume = m_basic_info.suspend_count;
93061da546Spatrick       m_suspend_count = -(times_to_resume - m_suspend_count);
94061da546Spatrick     } else
95061da546Spatrick       times_to_resume = 0;
96061da546Spatrick   } else {
97061da546Spatrick     times_to_resume = m_suspend_count;
98061da546Spatrick     m_suspend_count = 0;
99061da546Spatrick   }
100061da546Spatrick 
101061da546Spatrick   if (times_to_resume > 0) {
102061da546Spatrick     while (times_to_resume > 0) {
103061da546Spatrick       err = ::thread_resume(m_mach_port_number);
104061da546Spatrick       if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
105061da546Spatrick         err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number);
106061da546Spatrick       if (err.Success())
107061da546Spatrick         --times_to_resume;
108061da546Spatrick       else {
109061da546Spatrick         if (GetBasicInfo())
110061da546Spatrick           times_to_resume = m_basic_info.suspend_count;
111061da546Spatrick         else
112061da546Spatrick           times_to_resume = 0;
113061da546Spatrick       }
114061da546Spatrick     }
115061da546Spatrick   }
116061da546Spatrick   return true;
117061da546Spatrick }
118061da546Spatrick 
RestoreSuspendCountAfterStop()119061da546Spatrick bool MachThread::RestoreSuspendCountAfterStop() {
120061da546Spatrick   DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )",
121061da546Spatrick                    __FUNCTION__);
122061da546Spatrick   DNBError err;
123061da546Spatrick   if (!MachPortNumberIsValid(m_mach_port_number))
124061da546Spatrick     return false;
125061da546Spatrick 
126061da546Spatrick   if (m_suspend_count > 0) {
127061da546Spatrick     while (m_suspend_count > 0) {
128061da546Spatrick       err = ::thread_resume(m_mach_port_number);
129061da546Spatrick       if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
130061da546Spatrick         err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number);
131061da546Spatrick       if (err.Success())
132061da546Spatrick         --m_suspend_count;
133061da546Spatrick       else {
134061da546Spatrick         if (GetBasicInfo())
135061da546Spatrick           m_suspend_count = m_basic_info.suspend_count;
136061da546Spatrick         else
137061da546Spatrick           m_suspend_count = 0;
138061da546Spatrick         return false; // ???
139061da546Spatrick       }
140061da546Spatrick     }
141061da546Spatrick   } else if (m_suspend_count < 0) {
142061da546Spatrick     while (m_suspend_count < 0) {
143061da546Spatrick       err = ::thread_suspend(m_mach_port_number);
144061da546Spatrick       if (err.Success())
145061da546Spatrick         ++m_suspend_count;
146061da546Spatrick       if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) {
147061da546Spatrick         err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")",
148061da546Spatrick                         m_mach_port_number);
149061da546Spatrick         return false;
150061da546Spatrick       }
151061da546Spatrick     }
152061da546Spatrick   }
153061da546Spatrick   return true;
154061da546Spatrick }
155061da546Spatrick 
GetBasicInfoAsString() const156061da546Spatrick const char *MachThread::GetBasicInfoAsString() const {
157061da546Spatrick   static char g_basic_info_string[1024];
158061da546Spatrick   struct thread_basic_info basicInfo;
159061da546Spatrick 
160061da546Spatrick   if (GetBasicInfo(m_mach_port_number, &basicInfo)) {
161061da546Spatrick 
162061da546Spatrick     //        char run_state_str[32];
163061da546Spatrick     //        size_t run_state_str_size = sizeof(run_state_str);
164061da546Spatrick     //        switch (basicInfo.run_state)
165061da546Spatrick     //        {
166061da546Spatrick     //        case TH_STATE_RUNNING:          strlcpy(run_state_str, "running",
167061da546Spatrick     //        run_state_str_size); break;
168061da546Spatrick     //        case TH_STATE_STOPPED:          strlcpy(run_state_str, "stopped",
169061da546Spatrick     //        run_state_str_size); break;
170061da546Spatrick     //        case TH_STATE_WAITING:          strlcpy(run_state_str, "waiting",
171061da546Spatrick     //        run_state_str_size); break;
172061da546Spatrick     //        case TH_STATE_UNINTERRUPTIBLE:  strlcpy(run_state_str,
173061da546Spatrick     //        "uninterruptible", run_state_str_size); break;
174061da546Spatrick     //        case TH_STATE_HALTED:           strlcpy(run_state_str, "halted",
175061da546Spatrick     //        run_state_str_size); break;
176061da546Spatrick     //        default:                        snprintf(run_state_str,
177061da546Spatrick     //        run_state_str_size, "%d", basicInfo.run_state); break;    // ???
178061da546Spatrick     //        }
179061da546Spatrick     float user = (float)basicInfo.user_time.seconds +
180061da546Spatrick                  (float)basicInfo.user_time.microseconds / 1000000.0f;
181061da546Spatrick     float system = (float)basicInfo.user_time.seconds +
182061da546Spatrick                    (float)basicInfo.user_time.microseconds / 1000000.0f;
183061da546Spatrick     snprintf(g_basic_info_string, sizeof(g_basic_info_string),
184061da546Spatrick              "Thread 0x%8.8" PRIx64 ": user=%f system=%f cpu=%d sleep_time=%d",
185061da546Spatrick              m_unique_id, user, system, basicInfo.cpu_usage,
186061da546Spatrick              basicInfo.sleep_time);
187061da546Spatrick 
188061da546Spatrick     return g_basic_info_string;
189061da546Spatrick   }
190061da546Spatrick   return NULL;
191061da546Spatrick }
192061da546Spatrick 
193061da546Spatrick // Finds the Mach port number for a given thread in the inferior process' port
194061da546Spatrick // namespace.
InferiorThreadID() const195061da546Spatrick thread_t MachThread::InferiorThreadID() const {
196061da546Spatrick   mach_msg_type_number_t i;
197061da546Spatrick   mach_port_name_array_t names;
198061da546Spatrick   mach_port_type_array_t types;
199061da546Spatrick   mach_msg_type_number_t ncount, tcount;
200061da546Spatrick   thread_t inferior_tid = INVALID_NUB_THREAD;
201061da546Spatrick   task_t my_task = ::mach_task_self();
202061da546Spatrick   task_t task = m_process->Task().TaskPort();
203061da546Spatrick 
204061da546Spatrick   kern_return_t kret =
205061da546Spatrick       ::mach_port_names(task, &names, &ncount, &types, &tcount);
206061da546Spatrick   if (kret == KERN_SUCCESS) {
207061da546Spatrick 
208061da546Spatrick     for (i = 0; i < ncount; i++) {
209061da546Spatrick       mach_port_t my_name;
210061da546Spatrick       mach_msg_type_name_t my_type;
211061da546Spatrick 
212061da546Spatrick       kret = ::mach_port_extract_right(task, names[i], MACH_MSG_TYPE_COPY_SEND,
213061da546Spatrick                                        &my_name, &my_type);
214061da546Spatrick       if (kret == KERN_SUCCESS) {
215061da546Spatrick         ::mach_port_deallocate(my_task, my_name);
216061da546Spatrick         if (my_name == m_mach_port_number) {
217061da546Spatrick           inferior_tid = names[i];
218061da546Spatrick           break;
219061da546Spatrick         }
220061da546Spatrick       }
221061da546Spatrick     }
222061da546Spatrick     // Free up the names and types
223061da546Spatrick     ::vm_deallocate(my_task, (vm_address_t)names,
224061da546Spatrick                     ncount * sizeof(mach_port_name_t));
225061da546Spatrick     ::vm_deallocate(my_task, (vm_address_t)types,
226061da546Spatrick                     tcount * sizeof(mach_port_type_t));
227061da546Spatrick   }
228061da546Spatrick   return inferior_tid;
229061da546Spatrick }
230061da546Spatrick 
IsUserReady()231061da546Spatrick bool MachThread::IsUserReady() {
232061da546Spatrick   if (m_basic_info.run_state == 0)
233061da546Spatrick     GetBasicInfo();
234061da546Spatrick 
235061da546Spatrick   switch (m_basic_info.run_state) {
236061da546Spatrick   default:
237061da546Spatrick   case TH_STATE_UNINTERRUPTIBLE:
238061da546Spatrick     break;
239061da546Spatrick 
240061da546Spatrick   case TH_STATE_RUNNING:
241061da546Spatrick   case TH_STATE_STOPPED:
242061da546Spatrick   case TH_STATE_WAITING:
243061da546Spatrick   case TH_STATE_HALTED:
244061da546Spatrick     return true;
245061da546Spatrick   }
246061da546Spatrick   return GetPC(0) != 0;
247061da546Spatrick }
248061da546Spatrick 
GetBasicInfo()249061da546Spatrick struct thread_basic_info *MachThread::GetBasicInfo() {
250061da546Spatrick   if (MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info))
251061da546Spatrick     return &m_basic_info;
252061da546Spatrick   return NULL;
253061da546Spatrick }
254061da546Spatrick 
GetBasicInfo(thread_t thread,struct thread_basic_info * basicInfoPtr)255061da546Spatrick bool MachThread::GetBasicInfo(thread_t thread,
256061da546Spatrick                               struct thread_basic_info *basicInfoPtr) {
257061da546Spatrick   if (MachPortNumberIsValid(thread)) {
258061da546Spatrick     unsigned int info_count = THREAD_BASIC_INFO_COUNT;
259061da546Spatrick     kern_return_t err = ::thread_info(thread, THREAD_BASIC_INFO,
260061da546Spatrick                                       (thread_info_t)basicInfoPtr, &info_count);
261061da546Spatrick     if (err == KERN_SUCCESS)
262061da546Spatrick       return true;
263061da546Spatrick   }
264061da546Spatrick   ::memset(basicInfoPtr, 0, sizeof(struct thread_basic_info));
265061da546Spatrick   return false;
266061da546Spatrick }
267061da546Spatrick 
ThreadIDIsValid(uint64_t thread)268061da546Spatrick bool MachThread::ThreadIDIsValid(uint64_t thread) { return thread != 0; }
269061da546Spatrick 
MachPortNumberIsValid(thread_t thread)270061da546Spatrick bool MachThread::MachPortNumberIsValid(thread_t thread) {
271061da546Spatrick   return thread != THREAD_NULL;
272061da546Spatrick }
273061da546Spatrick 
GetRegisterState(int flavor,bool force)274061da546Spatrick bool MachThread::GetRegisterState(int flavor, bool force) {
275061da546Spatrick   return m_arch_up->GetRegisterState(flavor, force) == KERN_SUCCESS;
276061da546Spatrick }
277061da546Spatrick 
SetRegisterState(int flavor)278061da546Spatrick bool MachThread::SetRegisterState(int flavor) {
279061da546Spatrick   return m_arch_up->SetRegisterState(flavor) == KERN_SUCCESS;
280061da546Spatrick }
281061da546Spatrick 
GetPC(uint64_t failValue)282061da546Spatrick uint64_t MachThread::GetPC(uint64_t failValue) {
283061da546Spatrick   // Get program counter
284061da546Spatrick   return m_arch_up->GetPC(failValue);
285061da546Spatrick }
286061da546Spatrick 
SetPC(uint64_t value)287061da546Spatrick bool MachThread::SetPC(uint64_t value) {
288061da546Spatrick   // Set program counter
289061da546Spatrick   return m_arch_up->SetPC(value);
290061da546Spatrick }
291061da546Spatrick 
GetSP(uint64_t failValue)292061da546Spatrick uint64_t MachThread::GetSP(uint64_t failValue) {
293061da546Spatrick   // Get stack pointer
294061da546Spatrick   return m_arch_up->GetSP(failValue);
295061da546Spatrick }
296061da546Spatrick 
ProcessID() const297061da546Spatrick nub_process_t MachThread::ProcessID() const {
298061da546Spatrick   if (m_process)
299061da546Spatrick     return m_process->ProcessID();
300061da546Spatrick   return INVALID_NUB_PROCESS;
301061da546Spatrick }
302061da546Spatrick 
Dump(uint32_t index)303061da546Spatrick void MachThread::Dump(uint32_t index) {
304061da546Spatrick   const char *thread_run_state = NULL;
305061da546Spatrick 
306061da546Spatrick   switch (m_basic_info.run_state) {
307061da546Spatrick   case TH_STATE_RUNNING:
308061da546Spatrick     thread_run_state = "running";
309061da546Spatrick     break; // 1 thread is running normally
310061da546Spatrick   case TH_STATE_STOPPED:
311061da546Spatrick     thread_run_state = "stopped";
312061da546Spatrick     break; // 2 thread is stopped
313061da546Spatrick   case TH_STATE_WAITING:
314061da546Spatrick     thread_run_state = "waiting";
315061da546Spatrick     break; // 3 thread is waiting normally
316061da546Spatrick   case TH_STATE_UNINTERRUPTIBLE:
317061da546Spatrick     thread_run_state = "uninter";
318061da546Spatrick     break; // 4 thread is in an uninterruptible wait
319061da546Spatrick   case TH_STATE_HALTED:
320061da546Spatrick     thread_run_state = "halted ";
321061da546Spatrick     break; // 5 thread is halted at a
322061da546Spatrick   default:
323061da546Spatrick     thread_run_state = "???";
324061da546Spatrick     break;
325061da546Spatrick   }
326061da546Spatrick 
327061da546Spatrick   DNBLogThreaded(
328061da546Spatrick       "[%3u] #%3u tid: 0x%8.8" PRIx64 ", pc: 0x%16.16" PRIx64
329061da546Spatrick       ", sp: 0x%16.16" PRIx64
330061da546Spatrick       ", user: %d.%6.6d, system: %d.%6.6d, cpu: %2d, policy: %2d, run_state: "
331061da546Spatrick       "%2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d",
332061da546Spatrick       index, m_seq_id, m_unique_id, GetPC(INVALID_NUB_ADDRESS),
333061da546Spatrick       GetSP(INVALID_NUB_ADDRESS), m_basic_info.user_time.seconds,
334061da546Spatrick       m_basic_info.user_time.microseconds, m_basic_info.system_time.seconds,
335061da546Spatrick       m_basic_info.system_time.microseconds, m_basic_info.cpu_usage,
336061da546Spatrick       m_basic_info.policy, m_basic_info.run_state, thread_run_state,
337061da546Spatrick       m_basic_info.flags, m_basic_info.suspend_count, m_suspend_count,
338061da546Spatrick       m_basic_info.sleep_time);
339061da546Spatrick   // DumpRegisterState(0);
340061da546Spatrick }
341061da546Spatrick 
ThreadWillResume(const DNBThreadResumeAction * thread_action,bool others_stopped)342061da546Spatrick void MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action,
343061da546Spatrick                                   bool others_stopped) {
344061da546Spatrick   if (thread_action->addr != INVALID_NUB_ADDRESS)
345061da546Spatrick     SetPC(thread_action->addr);
346061da546Spatrick 
347061da546Spatrick   SetState(thread_action->state);
348061da546Spatrick   switch (thread_action->state) {
349061da546Spatrick   case eStateStopped:
350061da546Spatrick   case eStateSuspended:
351061da546Spatrick     assert(others_stopped == false);
352061da546Spatrick     Suspend();
353061da546Spatrick     break;
354061da546Spatrick 
355061da546Spatrick   case eStateRunning:
356061da546Spatrick   case eStateStepping:
357061da546Spatrick     Resume(others_stopped);
358061da546Spatrick     break;
359061da546Spatrick   default:
360061da546Spatrick     break;
361061da546Spatrick   }
362061da546Spatrick   m_arch_up->ThreadWillResume();
363061da546Spatrick   m_stop_exception.Clear();
364061da546Spatrick }
365061da546Spatrick 
CurrentBreakpoint()366061da546Spatrick DNBBreakpoint *MachThread::CurrentBreakpoint() {
367061da546Spatrick   return m_process->Breakpoints().FindByAddress(GetPC());
368061da546Spatrick }
369061da546Spatrick 
ShouldStop(bool & step_more)370061da546Spatrick bool MachThread::ShouldStop(bool &step_more) {
371061da546Spatrick   // See if this thread is at a breakpoint?
372061da546Spatrick   DNBBreakpoint *bp = CurrentBreakpoint();
373061da546Spatrick 
374061da546Spatrick   if (bp) {
375061da546Spatrick     // This thread is sitting at a breakpoint, ask the breakpoint
376061da546Spatrick     // if we should be stopping here.
377061da546Spatrick     return true;
378061da546Spatrick   } else {
379061da546Spatrick     if (m_arch_up->StepNotComplete()) {
380061da546Spatrick       step_more = true;
381061da546Spatrick       return false;
382061da546Spatrick     }
383061da546Spatrick     // The thread state is used to let us know what the thread was
384061da546Spatrick     // trying to do. MachThread::ThreadWillResume() will set the
385061da546Spatrick     // thread state to various values depending if the thread was
386061da546Spatrick     // the current thread and if it was to be single stepped, or
387061da546Spatrick     // resumed.
388061da546Spatrick     if (GetState() == eStateRunning) {
389061da546Spatrick       // If our state is running, then we should continue as we are in
390061da546Spatrick       // the process of stepping over a breakpoint.
391061da546Spatrick       return false;
392061da546Spatrick     } else {
393061da546Spatrick       // Stop if we have any kind of valid exception for this
394061da546Spatrick       // thread.
395061da546Spatrick       if (GetStopException().IsValid())
396061da546Spatrick         return true;
397061da546Spatrick     }
398061da546Spatrick   }
399061da546Spatrick   return false;
400061da546Spatrick }
IsStepping()401061da546Spatrick bool MachThread::IsStepping() { return GetState() == eStateStepping; }
402061da546Spatrick 
ThreadDidStop()403061da546Spatrick bool MachThread::ThreadDidStop() {
404061da546Spatrick   // This thread has existed prior to resuming under debug nub control,
405061da546Spatrick   // and has just been stopped. Do any cleanup that needs to be done
406061da546Spatrick   // after running.
407061da546Spatrick 
408061da546Spatrick   // The thread state and breakpoint will still have the same values
409061da546Spatrick   // as they had prior to resuming the thread, so it makes it easy to check
410061da546Spatrick   // if we were trying to step a thread, or we tried to resume while being
411061da546Spatrick   // at a breakpoint.
412061da546Spatrick 
413061da546Spatrick   // When this method gets called, the process state is still in the
414061da546Spatrick   // state it was in while running so we can act accordingly.
415061da546Spatrick   m_arch_up->ThreadDidStop();
416061da546Spatrick 
417061da546Spatrick   // We may have suspended this thread so the primary thread could step
418061da546Spatrick   // without worrying about race conditions, so lets restore our suspend
419061da546Spatrick   // count.
420061da546Spatrick   RestoreSuspendCountAfterStop();
421061da546Spatrick 
422061da546Spatrick   // Update the basic information for a thread
423061da546Spatrick   MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info);
424061da546Spatrick 
425061da546Spatrick   if (m_basic_info.suspend_count > 0)
426061da546Spatrick     SetState(eStateSuspended);
427061da546Spatrick   else
428061da546Spatrick     SetState(eStateStopped);
429061da546Spatrick   return true;
430061da546Spatrick }
431061da546Spatrick 
NotifyException(MachException::Data & exc)432061da546Spatrick bool MachThread::NotifyException(MachException::Data &exc) {
433061da546Spatrick   // Allow the arch specific protocol to process (MachException::Data &)exc
434061da546Spatrick   // first before possible reassignment of m_stop_exception with exc.
435061da546Spatrick   // See also MachThread::GetStopException().
436061da546Spatrick   bool handled = m_arch_up->NotifyException(exc);
437061da546Spatrick 
438061da546Spatrick   if (m_stop_exception.IsValid()) {
439061da546Spatrick     // We may have more than one exception for a thread, but we need to
440061da546Spatrick     // only remember the one that we will say is the reason we stopped.
441061da546Spatrick     // We may have been single stepping and also gotten a signal exception,
442061da546Spatrick     // so just remember the most pertinent one.
443061da546Spatrick     if (m_stop_exception.IsBreakpoint())
444061da546Spatrick       m_stop_exception = exc;
445061da546Spatrick   } else {
446061da546Spatrick     m_stop_exception = exc;
447061da546Spatrick   }
448061da546Spatrick 
449061da546Spatrick   return handled;
450061da546Spatrick }
451061da546Spatrick 
GetState()452061da546Spatrick nub_state_t MachThread::GetState() {
453061da546Spatrick   // If any other threads access this we will need a mutex for it
454061da546Spatrick   PTHREAD_MUTEX_LOCKER(locker, m_state_mutex);
455061da546Spatrick   return m_state;
456061da546Spatrick }
457061da546Spatrick 
SetState(nub_state_t state)458061da546Spatrick void MachThread::SetState(nub_state_t state) {
459061da546Spatrick   PTHREAD_MUTEX_LOCKER(locker, m_state_mutex);
460061da546Spatrick   m_state = state;
461061da546Spatrick   DNBLogThreadedIf(LOG_THREAD,
462061da546Spatrick                    "MachThread::SetState ( %s ) for tid = 0x%8.8" PRIx64 "",
463061da546Spatrick                    DNBStateAsString(state), m_unique_id);
464061da546Spatrick }
465061da546Spatrick 
GetNumRegistersInSet(nub_size_t regSet) const466061da546Spatrick nub_size_t MachThread::GetNumRegistersInSet(nub_size_t regSet) const {
467061da546Spatrick   if (regSet < m_num_reg_sets)
468061da546Spatrick     return m_reg_sets[regSet].num_registers;
469061da546Spatrick   return 0;
470061da546Spatrick }
471061da546Spatrick 
GetRegisterSetName(nub_size_t regSet) const472061da546Spatrick const char *MachThread::GetRegisterSetName(nub_size_t regSet) const {
473061da546Spatrick   if (regSet < m_num_reg_sets)
474061da546Spatrick     return m_reg_sets[regSet].name;
475061da546Spatrick   return NULL;
476061da546Spatrick }
477061da546Spatrick 
GetRegisterInfo(nub_size_t regSet,nub_size_t regIndex) const478061da546Spatrick const DNBRegisterInfo *MachThread::GetRegisterInfo(nub_size_t regSet,
479061da546Spatrick                                                    nub_size_t regIndex) const {
480061da546Spatrick   if (regSet < m_num_reg_sets)
481061da546Spatrick     if (regIndex < m_reg_sets[regSet].num_registers)
482061da546Spatrick       return &m_reg_sets[regSet].registers[regIndex];
483061da546Spatrick   return NULL;
484061da546Spatrick }
DumpRegisterState(nub_size_t regSet)485061da546Spatrick void MachThread::DumpRegisterState(nub_size_t regSet) {
486061da546Spatrick   if (regSet == REGISTER_SET_ALL) {
487061da546Spatrick     for (regSet = 1; regSet < m_num_reg_sets; regSet++)
488061da546Spatrick       DumpRegisterState(regSet);
489061da546Spatrick   } else {
490061da546Spatrick     if (m_arch_up->RegisterSetStateIsValid((int)regSet)) {
491061da546Spatrick       const size_t numRegisters = GetNumRegistersInSet(regSet);
492061da546Spatrick       uint32_t regIndex = 0;
493061da546Spatrick       DNBRegisterValueClass reg;
494061da546Spatrick       for (regIndex = 0; regIndex < numRegisters; ++regIndex) {
495061da546Spatrick         if (m_arch_up->GetRegisterValue((uint32_t)regSet, regIndex, &reg)) {
496061da546Spatrick           reg.Dump(NULL, NULL);
497061da546Spatrick         }
498061da546Spatrick       }
499061da546Spatrick     } else {
500061da546Spatrick       DNBLog("%s: registers are not currently valid.",
501061da546Spatrick              GetRegisterSetName(regSet));
502061da546Spatrick     }
503061da546Spatrick   }
504061da546Spatrick }
505061da546Spatrick 
506061da546Spatrick const DNBRegisterSetInfo *
GetRegisterSetInfo(nub_size_t * num_reg_sets) const507061da546Spatrick MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets) const {
508061da546Spatrick   *num_reg_sets = m_num_reg_sets;
509061da546Spatrick   return &m_reg_sets[0];
510061da546Spatrick }
511061da546Spatrick 
GetRegisterValue(uint32_t set,uint32_t reg,DNBRegisterValue * value)512061da546Spatrick bool MachThread::GetRegisterValue(uint32_t set, uint32_t reg,
513061da546Spatrick                                   DNBRegisterValue *value) {
514061da546Spatrick   return m_arch_up->GetRegisterValue(set, reg, value);
515061da546Spatrick }
516061da546Spatrick 
SetRegisterValue(uint32_t set,uint32_t reg,const DNBRegisterValue * value)517061da546Spatrick bool MachThread::SetRegisterValue(uint32_t set, uint32_t reg,
518061da546Spatrick                                   const DNBRegisterValue *value) {
519061da546Spatrick   return m_arch_up->SetRegisterValue(set, reg, value);
520061da546Spatrick }
521061da546Spatrick 
GetRegisterContext(void * buf,nub_size_t buf_len)522061da546Spatrick nub_size_t MachThread::GetRegisterContext(void *buf, nub_size_t buf_len) {
523061da546Spatrick   return m_arch_up->GetRegisterContext(buf, buf_len);
524061da546Spatrick }
525061da546Spatrick 
SetRegisterContext(const void * buf,nub_size_t buf_len)526061da546Spatrick nub_size_t MachThread::SetRegisterContext(const void *buf, nub_size_t buf_len) {
527061da546Spatrick   return m_arch_up->SetRegisterContext(buf, buf_len);
528061da546Spatrick }
529061da546Spatrick 
SaveRegisterState()530061da546Spatrick uint32_t MachThread::SaveRegisterState() {
531061da546Spatrick   return m_arch_up->SaveRegisterState();
532061da546Spatrick }
RestoreRegisterState(uint32_t save_id)533061da546Spatrick bool MachThread::RestoreRegisterState(uint32_t save_id) {
534061da546Spatrick   return m_arch_up->RestoreRegisterState(save_id);
535061da546Spatrick }
536061da546Spatrick 
EnableHardwareBreakpoint(const DNBBreakpoint * bp,bool also_set_on_task)537dda28197Spatrick uint32_t MachThread::EnableHardwareBreakpoint(const DNBBreakpoint *bp,
538dda28197Spatrick                                               bool also_set_on_task) {
539dda28197Spatrick   if (bp != NULL && bp->IsBreakpoint()) {
540dda28197Spatrick     return m_arch_up->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize(),
541dda28197Spatrick                                                also_set_on_task);
542dda28197Spatrick   }
543061da546Spatrick   return INVALID_NUB_HW_INDEX;
544061da546Spatrick }
545061da546Spatrick 
EnableHardwareWatchpoint(const DNBBreakpoint * wp,bool also_set_on_task)546061da546Spatrick uint32_t MachThread::EnableHardwareWatchpoint(const DNBBreakpoint *wp,
547061da546Spatrick                                               bool also_set_on_task) {
548061da546Spatrick   if (wp != NULL && wp->IsWatchpoint())
549061da546Spatrick     return m_arch_up->EnableHardwareWatchpoint(
550061da546Spatrick         wp->Address(), wp->ByteSize(), wp->WatchpointRead(),
551061da546Spatrick         wp->WatchpointWrite(), also_set_on_task);
552061da546Spatrick   return INVALID_NUB_HW_INDEX;
553061da546Spatrick }
554061da546Spatrick 
RollbackTransForHWP()555061da546Spatrick bool MachThread::RollbackTransForHWP() {
556061da546Spatrick   return m_arch_up->RollbackTransForHWP();
557061da546Spatrick }
558061da546Spatrick 
FinishTransForHWP()559061da546Spatrick bool MachThread::FinishTransForHWP() { return m_arch_up->FinishTransForHWP(); }
560061da546Spatrick 
DisableHardwareBreakpoint(const DNBBreakpoint * bp,bool also_set_on_task)561dda28197Spatrick bool MachThread::DisableHardwareBreakpoint(const DNBBreakpoint *bp,
562dda28197Spatrick                                            bool also_set_on_task) {
563dda28197Spatrick   if (bp != NULL && bp->IsHardware()) {
564dda28197Spatrick     return m_arch_up->DisableHardwareBreakpoint(bp->GetHardwareIndex(),
565dda28197Spatrick                                                 also_set_on_task);
566dda28197Spatrick   }
567061da546Spatrick   return false;
568061da546Spatrick }
569061da546Spatrick 
DisableHardwareWatchpoint(const DNBBreakpoint * wp,bool also_set_on_task)570061da546Spatrick bool MachThread::DisableHardwareWatchpoint(const DNBBreakpoint *wp,
571061da546Spatrick                                            bool also_set_on_task) {
572061da546Spatrick   if (wp != NULL && wp->IsHardware())
573061da546Spatrick     return m_arch_up->DisableHardwareWatchpoint(wp->GetHardwareIndex(),
574061da546Spatrick                                                 also_set_on_task);
575061da546Spatrick   return false;
576061da546Spatrick }
577061da546Spatrick 
NumSupportedHardwareWatchpoints() const578061da546Spatrick uint32_t MachThread::NumSupportedHardwareWatchpoints() const {
579061da546Spatrick   return m_arch_up->NumSupportedHardwareWatchpoints();
580061da546Spatrick }
581061da546Spatrick 
GetIdentifierInfo()582061da546Spatrick bool MachThread::GetIdentifierInfo() {
583061da546Spatrick   // Don't try to get the thread info once and cache it for the life of the
584061da546Spatrick   // thread.  It changes over time, for instance
585061da546Spatrick   // if the thread name changes, then the thread_handle also changes...  So you
586061da546Spatrick   // have to refetch it every time.
587061da546Spatrick   mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
588061da546Spatrick   kern_return_t kret = ::thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO,
589061da546Spatrick                                      (thread_info_t)&m_ident_info, &count);
590061da546Spatrick   return kret == KERN_SUCCESS;
591061da546Spatrick 
592061da546Spatrick   return false;
593061da546Spatrick }
594061da546Spatrick 
GetName()595061da546Spatrick const char *MachThread::GetName() {
596061da546Spatrick   if (GetIdentifierInfo()) {
597061da546Spatrick     int len = ::proc_pidinfo(m_process->ProcessID(), PROC_PIDTHREADINFO,
598061da546Spatrick                              m_ident_info.thread_handle, &m_proc_threadinfo,
599061da546Spatrick                              sizeof(m_proc_threadinfo));
600061da546Spatrick 
601061da546Spatrick     if (len && m_proc_threadinfo.pth_name[0])
602061da546Spatrick       return m_proc_threadinfo.pth_name;
603061da546Spatrick   }
604061da546Spatrick   return NULL;
605061da546Spatrick }
606061da546Spatrick 
607061da546Spatrick uint64_t
GetGloballyUniqueThreadIDForMachPortID(thread_t mach_port_id)608061da546Spatrick MachThread::GetGloballyUniqueThreadIDForMachPortID(thread_t mach_port_id) {
609061da546Spatrick   kern_return_t kr;
610061da546Spatrick   thread_identifier_info_data_t tident;
611061da546Spatrick   mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
612061da546Spatrick   kr = thread_info(mach_port_id, THREAD_IDENTIFIER_INFO, (thread_info_t)&tident,
613061da546Spatrick                    &tident_count);
614061da546Spatrick   if (kr != KERN_SUCCESS) {
615061da546Spatrick     return mach_port_id;
616061da546Spatrick   }
617061da546Spatrick   return tident.thread_id;
618061da546Spatrick }
619061da546Spatrick 
GetPThreadT()620061da546Spatrick nub_addr_t MachThread::GetPThreadT() {
621061da546Spatrick   nub_addr_t pthread_t_value = INVALID_NUB_ADDRESS;
622061da546Spatrick   if (MachPortNumberIsValid(m_mach_port_number)) {
623061da546Spatrick     kern_return_t kr;
624061da546Spatrick     thread_identifier_info_data_t tident;
625061da546Spatrick     mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
626061da546Spatrick     kr = thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO,
627061da546Spatrick                      (thread_info_t)&tident, &tident_count);
628061da546Spatrick     if (kr == KERN_SUCCESS) {
629061da546Spatrick       // Dereference thread_handle to get the pthread_t value for this thread.
630061da546Spatrick       if (m_is_64_bit) {
631061da546Spatrick         uint64_t addr;
632061da546Spatrick         if (m_process->ReadMemory(tident.thread_handle, 8, &addr) == 8) {
633061da546Spatrick           if (addr != 0) {
634061da546Spatrick             pthread_t_value = addr;
635061da546Spatrick           }
636061da546Spatrick         }
637061da546Spatrick       } else {
638061da546Spatrick         uint32_t addr;
639061da546Spatrick         if (m_process->ReadMemory(tident.thread_handle, 4, &addr) == 4) {
640061da546Spatrick           if (addr != 0) {
641061da546Spatrick             pthread_t_value = addr;
642061da546Spatrick           }
643061da546Spatrick         }
644061da546Spatrick       }
645061da546Spatrick     }
646061da546Spatrick   }
647061da546Spatrick   return pthread_t_value;
648061da546Spatrick }
649061da546Spatrick 
650061da546Spatrick // Return this thread's TSD (Thread Specific Data) address.
651061da546Spatrick // This is computed based on this thread's pthread_t value.
652061da546Spatrick //
653061da546Spatrick // We compute the TSD from the pthread_t by one of two methods.
654061da546Spatrick //
655061da546Spatrick // If plo_pthread_tsd_base_offset is non-zero, this is a simple offset that we
656061da546Spatrick // add to
657061da546Spatrick // the pthread_t to get the TSD base address.
658061da546Spatrick //
659061da546Spatrick // Else we read a pointer from memory at pthread_t +
660061da546Spatrick // plo_pthread_tsd_base_address_offset and
661061da546Spatrick // that gives us the TSD address.
662061da546Spatrick //
663061da546Spatrick // These plo_pthread_tsd_base values must be read out of libpthread by lldb &
664061da546Spatrick // provided to debugserver.
665061da546Spatrick 
666061da546Spatrick 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)667061da546Spatrick MachThread::GetTSDAddressForThread(uint64_t plo_pthread_tsd_base_address_offset,
668061da546Spatrick                                    uint64_t plo_pthread_tsd_base_offset,
669061da546Spatrick                                    uint64_t plo_pthread_tsd_entry_size) {
670061da546Spatrick   nub_addr_t tsd_addr = INVALID_NUB_ADDRESS;
671061da546Spatrick   nub_addr_t pthread_t_value = GetPThreadT();
672061da546Spatrick   if (plo_pthread_tsd_base_offset != 0 &&
673061da546Spatrick       plo_pthread_tsd_base_offset != INVALID_NUB_ADDRESS) {
674061da546Spatrick     tsd_addr = pthread_t_value + plo_pthread_tsd_base_offset;
675061da546Spatrick   } else {
676061da546Spatrick     if (plo_pthread_tsd_entry_size == 4) {
677061da546Spatrick       uint32_t addr = 0;
678061da546Spatrick       if (m_process->ReadMemory(pthread_t_value +
679061da546Spatrick                                     plo_pthread_tsd_base_address_offset,
680061da546Spatrick                                 4, &addr) == 4) {
681061da546Spatrick         if (addr != 0) {
682061da546Spatrick           tsd_addr = addr;
683061da546Spatrick         }
684061da546Spatrick       }
685061da546Spatrick     }
686061da546Spatrick     if (plo_pthread_tsd_entry_size == 4) {
687061da546Spatrick       uint64_t addr = 0;
688061da546Spatrick       if (m_process->ReadMemory(pthread_t_value +
689061da546Spatrick                                     plo_pthread_tsd_base_address_offset,
690061da546Spatrick                                 8, &addr) == 8) {
691061da546Spatrick         if (addr != 0) {
692061da546Spatrick           tsd_addr = addr;
693061da546Spatrick         }
694061da546Spatrick       }
695061da546Spatrick     }
696061da546Spatrick   }
697061da546Spatrick   return tsd_addr;
698061da546Spatrick }
699061da546Spatrick 
GetDispatchQueueT()700061da546Spatrick nub_addr_t MachThread::GetDispatchQueueT() {
701061da546Spatrick   nub_addr_t dispatch_queue_t_value = INVALID_NUB_ADDRESS;
702061da546Spatrick   if (MachPortNumberIsValid(m_mach_port_number)) {
703061da546Spatrick     kern_return_t kr;
704061da546Spatrick     thread_identifier_info_data_t tident;
705061da546Spatrick     mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
706061da546Spatrick     kr = thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO,
707061da546Spatrick                      (thread_info_t)&tident, &tident_count);
708061da546Spatrick     if (kr == KERN_SUCCESS && tident.dispatch_qaddr != 0 &&
709061da546Spatrick         tident.dispatch_qaddr != INVALID_NUB_ADDRESS) {
710061da546Spatrick       // Dereference dispatch_qaddr to get the dispatch_queue_t value for this
711061da546Spatrick       // thread's queue, if any.
712061da546Spatrick       if (m_is_64_bit) {
713061da546Spatrick         uint64_t addr;
714061da546Spatrick         if (m_process->ReadMemory(tident.dispatch_qaddr, 8, &addr) == 8) {
715061da546Spatrick           if (addr != 0)
716061da546Spatrick             dispatch_queue_t_value = addr;
717061da546Spatrick         }
718061da546Spatrick       } else {
719061da546Spatrick         uint32_t addr;
720061da546Spatrick         if (m_process->ReadMemory(tident.dispatch_qaddr, 4, &addr) == 4) {
721061da546Spatrick           if (addr != 0)
722061da546Spatrick             dispatch_queue_t_value = addr;
723061da546Spatrick         }
724061da546Spatrick       }
725061da546Spatrick     }
726061da546Spatrick   }
727061da546Spatrick   return dispatch_queue_t_value;
728061da546Spatrick }
729061da546Spatrick 
GetRequestedQoS(nub_addr_t tsd,uint64_t dti_qos_class_index)730061da546Spatrick ThreadInfo::QoS MachThread::GetRequestedQoS(nub_addr_t tsd,
731061da546Spatrick                                             uint64_t dti_qos_class_index) {
732061da546Spatrick   ThreadInfo::QoS qos_value;
733061da546Spatrick   if (MachPortNumberIsValid(m_mach_port_number) &&
734061da546Spatrick       m_pthread_qos_class_decode != nullptr) {
735061da546Spatrick     uint64_t pthread_priority_value = 0;
736061da546Spatrick     if (m_is_64_bit) {
737061da546Spatrick       uint64_t pri;
738061da546Spatrick       if (m_process->ReadMemory(tsd + (dti_qos_class_index * 8), 8, &pri) ==
739061da546Spatrick           8) {
740061da546Spatrick         pthread_priority_value = pri;
741061da546Spatrick       }
742061da546Spatrick     } else {
743061da546Spatrick       uint32_t pri;
744061da546Spatrick       if (m_process->ReadMemory(tsd + (dti_qos_class_index * 4), 4, &pri) ==
745061da546Spatrick           4) {
746061da546Spatrick         pthread_priority_value = pri;
747061da546Spatrick       }
748061da546Spatrick     }
749061da546Spatrick 
750061da546Spatrick     uint32_t requested_qos =
751061da546Spatrick         m_pthread_qos_class_decode(pthread_priority_value, NULL, NULL);
752061da546Spatrick 
753061da546Spatrick     switch (requested_qos) {
754061da546Spatrick     // These constants from <pthread/qos.h>
755061da546Spatrick     case 0x21:
756061da546Spatrick       qos_value.enum_value = requested_qos;
757061da546Spatrick       qos_value.constant_name = "QOS_CLASS_USER_INTERACTIVE";
758061da546Spatrick       qos_value.printable_name = "User Interactive";
759061da546Spatrick       break;
760061da546Spatrick     case 0x19:
761061da546Spatrick       qos_value.enum_value = requested_qos;
762061da546Spatrick       qos_value.constant_name = "QOS_CLASS_USER_INITIATED";
763061da546Spatrick       qos_value.printable_name = "User Initiated";
764061da546Spatrick       break;
765061da546Spatrick     case 0x15:
766061da546Spatrick       qos_value.enum_value = requested_qos;
767061da546Spatrick       qos_value.constant_name = "QOS_CLASS_DEFAULT";
768061da546Spatrick       qos_value.printable_name = "Default";
769061da546Spatrick       break;
770061da546Spatrick     case 0x11:
771061da546Spatrick       qos_value.enum_value = requested_qos;
772061da546Spatrick       qos_value.constant_name = "QOS_CLASS_UTILITY";
773061da546Spatrick       qos_value.printable_name = "Utility";
774061da546Spatrick       break;
775061da546Spatrick     case 0x09:
776061da546Spatrick       qos_value.enum_value = requested_qos;
777061da546Spatrick       qos_value.constant_name = "QOS_CLASS_BACKGROUND";
778061da546Spatrick       qos_value.printable_name = "Background";
779061da546Spatrick       break;
780061da546Spatrick     case 0x00:
781061da546Spatrick       qos_value.enum_value = requested_qos;
782061da546Spatrick       qos_value.constant_name = "QOS_CLASS_UNSPECIFIED";
783061da546Spatrick       qos_value.printable_name = "Unspecified";
784061da546Spatrick       break;
785061da546Spatrick     }
786061da546Spatrick   }
787061da546Spatrick   return qos_value;
788061da546Spatrick }
789