2 * rawbuffer.c: Manages buffers that might have been mmapped or malloced
5 * Miguel de Icaza (miguel@ximian.com)
7 * (C) 2001 Ximian, Inc.
10 #if defined(PLATFORM_WIN32)
11 #define USE_WIN32_API 1
23 #include <sys/types.h>
25 #include "rawbuffer.h"
27 #include <mono/io-layer/io-layer.h>
29 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
30 #define ROUND_UP(VALUE,SIZE) (ROUND_DOWN((VALUE) + (SIZE) - 1, (SIZE)))
31 #if SIZEOF_VOID_P == 8
32 #define UINTPTR_TYPE guint64
34 #define UINTPTR_TYPE guint32
37 static GHashTable *mmap_map = NULL;
38 static size_t alignment = 0;
39 #define mono_mmap_lock() EnterCriticalSection (&mmap_mutex)
40 #define mono_mmap_unlock() LeaveCriticalSection (&mmap_mutex)
41 static CRITICAL_SECTION mmap_mutex;
42 static gboolean make_unreadable = FALSE;
43 static guint32 n_pagefaults = 0;
51 GetSystemInfo (&info);
52 alignment = info.dwAllocationGranularity;
54 alignment = getpagesize ();
59 mono_raw_buffer_load_malloc (int fd, int is_writable, guint32 base, size_t size)
63 ptr = g_malloc (size);
67 if (lseek (fd, base, 0) == (off_t) -1) {
77 mono_raw_buffer_free_malloc (void *base)
83 mono_raw_buffer_init (void)
85 InitializeCriticalSection (&mmap_mutex);
89 mmap_map = g_hash_table_new (NULL, NULL);
93 mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size)
96 /* FileMapping implementation */
101 HANDLE file, mapping;
103 start = ROUND_DOWN (base, alignment);
107 prot = PAGE_WRITECOPY;
108 access = FILE_MAP_COPY;
111 prot = PAGE_READONLY;
112 access = FILE_MAP_READ;
115 file = (HANDLE) _get_osfhandle (fd);
116 mapping = CreateFileMapping (file, NULL, prot, 0, 0, NULL);
120 ptr = MapViewOfFile (mapping, access, 0, start, end - start);
122 CloseHandle (mapping);
127 g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (mapping));
130 return ((char *)ptr) + (base - start);
133 /* mmap implementation */
137 int prot = PROT_READ;
141 start = ROUND_DOWN (base, alignment);
142 end = ROUND_UP (base + size, alignment);
151 ptr = mmap (0, end - start, prot, flags, fd, start);
153 if (ptr == (void *) -1)
157 * This seems to prevent segmentation faults on Fedora Linux, no
159 * http://bugzilla.ximian.com/show_bug.cgi?id=49499
162 if (mprotect (ptr, end - start, prot | PROT_EXEC) != 0)
163 g_warning (G_GNUC_PRETTY_FUNCTION
164 ": mprotect failed: %s", g_strerror (errno));
166 if (make_unreadable) {
167 int res = mprotect (ptr, end - start, 0);
172 g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (size));
175 return ((char *)ptr) + (base - start);
180 mono_raw_buffer_free_mmap (void *base)
185 value = GPOINTER_TO_INT (g_hash_table_lookup (mmap_map, base));
189 UnmapViewOfFile (base);
190 CloseHandle ((HANDLE) value);
192 munmap (base, value);
197 mono_raw_buffer_update_mmap (void *base, size_t size)
200 FlushViewOfFile (base, size);
202 msync (base, size, MS_SYNC);
207 mono_raw_buffer_load (int fd, int is_writable, guint32 base, size_t size)
211 ptr = mono_raw_buffer_load_mmap (fd, is_writable, base, size);
213 ptr = mono_raw_buffer_load_malloc (fd, is_writable, base, size);
219 mono_raw_buffer_update (void *buffer, size_t size)
224 mmap_base = (gpointer)(ROUND_DOWN ((UINTPTR_TYPE) (buffer), alignment));
227 exists = g_hash_table_lookup (mmap_map, mmap_base) != NULL;
230 mono_raw_buffer_update_mmap (mmap_base, size);
234 mono_raw_buffer_free (void *buffer)
239 mmap_base = (gpointer)(ROUND_DOWN ((UINTPTR_TYPE) (buffer), alignment));
241 exists = g_hash_table_lookup (mmap_map, mmap_base) != NULL;
243 mono_raw_buffer_free_mmap (mmap_base);
245 mono_raw_buffer_free_malloc (buffer);
249 * mono_raw_buffer_set_make_unreadable:
251 * Set whenever to make all mmaped memory unreadable. In conjuction with a
252 * SIGSEGV handler, this is useful to find out which pages the runtime tries to read.
255 mono_raw_buffer_set_make_unreadable (gboolean unreadable)
257 make_unreadable = unreadable;
266 find_map (void *start, guint32 size, gpointer user_data)
268 FindMapUserData *data = (FindMapUserData*)user_data;
271 if (((guint8*)data->ptr >= (guint8*)start) && ((guint8*)data->ptr < (guint8*)start + size))
276 * mono_raw_buffer_is_pagefault:
278 * Should be called from a SIGSEGV signal handler to find out whenever @ptr is
279 * within memory allocated by this module.
282 mono_raw_buffer_is_pagefault (void *ptr)
284 FindMapUserData data;
286 if (!make_unreadable)
293 g_hash_table_foreach (mmap_map, (GHFunc)find_map, &data);
300 * mono_raw_buffer_handle_pagefault:
302 * Handle a pagefault caused by an unreadable page by making it readable again.
305 mono_raw_buffer_handle_pagefault (void *ptr)
307 #ifndef PLATFORM_WIN32
308 guint8* start = (guint8*)ROUND_DOWN (((gssize)ptr), alignment);
312 res = mprotect (start, alignment, PROT_READ);
321 * mono_raw_buffer_get_n_pagefaults:
323 * Return the number of times handle_pagefault is called.
324 * To count the number of pagefaults caused by a block of code use code like this:
326 * int prev_pagefaults = mono_raw_buffer_get_n_pagefaults ();
328 * int new_pagefaults = mono_raw_buffer_get_n_pagefaults () - prev_pagefaults;
331 mono_raw_buffer_get_n_pagefaults (void)