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