xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_win.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
10eae32dcSDimitry Andric //===-- sanitizer_stoptheworld_win.cpp ------------------------------------===//
20eae32dcSDimitry Andric //
30eae32dcSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40eae32dcSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50eae32dcSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60eae32dcSDimitry Andric //
70eae32dcSDimitry Andric //===----------------------------------------------------------------------===//
80eae32dcSDimitry Andric //
90eae32dcSDimitry Andric // See sanitizer_stoptheworld.h for details.
100eae32dcSDimitry Andric //
110eae32dcSDimitry Andric //===----------------------------------------------------------------------===//
120eae32dcSDimitry Andric 
130eae32dcSDimitry Andric #include "sanitizer_platform.h"
140eae32dcSDimitry Andric 
150eae32dcSDimitry Andric #if SANITIZER_WINDOWS
160eae32dcSDimitry Andric 
170eae32dcSDimitry Andric #  define WIN32_LEAN_AND_MEAN
180eae32dcSDimitry Andric #  include <windows.h>
190eae32dcSDimitry Andric // windows.h needs to be included before tlhelp32.h
200eae32dcSDimitry Andric #  include <tlhelp32.h>
210eae32dcSDimitry Andric 
220eae32dcSDimitry Andric #  include "sanitizer_stoptheworld.h"
230eae32dcSDimitry Andric 
240eae32dcSDimitry Andric namespace __sanitizer {
250eae32dcSDimitry Andric 
260eae32dcSDimitry Andric namespace {
270eae32dcSDimitry Andric 
280eae32dcSDimitry Andric struct SuspendedThreadsListWindows final : public SuspendedThreadsList {
290eae32dcSDimitry Andric   InternalMmapVector<HANDLE> threadHandles;
300eae32dcSDimitry Andric   InternalMmapVector<DWORD> threadIds;
310eae32dcSDimitry Andric 
SuspendedThreadsListWindows__sanitizer::__anonc9cb93190111::SuspendedThreadsListWindows320eae32dcSDimitry Andric   SuspendedThreadsListWindows() {
330eae32dcSDimitry Andric     threadIds.reserve(1024);
340eae32dcSDimitry Andric     threadHandles.reserve(1024);
350eae32dcSDimitry Andric   }
360eae32dcSDimitry Andric 
370eae32dcSDimitry Andric   PtraceRegistersStatus GetRegistersAndSP(uptr index,
380eae32dcSDimitry Andric                                           InternalMmapVector<uptr> *buffer,
390eae32dcSDimitry Andric                                           uptr *sp) const override;
400eae32dcSDimitry Andric 
410eae32dcSDimitry Andric   tid_t GetThreadID(uptr index) const override;
420eae32dcSDimitry Andric   uptr ThreadCount() const override;
430eae32dcSDimitry Andric };
440eae32dcSDimitry Andric 
450eae32dcSDimitry Andric // Stack Pointer register names on different architectures
460eae32dcSDimitry Andric #  if SANITIZER_X64
470eae32dcSDimitry Andric #    define SP_REG Rsp
480eae32dcSDimitry Andric #  elif SANITIZER_I386
490eae32dcSDimitry Andric #    define SP_REG Esp
500eae32dcSDimitry Andric #  elif SANITIZER_ARM | SANITIZER_ARM64
510eae32dcSDimitry Andric #    define SP_REG Sp
520eae32dcSDimitry Andric #  else
530eae32dcSDimitry Andric #    error Architecture not supported!
540eae32dcSDimitry Andric #  endif
550eae32dcSDimitry Andric 
GetRegistersAndSP(uptr index,InternalMmapVector<uptr> * buffer,uptr * sp) const560eae32dcSDimitry Andric PtraceRegistersStatus SuspendedThreadsListWindows::GetRegistersAndSP(
570eae32dcSDimitry Andric     uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {
580eae32dcSDimitry Andric   CHECK_LT(index, threadHandles.size());
590eae32dcSDimitry Andric 
600eae32dcSDimitry Andric   buffer->resize(RoundUpTo(sizeof(CONTEXT), sizeof(uptr)) / sizeof(uptr));
610eae32dcSDimitry Andric   CONTEXT *thread_context = reinterpret_cast<CONTEXT *>(buffer->data());
620eae32dcSDimitry Andric   thread_context->ContextFlags = CONTEXT_ALL;
630eae32dcSDimitry Andric   CHECK(GetThreadContext(threadHandles[index], thread_context));
640eae32dcSDimitry Andric   *sp = thread_context->SP_REG;
650eae32dcSDimitry Andric 
660eae32dcSDimitry Andric   return REGISTERS_AVAILABLE;
670eae32dcSDimitry Andric }
680eae32dcSDimitry Andric 
GetThreadID(uptr index) const690eae32dcSDimitry Andric tid_t SuspendedThreadsListWindows::GetThreadID(uptr index) const {
700eae32dcSDimitry Andric   CHECK_LT(index, threadIds.size());
710eae32dcSDimitry Andric   return threadIds[index];
720eae32dcSDimitry Andric }
730eae32dcSDimitry Andric 
ThreadCount() const740eae32dcSDimitry Andric uptr SuspendedThreadsListWindows::ThreadCount() const {
750eae32dcSDimitry Andric   return threadIds.size();
760eae32dcSDimitry Andric }
770eae32dcSDimitry Andric 
780eae32dcSDimitry Andric struct RunThreadArgs {
790eae32dcSDimitry Andric   StopTheWorldCallback callback;
800eae32dcSDimitry Andric   void *argument;
810eae32dcSDimitry Andric };
820eae32dcSDimitry Andric 
RunThread(void * argument)830eae32dcSDimitry Andric DWORD WINAPI RunThread(void *argument) {
840eae32dcSDimitry Andric   RunThreadArgs *run_args = (RunThreadArgs *)argument;
850eae32dcSDimitry Andric 
860eae32dcSDimitry Andric   const DWORD this_thread = GetCurrentThreadId();
870eae32dcSDimitry Andric   const DWORD this_process = GetCurrentProcessId();
880eae32dcSDimitry Andric 
890eae32dcSDimitry Andric   SuspendedThreadsListWindows suspended_threads_list;
900eae32dcSDimitry Andric   bool new_thread_found;
910eae32dcSDimitry Andric 
920eae32dcSDimitry Andric   do {
930eae32dcSDimitry Andric     // Take a snapshot of all Threads
940eae32dcSDimitry Andric     const HANDLE threads = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
950eae32dcSDimitry Andric     CHECK(threads != INVALID_HANDLE_VALUE);
960eae32dcSDimitry Andric 
970eae32dcSDimitry Andric     THREADENTRY32 thread_entry;
980eae32dcSDimitry Andric     thread_entry.dwSize = sizeof(thread_entry);
990eae32dcSDimitry Andric     new_thread_found = false;
1000eae32dcSDimitry Andric 
1010eae32dcSDimitry Andric     if (!Thread32First(threads, &thread_entry))
1020eae32dcSDimitry Andric       break;
1030eae32dcSDimitry Andric 
1040eae32dcSDimitry Andric     do {
1050eae32dcSDimitry Andric       if (thread_entry.th32ThreadID == this_thread ||
1060eae32dcSDimitry Andric           thread_entry.th32OwnerProcessID != this_process)
1070eae32dcSDimitry Andric         continue;
1080eae32dcSDimitry Andric 
1090eae32dcSDimitry Andric       bool suspended_thread = false;
1100eae32dcSDimitry Andric       for (const auto thread_id : suspended_threads_list.threadIds) {
1110eae32dcSDimitry Andric         if (thread_id == thread_entry.th32ThreadID) {
1120eae32dcSDimitry Andric           suspended_thread = true;
1130eae32dcSDimitry Andric           break;
1140eae32dcSDimitry Andric         }
1150eae32dcSDimitry Andric       }
1160eae32dcSDimitry Andric 
1170eae32dcSDimitry Andric       // Skip the Thread if it was already suspended
1180eae32dcSDimitry Andric       if (suspended_thread)
1190eae32dcSDimitry Andric         continue;
1200eae32dcSDimitry Andric 
1210eae32dcSDimitry Andric       const HANDLE thread =
1220eae32dcSDimitry Andric           OpenThread(THREAD_ALL_ACCESS, FALSE, thread_entry.th32ThreadID);
1230eae32dcSDimitry Andric       CHECK(thread);
1240eae32dcSDimitry Andric 
125*04eeddc0SDimitry Andric       if (SuspendThread(thread) == (DWORD)-1) {
1260eae32dcSDimitry Andric         DWORD last_error = GetLastError();
1270eae32dcSDimitry Andric 
1280eae32dcSDimitry Andric         VPrintf(1, "Could not suspend thread %lu (error %lu)",
1290eae32dcSDimitry Andric                 thread_entry.th32ThreadID, last_error);
1300eae32dcSDimitry Andric         continue;
1310eae32dcSDimitry Andric       }
1320eae32dcSDimitry Andric 
1330eae32dcSDimitry Andric       suspended_threads_list.threadIds.push_back(thread_entry.th32ThreadID);
1340eae32dcSDimitry Andric       suspended_threads_list.threadHandles.push_back(thread);
1350eae32dcSDimitry Andric       new_thread_found = true;
1360eae32dcSDimitry Andric     } while (Thread32Next(threads, &thread_entry));
1370eae32dcSDimitry Andric 
1380eae32dcSDimitry Andric     CloseHandle(threads);
1390eae32dcSDimitry Andric 
1400eae32dcSDimitry Andric     // Between the call to `CreateToolhelp32Snapshot` and suspending the
1410eae32dcSDimitry Andric     // relevant Threads, new Threads could have potentially been created. So
1420eae32dcSDimitry Andric     // continue to find and suspend new Threads until we don't find any.
1430eae32dcSDimitry Andric   } while (new_thread_found);
1440eae32dcSDimitry Andric 
1450eae32dcSDimitry Andric   // Now all Threads of this Process except of this Thread should be suspended.
1460eae32dcSDimitry Andric   // Execute the callback function.
1470eae32dcSDimitry Andric   run_args->callback(suspended_threads_list, run_args->argument);
1480eae32dcSDimitry Andric 
1490eae32dcSDimitry Andric   // Resume all Threads
1500eae32dcSDimitry Andric   for (const auto suspended_thread_handle :
1510eae32dcSDimitry Andric        suspended_threads_list.threadHandles) {
1520eae32dcSDimitry Andric     CHECK_NE(ResumeThread(suspended_thread_handle), -1);
1530eae32dcSDimitry Andric     CloseHandle(suspended_thread_handle);
1540eae32dcSDimitry Andric   }
1550eae32dcSDimitry Andric 
1560eae32dcSDimitry Andric   return 0;
1570eae32dcSDimitry Andric }
1580eae32dcSDimitry Andric 
1590eae32dcSDimitry Andric }  // namespace
1600eae32dcSDimitry Andric 
StopTheWorld(StopTheWorldCallback callback,void * argument)1610eae32dcSDimitry Andric void StopTheWorld(StopTheWorldCallback callback, void *argument) {
1620eae32dcSDimitry Andric   struct RunThreadArgs arg = {callback, argument};
1630eae32dcSDimitry Andric   DWORD trace_thread_id;
1640eae32dcSDimitry Andric 
1650eae32dcSDimitry Andric   auto trace_thread =
1660eae32dcSDimitry Andric       CreateThread(nullptr, 0, RunThread, &arg, 0, &trace_thread_id);
1670eae32dcSDimitry Andric   CHECK(trace_thread);
1680eae32dcSDimitry Andric 
1690eae32dcSDimitry Andric   WaitForSingleObject(trace_thread, INFINITE);
1700eae32dcSDimitry Andric   CloseHandle(trace_thread);
1710eae32dcSDimitry Andric }
1720eae32dcSDimitry Andric 
1730eae32dcSDimitry Andric }  // namespace __sanitizer
1740eae32dcSDimitry Andric 
1750eae32dcSDimitry Andric #endif  // SANITIZER_WINDOWS
176