1 //===-- sanitizer_stoptheworld_mac.cpp ------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // See sanitizer_stoptheworld.h for details. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "sanitizer_platform.h" 14 15 #if SANITIZER_APPLE && (defined(__x86_64__) || defined(__aarch64__) || \ 16 defined(__i386)) 17 18 #include <mach/mach.h> 19 #include <mach/thread_info.h> 20 #include <pthread.h> 21 22 #include "sanitizer_stoptheworld.h" 23 24 namespace __sanitizer { 25 typedef struct { 26 tid_t tid; 27 thread_t thread; 28 } SuspendedThreadInfo; 29 30 class SuspendedThreadsListMac final : public SuspendedThreadsList { 31 public: 32 SuspendedThreadsListMac() = default; 33 34 tid_t GetThreadID(uptr index) const override; 35 thread_t GetThread(uptr index) const; 36 uptr ThreadCount() const override; 37 bool ContainsThread(thread_t thread) const; 38 void Append(thread_t thread); 39 40 PtraceRegistersStatus GetRegistersAndSP(uptr index, 41 InternalMmapVector<uptr> *buffer, 42 uptr *sp) const override; 43 44 private: 45 InternalMmapVector<SuspendedThreadInfo> threads_; 46 }; 47 48 struct RunThreadArgs { 49 StopTheWorldCallback callback; 50 void *argument; 51 }; 52 53 void *RunThread(void *arg) { 54 struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg; 55 SuspendedThreadsListMac suspended_threads_list; 56 57 thread_array_t threads; 58 mach_msg_type_number_t num_threads; 59 kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads); 60 if (err != KERN_SUCCESS) { 61 VReport(1, "Failed to get threads for task (errno %d).\n", err); 62 return nullptr; 63 } 64 65 thread_t thread_self = mach_thread_self(); 66 for (unsigned int i = 0; i < num_threads; ++i) { 67 if (threads[i] == thread_self) continue; 68 69 thread_suspend(threads[i]); 70 suspended_threads_list.Append(threads[i]); 71 } 72 73 run_args->callback(suspended_threads_list, run_args->argument); 74 75 uptr num_suspended = suspended_threads_list.ThreadCount(); 76 for (unsigned int i = 0; i < num_suspended; ++i) { 77 thread_resume(suspended_threads_list.GetThread(i)); 78 } 79 return nullptr; 80 } 81 82 void StopTheWorld(StopTheWorldCallback callback, void *argument) { 83 struct RunThreadArgs arg = {callback, argument}; 84 pthread_t run_thread = (pthread_t)internal_start_thread(RunThread, &arg); 85 internal_join_thread(run_thread); 86 } 87 88 #if defined(__x86_64__) 89 typedef x86_thread_state64_t regs_struct; 90 91 #define SP_REG __rsp 92 93 #elif defined(__aarch64__) 94 typedef arm_thread_state64_t regs_struct; 95 96 # if __DARWIN_UNIX03 97 # define SP_REG __sp 98 # else 99 # define SP_REG sp 100 # endif 101 102 #elif defined(__i386) 103 typedef x86_thread_state32_t regs_struct; 104 105 #define SP_REG __esp 106 107 #else 108 #error "Unsupported architecture" 109 #endif 110 111 tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const { 112 CHECK_LT(index, threads_.size()); 113 return threads_[index].tid; 114 } 115 116 thread_t SuspendedThreadsListMac::GetThread(uptr index) const { 117 CHECK_LT(index, threads_.size()); 118 return threads_[index].thread; 119 } 120 121 uptr SuspendedThreadsListMac::ThreadCount() const { 122 return threads_.size(); 123 } 124 125 bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const { 126 for (uptr i = 0; i < threads_.size(); i++) { 127 if (threads_[i].thread == thread) return true; 128 } 129 return false; 130 } 131 132 void SuspendedThreadsListMac::Append(thread_t thread) { 133 thread_identifier_info_data_t info; 134 mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT; 135 kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO, 136 (thread_info_t)&info, &info_count); 137 if (err != KERN_SUCCESS) { 138 VReport(1, "Error - unable to get thread ident for a thread\n"); 139 return; 140 } 141 threads_.push_back({info.thread_id, thread}); 142 } 143 144 PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( 145 uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { 146 thread_t thread = GetThread(index); 147 regs_struct regs; 148 int err; 149 mach_msg_type_number_t reg_count = MACHINE_THREAD_STATE_COUNT; 150 err = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)®s, 151 ®_count); 152 if (err != KERN_SUCCESS) { 153 VReport(1, "Error - unable to get registers for a thread\n"); 154 // KERN_INVALID_ARGUMENT indicates that either the flavor is invalid, 155 // or the thread does not exist. The other possible error case, 156 // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's 157 // still safe to proceed. 158 return err == KERN_INVALID_ARGUMENT ? REGISTERS_UNAVAILABLE_FATAL 159 : REGISTERS_UNAVAILABLE; 160 } 161 162 buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr)); 163 internal_memcpy(buffer->data(), ®s, sizeof(regs)); 164 #if defined(__aarch64__) && defined(arm_thread_state64_get_sp) 165 *sp = arm_thread_state64_get_sp(regs); 166 #else 167 *sp = regs.SP_REG; 168 #endif 169 170 // On x86_64 and aarch64, we must account for the stack redzone, which is 128 171 // bytes. 172 if (SANITIZER_WORDSIZE == 64) *sp -= 128; 173 174 return REGISTERS_AVAILABLE; 175 } 176 177 } // namespace __sanitizer 178 179 #endif // SANITIZER_APPLE && (defined(__x86_64__) || defined(__aarch64__)) || 180 // defined(__i386)) 181