xref: /openbsd-src/gnu/llvm/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
1*810390e3Srobert //===-- sanitizer_stoptheworld_win.cpp ------------------------------------===//
2*810390e3Srobert //
3*810390e3Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*810390e3Srobert // See https://llvm.org/LICENSE.txt for license information.
5*810390e3Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*810390e3Srobert //
7*810390e3Srobert //===----------------------------------------------------------------------===//
8*810390e3Srobert //
9*810390e3Srobert // See sanitizer_stoptheworld.h for details.
10*810390e3Srobert //
11*810390e3Srobert //===----------------------------------------------------------------------===//
12*810390e3Srobert 
13*810390e3Srobert #include "sanitizer_platform.h"
14*810390e3Srobert 
15*810390e3Srobert #if SANITIZER_WINDOWS
16*810390e3Srobert 
17*810390e3Srobert #  define WIN32_LEAN_AND_MEAN
18*810390e3Srobert #  include <windows.h>
19*810390e3Srobert // windows.h needs to be included before tlhelp32.h
20*810390e3Srobert #  include <tlhelp32.h>
21*810390e3Srobert 
22*810390e3Srobert #  include "sanitizer_stoptheworld.h"
23*810390e3Srobert 
24*810390e3Srobert namespace __sanitizer {
25*810390e3Srobert 
26*810390e3Srobert namespace {
27*810390e3Srobert 
28*810390e3Srobert struct SuspendedThreadsListWindows final : public SuspendedThreadsList {
29*810390e3Srobert   InternalMmapVector<HANDLE> threadHandles;
30*810390e3Srobert   InternalMmapVector<DWORD> threadIds;
31*810390e3Srobert 
SuspendedThreadsListWindows__sanitizer::__anonc8a8899e0111::SuspendedThreadsListWindows32*810390e3Srobert   SuspendedThreadsListWindows() {
33*810390e3Srobert     threadIds.reserve(1024);
34*810390e3Srobert     threadHandles.reserve(1024);
35*810390e3Srobert   }
36*810390e3Srobert 
37*810390e3Srobert   PtraceRegistersStatus GetRegistersAndSP(uptr index,
38*810390e3Srobert                                           InternalMmapVector<uptr> *buffer,
39*810390e3Srobert                                           uptr *sp) const override;
40*810390e3Srobert 
41*810390e3Srobert   tid_t GetThreadID(uptr index) const override;
42*810390e3Srobert   uptr ThreadCount() const override;
43*810390e3Srobert };
44*810390e3Srobert 
45*810390e3Srobert // Stack Pointer register names on different architectures
46*810390e3Srobert #  if SANITIZER_X64
47*810390e3Srobert #    define SP_REG Rsp
48*810390e3Srobert #  elif SANITIZER_I386
49*810390e3Srobert #    define SP_REG Esp
50*810390e3Srobert #  elif SANITIZER_ARM | SANITIZER_ARM64
51*810390e3Srobert #    define SP_REG Sp
52*810390e3Srobert #  else
53*810390e3Srobert #    error Architecture not supported!
54*810390e3Srobert #  endif
55*810390e3Srobert 
GetRegistersAndSP(uptr index,InternalMmapVector<uptr> * buffer,uptr * sp) const56*810390e3Srobert PtraceRegistersStatus SuspendedThreadsListWindows::GetRegistersAndSP(
57*810390e3Srobert     uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {
58*810390e3Srobert   CHECK_LT(index, threadHandles.size());
59*810390e3Srobert 
60*810390e3Srobert   buffer->resize(RoundUpTo(sizeof(CONTEXT), sizeof(uptr)) / sizeof(uptr));
61*810390e3Srobert   CONTEXT *thread_context = reinterpret_cast<CONTEXT *>(buffer->data());
62*810390e3Srobert   thread_context->ContextFlags = CONTEXT_ALL;
63*810390e3Srobert   CHECK(GetThreadContext(threadHandles[index], thread_context));
64*810390e3Srobert   *sp = thread_context->SP_REG;
65*810390e3Srobert 
66*810390e3Srobert   return REGISTERS_AVAILABLE;
67*810390e3Srobert }
68*810390e3Srobert 
GetThreadID(uptr index) const69*810390e3Srobert tid_t SuspendedThreadsListWindows::GetThreadID(uptr index) const {
70*810390e3Srobert   CHECK_LT(index, threadIds.size());
71*810390e3Srobert   return threadIds[index];
72*810390e3Srobert }
73*810390e3Srobert 
ThreadCount() const74*810390e3Srobert uptr SuspendedThreadsListWindows::ThreadCount() const {
75*810390e3Srobert   return threadIds.size();
76*810390e3Srobert }
77*810390e3Srobert 
78*810390e3Srobert struct RunThreadArgs {
79*810390e3Srobert   StopTheWorldCallback callback;
80*810390e3Srobert   void *argument;
81*810390e3Srobert };
82*810390e3Srobert 
RunThread(void * argument)83*810390e3Srobert DWORD WINAPI RunThread(void *argument) {
84*810390e3Srobert   RunThreadArgs *run_args = (RunThreadArgs *)argument;
85*810390e3Srobert 
86*810390e3Srobert   const DWORD this_thread = GetCurrentThreadId();
87*810390e3Srobert   const DWORD this_process = GetCurrentProcessId();
88*810390e3Srobert 
89*810390e3Srobert   SuspendedThreadsListWindows suspended_threads_list;
90*810390e3Srobert   bool new_thread_found;
91*810390e3Srobert 
92*810390e3Srobert   do {
93*810390e3Srobert     // Take a snapshot of all Threads
94*810390e3Srobert     const HANDLE threads = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
95*810390e3Srobert     CHECK(threads != INVALID_HANDLE_VALUE);
96*810390e3Srobert 
97*810390e3Srobert     THREADENTRY32 thread_entry;
98*810390e3Srobert     thread_entry.dwSize = sizeof(thread_entry);
99*810390e3Srobert     new_thread_found = false;
100*810390e3Srobert 
101*810390e3Srobert     if (!Thread32First(threads, &thread_entry))
102*810390e3Srobert       break;
103*810390e3Srobert 
104*810390e3Srobert     do {
105*810390e3Srobert       if (thread_entry.th32ThreadID == this_thread ||
106*810390e3Srobert           thread_entry.th32OwnerProcessID != this_process)
107*810390e3Srobert         continue;
108*810390e3Srobert 
109*810390e3Srobert       bool suspended_thread = false;
110*810390e3Srobert       for (const auto thread_id : suspended_threads_list.threadIds) {
111*810390e3Srobert         if (thread_id == thread_entry.th32ThreadID) {
112*810390e3Srobert           suspended_thread = true;
113*810390e3Srobert           break;
114*810390e3Srobert         }
115*810390e3Srobert       }
116*810390e3Srobert 
117*810390e3Srobert       // Skip the Thread if it was already suspended
118*810390e3Srobert       if (suspended_thread)
119*810390e3Srobert         continue;
120*810390e3Srobert 
121*810390e3Srobert       const HANDLE thread =
122*810390e3Srobert           OpenThread(THREAD_ALL_ACCESS, FALSE, thread_entry.th32ThreadID);
123*810390e3Srobert       CHECK(thread);
124*810390e3Srobert 
125*810390e3Srobert       if (SuspendThread(thread) == (DWORD)-1) {
126*810390e3Srobert         DWORD last_error = GetLastError();
127*810390e3Srobert 
128*810390e3Srobert         VPrintf(1, "Could not suspend thread %lu (error %lu)",
129*810390e3Srobert                 thread_entry.th32ThreadID, last_error);
130*810390e3Srobert         continue;
131*810390e3Srobert       }
132*810390e3Srobert 
133*810390e3Srobert       suspended_threads_list.threadIds.push_back(thread_entry.th32ThreadID);
134*810390e3Srobert       suspended_threads_list.threadHandles.push_back(thread);
135*810390e3Srobert       new_thread_found = true;
136*810390e3Srobert     } while (Thread32Next(threads, &thread_entry));
137*810390e3Srobert 
138*810390e3Srobert     CloseHandle(threads);
139*810390e3Srobert 
140*810390e3Srobert     // Between the call to `CreateToolhelp32Snapshot` and suspending the
141*810390e3Srobert     // relevant Threads, new Threads could have potentially been created. So
142*810390e3Srobert     // continue to find and suspend new Threads until we don't find any.
143*810390e3Srobert   } while (new_thread_found);
144*810390e3Srobert 
145*810390e3Srobert   // Now all Threads of this Process except of this Thread should be suspended.
146*810390e3Srobert   // Execute the callback function.
147*810390e3Srobert   run_args->callback(suspended_threads_list, run_args->argument);
148*810390e3Srobert 
149*810390e3Srobert   // Resume all Threads
150*810390e3Srobert   for (const auto suspended_thread_handle :
151*810390e3Srobert        suspended_threads_list.threadHandles) {
152*810390e3Srobert     CHECK_NE(ResumeThread(suspended_thread_handle), -1);
153*810390e3Srobert     CloseHandle(suspended_thread_handle);
154*810390e3Srobert   }
155*810390e3Srobert 
156*810390e3Srobert   return 0;
157*810390e3Srobert }
158*810390e3Srobert 
159*810390e3Srobert }  // namespace
160*810390e3Srobert 
StopTheWorld(StopTheWorldCallback callback,void * argument)161*810390e3Srobert void StopTheWorld(StopTheWorldCallback callback, void *argument) {
162*810390e3Srobert   struct RunThreadArgs arg = {callback, argument};
163*810390e3Srobert   DWORD trace_thread_id;
164*810390e3Srobert 
165*810390e3Srobert   auto trace_thread =
166*810390e3Srobert       CreateThread(nullptr, 0, RunThread, &arg, 0, &trace_thread_id);
167*810390e3Srobert   CHECK(trace_thread);
168*810390e3Srobert 
169*810390e3Srobert   WaitForSingleObject(trace_thread, INFINITE);
170*810390e3Srobert   CloseHandle(trace_thread);
171*810390e3Srobert }
172*810390e3Srobert 
173*810390e3Srobert }  // namespace __sanitizer
174*810390e3Srobert 
175*810390e3Srobert #endif  // SANITIZER_WINDOWS
176