blob: 46bc8f7c9e5997e56ef8592c57501e2f20d295f4 [file]
//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// system_utils_win32.cpp: Implementation of OS-specific functions for Windows.
#include "common/FastVector.h"
#include "system_utils.h"
#include <windows.h>
#include <array>
namespace angle
{
bool UnsetEnvironmentVar(const char *variableName)
{
return (SetEnvironmentVariableA(variableName, nullptr) == TRUE);
}
bool SetEnvironmentVar(const char *variableName, const char *value)
{
return (SetEnvironmentVariableA(variableName, value) == TRUE);
}
std::string GetEnvironmentVar(const char *variableName)
{
FastVector<char, MAX_PATH> value;
DWORD result;
// First get the length of the variable, including the null terminator
result = GetEnvironmentVariableA(variableName, nullptr, 0);
// Zero means the variable was not found, so return now.
if (result == 0)
{
return std::string();
}
// Now size the vector to fit the data, and read the environment variable.
value.resize(result, 0);
result = GetEnvironmentVariableA(variableName, value.data(), result);
return std::string(value.data());
}
class Win32Library : public Library
{
public:
Win32Library(const char *libraryName, SearchType searchType, std::string *errorOut)
{
switch (searchType)
{
case SearchType::ModuleDir:
{
std::string moduleRelativePath = ConcatenatePath(GetModuleDirectory(), libraryName);
if (errorOut)
{
*errorOut = moduleRelativePath;
}
mModule = LoadLibraryA(moduleRelativePath.c_str());
break;
}
case SearchType::SystemDir:
if (errorOut)
{
*errorOut = libraryName;
}
mModule = LoadLibraryExA(libraryName, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
break;
case SearchType::AlreadyLoaded:
if (errorOut)
{
*errorOut = libraryName;
}
mModule = GetModuleHandleA(libraryName);
break;
}
}
~Win32Library() override
{
if (mModule)
{
FreeLibrary(mModule);
}
}
void *getSymbol(const char *symbolName) override
{
if (!mModule)
{
fprintf(stderr, "Module was not loaded\n");
return nullptr;
}
return reinterpret_cast<void *>(GetProcAddress(mModule, symbolName));
}
void *getNative() const override { return reinterpret_cast<void *>(mModule); }
std::string getPath() const override
{
if (!mModule)
{
return "";
}
std::array<char, MAX_PATH> buffer;
if (GetModuleFileNameA(mModule, buffer.data(), buffer.size()) == 0)
{
return "";
}
return std::string(buffer.data());
}
private:
HMODULE mModule = nullptr;
};
Library *OpenSharedLibrary(const char *libraryName, SearchType searchType)
{
return OpenSharedLibraryAndGetError(libraryName, searchType, nullptr);
}
Library *OpenSharedLibraryWithExtension(const char *libraryName, SearchType searchType)
{
return OpenSharedLibraryWithExtensionAndGetError(libraryName, searchType, nullptr);
}
Library *OpenSharedLibraryAndGetError(const char *libraryName,
SearchType searchType,
std::string *errorOut)
{
char buffer[MAX_PATH];
int ret = snprintf(buffer, MAX_PATH, "%s.%s", libraryName, GetSharedLibraryExtension());
if (ret > 0 && ret < MAX_PATH)
{
return new Win32Library(buffer, searchType, errorOut);
}
else
{
fprintf(stderr, "Error loading shared library: 0x%x", ret);
return nullptr;
}
}
Library *OpenSharedLibraryWithExtensionAndGetError(const char *libraryName,
SearchType searchType,
std::string *errorOut)
{
return new Win32Library(libraryName, searchType, errorOut);
}
namespace
{
class Win32PageFaultHandler : public PageFaultHandler
{
public:
Win32PageFaultHandler(PageFaultCallback callback) : PageFaultHandler(callback) {}
~Win32PageFaultHandler() override {}
bool enable() override;
bool disable() override;
LONG handle(PEXCEPTION_POINTERS pExceptionInfo);
private:
void *mVectoredExceptionHandler = nullptr;
};
Win32PageFaultHandler *gWin32PageFaultHandler = nullptr;
static LONG CALLBACK VectoredExceptionHandler(PEXCEPTION_POINTERS info)
{
return gWin32PageFaultHandler->handle(info);
}
bool SetMemoryProtection(uintptr_t start, size_t size, DWORD protections)
{
DWORD oldProtect;
BOOL res = VirtualProtect(reinterpret_cast<LPVOID>(start), size, protections, &oldProtect);
if (!res)
{
DWORD lastError = GetLastError();
fprintf(stderr, "VirtualProtect failed: 0x%lx\n", lastError);
return false;
}
return true;
}
LONG Win32PageFaultHandler::handle(PEXCEPTION_POINTERS info)
{
bool found = false;
if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
info->ExceptionRecord->NumberParameters >= 2 &&
info->ExceptionRecord->ExceptionInformation[0] == 1)
{
found = mCallback(static_cast<uintptr_t>(info->ExceptionRecord->ExceptionInformation[1])) ==
PageFaultHandlerRangeType::InRange;
}
if (found)
{
return EXCEPTION_CONTINUE_EXECUTION;
}
else
{
return EXCEPTION_CONTINUE_SEARCH;
}
}
bool Win32PageFaultHandler::disable()
{
if (mVectoredExceptionHandler)
{
ULONG res = RemoveVectoredExceptionHandler(mVectoredExceptionHandler);
mVectoredExceptionHandler = nullptr;
if (res == 0)
{
DWORD lastError = GetLastError();
fprintf(stderr, "RemoveVectoredExceptionHandler failed: 0x%lx\n", lastError);
return false;
}
}
return true;
}
bool Win32PageFaultHandler::enable()
{
if (mVectoredExceptionHandler)
{
return true;
}
PVECTORED_EXCEPTION_HANDLER handler =
reinterpret_cast<PVECTORED_EXCEPTION_HANDLER>(&VectoredExceptionHandler);
mVectoredExceptionHandler = AddVectoredExceptionHandler(1, handler);
if (!mVectoredExceptionHandler)
{
DWORD lastError = GetLastError();
fprintf(stderr, "AddVectoredExceptionHandler failed: 0x%lx\n", lastError);
return false;
}
return true;
}
} // namespace
// Set write protection
bool ProtectMemory(uintptr_t start, size_t size)
{
return SetMemoryProtection(start, size, PAGE_READONLY);
}
// Allow reading and writing
bool UnprotectMemory(uintptr_t start, size_t size)
{
return SetMemoryProtection(start, size, PAGE_READWRITE);
}
size_t GetPageSize()
{
SYSTEM_INFO info;
GetSystemInfo(&info);
return static_cast<size_t>(info.dwPageSize);
}
PageFaultHandler *CreatePageFaultHandler(PageFaultCallback callback)
{
gWin32PageFaultHandler = new Win32PageFaultHandler(callback);
return gWin32PageFaultHandler;
}
} // namespace angle