sanitizer_stoptheworld_mac.cpp 5.4 KB

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