19b4f179bSClemens Wasser //===-- sanitizer_stoptheworld_win.cpp ------------------------------------===//
29b4f179bSClemens Wasser //
39b4f179bSClemens Wasser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49b4f179bSClemens Wasser // See https://llvm.org/LICENSE.txt for license information.
59b4f179bSClemens Wasser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69b4f179bSClemens Wasser //
79b4f179bSClemens Wasser //===----------------------------------------------------------------------===//
89b4f179bSClemens Wasser //
99b4f179bSClemens Wasser // See sanitizer_stoptheworld.h for details.
109b4f179bSClemens Wasser //
119b4f179bSClemens Wasser //===----------------------------------------------------------------------===//
129b4f179bSClemens Wasser
139b4f179bSClemens Wasser #include "sanitizer_platform.h"
149b4f179bSClemens Wasser
159b4f179bSClemens Wasser #if SANITIZER_WINDOWS
169b4f179bSClemens Wasser
179b4f179bSClemens Wasser # define WIN32_LEAN_AND_MEAN
189b4f179bSClemens Wasser # include <windows.h>
199b4f179bSClemens Wasser // windows.h needs to be included before tlhelp32.h
209b4f179bSClemens Wasser # include <tlhelp32.h>
219b4f179bSClemens Wasser
229b4f179bSClemens Wasser # include "sanitizer_stoptheworld.h"
239b4f179bSClemens Wasser
249b4f179bSClemens Wasser namespace __sanitizer {
259b4f179bSClemens Wasser
269b4f179bSClemens Wasser namespace {
279b4f179bSClemens Wasser
289b4f179bSClemens Wasser struct SuspendedThreadsListWindows final : public SuspendedThreadsList {
299b4f179bSClemens Wasser InternalMmapVector<HANDLE> threadHandles;
309b4f179bSClemens Wasser InternalMmapVector<DWORD> threadIds;
319b4f179bSClemens Wasser
SuspendedThreadsListWindows__sanitizer::__anon9291efba0111::SuspendedThreadsListWindows329b4f179bSClemens Wasser SuspendedThreadsListWindows() {
339b4f179bSClemens Wasser threadIds.reserve(1024);
349b4f179bSClemens Wasser threadHandles.reserve(1024);
359b4f179bSClemens Wasser }
369b4f179bSClemens Wasser
379b4f179bSClemens Wasser PtraceRegistersStatus GetRegistersAndSP(uptr index,
389b4f179bSClemens Wasser InternalMmapVector<uptr> *buffer,
399b4f179bSClemens Wasser uptr *sp) const override;
409b4f179bSClemens Wasser
419b4f179bSClemens Wasser tid_t GetThreadID(uptr index) const override;
429b4f179bSClemens Wasser uptr ThreadCount() const override;
439b4f179bSClemens Wasser };
449b4f179bSClemens Wasser
459b4f179bSClemens Wasser // Stack Pointer register names on different architectures
469b4f179bSClemens Wasser # if SANITIZER_X64
479b4f179bSClemens Wasser # define SP_REG Rsp
489b4f179bSClemens Wasser # elif SANITIZER_I386
499b4f179bSClemens Wasser # define SP_REG Esp
509b4f179bSClemens Wasser # elif SANITIZER_ARM | SANITIZER_ARM64
519b4f179bSClemens Wasser # define SP_REG Sp
529b4f179bSClemens Wasser # else
539b4f179bSClemens Wasser # error Architecture not supported!
549b4f179bSClemens Wasser # endif
559b4f179bSClemens Wasser
GetRegistersAndSP(uptr index,InternalMmapVector<uptr> * buffer,uptr * sp) const569b4f179bSClemens Wasser PtraceRegistersStatus SuspendedThreadsListWindows::GetRegistersAndSP(
579b4f179bSClemens Wasser uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {
589b4f179bSClemens Wasser CHECK_LT(index, threadHandles.size());
599b4f179bSClemens Wasser
609b4f179bSClemens Wasser buffer->resize(RoundUpTo(sizeof(CONTEXT), sizeof(uptr)) / sizeof(uptr));
619b4f179bSClemens Wasser CONTEXT *thread_context = reinterpret_cast<CONTEXT *>(buffer->data());
629b4f179bSClemens Wasser thread_context->ContextFlags = CONTEXT_ALL;
639b4f179bSClemens Wasser CHECK(GetThreadContext(threadHandles[index], thread_context));
649b4f179bSClemens Wasser *sp = thread_context->SP_REG;
659b4f179bSClemens Wasser
669b4f179bSClemens Wasser return REGISTERS_AVAILABLE;
679b4f179bSClemens Wasser }
689b4f179bSClemens Wasser
GetThreadID(uptr index) const699b4f179bSClemens Wasser tid_t SuspendedThreadsListWindows::GetThreadID(uptr index) const {
709b4f179bSClemens Wasser CHECK_LT(index, threadIds.size());
719b4f179bSClemens Wasser return threadIds[index];
729b4f179bSClemens Wasser }
739b4f179bSClemens Wasser
ThreadCount() const749b4f179bSClemens Wasser uptr SuspendedThreadsListWindows::ThreadCount() const {
759b4f179bSClemens Wasser return threadIds.size();
769b4f179bSClemens Wasser }
779b4f179bSClemens Wasser
789b4f179bSClemens Wasser struct RunThreadArgs {
799b4f179bSClemens Wasser StopTheWorldCallback callback;
809b4f179bSClemens Wasser void *argument;
819b4f179bSClemens Wasser };
829b4f179bSClemens Wasser
RunThread(void * argument)839b4f179bSClemens Wasser DWORD WINAPI RunThread(void *argument) {
849b4f179bSClemens Wasser RunThreadArgs *run_args = (RunThreadArgs *)argument;
859b4f179bSClemens Wasser
869b4f179bSClemens Wasser const DWORD this_thread = GetCurrentThreadId();
879b4f179bSClemens Wasser const DWORD this_process = GetCurrentProcessId();
889b4f179bSClemens Wasser
899b4f179bSClemens Wasser SuspendedThreadsListWindows suspended_threads_list;
909b4f179bSClemens Wasser bool new_thread_found;
919b4f179bSClemens Wasser
929b4f179bSClemens Wasser do {
939b4f179bSClemens Wasser // Take a snapshot of all Threads
949b4f179bSClemens Wasser const HANDLE threads = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
959b4f179bSClemens Wasser CHECK(threads != INVALID_HANDLE_VALUE);
969b4f179bSClemens Wasser
979b4f179bSClemens Wasser THREADENTRY32 thread_entry;
989b4f179bSClemens Wasser thread_entry.dwSize = sizeof(thread_entry);
999b4f179bSClemens Wasser new_thread_found = false;
1009b4f179bSClemens Wasser
1019b4f179bSClemens Wasser if (!Thread32First(threads, &thread_entry))
1029b4f179bSClemens Wasser break;
1039b4f179bSClemens Wasser
1049b4f179bSClemens Wasser do {
1059b4f179bSClemens Wasser if (thread_entry.th32ThreadID == this_thread ||
1069b4f179bSClemens Wasser thread_entry.th32OwnerProcessID != this_process)
1079b4f179bSClemens Wasser continue;
1089b4f179bSClemens Wasser
1099b4f179bSClemens Wasser bool suspended_thread = false;
1109b4f179bSClemens Wasser for (const auto thread_id : suspended_threads_list.threadIds) {
1119b4f179bSClemens Wasser if (thread_id == thread_entry.th32ThreadID) {
1129b4f179bSClemens Wasser suspended_thread = true;
1139b4f179bSClemens Wasser break;
1149b4f179bSClemens Wasser }
1159b4f179bSClemens Wasser }
1169b4f179bSClemens Wasser
1179b4f179bSClemens Wasser // Skip the Thread if it was already suspended
1189b4f179bSClemens Wasser if (suspended_thread)
1199b4f179bSClemens Wasser continue;
1209b4f179bSClemens Wasser
1219b4f179bSClemens Wasser const HANDLE thread =
1229b4f179bSClemens Wasser OpenThread(THREAD_ALL_ACCESS, FALSE, thread_entry.th32ThreadID);
1239b4f179bSClemens Wasser CHECK(thread);
1249b4f179bSClemens Wasser
125*5d5d806eSAlexandre Ganea if (SuspendThread(thread) == (DWORD)-1) {
1269b4f179bSClemens Wasser DWORD last_error = GetLastError();
1279b4f179bSClemens Wasser
1289b4f179bSClemens Wasser VPrintf(1, "Could not suspend thread %lu (error %lu)",
1299b4f179bSClemens Wasser thread_entry.th32ThreadID, last_error);
1309b4f179bSClemens Wasser continue;
1319b4f179bSClemens Wasser }
1329b4f179bSClemens Wasser
1339b4f179bSClemens Wasser suspended_threads_list.threadIds.push_back(thread_entry.th32ThreadID);
1349b4f179bSClemens Wasser suspended_threads_list.threadHandles.push_back(thread);
1359b4f179bSClemens Wasser new_thread_found = true;
1369b4f179bSClemens Wasser } while (Thread32Next(threads, &thread_entry));
1379b4f179bSClemens Wasser
1389b4f179bSClemens Wasser CloseHandle(threads);
1399b4f179bSClemens Wasser
1409b4f179bSClemens Wasser // Between the call to `CreateToolhelp32Snapshot` and suspending the
1419b4f179bSClemens Wasser // relevant Threads, new Threads could have potentially been created. So
1429b4f179bSClemens Wasser // continue to find and suspend new Threads until we don't find any.
1439b4f179bSClemens Wasser } while (new_thread_found);
1449b4f179bSClemens Wasser
1459b4f179bSClemens Wasser // Now all Threads of this Process except of this Thread should be suspended.
1469b4f179bSClemens Wasser // Execute the callback function.
1479b4f179bSClemens Wasser run_args->callback(suspended_threads_list, run_args->argument);
1489b4f179bSClemens Wasser
1499b4f179bSClemens Wasser // Resume all Threads
1509b4f179bSClemens Wasser for (const auto suspended_thread_handle :
1519b4f179bSClemens Wasser suspended_threads_list.threadHandles) {
1529b4f179bSClemens Wasser CHECK_NE(ResumeThread(suspended_thread_handle), -1);
1539b4f179bSClemens Wasser CloseHandle(suspended_thread_handle);
1549b4f179bSClemens Wasser }
1559b4f179bSClemens Wasser
1569b4f179bSClemens Wasser return 0;
1579b4f179bSClemens Wasser }
1589b4f179bSClemens Wasser
1599b4f179bSClemens Wasser } // namespace
1609b4f179bSClemens Wasser
StopTheWorld(StopTheWorldCallback callback,void * argument)1619b4f179bSClemens Wasser void StopTheWorld(StopTheWorldCallback callback, void *argument) {
1629b4f179bSClemens Wasser struct RunThreadArgs arg = {callback, argument};
1639b4f179bSClemens Wasser DWORD trace_thread_id;
1649b4f179bSClemens Wasser
1659b4f179bSClemens Wasser auto trace_thread =
1669b4f179bSClemens Wasser CreateThread(nullptr, 0, RunThread, &arg, 0, &trace_thread_id);
1679b4f179bSClemens Wasser CHECK(trace_thread);
1689b4f179bSClemens Wasser
1699b4f179bSClemens Wasser WaitForSingleObject(trace_thread, INFINITE);
1709b4f179bSClemens Wasser CloseHandle(trace_thread);
1719b4f179bSClemens Wasser }
1729b4f179bSClemens Wasser
1739b4f179bSClemens Wasser } // namespace __sanitizer
1749b4f179bSClemens Wasser
1759b4f179bSClemens Wasser #endif // SANITIZER_WINDOWS
176