123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- //===-- sanitizer_stoptheworld_win.cpp ------------------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // See sanitizer_stoptheworld.h for details.
- //
- //===----------------------------------------------------------------------===//
- #include "sanitizer_platform.h"
- #if SANITIZER_WINDOWS
- # define WIN32_LEAN_AND_MEAN
- # include <windows.h>
- // windows.h needs to be included before tlhelp32.h
- # include <tlhelp32.h>
- # include "sanitizer_stoptheworld.h"
- namespace __sanitizer {
- namespace {
- struct SuspendedThreadsListWindows final : public SuspendedThreadsList {
- InternalMmapVector<HANDLE> threadHandles;
- InternalMmapVector<DWORD> threadIds;
- SuspendedThreadsListWindows() {
- threadIds.reserve(1024);
- threadHandles.reserve(1024);
- }
- PtraceRegistersStatus GetRegistersAndSP(uptr index,
- InternalMmapVector<uptr> *buffer,
- uptr *sp) const override;
- tid_t GetThreadID(uptr index) const override;
- uptr ThreadCount() const override;
- };
- // Stack Pointer register names on different architectures
- # if SANITIZER_X64
- # define SP_REG Rsp
- # elif SANITIZER_I386
- # define SP_REG Esp
- # elif SANITIZER_ARM | SANITIZER_ARM64
- # define SP_REG Sp
- # else
- # error Architecture not supported!
- # endif
- PtraceRegistersStatus SuspendedThreadsListWindows::GetRegistersAndSP(
- uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {
- CHECK_LT(index, threadHandles.size());
- buffer->resize(RoundUpTo(sizeof(CONTEXT), sizeof(uptr)) / sizeof(uptr));
- CONTEXT *thread_context = reinterpret_cast<CONTEXT *>(buffer->data());
- thread_context->ContextFlags = CONTEXT_ALL;
- CHECK(GetThreadContext(threadHandles[index], thread_context));
- *sp = thread_context->SP_REG;
- return REGISTERS_AVAILABLE;
- }
- tid_t SuspendedThreadsListWindows::GetThreadID(uptr index) const {
- CHECK_LT(index, threadIds.size());
- return threadIds[index];
- }
- uptr SuspendedThreadsListWindows::ThreadCount() const {
- return threadIds.size();
- }
- struct RunThreadArgs {
- StopTheWorldCallback callback;
- void *argument;
- };
- DWORD WINAPI RunThread(void *argument) {
- RunThreadArgs *run_args = (RunThreadArgs *)argument;
- const DWORD this_thread = GetCurrentThreadId();
- const DWORD this_process = GetCurrentProcessId();
- SuspendedThreadsListWindows suspended_threads_list;
- bool new_thread_found;
- do {
- // Take a snapshot of all Threads
- const HANDLE threads = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
- CHECK(threads != INVALID_HANDLE_VALUE);
- THREADENTRY32 thread_entry;
- thread_entry.dwSize = sizeof(thread_entry);
- new_thread_found = false;
- if (!Thread32First(threads, &thread_entry))
- break;
- do {
- if (thread_entry.th32ThreadID == this_thread ||
- thread_entry.th32OwnerProcessID != this_process)
- continue;
- bool suspended_thread = false;
- for (const auto thread_id : suspended_threads_list.threadIds) {
- if (thread_id == thread_entry.th32ThreadID) {
- suspended_thread = true;
- break;
- }
- }
- // Skip the Thread if it was already suspended
- if (suspended_thread)
- continue;
- const HANDLE thread =
- OpenThread(THREAD_ALL_ACCESS, FALSE, thread_entry.th32ThreadID);
- CHECK(thread);
- if (SuspendThread(thread) == (DWORD)-1) {
- DWORD last_error = GetLastError();
- VPrintf(1, "Could not suspend thread %lu (error %lu)",
- thread_entry.th32ThreadID, last_error);
- continue;
- }
- suspended_threads_list.threadIds.push_back(thread_entry.th32ThreadID);
- suspended_threads_list.threadHandles.push_back(thread);
- new_thread_found = true;
- } while (Thread32Next(threads, &thread_entry));
- CloseHandle(threads);
- // Between the call to `CreateToolhelp32Snapshot` and suspending the
- // relevant Threads, new Threads could have potentially been created. So
- // continue to find and suspend new Threads until we don't find any.
- } while (new_thread_found);
- // Now all Threads of this Process except of this Thread should be suspended.
- // Execute the callback function.
- run_args->callback(suspended_threads_list, run_args->argument);
- // Resume all Threads
- for (const auto suspended_thread_handle :
- suspended_threads_list.threadHandles) {
- CHECK_NE(ResumeThread(suspended_thread_handle), -1);
- CloseHandle(suspended_thread_handle);
- }
- return 0;
- }
- } // namespace
- void StopTheWorld(StopTheWorldCallback callback, void *argument) {
- struct RunThreadArgs arg = {callback, argument};
- DWORD trace_thread_id;
- auto trace_thread =
- CreateThread(nullptr, 0, RunThread, &arg, 0, &trace_thread_id);
- CHECK(trace_thread);
- WaitForSingleObject(trace_thread, INFINITE);
- CloseHandle(trace_thread);
- }
- } // namespace __sanitizer
- #endif // SANITIZER_WINDOWS
|