blob: 8609d39dd6dfa152c2c6e7e94bc0417b692be33c [file] [log] [blame]
Reid Spencer566ac282004-09-11 04:59:30 +00001//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===//
Michael J. Spencer447762d2010-11-29 18:16:10 +00002//
Reid Spencer566ac282004-09-11 04:59:30 +00003// The LLVM Compiler Infrastructure
4//
Chris Lattnerf3ebc3f2007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Michael J. Spencer447762d2010-11-29 18:16:10 +00007//
Reid Spencer566ac282004-09-11 04:59:30 +00008//===----------------------------------------------------------------------===//
9//
10// This file provides the Win32 specific implementation of various Memory
11// management utilities
12//
13//===----------------------------------------------------------------------===//
14
Michael J. Spencer447762d2010-11-29 18:16:10 +000015#include "Windows.h"
16#include "llvm/Support/DataTypes.h"
17#include "llvm/Support/Process.h"
Reid Spencer566ac282004-09-11 04:59:30 +000018
19namespace llvm {
20using namespace sys;
21
22//===----------------------------------------------------------------------===//
Michael J. Spencer447762d2010-11-29 18:16:10 +000023//=== WARNING: Implementation here must contain only Win32 specific code
Reid Spencerb88212e2004-09-15 05:49:50 +000024//=== and must not be UNIX code
Reid Spencer566ac282004-09-11 04:59:30 +000025//===----------------------------------------------------------------------===//
26
Reid Kleckner4b3a3562009-07-23 21:46:56 +000027MemoryBlock Memory::AllocateRWX(size_t NumBytes,
Chris Lattner5a9d2e52006-07-07 17:32:37 +000028 const MemoryBlock *NearBlock,
29 std::string *ErrMsg) {
Reid Spencerf7948482004-09-13 22:38:11 +000030 if (NumBytes == 0) return MemoryBlock();
Reid Spencer566ac282004-09-11 04:59:30 +000031
Reid Kleckner4b3a3562009-07-23 21:46:56 +000032 static const size_t pageSize = Process::GetPageSize();
33 size_t NumPages = (NumBytes+pageSize-1)/pageSize;
Reid Spencerb88212e2004-09-15 05:49:50 +000034
Andrew Lenharth09402182005-07-29 23:40:16 +000035 //FIXME: support NearBlock if ever needed on Win64.
36
Reid Spencerb88212e2004-09-15 05:49:50 +000037 void *pa = VirtualAlloc(NULL, NumPages*pageSize, MEM_COMMIT,
38 PAGE_EXECUTE_READWRITE);
39 if (pa == NULL) {
Reid Spencer50eac3b2006-08-25 21:37:17 +000040 MakeErrMsg(ErrMsg, "Can't allocate RWX Memory: ");
Chris Lattner5a9d2e52006-07-07 17:32:37 +000041 return MemoryBlock();
Reid Spencer566ac282004-09-11 04:59:30 +000042 }
Reid Spencerb88212e2004-09-15 05:49:50 +000043
Reid Spencerf7948482004-09-13 22:38:11 +000044 MemoryBlock result;
Reid Spencerb88212e2004-09-15 05:49:50 +000045 result.Address = pa;
46 result.Size = NumPages*pageSize;
Reid Spencerf7948482004-09-13 22:38:11 +000047 return result;
Reid Spencer566ac282004-09-11 04:59:30 +000048}
49
Chris Lattner5a9d2e52006-07-07 17:32:37 +000050bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) {
Chris Lattner963ac142006-07-26 20:37:11 +000051 if (M.Address == 0 || M.Size == 0) return false;
Chris Lattner5a9d2e52006-07-07 17:32:37 +000052 if (!VirtualFree(M.Address, 0, MEM_RELEASE))
Reid Spencer50eac3b2006-08-25 21:37:17 +000053 return MakeErrMsg(ErrMsg, "Can't release RWX Memory: ");
Chris Lattner963ac142006-07-26 20:37:11 +000054 return false;
Reid Spencer566ac282004-09-11 04:59:30 +000055}
Reid Spencerb88212e2004-09-15 05:49:50 +000056
Michael J. Spencera7a90bf2011-10-13 23:16:01 +000057static DWORD getProtection(const void *addr) {
58 MEMORY_BASIC_INFORMATION info;
59 if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) {
60 return info.Protect;
61 }
62 return 0;
63}
64
Jim Grosbach93960512008-10-20 21:39:23 +000065bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) {
Michael J. Spencera7a90bf2011-10-13 23:16:01 +000066 if (!setRangeWritable(M.Address, M.Size)) {
67 return MakeErrMsg(ErrMsg, "Cannot set memory to writeable: ");
68 }
Argyrios Kyrtzidisa6f9bb72008-10-04 08:15:32 +000069 return true;
70}
71
Jim Grosbach93960512008-10-20 21:39:23 +000072bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) {
Michael J. Spencera7a90bf2011-10-13 23:16:01 +000073 if (!setRangeExecutable(M.Address, M.Size)) {
74 return MakeErrMsg(ErrMsg, "Cannot set memory to executable: ");
75 }
Jim Grosbach93960512008-10-20 21:39:23 +000076 return true;
77}
78
Michael J. Spencera7a90bf2011-10-13 23:16:01 +000079bool Memory::setRangeWritable(const void *Addr, size_t Size) {
80 DWORD prot = getProtection(Addr);
81 if (!prot)
82 return false;
83
84 if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) {
85 prot = PAGE_EXECUTE_READWRITE;
86 } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) {
87 prot = PAGE_READWRITE;
88 }
89
90 DWORD oldProt;
91 sys::Memory::InvalidateInstructionCache(Addr, Size);
92 return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
93 == TRUE;
94}
95
Jim Grosbach93960512008-10-20 21:39:23 +000096bool Memory::setRangeExecutable(const void *Addr, size_t Size) {
Michael J. Spencera7a90bf2011-10-13 23:16:01 +000097 DWORD prot = getProtection(Addr);
98 if (!prot)
99 return false;
100
101 if (prot == PAGE_NOACCESS) {
102 prot = PAGE_EXECUTE;
103 } else if (prot == PAGE_READONLY) {
104 prot = PAGE_EXECUTE_READ;
105 } else if (prot == PAGE_READWRITE) {
106 prot = PAGE_EXECUTE_READWRITE;
107 }
108
109 DWORD oldProt;
110 sys::Memory::InvalidateInstructionCache(Addr, Size);
111 return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt)
112 == TRUE;
Argyrios Kyrtzidisa6f9bb72008-10-04 08:15:32 +0000113}
114
Reid Spencerb88212e2004-09-15 05:49:50 +0000115}