Memory.inc revision 226633
1218885Sdim//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// 2218885Sdim// 3218885Sdim// The LLVM Compiler Infrastructure 4218885Sdim// 5218885Sdim// This file is distributed under the University of Illinois Open Source 6218885Sdim// License. See LICENSE.TXT for details. 7218885Sdim// 8218885Sdim//===----------------------------------------------------------------------===// 9218885Sdim// 10218885Sdim// This file provides the Win32 specific implementation of various Memory 11218885Sdim// management utilities 12218885Sdim// 13218885Sdim//===----------------------------------------------------------------------===// 14218885Sdim 15218885Sdim#include "Windows.h" 16218885Sdim#include "llvm/Support/DataTypes.h" 17218885Sdim#include "llvm/Support/Process.h" 18218885Sdim 19218885Sdimnamespace llvm { 20218885Sdimusing namespace sys; 21218885Sdim 22218885Sdim//===----------------------------------------------------------------------===// 23218885Sdim//=== WARNING: Implementation here must contain only Win32 specific code 24218885Sdim//=== and must not be UNIX code 25218885Sdim//===----------------------------------------------------------------------===// 26218885Sdim 27218885SdimMemoryBlock Memory::AllocateRWX(size_t NumBytes, 28218885Sdim const MemoryBlock *NearBlock, 29218885Sdim std::string *ErrMsg) { 30218885Sdim if (NumBytes == 0) return MemoryBlock(); 31218885Sdim 32218885Sdim static const size_t pageSize = Process::GetPageSize(); 33218885Sdim size_t NumPages = (NumBytes+pageSize-1)/pageSize; 34218885Sdim 35226633Sdim PVOID start = NearBlock ? static_cast<unsigned char *>(NearBlock->base()) + 36226633Sdim NearBlock->size() : NULL; 37218885Sdim 38226633Sdim void *pa = VirtualAlloc(start, NumPages*pageSize, MEM_RESERVE | MEM_COMMIT, 39218885Sdim PAGE_EXECUTE_READWRITE); 40218885Sdim if (pa == NULL) { 41226633Sdim if (NearBlock) { 42226633Sdim // Try again without the NearBlock hint 43226633Sdim return AllocateRWX(NumBytes, NULL, ErrMsg); 44226633Sdim } 45218885Sdim MakeErrMsg(ErrMsg, "Can't allocate RWX Memory: "); 46218885Sdim return MemoryBlock(); 47218885Sdim } 48218885Sdim 49218885Sdim MemoryBlock result; 50218885Sdim result.Address = pa; 51218885Sdim result.Size = NumPages*pageSize; 52218885Sdim return result; 53218885Sdim} 54218885Sdim 55218885Sdimbool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { 56218885Sdim if (M.Address == 0 || M.Size == 0) return false; 57218885Sdim if (!VirtualFree(M.Address, 0, MEM_RELEASE)) 58218885Sdim return MakeErrMsg(ErrMsg, "Can't release RWX Memory: "); 59218885Sdim return false; 60218885Sdim} 61218885Sdim 62226633Sdimstatic DWORD getProtection(const void *addr) { 63226633Sdim MEMORY_BASIC_INFORMATION info; 64226633Sdim if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) { 65226633Sdim return info.Protect; 66226633Sdim } 67226633Sdim return 0; 68226633Sdim} 69226633Sdim 70218885Sdimbool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) { 71226633Sdim if (!setRangeWritable(M.Address, M.Size)) { 72226633Sdim return MakeErrMsg(ErrMsg, "Cannot set memory to writeable: "); 73226633Sdim } 74218885Sdim return true; 75218885Sdim} 76218885Sdim 77218885Sdimbool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) { 78226633Sdim if (!setRangeExecutable(M.Address, M.Size)) { 79226633Sdim return MakeErrMsg(ErrMsg, "Cannot set memory to executable: "); 80226633Sdim } 81226633Sdim return true; 82218885Sdim} 83218885Sdim 84218885Sdimbool Memory::setRangeWritable(const void *Addr, size_t Size) { 85226633Sdim DWORD prot = getProtection(Addr); 86226633Sdim if (!prot) 87226633Sdim return false; 88226633Sdim 89226633Sdim if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) { 90226633Sdim prot = PAGE_EXECUTE_READWRITE; 91226633Sdim } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) { 92226633Sdim prot = PAGE_READWRITE; 93226633Sdim } 94226633Sdim 95226633Sdim DWORD oldProt; 96226633Sdim sys::Memory::InvalidateInstructionCache(Addr, Size); 97226633Sdim return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) 98226633Sdim == TRUE; 99218885Sdim} 100218885Sdim 101218885Sdimbool Memory::setRangeExecutable(const void *Addr, size_t Size) { 102226633Sdim DWORD prot = getProtection(Addr); 103226633Sdim if (!prot) 104226633Sdim return false; 105226633Sdim 106226633Sdim if (prot == PAGE_NOACCESS) { 107226633Sdim prot = PAGE_EXECUTE; 108226633Sdim } else if (prot == PAGE_READONLY) { 109226633Sdim prot = PAGE_EXECUTE_READ; 110226633Sdim } else if (prot == PAGE_READWRITE) { 111226633Sdim prot = PAGE_EXECUTE_READWRITE; 112226633Sdim } 113226633Sdim 114226633Sdim DWORD oldProt; 115226633Sdim sys::Memory::InvalidateInstructionCache(Addr, Size); 116226633Sdim return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) 117226633Sdim == TRUE; 118218885Sdim} 119218885Sdim 120218885Sdim} 121