X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Frawbuffer.c;h=167d9b8391d9480767114e007cb819af3cf03467;hb=e66357c45bb0e159aa3d02276347757e75a15dd7;hp=9c1ee78c1a8459766d490f13873edeb24369b3ae;hpb=0649b90c407fc29ee8377f2c6fb42ae2c006e26a;p=mono.git diff --git a/mono/metadata/rawbuffer.c b/mono/metadata/rawbuffer.c index 9c1ee78c1a8..167d9b8391d 100644 --- a/mono/metadata/rawbuffer.c +++ b/mono/metadata/rawbuffer.c @@ -11,7 +11,9 @@ #define USE_WIN32_API 1 #endif +#ifdef HAVE_UNISTD_H #include +#endif #include #ifdef USE_WIN32_API #include @@ -36,7 +38,11 @@ static GHashTable *mmap_map = NULL; static size_t alignment = 0; +#define mono_mmap_lock() EnterCriticalSection (&mmap_mutex) +#define mono_mmap_unlock() LeaveCriticalSection (&mmap_mutex) static CRITICAL_SECTION mmap_mutex; +static gboolean make_unreadable = FALSE; +static guint32 n_pagefaults = 0; static void get_alignment (void) @@ -85,6 +91,14 @@ mono_raw_buffer_init (void) mmap_map = g_hash_table_new (NULL, NULL); } +void +mono_raw_buffer_cleanup (void) +{ + g_hash_table_destroy (mmap_map); + + DeleteCriticalSection (&mmap_mutex); +} + static void * mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size) { @@ -119,9 +133,9 @@ mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size) return 0; } - EnterCriticalSection (&mmap_mutex); + mono_mmap_lock (); g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (mapping)); - LeaveCriticalSection (&mmap_mutex); + mono_mmap_unlock (); return ((char *)ptr) + (base - start); @@ -155,13 +169,16 @@ mono_raw_buffer_load_mmap (int fd, int is_writable, guint32 base, size_t size) * http://bugzilla.ximian.com/show_bug.cgi?id=49499 * for more info. */ - if (mprotect (ptr, end - start, prot | PROT_EXEC) != 0) - g_warning (G_GNUC_PRETTY_FUNCTION - ": mprotect failed: %s", g_strerror (errno)); - - EnterCriticalSection (&mmap_mutex); + mprotect (ptr, end - start, prot | PROT_EXEC); + + if (make_unreadable) { + int res = mprotect (ptr, end - start, 0); + g_assert (res == 0); + } + + mono_mmap_lock (); g_hash_table_insert (mmap_map, ptr, GINT_TO_POINTER (size)); - LeaveCriticalSection (&mmap_mutex); + mono_mmap_unlock (); return ((char *)ptr) + (base - start); #endif @@ -172,9 +189,9 @@ mono_raw_buffer_free_mmap (void *base) { int value; - EnterCriticalSection (&mmap_mutex); + mono_mmap_lock (); value = GPOINTER_TO_INT (g_hash_table_lookup (mmap_map, base)); - LeaveCriticalSection (&mmap_mutex); + mono_mmap_unlock (); #ifdef USE_WIN32_API UnmapViewOfFile (base); @@ -214,9 +231,9 @@ mono_raw_buffer_update (void *buffer, size_t size) mmap_base = (gpointer)(ROUND_DOWN ((UINTPTR_TYPE) (buffer), alignment)); - EnterCriticalSection (&mmap_mutex); + mono_mmap_lock (); exists = g_hash_table_lookup (mmap_map, mmap_base) != NULL; - LeaveCriticalSection (&mmap_mutex); + mono_mmap_unlock (); if (exists) mono_raw_buffer_update_mmap (mmap_base, size); } @@ -236,3 +253,90 @@ mono_raw_buffer_free (void *buffer) mono_raw_buffer_free_malloc (buffer); } +/* + * mono_raw_buffer_set_make_unreadable: + * + * Set whenever to make all mmaped memory unreadable. In conjuction with a + * SIGSEGV handler, this is useful to find out which pages the runtime tries to read. + */ +void +mono_raw_buffer_set_make_unreadable (gboolean unreadable) +{ + make_unreadable = unreadable; +} + +typedef struct { + gboolean found; + void *ptr; +} FindMapUserData; + +static void +find_map (void *start, guint32 size, gpointer user_data) +{ + FindMapUserData *data = (FindMapUserData*)user_data; + + if (!data->found) + if (((guint8*)data->ptr >= (guint8*)start) && ((guint8*)data->ptr < (guint8*)start + size)) + data->found = TRUE; +} + +/* + * mono_raw_buffer_is_pagefault: + * + * Should be called from a SIGSEGV signal handler to find out whenever @ptr is + * within memory allocated by this module. + */ +gboolean +mono_raw_buffer_is_pagefault (void *ptr) +{ + FindMapUserData data; + + if (!make_unreadable) + return FALSE; + + data.found = FALSE; + data.ptr = ptr; + + mono_mmap_lock (); + g_hash_table_foreach (mmap_map, (GHFunc)find_map, &data); + mono_mmap_unlock (); + + return data.found; +} + +/* + * mono_raw_buffer_handle_pagefault: + * + * Handle a pagefault caused by an unreadable page by making it readable again. + */ +void +mono_raw_buffer_handle_pagefault (void *ptr) +{ +#ifndef PLATFORM_WIN32 + guint8* start = (guint8*)ROUND_DOWN (((gssize)ptr), alignment); + int res; + + mono_mmap_lock (); + res = mprotect (start, alignment, PROT_READ); + g_assert (res == 0); + + n_pagefaults ++; + mono_mmap_unlock (); +#endif +} + +/* + * mono_raw_buffer_get_n_pagefaults: + * + * Return the number of times handle_pagefault is called. + * To count the number of pagefaults caused by a block of code use code like this: + * + * int prev_pagefaults = mono_raw_buffer_get_n_pagefaults (); + * + * int new_pagefaults = mono_raw_buffer_get_n_pagefaults () - prev_pagefaults; + */ +guint32 +mono_raw_buffer_get_n_pagefaults (void) +{ + return n_pagefaults; +}