Remove duplication in Program::Execute{And,No}Wait.
[oota-llvm.git] / lib / System / Unix / Memory.inc
1 //===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines some functions for various memory management utilities.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "Unix.h"
15 #include "llvm/System/Process.h"
16
17 #ifdef HAVE_SYS_MMAN_H
18 #include <sys/mman.h>
19 #endif
20
21 #ifdef __APPLE__
22 #include <mach/mach.h>
23 #endif
24
25 /// AllocateRWX - Allocate a slab of memory with read/write/execute
26 /// permissions.  This is typically used for JIT applications where we want
27 /// to emit code to the memory then jump to it.  Getting this type of memory
28 /// is very OS specific.
29 ///
30 llvm::sys::MemoryBlock 
31 llvm::sys::Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock,
32                                std::string *ErrMsg) {
33   if (NumBytes == 0) return MemoryBlock();
34
35   unsigned pageSize = Process::GetPageSize();
36   unsigned NumPages = (NumBytes+pageSize-1)/pageSize;
37
38   int fd = -1;
39 #ifdef NEED_DEV_ZERO_FOR_MMAP
40   static int zero_fd = open("/dev/zero", O_RDWR);
41   if (zero_fd == -1) {
42     MakeErrMsg(ErrMsg, "Can't open /dev/zero device");
43     return MemoryBlock();
44   }
45   fd = zero_fd;
46 #endif
47
48   int flags = MAP_PRIVATE |
49 #ifdef HAVE_MMAP_ANONYMOUS
50   MAP_ANONYMOUS
51 #else
52   MAP_ANON
53 #endif
54   ;
55
56   void* start = NearBlock ? (unsigned char*)NearBlock->base() + 
57                             NearBlock->size() : 0;
58
59 #if defined(__APPLE__) && defined(__arm__)
60   void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_EXEC,
61                     flags, fd, 0);
62 #else
63   void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC,
64                     flags, fd, 0);
65 #endif
66   if (pa == MAP_FAILED) {
67     if (NearBlock) //Try again without a near hint
68       return AllocateRWX(NumBytes, 0);
69
70     MakeErrMsg(ErrMsg, "Can't allocate RWX Memory");
71     return MemoryBlock();
72   }
73
74 #if defined(__APPLE__) && defined(__arm__)
75   kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)pa,
76                                 (vm_size_t)(pageSize*NumPages), 0,
77                                 VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY);
78   if (KERN_SUCCESS != kr) {
79     MakeErrMsg(ErrMsg, "vm_protect max RX failed");
80     return sys::MemoryBlock();
81   }
82
83   kr = vm_protect(mach_task_self(), (vm_address_t)pa,
84                   (vm_size_t)(pageSize*NumPages), 0,
85                   VM_PROT_READ | VM_PROT_WRITE);
86   if (KERN_SUCCESS != kr) {
87     MakeErrMsg(ErrMsg, "vm_protect RW failed");
88     return sys::MemoryBlock();
89   }
90 #endif
91
92   MemoryBlock result;
93   result.Address = pa;
94   result.Size = NumPages*pageSize;
95
96   return result;
97 }
98
99 bool llvm::sys::Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) {
100   if (M.Address == 0 || M.Size == 0) return false;
101   if (0 != ::munmap(M.Address, M.Size))
102     return MakeErrMsg(ErrMsg, "Can't release RWX Memory");
103   return false;
104 }
105
106 bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) {
107 #if defined(__APPLE__) && defined(__arm__)
108   if (M.Address == 0 || M.Size == 0) return false;
109   sys::Memory::InvalidateInstructionCache(M.Address, M.Size);
110   kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address,
111     (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_WRITE);
112   return KERN_SUCCESS == kr;
113 #else
114   return true;
115 #endif
116 }
117
118 bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) {
119 #if defined(__APPLE__) && defined(__arm__)
120   if (M.Address == 0 || M.Size == 0) return false;
121   sys::Memory::InvalidateInstructionCache(M.Address, M.Size);
122   kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address,
123     (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY);
124   return KERN_SUCCESS == kr;
125 #else
126   return false;
127 #endif
128 }
129
130 bool llvm::sys::Memory::setRangeWritable(const void *Addr, size_t Size) {
131 #if defined(__APPLE__) && defined(__arm__)
132   kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr,
133                                 (vm_size_t)Size, 0,
134                                 VM_PROT_READ | VM_PROT_WRITE);
135   return KERN_SUCCESS == kr;
136 #else
137   return true;
138 #endif
139 }
140
141 bool llvm::sys::Memory::setRangeExecutable(const void *Addr, size_t Size) {
142 #if defined(__APPLE__) && defined(__arm__)
143   kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr,
144                                 (vm_size_t)Size, 0,
145                                 VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY);
146   return KERN_SUCCESS == kr;
147 #else
148   return true;
149 #endif
150 }