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