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