sanitizer_stoptheworld_mac.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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_APPLE && (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() = default;
  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 regs_flavor x86_THREAD_STATE64
  73. #define SP_REG __rsp
  74. #elif defined(__aarch64__)
  75. typedef arm_thread_state64_t regs_struct;
  76. #define regs_flavor ARM_THREAD_STATE64
  77. # if __DARWIN_UNIX03
  78. # define SP_REG __sp
  79. # else
  80. # define SP_REG sp
  81. # endif
  82. #elif defined(__i386)
  83. typedef x86_thread_state32_t regs_struct;
  84. #define regs_flavor x86_THREAD_STATE32
  85. #define SP_REG __esp
  86. #else
  87. #error "Unsupported architecture"
  88. #endif
  89. tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const {
  90. CHECK_LT(index, threads_.size());
  91. return threads_[index].tid;
  92. }
  93. thread_t SuspendedThreadsListMac::GetThread(uptr index) const {
  94. CHECK_LT(index, threads_.size());
  95. return threads_[index].thread;
  96. }
  97. uptr SuspendedThreadsListMac::ThreadCount() const {
  98. return threads_.size();
  99. }
  100. bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const {
  101. for (uptr i = 0; i < threads_.size(); i++) {
  102. if (threads_[i].thread == thread) return true;
  103. }
  104. return false;
  105. }
  106. void SuspendedThreadsListMac::Append(thread_t thread) {
  107. thread_identifier_info_data_t info;
  108. mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT;
  109. kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO,
  110. (thread_info_t)&info, &info_count);
  111. if (err != KERN_SUCCESS) {
  112. VReport(1, "Error - unable to get thread ident for a thread\n");
  113. return;
  114. }
  115. threads_.push_back({info.thread_id, thread});
  116. }
  117. PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP(
  118. uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {
  119. thread_t thread = GetThread(index);
  120. regs_struct regs;
  121. int err;
  122. mach_msg_type_number_t reg_count = sizeof(regs) / sizeof(natural_t);
  123. err = thread_get_state(thread, regs_flavor, (thread_state_t)&regs,
  124. &reg_count);
  125. if (err != KERN_SUCCESS) {
  126. VReport(1, "Error - unable to get registers for a thread\n");
  127. // KERN_INVALID_ARGUMENT indicates that either the flavor is invalid,
  128. // or the thread does not exist. The other possible error case,
  129. // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's
  130. // still safe to proceed.
  131. return err == KERN_INVALID_ARGUMENT ? REGISTERS_UNAVAILABLE_FATAL
  132. : REGISTERS_UNAVAILABLE;
  133. }
  134. buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr));
  135. internal_memcpy(buffer->data(), &regs, sizeof(regs));
  136. #if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
  137. *sp = arm_thread_state64_get_sp(regs);
  138. #else
  139. *sp = regs.SP_REG;
  140. #endif
  141. // On x86_64 and aarch64, we must account for the stack redzone, which is 128
  142. // bytes.
  143. if (SANITIZER_WORDSIZE == 64) *sp -= 128;
  144. return REGISTERS_AVAILABLE;
  145. }
  146. } // namespace __sanitizer
  147. #endif // SANITIZER_APPLE && (defined(__x86_64__) || defined(__aarch64__)) ||
  148. // defined(__i386))