Merge pull request #811 from criteo/16334-ConcurrentBag
[mono.git] / mono / metadata / mono-debug.c
index e00693296dd096b092155974b7749be8db16d44e..6eff0ecbda320d6a165b4be0582e800fa2fdc057 100644 (file)
@@ -1,3 +1,14 @@
+/*
+ * mono-debug.c: 
+ *
+ * Author:
+ *     Mono Project (http://www.mono-project.com)
+ *
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
+ */
+
 #include <config.h>
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/tabledefs.h>
@@ -7,9 +18,10 @@
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/mono-debug-debugger.h>
 #include <mono/metadata/mono-endian.h>
+#include <mono/metadata/gc-internal.h>
 #include <string.h>
 
-#define DATA_TABLE_CHUNK_SIZE          16384
+#define DATA_TABLE_CHUNK_SIZE          (16384-sizeof (MonoDebugDataChunk))
 
 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
 
@@ -62,7 +74,7 @@ struct _MonoDebugDataTable {
 
 typedef struct {
        const gchar *method_name;
-       const gchar *cil_code;
+       const gchar *obsolete_cil_code;
        guint32 wrapper_type;
 } MonoDebugWrapperData;
 
@@ -96,11 +108,11 @@ typedef struct {
 
 MonoSymbolTable *mono_symbol_table = NULL;
 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
-gint32 mono_debug_debugger_version = 3;
+gint32 mono_debug_debugger_version = 5;
+gint32 _mono_debug_using_mono_debugger = 0;
 
-static gboolean in_the_mono_debugger = FALSE;
 static gboolean mono_debug_initialized = FALSE;
-GHashTable *mono_debug_handles = NULL;
+static GHashTable *mono_debug_handles = NULL;
 
 static GHashTable *data_table_hash = NULL;
 static int next_symbol_file_id = 0;
@@ -112,6 +124,8 @@ static void                 mono_debug_add_assembly    (MonoAssembly *assembly,
                                                        gpointer user_data);
 static void                 mono_debug_add_type        (MonoClass *klass);
 
+static MonoDebugHandle     *open_symfile_from_bundle   (MonoImage *image);
+
 void _mono_debug_init_corlib (MonoDomain *domain);
 
 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
@@ -149,10 +163,9 @@ free_header_data (gpointer key, gpointer value, gpointer user_data)
 
        if (header->wrapper_data) {
                g_free ((gpointer)header->wrapper_data->method_name);
-               g_free ((gpointer)header->wrapper_data->cil_code);
-               g_slist_free (header->address_list);
                g_free (header->wrapper_data);
        }
+       g_slist_free (header->address_list);
 }
 
 static void
@@ -185,7 +198,10 @@ lookup_data_table (MonoDomain *domain)
        MonoDebugDataTable *table;
 
        table = g_hash_table_lookup (data_table_hash, domain);
-       g_assert (table);
+       if (!table) {
+               g_error ("lookup_data_table () failed for %p\n", domain);
+               g_assert (table);
+       }
        return table;
 }
 
@@ -213,17 +229,25 @@ mono_debug_init (MonoDebugFormat format)
 {
        g_assert (!mono_debug_initialized);
 
+       if (_mono_debug_using_mono_debugger)
+               format = MONO_DEBUG_FORMAT_DEBUGGER;
+
        mono_debug_initialized = TRUE;
        mono_debug_format = format;
-       in_the_mono_debugger = format == MONO_DEBUG_FORMAT_DEBUGGER;
 
-       mono_debugger_initialize (in_the_mono_debugger);
+       /*
+        * This must be called before mono_debugger_initialize(), because the
+        * latter registers GC roots.
+        */
+       mono_gc_base_init ();
+
+       mono_debugger_initialize (_mono_debug_using_mono_debugger);
 
        mono_debugger_lock ();
 
        mono_symbol_table = g_new0 (MonoSymbolTable, 1);
        mono_symbol_table->magic = MONO_DEBUGGER_MAGIC;
-       mono_symbol_table->version = MONO_DEBUGGER_VERSION;
+       mono_symbol_table->version = MONO_DEBUGGER_MAJOR_VERSION;
        mono_symbol_table->total_size = sizeof (MonoSymbolTable);
 
        mono_debug_handles = g_hash_table_new_full
@@ -258,6 +282,9 @@ _mono_debug_init_corlib (MonoDomain *domain)
 void
 mono_debug_open_image_from_memory (MonoImage *image, const guint8 *raw_contents, int size)
 {
+       if (!mono_debug_initialized)
+               return;
+
        mono_debug_open_image (image, raw_contents, size);
 }
 
@@ -265,7 +292,7 @@ mono_debug_open_image_from_memory (MonoImage *image, const guint8 *raw_contents,
 gboolean
 mono_debug_using_mono_debugger (void)
 {
-       return in_the_mono_debugger;
+       return _mono_debug_using_mono_debugger;
 }
 
 void
@@ -280,8 +307,13 @@ mono_debug_cleanup (void)
                data_table_hash = NULL;
        }
 
-       g_free (mono_symbol_table);
-       mono_symbol_table = NULL;
+       if (mono_symbol_table) {
+               if (mono_symbol_table->global_data_table)
+                       free_data_table (mono_symbol_table->global_data_table);
+
+               g_free (mono_symbol_table);
+               mono_symbol_table = NULL;
+       }
 }
 
 void
@@ -328,6 +360,9 @@ mono_debug_domain_unload (MonoDomain *domain)
        mono_debugger_unlock ();
 }
 
+/*
+ * LOCKING: Assumes the debug lock is held.
+ */
 static MonoDebugHandle *
 _mono_debug_get_image (MonoImage *image)
 {
@@ -342,11 +377,13 @@ mono_debug_close_image (MonoImage *image)
        if (!mono_debug_initialized)
                return;
 
+       mono_debugger_lock ();
+
        handle = _mono_debug_get_image (image);
-       if (!handle)
+       if (!handle) {
+               mono_debugger_unlock ();
                return;
-
-       mono_debugger_lock ();
+       }
 
        mono_debugger_event (MONO_DEBUGGER_EVENT_UNLOAD_MODULE, (guint64) (gsize) handle,
                             handle->index);
@@ -365,11 +402,13 @@ mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
        if (mono_image_is_dynamic (image))
                return NULL;
 
+       mono_debugger_lock ();
+
        handle = _mono_debug_get_image (image);
-       if (handle != NULL)
+       if (handle != NULL) {
+               mono_debugger_unlock ();
                return handle;
-
-       mono_debugger_lock ();
+       }
 
        handle = g_new0 (MonoDebugHandle, 1);
        handle->index = ++next_symbol_file_id;
@@ -380,7 +419,8 @@ mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
 
        handle->type_table = create_data_table (NULL);
 
-       handle->symfile = mono_debug_open_mono_symbols (handle, raw_contents, size, in_the_mono_debugger);
+       handle->symfile = mono_debug_open_mono_symbols (
+               handle, raw_contents, size, _mono_debug_using_mono_debugger);
 
        mono_debug_list_add (&mono_symbol_table->symbol_files, handle);
 
@@ -398,8 +438,14 @@ mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
 static void
 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
 {
+       MonoDebugHandle *handle;
+       MonoImage *image;
+
        mono_debugger_lock ();
-       mono_debug_open_image (mono_assembly_get_image (assembly), NULL, 0);
+       image = mono_assembly_get_image (assembly);
+       handle = open_symfile_from_bundle (image);
+       if (!handle)
+               mono_debug_open_image (image, NULL, 0);
        mono_debugger_unlock ();
 }
 
@@ -558,7 +604,6 @@ mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDoma
        guint8 buffer [BUFSIZ];
        guint8 *ptr, *oldptr;
        guint32 i, size, total_size, max_size;
-       gint32 last_il_offset = 0, last_native_offset = 0;
        gboolean is_wrapper = FALSE;
 
        mono_debugger_lock ();
@@ -576,10 +621,8 @@ mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDoma
                is_wrapper = TRUE;
        }
 
-       jit->num_lexical_blocks = minfo ? minfo->num_lexical_blocks : 0;
-
-       max_size = 24 + 8 * jit->num_line_numbers + 16 * jit->num_lexical_blocks +
-               (20 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
+       max_size = (5 * 5) + 1 + (10 * jit->num_line_numbers) +
+               (25 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
 
        if (max_size > BUFSIZ)
                ptr = oldptr = g_malloc (max_size);
@@ -593,41 +636,8 @@ mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDoma
        for (i = 0; i < jit->num_line_numbers; i++) {
                MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
 
-               write_sleb128 (lne->il_offset - last_il_offset, ptr, &ptr);
-               write_sleb128 (lne->native_offset - last_native_offset, ptr, &ptr);
-
-               last_il_offset = lne->il_offset;
-               last_native_offset = lne->native_offset;
-       }
-
-       jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
-       for (i = 0; i < jit->num_lexical_blocks; i ++) {
-               MonoDebugLexicalBlockEntry *jit_lbe = &jit->lexical_blocks [i];
-               MonoSymbolFileLexicalBlockEntry *minfo_lbe = &minfo->lexical_blocks [i];
-               jit_lbe->il_start_offset = read32 (&(minfo_lbe->_start_offset));
-               jit_lbe->native_start_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_start_offset);
-
-               jit_lbe->il_end_offset = read32 (&(minfo_lbe->_end_offset));
-               jit_lbe->native_end_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_end_offset);
-       }
-
-       last_il_offset = 0;
-       last_native_offset = 0;
-       write_leb128 (jit->num_lexical_blocks, ptr, &ptr);
-       for (i = 0; i < jit->num_lexical_blocks; i++) {
-               MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
-
-               write_sleb128 (lbe->il_start_offset - last_il_offset, ptr, &ptr);
-               write_sleb128 (lbe->native_start_offset - last_native_offset, ptr, &ptr);
-
-               last_il_offset = lbe->il_start_offset;
-               last_native_offset = lbe->native_start_offset;
-
-               write_sleb128 (lbe->il_end_offset - last_il_offset, ptr, &ptr);
-               write_sleb128 (lbe->native_end_offset - last_native_offset, ptr, &ptr);
-
-               last_il_offset = lbe->il_end_offset;
-               last_native_offset = lbe->native_end_offset;
+               write_sleb128 (lne->il_offset, ptr, &ptr);
+               write_sleb128 (lne->native_offset, ptr, &ptr);
        }
 
        *ptr++ = jit->this_var ? 1 : 0;
@@ -642,12 +652,22 @@ mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDoma
        for (i = 0; i < jit->num_locals; i++)
                write_variable (&jit->locals [i], ptr, &ptr);
 
+       *ptr++ = jit->gsharedvt_info_var ? 1 : 0;
+       if (jit->gsharedvt_info_var) {
+               write_variable (jit->gsharedvt_info_var, ptr, &ptr);
+               write_variable (jit->gsharedvt_locals_var, ptr, &ptr);
+       }
+
        size = ptr - oldptr;
        g_assert (size < max_size);
        total_size = size + sizeof (MonoDebugMethodAddress);
 
-       address = (MonoDebugMethodAddress *) allocate_data_item (
-               table, MONO_DEBUG_DATA_ITEM_METHOD, total_size);
+       if (method->dynamic) {
+               address = g_malloc0 (total_size);
+       } else {
+               address = (MonoDebugMethodAddress *) allocate_data_item (
+                                 table, MONO_DEBUG_DATA_ITEM_METHOD, total_size);
+       }
 
        address->header.size = total_size;
        address->header.symfile_id = handle ? handle->index : 0;
@@ -670,20 +690,13 @@ mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDoma
                g_hash_table_insert (table->method_hash, declaring, header);
 
                if (is_wrapper) {
-                       const unsigned char* il_code;
-                       MonoMethodHeader *mheader;
                        MonoDebugWrapperData *wrapper;
-                       guint32 il_codesize;
-
-                       mheader = mono_method_get_header (declaring);
-                       il_code = mono_method_header_get_code (mheader, &il_codesize, NULL);
 
                        header->wrapper_data = wrapper = g_new0 (MonoDebugWrapperData, 1);
 
                        wrapper->wrapper_type = method->wrapper_type;
                        wrapper->method_name = mono_method_full_name (declaring, TRUE);
-                       wrapper->cil_code = mono_disasm_code (
-                               NULL, declaring, il_code, il_code + il_codesize);
+                       wrapper->obsolete_cil_code = "";
                }
        } else {
                address->header.wrapper_data = header->wrapper_data;
@@ -692,12 +705,49 @@ mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDoma
 
        g_hash_table_insert (table->method_address_hash, method, address);
 
-       write_data_item (table, (guint8 *) address);
+       if (!method->dynamic)
+               write_data_item (table, (guint8 *) address);
 
        mono_debugger_unlock ();
        return address;
 }
 
+void
+mono_debug_remove_method (MonoMethod *method, MonoDomain *domain)
+{
+       MonoMethod *declaring;
+       MonoDebugDataTable *table;
+       MonoDebugMethodHeader *header;
+       MonoDebugMethodAddress *address;
+
+       if (!mono_debug_initialized)
+               return;
+
+       g_assert (method->dynamic);
+
+       mono_debugger_lock ();
+
+       table = lookup_data_table (domain);
+
+       declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
+       g_hash_table_remove (table->method_hash, declaring);
+
+       address = g_hash_table_lookup (table->method_address_hash, method);
+       if (address) {
+               header = &address->header;
+
+               if (header->wrapper_data) {
+                       g_free ((char*)header->wrapper_data->method_name);
+                       g_free (header->wrapper_data);
+               }
+               g_free (address);
+       }
+
+       g_hash_table_remove (table->method_address_hash, method);
+
+       mono_debugger_unlock ();
+}
+
 void
 mono_debug_add_delegate_trampoline (gpointer code, int size)
 {
@@ -774,11 +824,25 @@ read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
        *rptr = ptr;
 }
 
+void
+mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
+{
+       if (!jit)
+               return;
+       g_free (jit->line_numbers);
+       g_free (jit->this_var);
+       g_free (jit->params);
+       g_free (jit->locals);
+       g_free (jit->gsharedvt_info_var);
+       g_free (jit->gsharedvt_locals_var);
+       g_free (jit);
+}
+
 static MonoDebugMethodJitInfo *
 mono_debug_read_method (MonoDebugMethodAddress *address)
 {
        MonoDebugMethodJitInfo *jit;
-       guint32 i, il_offset = 0, native_offset = 0;
+       guint32 i;
        guint8 *ptr;
 
        jit = g_new0 (MonoDebugMethodJitInfo, 1);
@@ -796,31 +860,8 @@ mono_debug_read_method (MonoDebugMethodAddress *address)
        for (i = 0; i < jit->num_line_numbers; i++) {
                MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
 
-               il_offset += read_sleb128 (ptr, &ptr);
-               native_offset += read_sleb128 (ptr, &ptr);
-
-               lne->il_offset = il_offset;
-               lne->native_offset = native_offset;
-       }
-
-       il_offset = 0;
-       native_offset = 0;
-       jit->num_lexical_blocks = read_leb128 (ptr, &ptr);
-       jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
-       for (i = 0; i < jit->num_lexical_blocks; i ++) {
-               MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
-
-               il_offset += read_sleb128 (ptr, &ptr);
-               native_offset += read_sleb128 (ptr, &ptr);
-
-               lbe->il_start_offset = il_offset;
-               lbe->native_start_offset = native_offset;
-
-               il_offset += read_sleb128 (ptr, &ptr);
-               native_offset += read_sleb128 (ptr, &ptr);
-
-               lbe->il_end_offset = il_offset;
-               lbe->native_end_offset = native_offset;
+               lne->il_offset = read_sleb128 (ptr, &ptr);
+               lne->native_offset = read_sleb128 (ptr, &ptr);
        }
 
        if (*ptr++) {
@@ -838,6 +879,13 @@ mono_debug_read_method (MonoDebugMethodAddress *address)
        for (i = 0; i < jit->num_locals; i++)
                read_variable (&jit->locals [i], ptr, &ptr);
 
+       if (*ptr++) {
+               jit->gsharedvt_info_var = g_new0 (MonoDebugVarInfo, 1);
+               jit->gsharedvt_locals_var = g_new0 (MonoDebugVarInfo, 1);
+               read_variable (jit->gsharedvt_info_var, ptr, &ptr);
+               read_variable (jit->gsharedvt_locals_var, ptr, &ptr);
+       }
+
        return jit;
 }
 
@@ -851,16 +899,18 @@ mono_debug_add_type (MonoClass *klass)
        guint32 size, total_size, max_size;
        int base_offset = 0;
 
-       handle = _mono_debug_get_image (klass->image);
-       if (!handle)
-               return;
-
        if (klass->generic_class || klass->rank ||
            (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
                return;
 
        mono_debugger_lock ();
 
+       handle = _mono_debug_get_image (klass->image);
+       if (!handle) {
+               mono_debugger_unlock ();
+               return;
+       }
+
        max_size = 12 + sizeof (gpointer);
        if (max_size > BUFSIZ)
                ptr = oldptr = g_malloc (max_size);
@@ -915,6 +965,10 @@ MonoDebugMethodJitInfo *
 mono_debug_find_method (MonoMethod *method, MonoDomain *domain)
 {
        MonoDebugMethodJitInfo *res;
+
+       if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
+               return NULL;
+
        mono_debugger_lock ();
        res = find_method (method, domain);
        mono_debugger_unlock ();
@@ -950,7 +1004,7 @@ mono_debug_lookup_method_addresses (MonoMethod *method)
        GSList *list;
        guint8 *ptr;
 
-       g_assert (mono_debug_debugger_version == 3);
+       g_assert ((mono_debug_debugger_version == 4) || (mono_debug_debugger_version == 5));
 
        mono_debugger_lock ();
 
@@ -996,18 +1050,42 @@ il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_o
 
        jit = find_method (method, domain);
        if (!jit || !jit->line_numbers)
-               return -1;
+               goto cleanup_and_fail;
 
        for (i = jit->num_line_numbers - 1; i >= 0; i--) {
                MonoDebugLineNumberEntry lne = jit->line_numbers [i];
 
-               if (lne.native_offset <= native_offset)
+               if (lne.native_offset <= native_offset) {
+                       mono_debug_free_method_jit_info (jit);
                        return lne.il_offset;
+               }
        }
 
+cleanup_and_fail:
+       mono_debug_free_method_jit_info (jit);
        return -1;
 }
 
+/**
+ * mono_debug_il_offset_from_address:
+ *
+ *   Compute the IL offset corresponding to NATIVE_OFFSET inside the native
+ * code of METHOD in DOMAIN.
+ */
+gint32
+mono_debug_il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
+{
+       gint32 res;
+
+       mono_debugger_lock ();
+
+       res = il_offset_from_address (method, domain, native_offset);
+
+       mono_debugger_unlock ();
+
+       return res;
+}
+
 /**
  * mono_debug_lookup_source_location:
  * @address: Native offset within the @method's machine code.
@@ -1031,7 +1109,7 @@ mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDoma
 
        mono_debugger_lock ();
        minfo = _mono_debug_lookup_method (method);
-       if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
+       if (!minfo || !minfo->handle || !minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile)) {
                mono_debugger_unlock ();
                return NULL;
        }
@@ -1047,6 +1125,34 @@ mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDoma
        return location;
 }
 
+/*
+ * mono_debug_lookup_locals:
+ *
+ *   Return information about the local variables of MINFO.
+ * The result should be freed using mono_debug_symfile_free_locals ().
+ */
+MonoDebugLocalsInfo*
+mono_debug_lookup_locals (MonoMethod *method)
+{
+       MonoDebugMethodInfo *minfo;
+       MonoDebugLocalsInfo *res;
+
+       if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
+               return NULL;
+
+       mono_debugger_lock ();
+       minfo = _mono_debug_lookup_method (method);
+       if (!minfo || !minfo->handle || !minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile)) {
+               mono_debugger_unlock ();
+               return NULL;
+       }
+
+       res = mono_debug_symfile_lookup_locals (minfo);
+       mono_debugger_unlock ();
+
+       return res;
+}
+
 /**
  * mono_debug_free_source_location:
  * @location: A `MonoDebugSourceLocation'.
@@ -1074,6 +1180,7 @@ mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDom
 {
        MonoDebugSourceLocation *location;
        gchar *fname, *ptr, *res;
+       int offset;
 
        fname = mono_method_full_name (method, TRUE);
        for (ptr = fname; *ptr; ptr++) {
@@ -1083,7 +1190,18 @@ mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDom
        location = mono_debug_lookup_source_location (method, native_offset, domain);
 
        if (!location) {
-               res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
+               if (mono_debug_initialized) {
+                       mono_debugger_lock ();
+                       offset = il_offset_from_address (method, domain, native_offset);
+                       mono_debugger_unlock ();
+               } else {
+                       offset = -1;
+               }
+
+               if (offset < 0)
+                       res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
+               else
+                       res = g_strdup_printf ("at %s <IL 0x%05x, 0x%05x>", fname, offset, native_offset);
                g_free (fname);
                return res;
        }
@@ -1126,3 +1244,60 @@ mono_debug_list_remove (MonoDebugList **list, gconstpointer data)
                break;
        }
 }
+
+static gboolean is_attached = FALSE;
+
+void
+mono_set_is_debugger_attached (gboolean attached)
+{
+       is_attached = attached;
+}
+
+gboolean
+mono_is_debugger_attached (void)
+{
+       return is_attached;
+}
+
+/*
+ * Bundles
+ */
+
+typedef struct _BundledSymfile BundledSymfile;
+
+struct _BundledSymfile {
+       BundledSymfile *next;
+       const char *aname;
+       const mono_byte *raw_contents;
+       int size;
+};
+
+static BundledSymfile *bundled_symfiles = NULL;
+
+void
+mono_register_symfile_for_assembly (const char *assembly_name, const mono_byte *raw_contents, int size)
+{
+       BundledSymfile *bsymfile;
+
+       bsymfile = g_new0 (BundledSymfile, 1);
+       bsymfile->aname = assembly_name;
+       bsymfile->raw_contents = raw_contents;
+       bsymfile->size = size;
+       bsymfile->next = bundled_symfiles;
+       bundled_symfiles = bsymfile;
+}
+
+static MonoDebugHandle *
+open_symfile_from_bundle (MonoImage *image)
+{
+       BundledSymfile *bsymfile;
+
+       for (bsymfile = bundled_symfiles; bsymfile; bsymfile = bsymfile->next) {
+               if (strcmp (bsymfile->aname, image->module_name))
+                       continue;
+
+               return mono_debug_open_image (image, bsymfile->raw_contents, bsymfile->size);
+       }
+
+       return NULL;
+}