130fdc8d8SChris Lattner //===-- MachThread.cpp ------------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner //
930fdc8d8SChris Lattner // Created by Greg Clayton on 6/19/07.
1030fdc8d8SChris Lattner //
1130fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1230fdc8d8SChris Lattner
13b9c1b51eSKate Stone #include "MachThread.h"
14b9c1b51eSKate Stone #include "DNB.h"
15b9c1b51eSKate Stone #include "DNBLog.h"
16b9c1b51eSKate Stone #include "MachProcess.h"
17b9c1b51eSKate Stone #include "ThreadInfo.h"
18*76e47d48SRaphael Isemann #include <cinttypes>
19b9c1b51eSKate Stone #include <dlfcn.h>
20705b1809SJason Molenda #include <mach/thread_policy.h>
2130fdc8d8SChris Lattner
GetSequenceID()22b9c1b51eSKate Stone static uint32_t GetSequenceID() {
2330fdc8d8SChris Lattner static uint32_t g_nextID = 0;
2430fdc8d8SChris Lattner return ++g_nextID;
2530fdc8d8SChris Lattner }
2630fdc8d8SChris Lattner
MachThread(MachProcess * process,bool is_64_bit,uint64_t unique_thread_id,thread_t mach_port_num)27b9c1b51eSKate Stone MachThread::MachThread(MachProcess *process, bool is_64_bit,
28b9c1b51eSKate Stone uint64_t unique_thread_id, thread_t mach_port_num)
29b9c1b51eSKate Stone : m_process(process), m_unique_id(unique_thread_id),
30b9c1b51eSKate Stone m_mach_port_number(mach_port_num), m_seq_id(GetSequenceID()),
31b9c1b51eSKate Stone m_state(eStateUnloaded), m_state_mutex(PTHREAD_MUTEX_RECURSIVE),
32b9c1b51eSKate Stone m_suspend_count(0), m_stop_exception(),
33d5b44036SJonas Devlieghere m_arch_up(DNBArchProtocol::Create(this)), m_reg_sets(NULL),
34b9c1b51eSKate Stone m_num_reg_sets(0), m_ident_info(), m_proc_threadinfo(),
35b9c1b51eSKate Stone m_dispatch_queue_name(), m_is_64_bit(is_64_bit),
36b9c1b51eSKate Stone m_pthread_qos_class_decode(nullptr) {
37c235ac76SGreg Clayton nub_size_t num_reg_sets = 0;
38d5b44036SJonas Devlieghere m_reg_sets = m_arch_up->GetRegisterSetInfo(&num_reg_sets);
39c235ac76SGreg Clayton m_num_reg_sets = num_reg_sets;
40c235ac76SGreg Clayton
41b9c1b51eSKate Stone m_pthread_qos_class_decode =
42b9c1b51eSKate Stone (unsigned int (*)(unsigned long, int *, unsigned long *))dlsym(
43b9c1b51eSKate Stone RTLD_DEFAULT, "_pthread_qos_class_decode");
44705b1809SJason Molenda
451b946bf6SGreg Clayton // Get the thread state so we know if a thread is in a state where we can't
461b946bf6SGreg Clayton // muck with it and also so we get the suspend count correct in case it was
471b946bf6SGreg Clayton // already suspended
48cdc7322bSGreg Clayton GetBasicInfo();
49b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE,
50b9c1b51eSKate Stone "MachThread::MachThread ( process = %p, tid = 0x%8.8" PRIx64
51b9c1b51eSKate Stone ", seq_id = %u )",
5265fdb342SRaphael Isemann static_cast<void *>(&m_process), m_unique_id, m_seq_id);
5330fdc8d8SChris Lattner }
5430fdc8d8SChris Lattner
~MachThread()55b9c1b51eSKate Stone MachThread::~MachThread() {
56b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE,
57b9c1b51eSKate Stone "MachThread::~MachThread() for tid = 0x%8.8" PRIx64 " (%u)",
58b9c1b51eSKate Stone m_unique_id, m_seq_id);
5930fdc8d8SChris Lattner }
6030fdc8d8SChris Lattner
Suspend()61b9c1b51eSKate Stone void MachThread::Suspend() {
62b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )",
63b9c1b51eSKate Stone __FUNCTION__);
64b9c1b51eSKate Stone if (MachPortNumberIsValid(m_mach_port_number)) {
651c73911dSJason Molenda DNBError err(::thread_suspend(m_mach_port_number), DNBError::MachKernel);
6630fdc8d8SChris Lattner if (err.Success())
67c235ac76SGreg Clayton m_suspend_count++;
6830fdc8d8SChris Lattner if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
691c73911dSJason Molenda err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number);
7030fdc8d8SChris Lattner }
7130fdc8d8SChris Lattner }
7230fdc8d8SChris Lattner
Resume(bool others_stopped)73b9c1b51eSKate Stone void MachThread::Resume(bool others_stopped) {
74b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )",
75b9c1b51eSKate Stone __FUNCTION__);
76b9c1b51eSKate Stone if (MachPortNumberIsValid(m_mach_port_number)) {
779411ddb6SJim Ingham SetSuspendCountBeforeResume(others_stopped);
7830fdc8d8SChris Lattner }
7930fdc8d8SChris Lattner }
8030fdc8d8SChris Lattner
SetSuspendCountBeforeResume(bool others_stopped)81b9c1b51eSKate Stone bool MachThread::SetSuspendCountBeforeResume(bool others_stopped) {
82b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )",
83b9c1b51eSKate Stone __FUNCTION__);
8430fdc8d8SChris Lattner DNBError err;
85a6682a41SJonas Devlieghere if (!MachPortNumberIsValid(m_mach_port_number))
8630fdc8d8SChris Lattner return false;
879411ddb6SJim Ingham
88ee2ed525SGreg Clayton integer_t times_to_resume;
899411ddb6SJim Ingham
90b9c1b51eSKate Stone if (others_stopped) {
91b9c1b51eSKate Stone if (GetBasicInfo()) {
9282283e8eSJim Ingham times_to_resume = m_basic_info.suspend_count;
93c235ac76SGreg Clayton m_suspend_count = -(times_to_resume - m_suspend_count);
94b9c1b51eSKate Stone } else
9582283e8eSJim Ingham times_to_resume = 0;
96b9c1b51eSKate Stone } else {
97c235ac76SGreg Clayton times_to_resume = m_suspend_count;
98c235ac76SGreg Clayton m_suspend_count = 0;
999411ddb6SJim Ingham }
1009411ddb6SJim Ingham
101b9c1b51eSKate Stone if (times_to_resume > 0) {
102b9c1b51eSKate Stone while (times_to_resume > 0) {
1031c73911dSJason Molenda err = ::thread_resume(m_mach_port_number);
1049411ddb6SJim Ingham if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
1051c73911dSJason Molenda err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number);
1069411ddb6SJim Ingham if (err.Success())
1079411ddb6SJim Ingham --times_to_resume;
108b9c1b51eSKate Stone else {
1099411ddb6SJim Ingham if (GetBasicInfo())
110c235ac76SGreg Clayton times_to_resume = m_basic_info.suspend_count;
1119411ddb6SJim Ingham else
1129411ddb6SJim Ingham times_to_resume = 0;
1139411ddb6SJim Ingham }
1149411ddb6SJim Ingham }
1159411ddb6SJim Ingham }
1169411ddb6SJim Ingham return true;
1179411ddb6SJim Ingham }
1189411ddb6SJim Ingham
RestoreSuspendCountAfterStop()119b9c1b51eSKate Stone bool MachThread::RestoreSuspendCountAfterStop() {
120b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )",
121b9c1b51eSKate Stone __FUNCTION__);
1229411ddb6SJim Ingham DNBError err;
123a6682a41SJonas Devlieghere if (!MachPortNumberIsValid(m_mach_port_number))
1249411ddb6SJim Ingham return false;
1259411ddb6SJim Ingham
126b9c1b51eSKate Stone if (m_suspend_count > 0) {
127b9c1b51eSKate Stone while (m_suspend_count > 0) {
1281c73911dSJason Molenda err = ::thread_resume(m_mach_port_number);
12930fdc8d8SChris Lattner if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail())
1301c73911dSJason Molenda err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number);
13130fdc8d8SChris Lattner if (err.Success())
132c235ac76SGreg Clayton --m_suspend_count;
133b9c1b51eSKate Stone else {
134cdc7322bSGreg Clayton if (GetBasicInfo())
135c235ac76SGreg Clayton m_suspend_count = m_basic_info.suspend_count;
1360dd2c627SGreg Clayton else
137c235ac76SGreg Clayton m_suspend_count = 0;
1380dd2c627SGreg Clayton return false; // ???
13930fdc8d8SChris Lattner }
14030fdc8d8SChris Lattner }
141b9c1b51eSKate Stone } else if (m_suspend_count < 0) {
142b9c1b51eSKate Stone while (m_suspend_count < 0) {
1431c73911dSJason Molenda err = ::thread_suspend(m_mach_port_number);
1449411ddb6SJim Ingham if (err.Success())
145c235ac76SGreg Clayton ++m_suspend_count;
146b9c1b51eSKate Stone if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) {
147b9c1b51eSKate Stone err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")",
148b9c1b51eSKate Stone m_mach_port_number);
149478235d8SJim Ingham return false;
150478235d8SJim Ingham }
1519411ddb6SJim Ingham }
1529411ddb6SJim Ingham }
1530dd2c627SGreg Clayton return true;
15430fdc8d8SChris Lattner }
15530fdc8d8SChris Lattner
GetBasicInfoAsString() const156b9c1b51eSKate Stone const char *MachThread::GetBasicInfoAsString() const {
15730fdc8d8SChris Lattner static char g_basic_info_string[1024];
15830fdc8d8SChris Lattner struct thread_basic_info basicInfo;
15930fdc8d8SChris Lattner
160b9c1b51eSKate Stone if (GetBasicInfo(m_mach_port_number, &basicInfo)) {
16130fdc8d8SChris Lattner
16230fdc8d8SChris Lattner // char run_state_str[32];
16330fdc8d8SChris Lattner // size_t run_state_str_size = sizeof(run_state_str);
16430fdc8d8SChris Lattner // switch (basicInfo.run_state)
16530fdc8d8SChris Lattner // {
166aae5b690SJason Molenda // case TH_STATE_RUNNING: strlcpy(run_state_str, "running",
167b9c1b51eSKate Stone // run_state_str_size); break;
168aae5b690SJason Molenda // case TH_STATE_STOPPED: strlcpy(run_state_str, "stopped",
169b9c1b51eSKate Stone // run_state_str_size); break;
170aae5b690SJason Molenda // case TH_STATE_WAITING: strlcpy(run_state_str, "waiting",
171b9c1b51eSKate Stone // run_state_str_size); break;
172aae5b690SJason Molenda // case TH_STATE_UNINTERRUPTIBLE: strlcpy(run_state_str,
173b9c1b51eSKate Stone // "uninterruptible", run_state_str_size); break;
174aae5b690SJason Molenda // case TH_STATE_HALTED: strlcpy(run_state_str, "halted",
175b9c1b51eSKate Stone // run_state_str_size); break;
176b9c1b51eSKate Stone // default: snprintf(run_state_str,
177b9c1b51eSKate Stone // run_state_str_size, "%d", basicInfo.run_state); break; // ???
17830fdc8d8SChris Lattner // }
179b9c1b51eSKate Stone float user = (float)basicInfo.user_time.seconds +
180b9c1b51eSKate Stone (float)basicInfo.user_time.microseconds / 1000000.0f;
181b9c1b51eSKate Stone float system = (float)basicInfo.user_time.seconds +
182b9c1b51eSKate Stone (float)basicInfo.user_time.microseconds / 1000000.0f;
183b9c1b51eSKate Stone snprintf(g_basic_info_string, sizeof(g_basic_info_string),
184b9c1b51eSKate Stone "Thread 0x%8.8" PRIx64 ": user=%f system=%f cpu=%d sleep_time=%d",
185b9c1b51eSKate Stone m_unique_id, user, system, basicInfo.cpu_usage,
18630fdc8d8SChris Lattner basicInfo.sleep_time);
18730fdc8d8SChris Lattner
18830fdc8d8SChris Lattner return g_basic_info_string;
18930fdc8d8SChris Lattner }
19030fdc8d8SChris Lattner return NULL;
19130fdc8d8SChris Lattner }
19230fdc8d8SChris Lattner
193b9c1b51eSKate Stone // Finds the Mach port number for a given thread in the inferior process' port
194b9c1b51eSKate Stone // namespace.
InferiorThreadID() const195b9c1b51eSKate Stone thread_t MachThread::InferiorThreadID() const {
19630fdc8d8SChris Lattner mach_msg_type_number_t i;
19730fdc8d8SChris Lattner mach_port_name_array_t names;
19830fdc8d8SChris Lattner mach_port_type_array_t types;
19930fdc8d8SChris Lattner mach_msg_type_number_t ncount, tcount;
20030fdc8d8SChris Lattner thread_t inferior_tid = INVALID_NUB_THREAD;
20130fdc8d8SChris Lattner task_t my_task = ::mach_task_self();
20230fdc8d8SChris Lattner task_t task = m_process->Task().TaskPort();
20330fdc8d8SChris Lattner
204b9c1b51eSKate Stone kern_return_t kret =
205b9c1b51eSKate Stone ::mach_port_names(task, &names, &ncount, &types, &tcount);
206b9c1b51eSKate Stone if (kret == KERN_SUCCESS) {
20730fdc8d8SChris Lattner
208b9c1b51eSKate Stone for (i = 0; i < ncount; i++) {
20930fdc8d8SChris Lattner mach_port_t my_name;
21030fdc8d8SChris Lattner mach_msg_type_name_t my_type;
21130fdc8d8SChris Lattner
212b9c1b51eSKate Stone kret = ::mach_port_extract_right(task, names[i], MACH_MSG_TYPE_COPY_SEND,
213b9c1b51eSKate Stone &my_name, &my_type);
214b9c1b51eSKate Stone if (kret == KERN_SUCCESS) {
21530fdc8d8SChris Lattner ::mach_port_deallocate(my_task, my_name);
216b9c1b51eSKate Stone if (my_name == m_mach_port_number) {
21730fdc8d8SChris Lattner inferior_tid = names[i];
21830fdc8d8SChris Lattner break;
21930fdc8d8SChris Lattner }
22030fdc8d8SChris Lattner }
22130fdc8d8SChris Lattner }
22230fdc8d8SChris Lattner // Free up the names and types
223b9c1b51eSKate Stone ::vm_deallocate(my_task, (vm_address_t)names,
224b9c1b51eSKate Stone ncount * sizeof(mach_port_name_t));
225b9c1b51eSKate Stone ::vm_deallocate(my_task, (vm_address_t)types,
226b9c1b51eSKate Stone tcount * sizeof(mach_port_type_t));
22730fdc8d8SChris Lattner }
22830fdc8d8SChris Lattner return inferior_tid;
22930fdc8d8SChris Lattner }
23030fdc8d8SChris Lattner
IsUserReady()231b9c1b51eSKate Stone bool MachThread::IsUserReady() {
232c235ac76SGreg Clayton if (m_basic_info.run_state == 0)
233cdc7322bSGreg Clayton GetBasicInfo();
2341b946bf6SGreg Clayton
235b9c1b51eSKate Stone switch (m_basic_info.run_state) {
2361b946bf6SGreg Clayton default:
2371b946bf6SGreg Clayton case TH_STATE_UNINTERRUPTIBLE:
2381b946bf6SGreg Clayton break;
2391b946bf6SGreg Clayton
2401b946bf6SGreg Clayton case TH_STATE_RUNNING:
2411b946bf6SGreg Clayton case TH_STATE_STOPPED:
2421b946bf6SGreg Clayton case TH_STATE_WAITING:
2431b946bf6SGreg Clayton case TH_STATE_HALTED:
2441b946bf6SGreg Clayton return true;
2451b946bf6SGreg Clayton }
246fcda044dSFrederic Riss return GetPC(0) != 0;
2471b946bf6SGreg Clayton }
2481b946bf6SGreg Clayton
GetBasicInfo()249b9c1b51eSKate Stone struct thread_basic_info *MachThread::GetBasicInfo() {
2501c73911dSJason Molenda if (MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info))
251c235ac76SGreg Clayton return &m_basic_info;
2521b946bf6SGreg Clayton return NULL;
2531b946bf6SGreg Clayton }
2541b946bf6SGreg Clayton
GetBasicInfo(thread_t thread,struct thread_basic_info * basicInfoPtr)255b9c1b51eSKate Stone bool MachThread::GetBasicInfo(thread_t thread,
256b9c1b51eSKate Stone struct thread_basic_info *basicInfoPtr) {
257b9c1b51eSKate Stone if (MachPortNumberIsValid(thread)) {
25830fdc8d8SChris Lattner unsigned int info_count = THREAD_BASIC_INFO_COUNT;
259b9c1b51eSKate Stone kern_return_t err = ::thread_info(thread, THREAD_BASIC_INFO,
260b9c1b51eSKate Stone (thread_info_t)basicInfoPtr, &info_count);
26130fdc8d8SChris Lattner if (err == KERN_SUCCESS)
26230fdc8d8SChris Lattner return true;
26330fdc8d8SChris Lattner }
26430fdc8d8SChris Lattner ::memset(basicInfoPtr, 0, sizeof(struct thread_basic_info));
26530fdc8d8SChris Lattner return false;
26630fdc8d8SChris Lattner }
26730fdc8d8SChris Lattner
ThreadIDIsValid(uint64_t thread)268b9c1b51eSKate Stone bool MachThread::ThreadIDIsValid(uint64_t thread) { return thread != 0; }
26930fdc8d8SChris Lattner
MachPortNumberIsValid(thread_t thread)270b9c1b51eSKate Stone bool MachThread::MachPortNumberIsValid(thread_t thread) {
27130fdc8d8SChris Lattner return thread != THREAD_NULL;
27230fdc8d8SChris Lattner }
27330fdc8d8SChris Lattner
GetRegisterState(int flavor,bool force)274b9c1b51eSKate Stone bool MachThread::GetRegisterState(int flavor, bool force) {
275d5b44036SJonas Devlieghere return m_arch_up->GetRegisterState(flavor, force) == KERN_SUCCESS;
27630fdc8d8SChris Lattner }
27730fdc8d8SChris Lattner
SetRegisterState(int flavor)278b9c1b51eSKate Stone bool MachThread::SetRegisterState(int flavor) {
279d5b44036SJonas Devlieghere return m_arch_up->SetRegisterState(flavor) == KERN_SUCCESS;
28030fdc8d8SChris Lattner }
28130fdc8d8SChris Lattner
GetPC(uint64_t failValue)282b9c1b51eSKate Stone uint64_t MachThread::GetPC(uint64_t failValue) {
28330fdc8d8SChris Lattner // Get program counter
284d5b44036SJonas Devlieghere return m_arch_up->GetPC(failValue);
28530fdc8d8SChris Lattner }
28630fdc8d8SChris Lattner
SetPC(uint64_t value)287b9c1b51eSKate Stone bool MachThread::SetPC(uint64_t value) {
28830fdc8d8SChris Lattner // Set program counter
289d5b44036SJonas Devlieghere return m_arch_up->SetPC(value);
29030fdc8d8SChris Lattner }
29130fdc8d8SChris Lattner
GetSP(uint64_t failValue)292b9c1b51eSKate Stone uint64_t MachThread::GetSP(uint64_t failValue) {
29330fdc8d8SChris Lattner // Get stack pointer
294d5b44036SJonas Devlieghere return m_arch_up->GetSP(failValue);
29530fdc8d8SChris Lattner }
29630fdc8d8SChris Lattner
ProcessID() const297b9c1b51eSKate Stone nub_process_t MachThread::ProcessID() const {
29830fdc8d8SChris Lattner if (m_process)
29930fdc8d8SChris Lattner return m_process->ProcessID();
30030fdc8d8SChris Lattner return INVALID_NUB_PROCESS;
30130fdc8d8SChris Lattner }
30230fdc8d8SChris Lattner
Dump(uint32_t index)303b9c1b51eSKate Stone void MachThread::Dump(uint32_t index) {
30430fdc8d8SChris Lattner const char *thread_run_state = NULL;
30530fdc8d8SChris Lattner
306b9c1b51eSKate Stone switch (m_basic_info.run_state) {
307b9c1b51eSKate Stone case TH_STATE_RUNNING:
308b9c1b51eSKate Stone thread_run_state = "running";
309b9c1b51eSKate Stone break; // 1 thread is running normally
310b9c1b51eSKate Stone case TH_STATE_STOPPED:
311b9c1b51eSKate Stone thread_run_state = "stopped";
312b9c1b51eSKate Stone break; // 2 thread is stopped
313b9c1b51eSKate Stone case TH_STATE_WAITING:
314b9c1b51eSKate Stone thread_run_state = "waiting";
315b9c1b51eSKate Stone break; // 3 thread is waiting normally
316b9c1b51eSKate Stone case TH_STATE_UNINTERRUPTIBLE:
317b9c1b51eSKate Stone thread_run_state = "uninter";
318b9c1b51eSKate Stone break; // 4 thread is in an uninterruptible wait
319b9c1b51eSKate Stone case TH_STATE_HALTED:
320b9c1b51eSKate Stone thread_run_state = "halted ";
321b9c1b51eSKate Stone break; // 5 thread is halted at a
322b9c1b51eSKate Stone default:
323b9c1b51eSKate Stone thread_run_state = "???";
324b9c1b51eSKate Stone break;
32530fdc8d8SChris Lattner }
32630fdc8d8SChris Lattner
327b9c1b51eSKate Stone DNBLogThreaded(
328b9c1b51eSKate Stone "[%3u] #%3u tid: 0x%8.8" PRIx64 ", pc: 0x%16.16" PRIx64
329b9c1b51eSKate Stone ", sp: 0x%16.16" PRIx64
330b9c1b51eSKate Stone ", user: %d.%6.6d, system: %d.%6.6d, cpu: %2d, policy: %2d, run_state: "
331b9c1b51eSKate Stone "%2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d",
332b9c1b51eSKate Stone index, m_seq_id, m_unique_id, GetPC(INVALID_NUB_ADDRESS),
333b9c1b51eSKate Stone GetSP(INVALID_NUB_ADDRESS), m_basic_info.user_time.seconds,
334b9c1b51eSKate Stone m_basic_info.user_time.microseconds, m_basic_info.system_time.seconds,
335b9c1b51eSKate Stone m_basic_info.system_time.microseconds, m_basic_info.cpu_usage,
336b9c1b51eSKate Stone m_basic_info.policy, m_basic_info.run_state, thread_run_state,
337b9c1b51eSKate Stone m_basic_info.flags, m_basic_info.suspend_count, m_suspend_count,
338c235ac76SGreg Clayton m_basic_info.sleep_time);
33930fdc8d8SChris Lattner // DumpRegisterState(0);
34030fdc8d8SChris Lattner }
34130fdc8d8SChris Lattner
ThreadWillResume(const DNBThreadResumeAction * thread_action,bool others_stopped)342b9c1b51eSKate Stone void MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action,
343b9c1b51eSKate Stone bool others_stopped) {
34430fdc8d8SChris Lattner if (thread_action->addr != INVALID_NUB_ADDRESS)
34530fdc8d8SChris Lattner SetPC(thread_action->addr);
346cdc7322bSGreg Clayton
34730fdc8d8SChris Lattner SetState(thread_action->state);
348b9c1b51eSKate Stone switch (thread_action->state) {
34930fdc8d8SChris Lattner case eStateStopped:
35030fdc8d8SChris Lattner case eStateSuspended:
3519411ddb6SJim Ingham assert(others_stopped == false);
35230fdc8d8SChris Lattner Suspend();
35330fdc8d8SChris Lattner break;
35430fdc8d8SChris Lattner
35530fdc8d8SChris Lattner case eStateRunning:
356b1e11121SJim Ingham case eStateStepping:
3579411ddb6SJim Ingham Resume(others_stopped);
358b1e11121SJim Ingham break;
359effe5c95SGreg Clayton default:
360effe5c95SGreg Clayton break;
36130fdc8d8SChris Lattner }
362d5b44036SJonas Devlieghere m_arch_up->ThreadWillResume();
36330fdc8d8SChris Lattner m_stop_exception.Clear();
36430fdc8d8SChris Lattner }
36530fdc8d8SChris Lattner
CurrentBreakpoint()366b9c1b51eSKate Stone DNBBreakpoint *MachThread::CurrentBreakpoint() {
367d8cf1a11SGreg Clayton return m_process->Breakpoints().FindByAddress(GetPC());
368c4e411ffSGreg Clayton }
369c4e411ffSGreg Clayton
ShouldStop(bool & step_more)370b9c1b51eSKate Stone bool MachThread::ShouldStop(bool &step_more) {
37130fdc8d8SChris Lattner // See if this thread is at a breakpoint?
372d8cf1a11SGreg Clayton DNBBreakpoint *bp = CurrentBreakpoint();
37330fdc8d8SChris Lattner
374b9c1b51eSKate Stone if (bp) {
37530fdc8d8SChris Lattner // This thread is sitting at a breakpoint, ask the breakpoint
37630fdc8d8SChris Lattner // if we should be stopping here.
37730fdc8d8SChris Lattner return true;
378b9c1b51eSKate Stone } else {
379d5b44036SJonas Devlieghere if (m_arch_up->StepNotComplete()) {
38030fdc8d8SChris Lattner step_more = true;
38130fdc8d8SChris Lattner return false;
38230fdc8d8SChris Lattner }
38330fdc8d8SChris Lattner // The thread state is used to let us know what the thread was
38430fdc8d8SChris Lattner // trying to do. MachThread::ThreadWillResume() will set the
38530fdc8d8SChris Lattner // thread state to various values depending if the thread was
38630fdc8d8SChris Lattner // the current thread and if it was to be single stepped, or
38730fdc8d8SChris Lattner // resumed.
388b9c1b51eSKate Stone if (GetState() == eStateRunning) {
38930fdc8d8SChris Lattner // If our state is running, then we should continue as we are in
39030fdc8d8SChris Lattner // the process of stepping over a breakpoint.
39130fdc8d8SChris Lattner return false;
392b9c1b51eSKate Stone } else {
39330fdc8d8SChris Lattner // Stop if we have any kind of valid exception for this
39430fdc8d8SChris Lattner // thread.
39530fdc8d8SChris Lattner if (GetStopException().IsValid())
39630fdc8d8SChris Lattner return true;
39730fdc8d8SChris Lattner }
39830fdc8d8SChris Lattner }
39930fdc8d8SChris Lattner return false;
40030fdc8d8SChris Lattner }
IsStepping()401b9c1b51eSKate Stone bool MachThread::IsStepping() { return GetState() == eStateStepping; }
40230fdc8d8SChris Lattner
ThreadDidStop()403b9c1b51eSKate Stone bool MachThread::ThreadDidStop() {
40430fdc8d8SChris Lattner // This thread has existed prior to resuming under debug nub control,
40530fdc8d8SChris Lattner // and has just been stopped. Do any cleanup that needs to be done
40630fdc8d8SChris Lattner // after running.
40730fdc8d8SChris Lattner
40830fdc8d8SChris Lattner // The thread state and breakpoint will still have the same values
40930fdc8d8SChris Lattner // as they had prior to resuming the thread, so it makes it easy to check
41030fdc8d8SChris Lattner // if we were trying to step a thread, or we tried to resume while being
41130fdc8d8SChris Lattner // at a breakpoint.
41230fdc8d8SChris Lattner
41330fdc8d8SChris Lattner // When this method gets called, the process state is still in the
41430fdc8d8SChris Lattner // state it was in while running so we can act accordingly.
415d5b44036SJonas Devlieghere m_arch_up->ThreadDidStop();
41630fdc8d8SChris Lattner
41730fdc8d8SChris Lattner // We may have suspended this thread so the primary thread could step
41830fdc8d8SChris Lattner // without worrying about race conditions, so lets restore our suspend
41930fdc8d8SChris Lattner // count.
4209411ddb6SJim Ingham RestoreSuspendCountAfterStop();
42130fdc8d8SChris Lattner
42230fdc8d8SChris Lattner // Update the basic information for a thread
4231c73911dSJason Molenda MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info);
42430fdc8d8SChris Lattner
425c235ac76SGreg Clayton if (m_basic_info.suspend_count > 0)
426c4e411ffSGreg Clayton SetState(eStateSuspended);
427c4e411ffSGreg Clayton else
428c4e411ffSGreg Clayton SetState(eStateStopped);
42930fdc8d8SChris Lattner return true;
43030fdc8d8SChris Lattner }
43130fdc8d8SChris Lattner
NotifyException(MachException::Data & exc)432b9c1b51eSKate Stone bool MachThread::NotifyException(MachException::Data &exc) {
43388c1b77fSJohnny Chen // Allow the arch specific protocol to process (MachException::Data &)exc
43488c1b77fSJohnny Chen // first before possible reassignment of m_stop_exception with exc.
43576abb3b5SJohnny Chen // See also MachThread::GetStopException().
436d5b44036SJonas Devlieghere bool handled = m_arch_up->NotifyException(exc);
43788c1b77fSJohnny Chen
438b9c1b51eSKate Stone if (m_stop_exception.IsValid()) {
43930fdc8d8SChris Lattner // We may have more than one exception for a thread, but we need to
44030fdc8d8SChris Lattner // only remember the one that we will say is the reason we stopped.
44130fdc8d8SChris Lattner // We may have been single stepping and also gotten a signal exception,
44230fdc8d8SChris Lattner // so just remember the most pertinent one.
44330fdc8d8SChris Lattner if (m_stop_exception.IsBreakpoint())
44430fdc8d8SChris Lattner m_stop_exception = exc;
445b9c1b51eSKate Stone } else {
44630fdc8d8SChris Lattner m_stop_exception = exc;
44730fdc8d8SChris Lattner }
44888c1b77fSJohnny Chen
44930fdc8d8SChris Lattner return handled;
45030fdc8d8SChris Lattner }
45130fdc8d8SChris Lattner
GetState()452b9c1b51eSKate Stone nub_state_t MachThread::GetState() {
45330fdc8d8SChris Lattner // If any other threads access this we will need a mutex for it
45430fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_state_mutex);
45530fdc8d8SChris Lattner return m_state;
45630fdc8d8SChris Lattner }
45730fdc8d8SChris Lattner
SetState(nub_state_t state)458b9c1b51eSKate Stone void MachThread::SetState(nub_state_t state) {
45930fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_state_mutex);
46030fdc8d8SChris Lattner m_state = state;
461b9c1b51eSKate Stone DNBLogThreadedIf(LOG_THREAD,
462b9c1b51eSKate Stone "MachThread::SetState ( %s ) for tid = 0x%8.8" PRIx64 "",
463b9c1b51eSKate Stone DNBStateAsString(state), m_unique_id);
46430fdc8d8SChris Lattner }
46530fdc8d8SChris Lattner
GetNumRegistersInSet(nub_size_t regSet) const466b9c1b51eSKate Stone nub_size_t MachThread::GetNumRegistersInSet(nub_size_t regSet) const {
467c235ac76SGreg Clayton if (regSet < m_num_reg_sets)
4683af9ea56SGreg Clayton return m_reg_sets[regSet].num_registers;
46930fdc8d8SChris Lattner return 0;
47030fdc8d8SChris Lattner }
47130fdc8d8SChris Lattner
GetRegisterSetName(nub_size_t regSet) const472b9c1b51eSKate Stone const char *MachThread::GetRegisterSetName(nub_size_t regSet) const {
473c235ac76SGreg Clayton if (regSet < m_num_reg_sets)
4743af9ea56SGreg Clayton return m_reg_sets[regSet].name;
47530fdc8d8SChris Lattner return NULL;
47630fdc8d8SChris Lattner }
47730fdc8d8SChris Lattner
GetRegisterInfo(nub_size_t regSet,nub_size_t regIndex) const478b9c1b51eSKate Stone const DNBRegisterInfo *MachThread::GetRegisterInfo(nub_size_t regSet,
479b9c1b51eSKate Stone nub_size_t regIndex) const {
480c235ac76SGreg Clayton if (regSet < m_num_reg_sets)
4813af9ea56SGreg Clayton if (regIndex < m_reg_sets[regSet].num_registers)
4823af9ea56SGreg Clayton return &m_reg_sets[regSet].registers[regIndex];
48330fdc8d8SChris Lattner return NULL;
48430fdc8d8SChris Lattner }
DumpRegisterState(nub_size_t regSet)485b9c1b51eSKate Stone void MachThread::DumpRegisterState(nub_size_t regSet) {
486b9c1b51eSKate Stone if (regSet == REGISTER_SET_ALL) {
487c235ac76SGreg Clayton for (regSet = 1; regSet < m_num_reg_sets; regSet++)
48830fdc8d8SChris Lattner DumpRegisterState(regSet);
489b9c1b51eSKate Stone } else {
490d5b44036SJonas Devlieghere if (m_arch_up->RegisterSetStateIsValid((int)regSet)) {
49130fdc8d8SChris Lattner const size_t numRegisters = GetNumRegistersInSet(regSet);
492ee2ed525SGreg Clayton uint32_t regIndex = 0;
49330fdc8d8SChris Lattner DNBRegisterValueClass reg;
494b9c1b51eSKate Stone for (regIndex = 0; regIndex < numRegisters; ++regIndex) {
495d5b44036SJonas Devlieghere if (m_arch_up->GetRegisterValue((uint32_t)regSet, regIndex, ®)) {
49630fdc8d8SChris Lattner reg.Dump(NULL, NULL);
49730fdc8d8SChris Lattner }
49830fdc8d8SChris Lattner }
499b9c1b51eSKate Stone } else {
500b9c1b51eSKate Stone DNBLog("%s: registers are not currently valid.",
501b9c1b51eSKate Stone GetRegisterSetName(regSet));
50230fdc8d8SChris Lattner }
50330fdc8d8SChris Lattner }
50430fdc8d8SChris Lattner }
50530fdc8d8SChris Lattner
50630fdc8d8SChris Lattner const DNBRegisterSetInfo *
GetRegisterSetInfo(nub_size_t * num_reg_sets) const507b9c1b51eSKate Stone MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets) const {
508c235ac76SGreg Clayton *num_reg_sets = m_num_reg_sets;
5093af9ea56SGreg Clayton return &m_reg_sets[0];
51030fdc8d8SChris Lattner }
51130fdc8d8SChris Lattner
GetRegisterValue(uint32_t set,uint32_t reg,DNBRegisterValue * value)512b9c1b51eSKate Stone bool MachThread::GetRegisterValue(uint32_t set, uint32_t reg,
513b9c1b51eSKate Stone DNBRegisterValue *value) {
514d5b44036SJonas Devlieghere return m_arch_up->GetRegisterValue(set, reg, value);
51530fdc8d8SChris Lattner }
51630fdc8d8SChris Lattner
SetRegisterValue(uint32_t set,uint32_t reg,const DNBRegisterValue * value)517b9c1b51eSKate Stone bool MachThread::SetRegisterValue(uint32_t set, uint32_t reg,
518b9c1b51eSKate Stone const DNBRegisterValue *value) {
519d5b44036SJonas Devlieghere return m_arch_up->SetRegisterValue(set, reg, value);
52030fdc8d8SChris Lattner }
52130fdc8d8SChris Lattner
GetRegisterContext(void * buf,nub_size_t buf_len)522b9c1b51eSKate Stone nub_size_t MachThread::GetRegisterContext(void *buf, nub_size_t buf_len) {
523d5b44036SJonas Devlieghere return m_arch_up->GetRegisterContext(buf, buf_len);
52430fdc8d8SChris Lattner }
52530fdc8d8SChris Lattner
SetRegisterContext(const void * buf,nub_size_t buf_len)526b9c1b51eSKate Stone nub_size_t MachThread::SetRegisterContext(const void *buf, nub_size_t buf_len) {
527d5b44036SJonas Devlieghere return m_arch_up->SetRegisterContext(buf, buf_len);
52830fdc8d8SChris Lattner }
52930fdc8d8SChris Lattner
SaveRegisterState()530b9c1b51eSKate Stone uint32_t MachThread::SaveRegisterState() {
531d5b44036SJonas Devlieghere return m_arch_up->SaveRegisterState();
532f74cf86bSGreg Clayton }
RestoreRegisterState(uint32_t save_id)533b9c1b51eSKate Stone bool MachThread::RestoreRegisterState(uint32_t save_id) {
534d5b44036SJonas Devlieghere return m_arch_up->RestoreRegisterState(save_id);
535f74cf86bSGreg Clayton }
536f74cf86bSGreg Clayton
EnableHardwareBreakpoint(const DNBBreakpoint * bp,bool also_set_on_task)5379902c8e3SJonas Devlieghere uint32_t MachThread::EnableHardwareBreakpoint(const DNBBreakpoint *bp,
5389902c8e3SJonas Devlieghere bool also_set_on_task) {
5399902c8e3SJonas Devlieghere if (bp != NULL && bp->IsBreakpoint()) {
5409902c8e3SJonas Devlieghere return m_arch_up->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize(),
5419902c8e3SJonas Devlieghere also_set_on_task);
5429902c8e3SJonas Devlieghere }
54330fdc8d8SChris Lattner return INVALID_NUB_HW_INDEX;
54430fdc8d8SChris Lattner }
54530fdc8d8SChris Lattner
EnableHardwareWatchpoint(const DNBBreakpoint * wp,bool also_set_on_task)546b9c1b51eSKate Stone uint32_t MachThread::EnableHardwareWatchpoint(const DNBBreakpoint *wp,
547b9c1b51eSKate Stone bool also_set_on_task) {
54830fdc8d8SChris Lattner if (wp != NULL && wp->IsWatchpoint())
549d5b44036SJonas Devlieghere return m_arch_up->EnableHardwareWatchpoint(
550b9c1b51eSKate Stone wp->Address(), wp->ByteSize(), wp->WatchpointRead(),
551b9c1b51eSKate Stone wp->WatchpointWrite(), also_set_on_task);
55230fdc8d8SChris Lattner return INVALID_NUB_HW_INDEX;
55330fdc8d8SChris Lattner }
55430fdc8d8SChris Lattner
RollbackTransForHWP()555b9c1b51eSKate Stone bool MachThread::RollbackTransForHWP() {
556d5b44036SJonas Devlieghere return m_arch_up->RollbackTransForHWP();
55784707560SJohnny Chen }
55884707560SJohnny Chen
FinishTransForHWP()559d5b44036SJonas Devlieghere bool MachThread::FinishTransForHWP() { return m_arch_up->FinishTransForHWP(); }
56084707560SJohnny Chen
DisableHardwareBreakpoint(const DNBBreakpoint * bp,bool also_set_on_task)5619902c8e3SJonas Devlieghere bool MachThread::DisableHardwareBreakpoint(const DNBBreakpoint *bp,
5629902c8e3SJonas Devlieghere bool also_set_on_task) {
5639902c8e3SJonas Devlieghere if (bp != NULL && bp->IsHardware()) {
5649902c8e3SJonas Devlieghere return m_arch_up->DisableHardwareBreakpoint(bp->GetHardwareIndex(),
5659902c8e3SJonas Devlieghere also_set_on_task);
5669902c8e3SJonas Devlieghere }
56730fdc8d8SChris Lattner return false;
56830fdc8d8SChris Lattner }
56930fdc8d8SChris Lattner
DisableHardwareWatchpoint(const DNBBreakpoint * wp,bool also_set_on_task)570b9c1b51eSKate Stone bool MachThread::DisableHardwareWatchpoint(const DNBBreakpoint *wp,
571b9c1b51eSKate Stone bool also_set_on_task) {
57230fdc8d8SChris Lattner if (wp != NULL && wp->IsHardware())
573d5b44036SJonas Devlieghere return m_arch_up->DisableHardwareWatchpoint(wp->GetHardwareIndex(),
574b9c1b51eSKate Stone also_set_on_task);
57530fdc8d8SChris Lattner return false;
57630fdc8d8SChris Lattner }
57730fdc8d8SChris Lattner
NumSupportedHardwareWatchpoints() const578b9c1b51eSKate Stone uint32_t MachThread::NumSupportedHardwareWatchpoints() const {
579d5b44036SJonas Devlieghere return m_arch_up->NumSupportedHardwareWatchpoints();
58064637205SJohnny Chen }
58164637205SJohnny Chen
GetIdentifierInfo()582b9c1b51eSKate Stone bool MachThread::GetIdentifierInfo() {
583b9c1b51eSKate Stone // Don't try to get the thread info once and cache it for the life of the
584b9c1b51eSKate Stone // thread. It changes over time, for instance
585b9c1b51eSKate Stone // if the thread name changes, then the thread_handle also changes... So you
586b9c1b51eSKate Stone // have to refetch it every time.
58730fdc8d8SChris Lattner mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
588b9c1b51eSKate Stone kern_return_t kret = ::thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO,
589b9c1b51eSKate Stone (thread_info_t)&m_ident_info, &count);
590f2c6ccf0SJim Ingham return kret == KERN_SUCCESS;
59130fdc8d8SChris Lattner
59230fdc8d8SChris Lattner return false;
59330fdc8d8SChris Lattner }
59430fdc8d8SChris Lattner
GetName()595b9c1b51eSKate Stone const char *MachThread::GetName() {
596b9c1b51eSKate Stone if (GetIdentifierInfo()) {
597b9c1b51eSKate Stone int len = ::proc_pidinfo(m_process->ProcessID(), PROC_PIDTHREADINFO,
598b9c1b51eSKate Stone m_ident_info.thread_handle, &m_proc_threadinfo,
599b9c1b51eSKate Stone sizeof(m_proc_threadinfo));
60030fdc8d8SChris Lattner
60130fdc8d8SChris Lattner if (len && m_proc_threadinfo.pth_name[0])
60230fdc8d8SChris Lattner return m_proc_threadinfo.pth_name;
60330fdc8d8SChris Lattner }
60430fdc8d8SChris Lattner return NULL;
60530fdc8d8SChris Lattner }
60630fdc8d8SChris Lattner
6071c73911dSJason Molenda uint64_t
GetGloballyUniqueThreadIDForMachPortID(thread_t mach_port_id)608b9c1b51eSKate Stone MachThread::GetGloballyUniqueThreadIDForMachPortID(thread_t mach_port_id) {
6091c73911dSJason Molenda kern_return_t kr;
6101c73911dSJason Molenda thread_identifier_info_data_t tident;
6111c73911dSJason Molenda mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
612b9c1b51eSKate Stone kr = thread_info(mach_port_id, THREAD_IDENTIFIER_INFO, (thread_info_t)&tident,
613b9c1b51eSKate Stone &tident_count);
614b9c1b51eSKate Stone if (kr != KERN_SUCCESS) {
6151c73911dSJason Molenda return mach_port_id;
6161c73911dSJason Molenda }
6171c73911dSJason Molenda return tident.thread_id;
6181c73911dSJason Molenda }
619705b1809SJason Molenda
GetPThreadT()620b9c1b51eSKate Stone nub_addr_t MachThread::GetPThreadT() {
621705b1809SJason Molenda nub_addr_t pthread_t_value = INVALID_NUB_ADDRESS;
622b9c1b51eSKate Stone if (MachPortNumberIsValid(m_mach_port_number)) {
623705b1809SJason Molenda kern_return_t kr;
624705b1809SJason Molenda thread_identifier_info_data_t tident;
625705b1809SJason Molenda mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
626705b1809SJason Molenda kr = thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO,
627705b1809SJason Molenda (thread_info_t)&tident, &tident_count);
628b9c1b51eSKate Stone if (kr == KERN_SUCCESS) {
629705b1809SJason Molenda // Dereference thread_handle to get the pthread_t value for this thread.
630b9c1b51eSKate Stone if (m_is_64_bit) {
631705b1809SJason Molenda uint64_t addr;
632b9c1b51eSKate Stone if (m_process->ReadMemory(tident.thread_handle, 8, &addr) == 8) {
633b9c1b51eSKate Stone if (addr != 0) {
634705b1809SJason Molenda pthread_t_value = addr;
635705b1809SJason Molenda }
636705b1809SJason Molenda }
637b9c1b51eSKate Stone } else {
638705b1809SJason Molenda uint32_t addr;
639b9c1b51eSKate Stone if (m_process->ReadMemory(tident.thread_handle, 4, &addr) == 4) {
640b9c1b51eSKate Stone if (addr != 0) {
641705b1809SJason Molenda pthread_t_value = addr;
642705b1809SJason Molenda }
643705b1809SJason Molenda }
644705b1809SJason Molenda }
645705b1809SJason Molenda }
646705b1809SJason Molenda }
647705b1809SJason Molenda return pthread_t_value;
648705b1809SJason Molenda }
649705b1809SJason Molenda
650705b1809SJason Molenda // Return this thread's TSD (Thread Specific Data) address.
651705b1809SJason Molenda // This is computed based on this thread's pthread_t value.
652705b1809SJason Molenda //
653705b1809SJason Molenda // We compute the TSD from the pthread_t by one of two methods.
654705b1809SJason Molenda //
655b9c1b51eSKate Stone // If plo_pthread_tsd_base_offset is non-zero, this is a simple offset that we
656b9c1b51eSKate Stone // add to
657705b1809SJason Molenda // the pthread_t to get the TSD base address.
658705b1809SJason Molenda //
659b9c1b51eSKate Stone // Else we read a pointer from memory at pthread_t +
660b9c1b51eSKate Stone // plo_pthread_tsd_base_address_offset and
661705b1809SJason Molenda // that gives us the TSD address.
662705b1809SJason Molenda //
663b9c1b51eSKate Stone // These plo_pthread_tsd_base values must be read out of libpthread by lldb &
664b9c1b51eSKate Stone // provided to debugserver.
665705b1809SJason Molenda
666705b1809SJason Molenda 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)667b9c1b51eSKate Stone MachThread::GetTSDAddressForThread(uint64_t plo_pthread_tsd_base_address_offset,
668b9c1b51eSKate Stone uint64_t plo_pthread_tsd_base_offset,
669b9c1b51eSKate Stone uint64_t plo_pthread_tsd_entry_size) {
670705b1809SJason Molenda nub_addr_t tsd_addr = INVALID_NUB_ADDRESS;
671705b1809SJason Molenda nub_addr_t pthread_t_value = GetPThreadT();
672b9c1b51eSKate Stone if (plo_pthread_tsd_base_offset != 0 &&
673b9c1b51eSKate Stone plo_pthread_tsd_base_offset != INVALID_NUB_ADDRESS) {
674705b1809SJason Molenda tsd_addr = pthread_t_value + plo_pthread_tsd_base_offset;
675b9c1b51eSKate Stone } else {
676b9c1b51eSKate Stone if (plo_pthread_tsd_entry_size == 4) {
677705b1809SJason Molenda uint32_t addr = 0;
678b9c1b51eSKate Stone if (m_process->ReadMemory(pthread_t_value +
679b9c1b51eSKate Stone plo_pthread_tsd_base_address_offset,
680b9c1b51eSKate Stone 4, &addr) == 4) {
681b9c1b51eSKate Stone if (addr != 0) {
682705b1809SJason Molenda tsd_addr = addr;
683705b1809SJason Molenda }
684705b1809SJason Molenda }
685705b1809SJason Molenda }
686b9c1b51eSKate Stone if (plo_pthread_tsd_entry_size == 4) {
687705b1809SJason Molenda uint64_t addr = 0;
688b9c1b51eSKate Stone if (m_process->ReadMemory(pthread_t_value +
689b9c1b51eSKate Stone plo_pthread_tsd_base_address_offset,
690b9c1b51eSKate Stone 8, &addr) == 8) {
691b9c1b51eSKate Stone if (addr != 0) {
692705b1809SJason Molenda tsd_addr = addr;
693705b1809SJason Molenda }
694705b1809SJason Molenda }
695705b1809SJason Molenda }
696705b1809SJason Molenda }
697705b1809SJason Molenda return tsd_addr;
698705b1809SJason Molenda }
699705b1809SJason Molenda
GetDispatchQueueT()700b9c1b51eSKate Stone nub_addr_t MachThread::GetDispatchQueueT() {
701705b1809SJason Molenda nub_addr_t dispatch_queue_t_value = INVALID_NUB_ADDRESS;
702b9c1b51eSKate Stone if (MachPortNumberIsValid(m_mach_port_number)) {
703705b1809SJason Molenda kern_return_t kr;
704705b1809SJason Molenda thread_identifier_info_data_t tident;
705705b1809SJason Molenda mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
706705b1809SJason Molenda kr = thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO,
707705b1809SJason Molenda (thread_info_t)&tident, &tident_count);
708b9c1b51eSKate Stone if (kr == KERN_SUCCESS && tident.dispatch_qaddr != 0 &&
709b9c1b51eSKate Stone tident.dispatch_qaddr != INVALID_NUB_ADDRESS) {
710b9c1b51eSKate Stone // Dereference dispatch_qaddr to get the dispatch_queue_t value for this
711b9c1b51eSKate Stone // thread's queue, if any.
712b9c1b51eSKate Stone if (m_is_64_bit) {
713705b1809SJason Molenda uint64_t addr;
714b9c1b51eSKate Stone if (m_process->ReadMemory(tident.dispatch_qaddr, 8, &addr) == 8) {
715705b1809SJason Molenda if (addr != 0)
716705b1809SJason Molenda dispatch_queue_t_value = addr;
717705b1809SJason Molenda }
718b9c1b51eSKate Stone } else {
719705b1809SJason Molenda uint32_t addr;
720b9c1b51eSKate Stone if (m_process->ReadMemory(tident.dispatch_qaddr, 4, &addr) == 4) {
721705b1809SJason Molenda if (addr != 0)
722705b1809SJason Molenda dispatch_queue_t_value = addr;
723705b1809SJason Molenda }
724705b1809SJason Molenda }
725705b1809SJason Molenda }
726705b1809SJason Molenda }
727705b1809SJason Molenda return dispatch_queue_t_value;
728705b1809SJason Molenda }
729705b1809SJason Molenda
GetRequestedQoS(nub_addr_t tsd,uint64_t dti_qos_class_index)730b9c1b51eSKate Stone ThreadInfo::QoS MachThread::GetRequestedQoS(nub_addr_t tsd,
731b9c1b51eSKate Stone uint64_t dti_qos_class_index) {
732705b1809SJason Molenda ThreadInfo::QoS qos_value;
733b9c1b51eSKate Stone if (MachPortNumberIsValid(m_mach_port_number) &&
734b9c1b51eSKate Stone m_pthread_qos_class_decode != nullptr) {
735705b1809SJason Molenda uint64_t pthread_priority_value = 0;
736b9c1b51eSKate Stone if (m_is_64_bit) {
737705b1809SJason Molenda uint64_t pri;
738b9c1b51eSKate Stone if (m_process->ReadMemory(tsd + (dti_qos_class_index * 8), 8, &pri) ==
739b9c1b51eSKate Stone 8) {
740705b1809SJason Molenda pthread_priority_value = pri;
741705b1809SJason Molenda }
742b9c1b51eSKate Stone } else {
743705b1809SJason Molenda uint32_t pri;
744b9c1b51eSKate Stone if (m_process->ReadMemory(tsd + (dti_qos_class_index * 4), 4, &pri) ==
745b9c1b51eSKate Stone 4) {
746705b1809SJason Molenda pthread_priority_value = pri;
747705b1809SJason Molenda }
748705b1809SJason Molenda }
749705b1809SJason Molenda
750b9c1b51eSKate Stone uint32_t requested_qos =
751b9c1b51eSKate Stone m_pthread_qos_class_decode(pthread_priority_value, NULL, NULL);
752705b1809SJason Molenda
753b9c1b51eSKate Stone switch (requested_qos) {
754705b1809SJason Molenda // These constants from <pthread/qos.h>
755705b1809SJason Molenda case 0x21:
756705b1809SJason Molenda qos_value.enum_value = requested_qos;
757705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_USER_INTERACTIVE";
758705b1809SJason Molenda qos_value.printable_name = "User Interactive";
759705b1809SJason Molenda break;
760705b1809SJason Molenda case 0x19:
761705b1809SJason Molenda qos_value.enum_value = requested_qos;
762705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_USER_INITIATED";
763705b1809SJason Molenda qos_value.printable_name = "User Initiated";
764705b1809SJason Molenda break;
765705b1809SJason Molenda case 0x15:
766705b1809SJason Molenda qos_value.enum_value = requested_qos;
767705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_DEFAULT";
768705b1809SJason Molenda qos_value.printable_name = "Default";
769705b1809SJason Molenda break;
770705b1809SJason Molenda case 0x11:
771705b1809SJason Molenda qos_value.enum_value = requested_qos;
772705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_UTILITY";
773705b1809SJason Molenda qos_value.printable_name = "Utility";
774705b1809SJason Molenda break;
775705b1809SJason Molenda case 0x09:
776705b1809SJason Molenda qos_value.enum_value = requested_qos;
777705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_BACKGROUND";
778705b1809SJason Molenda qos_value.printable_name = "Background";
779705b1809SJason Molenda break;
780705b1809SJason Molenda case 0x00:
781705b1809SJason Molenda qos_value.enum_value = requested_qos;
782705b1809SJason Molenda qos_value.constant_name = "QOS_CLASS_UNSPECIFIED";
783705b1809SJason Molenda qos_value.printable_name = "Unspecified";
784705b1809SJason Molenda break;
785705b1809SJason Molenda }
786705b1809SJason Molenda }
787705b1809SJason Molenda return qos_value;
788705b1809SJason Molenda }
789