brintos

brintos / llvm-project-archived public Read only

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