sanitizer_stoptheworld_win.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. //===-- sanitizer_stoptheworld_win.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_WINDOWS
  14. # define WIN32_LEAN_AND_MEAN
  15. # include <windows.h>
  16. // windows.h needs to be included before tlhelp32.h
  17. # include <tlhelp32.h>
  18. # include "sanitizer_stoptheworld.h"
  19. namespace __sanitizer {
  20. namespace {
  21. struct SuspendedThreadsListWindows final : public SuspendedThreadsList {
  22. InternalMmapVector<HANDLE> threadHandles;
  23. InternalMmapVector<DWORD> threadIds;
  24. SuspendedThreadsListWindows() {
  25. threadIds.reserve(1024);
  26. threadHandles.reserve(1024);
  27. }
  28. PtraceRegistersStatus GetRegistersAndSP(uptr index,
  29. InternalMmapVector<uptr> *buffer,
  30. uptr *sp) const override;
  31. tid_t GetThreadID(uptr index) const override;
  32. uptr ThreadCount() const override;
  33. };
  34. // Stack Pointer register names on different architectures
  35. # if SANITIZER_X64
  36. # define SP_REG Rsp
  37. # elif SANITIZER_I386
  38. # define SP_REG Esp
  39. # elif SANITIZER_ARM | SANITIZER_ARM64
  40. # define SP_REG Sp
  41. # else
  42. # error Architecture not supported!
  43. # endif
  44. PtraceRegistersStatus SuspendedThreadsListWindows::GetRegistersAndSP(
  45. uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {
  46. CHECK_LT(index, threadHandles.size());
  47. buffer->resize(RoundUpTo(sizeof(CONTEXT), sizeof(uptr)) / sizeof(uptr));
  48. CONTEXT *thread_context = reinterpret_cast<CONTEXT *>(buffer->data());
  49. thread_context->ContextFlags = CONTEXT_ALL;
  50. CHECK(GetThreadContext(threadHandles[index], thread_context));
  51. *sp = thread_context->SP_REG;
  52. return REGISTERS_AVAILABLE;
  53. }
  54. tid_t SuspendedThreadsListWindows::GetThreadID(uptr index) const {
  55. CHECK_LT(index, threadIds.size());
  56. return threadIds[index];
  57. }
  58. uptr SuspendedThreadsListWindows::ThreadCount() const {
  59. return threadIds.size();
  60. }
  61. struct RunThreadArgs {
  62. StopTheWorldCallback callback;
  63. void *argument;
  64. };
  65. DWORD WINAPI RunThread(void *argument) {
  66. RunThreadArgs *run_args = (RunThreadArgs *)argument;
  67. const DWORD this_thread = GetCurrentThreadId();
  68. const DWORD this_process = GetCurrentProcessId();
  69. SuspendedThreadsListWindows suspended_threads_list;
  70. bool new_thread_found;
  71. do {
  72. // Take a snapshot of all Threads
  73. const HANDLE threads = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
  74. CHECK(threads != INVALID_HANDLE_VALUE);
  75. THREADENTRY32 thread_entry;
  76. thread_entry.dwSize = sizeof(thread_entry);
  77. new_thread_found = false;
  78. if (!Thread32First(threads, &thread_entry))
  79. break;
  80. do {
  81. if (thread_entry.th32ThreadID == this_thread ||
  82. thread_entry.th32OwnerProcessID != this_process)
  83. continue;
  84. bool suspended_thread = false;
  85. for (const auto thread_id : suspended_threads_list.threadIds) {
  86. if (thread_id == thread_entry.th32ThreadID) {
  87. suspended_thread = true;
  88. break;
  89. }
  90. }
  91. // Skip the Thread if it was already suspended
  92. if (suspended_thread)
  93. continue;
  94. const HANDLE thread =
  95. OpenThread(THREAD_ALL_ACCESS, FALSE, thread_entry.th32ThreadID);
  96. CHECK(thread);
  97. if (SuspendThread(thread) == (DWORD)-1) {
  98. DWORD last_error = GetLastError();
  99. VPrintf(1, "Could not suspend thread %lu (error %lu)",
  100. thread_entry.th32ThreadID, last_error);
  101. continue;
  102. }
  103. suspended_threads_list.threadIds.push_back(thread_entry.th32ThreadID);
  104. suspended_threads_list.threadHandles.push_back(thread);
  105. new_thread_found = true;
  106. } while (Thread32Next(threads, &thread_entry));
  107. CloseHandle(threads);
  108. // Between the call to `CreateToolhelp32Snapshot` and suspending the
  109. // relevant Threads, new Threads could have potentially been created. So
  110. // continue to find and suspend new Threads until we don't find any.
  111. } while (new_thread_found);
  112. // Now all Threads of this Process except of this Thread should be suspended.
  113. // Execute the callback function.
  114. run_args->callback(suspended_threads_list, run_args->argument);
  115. // Resume all Threads
  116. for (const auto suspended_thread_handle :
  117. suspended_threads_list.threadHandles) {
  118. CHECK_NE(ResumeThread(suspended_thread_handle), -1);
  119. CloseHandle(suspended_thread_handle);
  120. }
  121. return 0;
  122. }
  123. } // namespace
  124. void StopTheWorld(StopTheWorldCallback callback, void *argument) {
  125. struct RunThreadArgs arg = {callback, argument};
  126. DWORD trace_thread_id;
  127. auto trace_thread =
  128. CreateThread(nullptr, 0, RunThread, &arg, 0, &trace_thread_id);
  129. CHECK(trace_thread);
  130. WaitForSingleObject(trace_thread, INFINITE);
  131. CloseHandle(trace_thread);
  132. }
  133. } // namespace __sanitizer
  134. #endif // SANITIZER_WINDOWS