168d75effSDimitry Andric //===-- sanitizer_stoptheworld_mac.cpp ------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // See sanitizer_stoptheworld.h for details. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric //===----------------------------------------------------------------------===// 1268d75effSDimitry Andric 1368d75effSDimitry Andric #include "sanitizer_platform.h" 1468d75effSDimitry Andric 1581ad6265SDimitry Andric #if SANITIZER_APPLE && (defined(__x86_64__) || defined(__aarch64__) || \ 1668d75effSDimitry Andric defined(__i386)) 1768d75effSDimitry Andric 1868d75effSDimitry Andric #include <mach/mach.h> 1968d75effSDimitry Andric #include <mach/thread_info.h> 2068d75effSDimitry Andric #include <pthread.h> 2168d75effSDimitry Andric 2268d75effSDimitry Andric #include "sanitizer_stoptheworld.h" 2368d75effSDimitry Andric 2468d75effSDimitry Andric namespace __sanitizer { 2568d75effSDimitry Andric typedef struct { 2668d75effSDimitry Andric tid_t tid; 2768d75effSDimitry Andric thread_t thread; 2868d75effSDimitry Andric } SuspendedThreadInfo; 2968d75effSDimitry Andric 30e8d8bef9SDimitry Andric class SuspendedThreadsListMac final : public SuspendedThreadsList { 3168d75effSDimitry Andric public: 32*fcaf7f86SDimitry Andric SuspendedThreadsListMac() = default; 3368d75effSDimitry Andric 34e8d8bef9SDimitry Andric tid_t GetThreadID(uptr index) const override; 3568d75effSDimitry Andric thread_t GetThread(uptr index) const; 36e8d8bef9SDimitry Andric uptr ThreadCount() const override; 3768d75effSDimitry Andric bool ContainsThread(thread_t thread) const; 3868d75effSDimitry Andric void Append(thread_t thread); 3968d75effSDimitry Andric 40e8d8bef9SDimitry Andric PtraceRegistersStatus GetRegistersAndSP(uptr index, 41e8d8bef9SDimitry Andric InternalMmapVector<uptr> *buffer, 42e8d8bef9SDimitry Andric uptr *sp) const override; 4368d75effSDimitry Andric 4468d75effSDimitry Andric private: 4568d75effSDimitry Andric InternalMmapVector<SuspendedThreadInfo> threads_; 4668d75effSDimitry Andric }; 4768d75effSDimitry Andric 4868d75effSDimitry Andric struct RunThreadArgs { 4968d75effSDimitry Andric StopTheWorldCallback callback; 5068d75effSDimitry Andric void *argument; 5168d75effSDimitry Andric }; 5268d75effSDimitry Andric 535ffd83dbSDimitry Andric void *RunThread(void *arg) { 5468d75effSDimitry Andric struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg; 5568d75effSDimitry Andric SuspendedThreadsListMac suspended_threads_list; 5668d75effSDimitry Andric 5768d75effSDimitry Andric thread_array_t threads; 5868d75effSDimitry Andric mach_msg_type_number_t num_threads; 5968d75effSDimitry Andric kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads); 6068d75effSDimitry Andric if (err != KERN_SUCCESS) { 6168d75effSDimitry Andric VReport(1, "Failed to get threads for task (errno %d).\n", err); 625ffd83dbSDimitry Andric return nullptr; 6368d75effSDimitry Andric } 6468d75effSDimitry Andric 6568d75effSDimitry Andric thread_t thread_self = mach_thread_self(); 6668d75effSDimitry Andric for (unsigned int i = 0; i < num_threads; ++i) { 6768d75effSDimitry Andric if (threads[i] == thread_self) continue; 6868d75effSDimitry Andric 6968d75effSDimitry Andric thread_suspend(threads[i]); 7068d75effSDimitry Andric suspended_threads_list.Append(threads[i]); 7168d75effSDimitry Andric } 7268d75effSDimitry Andric 7368d75effSDimitry Andric run_args->callback(suspended_threads_list, run_args->argument); 7468d75effSDimitry Andric 7568d75effSDimitry Andric uptr num_suspended = suspended_threads_list.ThreadCount(); 7668d75effSDimitry Andric for (unsigned int i = 0; i < num_suspended; ++i) { 7768d75effSDimitry Andric thread_resume(suspended_threads_list.GetThread(i)); 7868d75effSDimitry Andric } 795ffd83dbSDimitry Andric return nullptr; 8068d75effSDimitry Andric } 8168d75effSDimitry Andric 8268d75effSDimitry Andric void StopTheWorld(StopTheWorldCallback callback, void *argument) { 8368d75effSDimitry Andric struct RunThreadArgs arg = {callback, argument}; 8468d75effSDimitry Andric pthread_t run_thread = (pthread_t)internal_start_thread(RunThread, &arg); 8568d75effSDimitry Andric internal_join_thread(run_thread); 8668d75effSDimitry Andric } 8768d75effSDimitry Andric 8868d75effSDimitry Andric #if defined(__x86_64__) 8968d75effSDimitry Andric typedef x86_thread_state64_t regs_struct; 9068d75effSDimitry Andric 9168d75effSDimitry Andric #define SP_REG __rsp 9268d75effSDimitry Andric 9368d75effSDimitry Andric #elif defined(__aarch64__) 9468d75effSDimitry Andric typedef arm_thread_state64_t regs_struct; 9568d75effSDimitry Andric 9668d75effSDimitry Andric # if __DARWIN_UNIX03 9768d75effSDimitry Andric # define SP_REG __sp 9868d75effSDimitry Andric # else 9968d75effSDimitry Andric # define SP_REG sp 10068d75effSDimitry Andric # endif 10168d75effSDimitry Andric 10268d75effSDimitry Andric #elif defined(__i386) 10368d75effSDimitry Andric typedef x86_thread_state32_t regs_struct; 10468d75effSDimitry Andric 10568d75effSDimitry Andric #define SP_REG __esp 10668d75effSDimitry Andric 10768d75effSDimitry Andric #else 10868d75effSDimitry Andric #error "Unsupported architecture" 10968d75effSDimitry Andric #endif 11068d75effSDimitry Andric 11168d75effSDimitry Andric tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const { 11268d75effSDimitry Andric CHECK_LT(index, threads_.size()); 11368d75effSDimitry Andric return threads_[index].tid; 11468d75effSDimitry Andric } 11568d75effSDimitry Andric 11668d75effSDimitry Andric thread_t SuspendedThreadsListMac::GetThread(uptr index) const { 11768d75effSDimitry Andric CHECK_LT(index, threads_.size()); 11868d75effSDimitry Andric return threads_[index].thread; 11968d75effSDimitry Andric } 12068d75effSDimitry Andric 12168d75effSDimitry Andric uptr SuspendedThreadsListMac::ThreadCount() const { 12268d75effSDimitry Andric return threads_.size(); 12368d75effSDimitry Andric } 12468d75effSDimitry Andric 12568d75effSDimitry Andric bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const { 12668d75effSDimitry Andric for (uptr i = 0; i < threads_.size(); i++) { 12768d75effSDimitry Andric if (threads_[i].thread == thread) return true; 12868d75effSDimitry Andric } 12968d75effSDimitry Andric return false; 13068d75effSDimitry Andric } 13168d75effSDimitry Andric 13268d75effSDimitry Andric void SuspendedThreadsListMac::Append(thread_t thread) { 13368d75effSDimitry Andric thread_identifier_info_data_t info; 13468d75effSDimitry Andric mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT; 13568d75effSDimitry Andric kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO, 13668d75effSDimitry Andric (thread_info_t)&info, &info_count); 13768d75effSDimitry Andric if (err != KERN_SUCCESS) { 13868d75effSDimitry Andric VReport(1, "Error - unable to get thread ident for a thread\n"); 13968d75effSDimitry Andric return; 14068d75effSDimitry Andric } 14168d75effSDimitry Andric threads_.push_back({info.thread_id, thread}); 14268d75effSDimitry Andric } 14368d75effSDimitry Andric 14468d75effSDimitry Andric PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( 145e8d8bef9SDimitry Andric uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const { 14668d75effSDimitry Andric thread_t thread = GetThread(index); 14768d75effSDimitry Andric regs_struct regs; 14868d75effSDimitry Andric int err; 14968d75effSDimitry Andric mach_msg_type_number_t reg_count = MACHINE_THREAD_STATE_COUNT; 15068d75effSDimitry Andric err = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)®s, 15168d75effSDimitry Andric ®_count); 15268d75effSDimitry Andric if (err != KERN_SUCCESS) { 15368d75effSDimitry Andric VReport(1, "Error - unable to get registers for a thread\n"); 15468d75effSDimitry Andric // KERN_INVALID_ARGUMENT indicates that either the flavor is invalid, 15568d75effSDimitry Andric // or the thread does not exist. The other possible error case, 15668d75effSDimitry Andric // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's 15768d75effSDimitry Andric // still safe to proceed. 15868d75effSDimitry Andric return err == KERN_INVALID_ARGUMENT ? REGISTERS_UNAVAILABLE_FATAL 15968d75effSDimitry Andric : REGISTERS_UNAVAILABLE; 16068d75effSDimitry Andric } 16168d75effSDimitry Andric 162e8d8bef9SDimitry Andric buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr)); 163e8d8bef9SDimitry Andric internal_memcpy(buffer->data(), ®s, sizeof(regs)); 1645ffd83dbSDimitry Andric #if defined(__aarch64__) && defined(arm_thread_state64_get_sp) 1655ffd83dbSDimitry Andric *sp = arm_thread_state64_get_sp(regs); 1665ffd83dbSDimitry Andric #else 16768d75effSDimitry Andric *sp = regs.SP_REG; 1685ffd83dbSDimitry Andric #endif 16968d75effSDimitry Andric 17068d75effSDimitry Andric // On x86_64 and aarch64, we must account for the stack redzone, which is 128 17168d75effSDimitry Andric // bytes. 17268d75effSDimitry Andric if (SANITIZER_WORDSIZE == 64) *sp -= 128; 17368d75effSDimitry Andric 17468d75effSDimitry Andric return REGISTERS_AVAILABLE; 17568d75effSDimitry Andric } 17668d75effSDimitry Andric 17768d75effSDimitry Andric } // namespace __sanitizer 17868d75effSDimitry Andric 17981ad6265SDimitry Andric #endif // SANITIZER_APPLE && (defined(__x86_64__) || defined(__aarch64__)) || 18068d75effSDimitry Andric // defined(__i386)) 181