* test-9.il: New test, test instaniating a class
[mono.git] / mono / jit / debug.c
index 288599af1a907ce42035e1e974926e5306e91146..eeec3bd81ff530dd231bcea80e0c730b562a49e9 100644 (file)
+#include <config.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <signal.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include <mono/metadata/class.h>
+#include <mono/metadata/assembly.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/tokentype.h>
+#include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/debug-mono-symfile.h>
-#include <mono/jit/codegen.h>
-#include <mono/jit/debug.h>
 
 #include "debug-private.h"
 
-/* See debug.h for documentation. */
+/*
+ * NOTE:  Functions and variables starting with `mono_debug_' and `debug_' are
+ *        part of the general debugging code.
+ *
+ *        Functions and variables starting with `mono_debugger_' and `debugger_'
+ *        are only used when the JIT is running inside the Mono Debugger.
+ *
+ * FIXME: This file needs some API loving.
+ */
+
+/* This is incremented each time the symbol table is modified.
+ * The debugger looks at this variable and if it has a higher value than its current
+ * copy of the symbol table, it must call mono_debug_update_symbol_file_table().
+ */
 guint32 mono_debugger_symbol_file_table_generation = 0;
+guint32 mono_debugger_symbol_file_table_modified = 0;
+
+/* Caution: This variable may be accessed at any time from the debugger;
+ *          it is very important not to modify the memory it is pointing to
+ *          without previously setting this pointer back to NULL.
+ */
 MonoDebuggerSymbolFileTable *mono_debugger_symbol_file_table = NULL;
 
 /* Caution: This function MUST be called before touching the symbol table! */
 static void release_symbol_file_table (void);
 
-static MonoDebugHandle *mono_debug_handles = NULL;
-static MonoDebugHandle *mono_default_debug_handle = NULL;
+MonoDebugHandle *mono_debug_handle = NULL;
+gboolean mono_debug_initialized = FALSE;
 
-/*
- * This is a global data symbol which is read by the debugger.
- */
-MonoDebuggerInfo MONO_DEBUGGER__debugger_info = {
-       MONO_SYMBOL_FILE_DYNAMIC_MAGIC,
-       MONO_SYMBOL_FILE_DYNAMIC_VERSION,
-       sizeof (MonoDebuggerInfo),
-       &mono_generic_trampoline_code,
-       &mono_debugger_symbol_file_table_generation,
-       &mono_debugger_symbol_file_table,
-       &mono_debugger_update_symbol_file_table,
-       &mono_compile_method
+static CRITICAL_SECTION debugger_lock_mutex;
+
+extern void (*mono_debugger_class_init_func) (MonoClass *klass);
+
+static void mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data);
+static void mono_debug_close_assembly (AssemblyDebugInfo* info);
+static AssemblyDebugInfo *mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image);
+
+static int running_in_the_mono_debugger = FALSE;
+void (*mono_debugger_event_handler) (MonoDebuggerEvent event, gpointer data, gpointer data2) = NULL;
+
+#ifndef PLATFORM_WIN32
+
+MonoDebuggerIOLayer mono_debugger_io_layer = {
+       InitializeCriticalSection, DeleteCriticalSection, TryEnterCriticalSection,
+       EnterCriticalSection, LeaveCriticalSection, WaitForSingleObject, SignalObjectAndWait,
+       WaitForMultipleObjects, CreateSemaphore, ReleaseSemaphore, CreateThread
 };
 
+#endif
+
+void
+mono_debugger_event (MonoDebuggerEvent event, gpointer data, gpointer data2)
+{
+       if (mono_debugger_event_handler)
+               (* mono_debugger_event_handler) (event, data, data2);
+}
+
+void
+mono_debug_init (int in_the_debugger)
+{
+       if (mono_debug_initialized)
+               return;
+
+       InitializeCriticalSection (&debugger_lock_mutex);
+       mono_debug_initialized = TRUE;
+       running_in_the_mono_debugger = in_the_debugger;
+}
+
+gpointer
+mono_debug_create_notification_function (gpointer *notification_address)
+{
+       guint8 *ptr, *buf;
+
+       ptr = buf = g_malloc0 (16);
+       mono_debug_codegen_breakpoint (&buf);
+       if (notification_address)
+               *notification_address = buf;
+       mono_debug_codegen_ret (&buf);
+
+       return ptr;
+}
+
+void
+mono_debug_lock (void)
+{
+       if (mono_debug_initialized)
+               EnterCriticalSection (&debugger_lock_mutex);
+}
+
+void
+mono_debug_unlock (void)
+{
+       if (mono_debug_initialized)
+               LeaveCriticalSection (&debugger_lock_mutex);
+}
+
 static void
 free_method_info (MonoDebugMethodInfo *minfo)
 {
        DebugMethodInfo *priv = minfo->user_data;
 
        if (priv) {
-               if (priv->line_numbers)
-                       g_ptr_array_free (priv->line_numbers, TRUE);
-
                g_free (priv->name);
                g_free (priv);
        }
 
        if (minfo->jit) {
-               g_free (minfo->jit->il_addresses);
+               g_array_free (minfo->jit->line_numbers, TRUE);
                g_free (minfo->jit->this_var);
                g_free (minfo->jit->params);
                g_free (minfo->jit->locals);
@@ -61,45 +133,37 @@ free_method_info (MonoDebugMethodInfo *minfo)
 }
 
 static void
-debug_arg_warning (const char *message)
+free_wrapper_info (DebugWrapperInfo *winfo)
 {
-       g_warning ("Error while processing --debug-args arguments: %s", message);
+       g_free (winfo);
 }
 
-static gchar *
-replace_suffix (const char *filename, const char *new_suffix)
+static void
+debug_arg_warning (const char *message)
 {
-       const char *pos = strrchr (filename, '.');
-
-       if (!pos)
-               return g_strdup_printf ("%s.%s", filename, new_suffix);
-       else {
-               int len = pos - filename;
-               gchar *retval = g_malloc0 (len + strlen (new_suffix) + 2);
-               memcpy (retval, filename, len);
-               retval [len] = '.';
-               memcpy (retval + len + 1, new_suffix, strlen (new_suffix) + 1);
-               return retval;
-       }
+       g_warning ("Error while processing --debug-args arguments: %s", message);
 }
 
 MonoDebugHandle*
-mono_debug_open (const char *name, MonoDebugFormat format, const char **args)
+mono_debug_open (MonoAssembly *assembly, MonoDebugFormat format, const char **args)
 {
        MonoDebugHandle *debug;
        const char **ptr;
 
-       release_symbol_file_table ();
-       
+       g_assert (!mono_debug_handle);
+
        debug = g_new0 (MonoDebugHandle, 1);
-       debug->name = g_strdup (name);
+       debug->name = g_strdup (assembly->image->name);
        debug->format = format;
+       debug->source_files = g_ptr_array_new ();
        debug->producer_name = g_strdup_printf ("Mono JIT compiler version %s", VERSION);
        debug->next_idx = 100;
        debug->dirty = TRUE;
 
        debug->type_hash = g_hash_table_new (NULL, NULL);
-       debug->source_files = g_ptr_array_new ();
+
+       debug->images = g_hash_table_new_full (NULL, NULL, NULL,
+                                              (GDestroyNotify) mono_debug_close_assembly);
 
        for (ptr = args; ptr && *ptr; ptr++) {
                const char *arg = *ptr;
@@ -145,11 +209,6 @@ mono_debug_open (const char *name, MonoDebugFormat format, const char **args)
                                debug->flags |= MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
                                continue;
                        }
-               } else {
-                       if (!strcmp (arg, "internal_mono_debugger")) {
-                               debug->flags |= MONO_DEBUG_FLAGS_MONO_DEBUGGER;
-                               continue;
-                       }
                }
 
                message = g_strdup_printf ("Unknown argument `%s'.", arg);
@@ -171,20 +230,83 @@ mono_debug_open (const char *name, MonoDebugFormat format, const char **args)
                        debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
                break;
        case MONO_DEBUG_FORMAT_MONO:
+               mono_debugger_class_init_func = mono_debug_add_type;
                break;
        default:
                g_assert_not_reached ();
        }
 
-       debug->next = mono_debug_handles;
-       mono_debug_handles = debug;
+       mono_debug_lock ();
+       release_symbol_file_table ();
 
-       if (!mono_default_debug_handle)
-               mono_default_debug_handle = debug;
+       mono_debug_handle = debug;
+       mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
+
+       mono_debug_open_image (mono_debug_handle, assembly->image);
+       mono_debug_open_image (mono_debug_handle, mono_defaults.corlib);
+
+       mono_debug_add_type (mono_defaults.object_class);
+       mono_debug_add_type (mono_defaults.object_class);
+       mono_debug_add_type (mono_defaults.byte_class);
+       mono_debug_add_type (mono_defaults.void_class);
+       mono_debug_add_type (mono_defaults.boolean_class);
+       mono_debug_add_type (mono_defaults.sbyte_class);
+       mono_debug_add_type (mono_defaults.int16_class);
+       mono_debug_add_type (mono_defaults.uint16_class);
+       mono_debug_add_type (mono_defaults.int32_class);
+       mono_debug_add_type (mono_defaults.uint32_class);
+       mono_debug_add_type (mono_defaults.int_class);
+       mono_debug_add_type (mono_defaults.uint_class);
+       mono_debug_add_type (mono_defaults.int64_class);
+       mono_debug_add_type (mono_defaults.uint64_class);
+       mono_debug_add_type (mono_defaults.single_class);
+       mono_debug_add_type (mono_defaults.double_class);
+       mono_debug_add_type (mono_defaults.char_class);
+       mono_debug_add_type (mono_defaults.string_class);
+       mono_debug_add_type (mono_defaults.enum_class);
+       mono_debug_add_type (mono_defaults.array_class);
+       mono_debug_add_type (mono_defaults.multicastdelegate_class);
+       mono_debug_add_type (mono_defaults.asyncresult_class);
+       mono_debug_add_type (mono_defaults.waithandle_class);
+       mono_debug_add_type (mono_defaults.typehandle_class);
+       mono_debug_add_type (mono_defaults.fieldhandle_class);
+       mono_debug_add_type (mono_defaults.methodhandle_class);
+       mono_debug_add_type (mono_defaults.monotype_class);
+       mono_debug_add_type (mono_defaults.exception_class);
+       mono_debug_add_type (mono_defaults.threadabortexception_class);
+       mono_debug_add_type (mono_defaults.thread_class);
+       mono_debug_add_type (mono_defaults.transparent_proxy_class);
+       mono_debug_add_type (mono_defaults.real_proxy_class);
+       mono_debug_add_type (mono_defaults.mono_method_message_class);
+       mono_debug_add_type (mono_defaults.appdomain_class);
+       mono_debug_add_type (mono_defaults.field_info_class);
+       mono_debug_add_type (mono_defaults.stringbuilder_class);
+       mono_debug_add_type (mono_defaults.math_class);
+       mono_debug_add_type (mono_defaults.stack_frame_class);
+       mono_debug_add_type (mono_defaults.stack_trace_class);
+       mono_debug_add_type (mono_defaults.marshal_class);
+       mono_debug_add_type (mono_defaults.iserializeable_class);
+       mono_debug_add_type (mono_defaults.serializationinfo_class);
+       mono_debug_add_type (mono_defaults.streamingcontext_class);
+
+       mono_debug_update_symbol_file_table ();
+
+       mono_debug_unlock ();
 
        return debug;
 }
 
+static void
+mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
+{
+       if (!mono_debug_handle)
+               return;
+
+       mono_debug_lock ();
+       mono_debug_open_image (mono_debug_handle, assembly->image);
+       mono_debug_unlock ();
+}
+
 static void
 generate_il_offsets (AssemblyDebugInfo *info, MonoMethod *method)
 {
@@ -243,6 +365,9 @@ generate_il_offsets (AssemblyDebugInfo *info, MonoMethod *method)
 
        priv->last_line = i;
 
+       minfo->start_line = priv->first_line;
+       minfo->end_line = priv->last_line;
+
        minfo->num_il_offsets = il_offsets->len;
        minfo->il_offsets = g_new0 (MonoSymbolFileLineNumberEntry, il_offsets->len);
        for (i = 0; i < il_offsets->len; i++) {
@@ -280,15 +405,36 @@ debug_load_method_lines (AssemblyDebugInfo* info)
 
                /* If the stat() failed or the file is older. */
                if (stat (info->ilfile, &statb)) {
-                       /* Don't create any new *.il files if the user told us not to do so. */
-                       if (!(info->handle->flags & MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES))
-                               need_update = TRUE;
+                       need_update = TRUE;
                } else if (statb.st_mtime < stata.st_mtime)
                        need_update = TRUE;
 
                if (need_update) {
+#ifndef PLATFORM_WIN32
+                       struct sigaction act, oldact;
+                       sigset_t old_set;
+#endif
+                       int ret;
+
+#ifndef PLATFORM_WIN32
+                       act.sa_handler = SIG_IGN;
+                       act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+                       sigemptyset (&act.sa_mask);
+                       sigaddset (&act.sa_mask, SIGCHLD);
+                       sigprocmask (SIG_BLOCK, &act.sa_mask, &old_set);
+                       sigaction (SIGCHLD, &act, &oldact);
+#endif
+                       
                        g_print ("Recreating %s from %s.\n", info->ilfile, info->image->name);
-                       if (system (command)) {
+
+                       ret = system (command);
+
+#ifndef PLATFORM_WIN32
+                       sigaction (SIGCHLD, &oldact, NULL);
+                       sigprocmask (SIG_SETMASK, &old_set, NULL);
+#endif
+
+                       if (ret) {
                                g_warning ("cannot create IL assembly file (%s): %s",
                                           command, g_strerror (errno));
                                g_free (command);
@@ -369,152 +515,69 @@ debug_load_method_lines (AssemblyDebugInfo* info)
        }
 }
 
-static void
-record_line_number (DebugMethodInfo *priv, gconstpointer address, guint32 line, int is_basic_block)
-{
-       DebugLineNumberInfo *lni = g_new0 (DebugLineNumberInfo, 1);
-
-       lni->address = address;
-       lni->line = line;
-       lni->is_basic_block = is_basic_block;
-       lni->source_file = priv->source_file;
-
-       g_ptr_array_add (priv->line_numbers, lni);
-}
-
-static void
-debug_generate_method_lines (AssemblyDebugInfo *info, MonoDebugMethodInfo *minfo, MonoFlowGraph* cfg)
+void
+_mono_debug_generate_line_number (MonoDebugMethodInfo *minfo, guint32 address, guint32 offset, int debug)
 {
-       guint32 st_address, st_line;
-       DebugMethodInfo *priv = minfo->user_data;
        int i;
 
-       if (!priv)
-               return;
-
-       priv->line_numbers = g_ptr_array_new ();
-
-       st_line = priv->first_line;
-       st_address = minfo->jit->prologue_end;
-
-       /* record_line_number takes absolute memory addresses. */
-       record_line_number (priv, minfo->jit->code_start, priv->start_line, FALSE);
-
-       /* This is the first actual code line of the method. */
-       record_line_number (priv, minfo->jit->code_start + st_address, st_line, TRUE);
-
-       /* start lines of basic blocks */
-       for (i = 0; i < cfg->block_count; ++i) {
-               int j;
-
-               for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
-                       MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
-                       gint32 line_inc = 0, addr_inc;
-
-                       if (!i && !j) {
-                               st_line = priv->first_line;
-                               st_address = t->addr;
+       if (debug)
+               g_message (G_STRLOC ": searching IL offset %x", offset);
 
-                               record_line_number (priv, cfg->start + st_address, st_line, TRUE);
-                       }
+       for (i = minfo->num_il_offsets - 1; i >= 0; i--) {
+               MonoDebugLineNumberEntry *lne;
 
-                       addr_inc = t->addr - st_address;
-                       st_address += addr_inc;
+               if (minfo->il_offsets [i].offset > offset)
+                       continue;
 
-                       if (!info->moffsets)
-                               continue;
+               if (debug)
+                       g_message (G_STRLOC ": found entry %d: offset = %x, row = %d",
+                                  i, minfo->il_offsets [i].offset, minfo->il_offsets [i].row);
 
-                       if (t->cli_addr != -1) {
-                               int *lines = info->moffsets + st_line;
-                               int *k = lines;
+               if (minfo->jit->line_numbers->len) {
+                       MonoDebugLineNumberEntry last = g_array_index (
+                               minfo->jit->line_numbers, MonoDebugLineNumberEntry,
+                               minfo->jit->line_numbers->len - 1);
 
-                               while ((*k != -1) && (*k < t->cli_addr))
-                                       k++;
+                       /* Avoid writing more than one entry for the same line. */
+                       if (minfo->il_offsets [i].row == last.line) {
+                               if (debug)
+                                       g_message (G_STRLOC ": skipping line: line = %d, last line = %d, "
+                                                  "last address = %x, address = %x, "
+                                                  "last offset = %x, offset = %x",
+                                                  last.line, minfo->il_offsets [i].row,
+                                                  last.address, address, last.offset, offset);
 
-                               line_inc = k - lines;
+                               return;
                        }
-
-                       st_line += line_inc;
-
-                       record_line_number (priv, minfo->jit->code_start + st_address,
-                                           st_line, j == 0);
                }
-       }
-}
-
-static void
-debug_update_il_offsets (AssemblyDebugInfo *info, MonoDebugMethodInfo *minfo, MonoFlowGraph* cfg)
-{
-       guint32 old_address, st_address;
-       int index, i;
-
-       minfo->jit->il_addresses = g_new0 (guint32, minfo->num_il_offsets);
-       if (minfo->num_il_offsets < 2)
-               return;
-
-       st_address = old_address = minfo->jit->prologue_end;
-
-       minfo->jit->il_addresses [0] = 0;
-       minfo->jit->il_addresses [1] = st_address;
-       index = 2;
-
-       /* start lines of basic blocks */
-       for (i = 0; i < cfg->block_count; ++i) {
-               int j;
-
-               for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
-                       MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
-                       gint32 addr_inc;
-
-                       if (!i && !j)
-                               st_address = t->addr;
 
-                       addr_inc = t->addr - st_address;
-                       st_address += addr_inc;
+               if (debug)
+                       g_message (G_STRLOC ": writing entry: line = %d, offfset = %x, address = %x",
+                                  minfo->il_offsets [i].row, offset, address);
 
-                       if (t->cli_addr == -1)
-                               continue;
-
-                       while (minfo->il_offsets [index].offset < t->cli_addr) {
-                               minfo->jit->il_addresses [index] = old_address;
-                               if (++index >= minfo->num_il_offsets)
-                                       return;
-                       }
+               lne = g_new0 (MonoDebugLineNumberEntry, 1);
+               lne->address = address;
+               lne->offset = offset;
+               lne->line = minfo->il_offsets [i].row;
 
-                       minfo->jit->il_addresses [index] = st_address;
-                       old_address = st_address;
-               }
+               g_array_append_val (minfo->jit->line_numbers, *lne);
+               return;
        }
-
-       while (index < minfo->num_il_offsets)
-               minfo->jit->il_addresses [index++] = minfo->jit->epilogue_begin;
 }
 
-static AssemblyDebugInfo *
-mono_debug_get_image (MonoDebugHandle* debug, MonoImage *image)
+AssemblyDebugInfo *
+_mono_debug_get_image (MonoDebugHandle* debug, MonoImage *image)
 {
-       GList *tmp;
-       AssemblyDebugInfo *info;
-
-       if (debug->format == MONO_DEBUG_FORMAT_NONE)
-               return NULL;
-
-       for (tmp = debug->info; tmp; tmp = tmp->next) {
-               info = (AssemblyDebugInfo*)tmp->data;
-
-               if (info->image == image)
-                       return info;
-       }
-
-       return NULL;
+       return g_hash_table_lookup (debug->images, image);
 }
 
 static AssemblyDebugInfo *
 mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image)
 {
        AssemblyDebugInfo *info;
+       MonoAssembly **ptr;
 
-       info = mono_debug_get_image (debug, image);
+       info = _mono_debug_get_image (debug, image);
        if (info != NULL)
                return info;
 
@@ -528,15 +591,20 @@ mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image)
        info->handle = debug;
        info->methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
                                               NULL, (GDestroyNotify) free_method_info);
+       info->wrapper_methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+                                                      NULL, (GDestroyNotify) free_wrapper_info);
 
-       info->source_file = debug->source_files->len;
-       g_ptr_array_add (debug->source_files, g_strdup_printf ("%s.il", image->assembly_name));
-
-       debug->info = g_list_prepend (debug->info, info);
+       g_hash_table_insert (debug->images, image, info);
 
        info->nmethods = image->tables [MONO_TABLE_METHOD].rows + 1;
        info->mlines = g_new0 (int, info->nmethods);
 
+       for (ptr = image->references; ptr && *ptr; ptr++)
+               mono_debug_add_assembly (*ptr, NULL);
+
+       if (image->assembly->dynamic)
+               return info;
+
        switch (info->format) {
        case MONO_DEBUG_FORMAT_STABS:
        case MONO_DEBUG_FORMAT_DWARF2:
@@ -546,13 +614,11 @@ mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image)
                        g_free (dirname);
                } else
                        info->ilfile = g_strdup_printf ("%s.il", info->name);
+               info->source_file = debug->source_files->len;
+               g_ptr_array_add (debug->source_files, info->ilfile);
                break;
        case MONO_DEBUG_FORMAT_MONO:
-               info->filename = replace_suffix (image->name, "dbg");
-               if (g_file_test (info->filename, G_FILE_TEST_EXISTS))
-                       info->symfile = mono_debug_open_mono_symbol_file (info->image, info->filename, TRUE);
-               else if (debug->flags & MONO_DEBUG_FLAGS_MONO_DEBUGGER)
-                       info->symfile = mono_debug_create_mono_symbol_file (info->image);
+               info->symfile = mono_debug_open_mono_symbol_file (info->image, running_in_the_mono_debugger);
                mono_debugger_symbol_file_table_generation++;
                break;
 
@@ -566,12 +632,6 @@ mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image)
        return info;
 }
 
-void
-mono_debug_add_image (MonoDebugHandle* debug, MonoImage *image)
-{
-       mono_debug_open_image (debug, image);
-}
-
 void
 mono_debug_write_symbols (MonoDebugHandle *debug)
 {
@@ -599,10 +659,24 @@ mono_debug_write_symbols (MonoDebugHandle *debug)
 void
 mono_debug_make_symbols (void)
 {
-       MonoDebugHandle *debug;
+       if (!mono_debug_handle || !mono_debug_handle->dirty)
+               return;
+       
+       switch (mono_debug_handle->format) {
+       case MONO_DEBUG_FORMAT_STABS:
+               mono_debug_write_stabs (mono_debug_handle);
+               break;
+       case MONO_DEBUG_FORMAT_DWARF2:
+               mono_debug_write_dwarf2 (mono_debug_handle);
+               break;
+       case MONO_DEBUG_FORMAT_MONO:
+               mono_debug_update_symbol_file_table ();
+               break;
+       default:
+               g_assert_not_reached ();
+       }
 
-       for (debug = mono_debug_handles; debug; debug = debug->next)
-               mono_debug_write_symbols (debug);
+       mono_debug_handle->dirty = FALSE;
 }
 
 static void
@@ -617,6 +691,7 @@ mono_debug_close_assembly (AssemblyDebugInfo* info)
                break;
        }
        g_hash_table_destroy (info->methods);
+       g_hash_table_destroy (info->wrapper_methods);
        g_free (info->mlines);
        g_free (info->moffsets);
        g_free (info->name);
@@ -629,34 +704,22 @@ mono_debug_close_assembly (AssemblyDebugInfo* info)
 void
 mono_debug_cleanup (void)
 {
-       MonoDebugHandle *debug, *temp;
-
        release_symbol_file_table ();
-       
-       for (debug = mono_debug_handles; debug; debug = temp) {
-               GList *tmp;
-
-               if (debug->flags & MONO_DEBUG_FLAGS_UPDATE_ON_EXIT)
-                       mono_debug_write_symbols (debug);
-
 
-               for (tmp = debug->info; tmp; tmp = tmp->next) {
-                       AssemblyDebugInfo* info = (AssemblyDebugInfo*)tmp->data;
-
-                       mono_debug_close_assembly (info);
-               }
+       if (!mono_debug_handle)
+               return;
 
-               g_ptr_array_free (debug->source_files, TRUE);
-               g_hash_table_destroy (debug->type_hash);
-               g_free (debug->producer_name);
-               g_free (debug->name);
+       if (mono_debug_handle->flags & MONO_DEBUG_FLAGS_UPDATE_ON_EXIT)
+               mono_debug_write_symbols (mono_debug_handle);
 
-               temp = debug->next;
-               g_free (debug);
-       }
+       g_hash_table_destroy (mono_debug_handle->images);
+       g_ptr_array_free (mono_debug_handle->source_files, FALSE);
+       g_hash_table_destroy (mono_debug_handle->type_hash);
+       g_free (mono_debug_handle->producer_name);
+       g_free (mono_debug_handle->name);
+       g_free (mono_debug_handle);
 
-       mono_debug_handles = NULL;
-       mono_default_debug_handle = NULL;
+       mono_debug_handle = NULL;
 }
 
 guint32
@@ -720,53 +783,21 @@ mono_debug_get_type (MonoDebugHandle *debug, MonoClass *klass)
        return index;
 }
 
-MonoDebugHandle *
-mono_debug_handle_from_class (MonoClass *klass)
-{
-       MonoDebugHandle *debug;
-
-       mono_class_init (klass);
-
-       for (debug = mono_debug_handles; debug; debug = debug->next) {
-               GList *tmp;
-
-               for (tmp = debug->info; tmp; tmp = tmp->next) {
-                       AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
-
-                       if (info->image == klass->image)
-                               return debug;
-               }
-       }
-
-       return NULL;
-}
-
 static gint32
 il_offset_from_address (MonoDebugMethodInfo *minfo, guint32 address)
 {
        int i;
 
-       if (!minfo->jit)
+       if (!minfo->jit || !minfo->jit->line_numbers)
                return -1;
 
-       for (i = 0; i < minfo->num_il_offsets; i++)
-               if (minfo->jit->il_addresses [i] > address)
-                       return minfo->il_offsets [i].offset;
-
-       return -1;
-}
-
-static gint32
-address_from_il_offset (MonoDebugMethodInfo *minfo, guint32 il_offset)
-{
-       int i;
-
-       if (!minfo->jit)
-               return -1;
+       for (i = minfo->jit->line_numbers->len - 1; i >= 0; i--) {
+               MonoDebugLineNumberEntry lne = g_array_index (
+                       minfo->jit->line_numbers, MonoDebugLineNumberEntry, i);
 
-       for (i = 0; i < minfo->num_il_offsets; i++)
-               if (minfo->il_offsets [i].offset > il_offset)
-                       return minfo->jit->il_addresses [i];
+               if (lne.address <= address)
+                       return lne.offset;
+       }
 
        return -1;
 }
@@ -774,177 +805,109 @@ address_from_il_offset (MonoDebugMethodInfo *minfo, guint32 il_offset)
 void
 mono_debug_add_type (MonoClass *klass)
 {
-       MonoDebugHandle *debug = mono_debug_handle_from_class (klass);
+       AssemblyDebugInfo* info;
 
-       g_assert (debug != NULL);
+       if (!mono_debug_handle)
+               return;
 
-       mono_debug_get_type (debug, klass);
-}
+       info = _mono_debug_get_image (mono_debug_handle, klass->image);
+       g_assert (info);
 
-static gint32
-il_offset_from_position (MonoFlowGraph *cfg, MonoPosition *pos)
-{
-       MonoBBlock *bblock;
-       MBTree *tree;
+       if (mono_debug_handle->format != MONO_DEBUG_FORMAT_MONO)
+               return;
 
-       if (pos->abs_pos == 0)
-               return -1;
+       if (info->symfile) {
+               mono_debug_lock ();
+               mono_debug_symfile_add_type (info->symfile, klass);
+               mono_debugger_event (MONO_DEBUGGER_EVENT_TYPE_ADDED, info->symfile, klass);
+               mono_debug_unlock ();
+       }
+}
 
-       if (pos->pos.bid >= cfg->block_count)
-               return -1;
+struct LookupMethodData
+{
+       MonoDebugMethodInfo *minfo;
+       MonoMethod *method;
+};
 
-       bblock = &cfg->bblocks [pos->pos.bid];
-       if (pos->pos.tid >= bblock->forest->len)
-               return -1;
+static void
+lookup_method_func (gpointer key, gpointer value, gpointer user_data)
+{
+       AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
+       struct LookupMethodData *data = (struct LookupMethodData *) user_data;
 
-       tree = (MBTree *) g_ptr_array_index (bblock->forest, pos->pos.tid);
+       if (data->minfo)
+               return;
 
-       return tree->cli_addr;
+       if (info->symfile)
+               data->minfo = mono_debug_find_method (info->symfile, data->method);
+       else
+               data->minfo = g_hash_table_lookup (info->methods, data->method);
 }
 
-static MonoDebugMethodInfo *
-lookup_method (MonoMethod *method)
+MonoDebugMethodInfo *
+_mono_debug_lookup_method (MonoMethod *method)
 {
-       MonoDebugHandle *debug;
-
-       for (debug = mono_debug_handles; debug; debug = debug->next) {
-               GList *tmp;
+       struct LookupMethodData data = { NULL, method };
 
-               for (tmp = debug->info; tmp; tmp = tmp->next) {
-                       AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
-                       MonoDebugMethodInfo *minfo;
-
-                       if (info->symfile)
-                               minfo = mono_debug_find_method (info->symfile, method);
-                       else
-                               minfo = g_hash_table_lookup (info->methods, method);
-
-                       if (minfo)
-                               return minfo;
-               }
-       }
+       if (!mono_debug_handle)
+               return NULL;
 
-       return NULL;
+       g_hash_table_foreach (mono_debug_handle->images, lookup_method_func, &data);
+       return data.minfo;
 }
 
 void
-mono_debug_add_method (MonoFlowGraph *cfg)
+mono_debug_add_wrapper (MonoMethod *method, MonoMethod *wrapper_method)
 {
-       MonoMethod *method = cfg->method;
        MonoClass *klass = method->klass;
-       MonoDebugHandle* debug;
        AssemblyDebugInfo* info;
-       MonoDebugMethodJitInfo *jit;
        MonoDebugMethodInfo *minfo;
-       int i;
-
-       mono_class_init (klass);
+       DebugWrapperInfo *winfo;
+       MonoDebugMethodJitInfo *jit;
 
-       if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
-           (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
-           (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
+       if (!mono_debug_handle)
                return;
 
-       if (method->wrapper_type != MONO_WRAPPER_NONE)
+       if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
                return;
 
-       debug = mono_debug_handle_from_class (klass);
-       if (!debug) {
-               if (mono_default_debug_handle)
-                       debug = mono_default_debug_handle;
-               else
-                       return;
-       }
-
-       info = mono_debug_get_image (debug, klass->image);
-       if (info == NULL) {
-               release_symbol_file_table ();
-               mono_debugger_symbol_file_table_generation++;
+       mono_class_init (klass);
 
-               info = mono_debug_open_image (debug, klass->image);
-       }
+       info = _mono_debug_get_image (mono_debug_handle, klass->image);
+       g_assert (info);
 
-       minfo = lookup_method (method);
+       minfo = _mono_debug_lookup_method (method);
        if (!minfo || minfo->jit)
                return;
 
-       debug->dirty = TRUE;
-
-       minfo->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
-       jit->code_start = cfg->start;
-       jit->code_size = cfg->epilogue_end;
-       jit->prologue_end = cfg->prologue_end;
-       jit->epilogue_begin = cfg->epilog;
-       jit->num_params = method->signature->param_count;
-       jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
-
-       if (method->signature->hasthis) {
-               MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index;
-
-               jit->this_var = g_new0 (MonoDebugVarInfo, 1);
-               jit->this_var->offset = ptr->offset;
-               jit->this_var->size = ptr->size;
-       }
-
-       for (i = 0; i < jit->num_params; i++) {
-               MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index +
-                       method->signature->hasthis;
+       winfo = g_hash_table_lookup (info->wrapper_methods, wrapper_method);
+       g_assert (winfo);
 
-               jit->params [i].offset = ptr [i].offset;
-               jit->params [i].size = ptr [i].size;
-       }
+       mono_debug_lock ();
 
-       debug_generate_method_lines (info, minfo, cfg);
-       debug_update_il_offsets (info, minfo, cfg);
-
-       if (!method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
-               MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
-               MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->locals_start_index;
-               MonoDebugVarInfo *locals;
-
-               locals = g_new0 (MonoDebugVarInfo, header->num_locals);
-               for (i = 0; i < header->num_locals; i++) {
-                       gint32 begin_offset, end_offset;
-                       gint32 begin_scope, end_scope;
-
-                       if (ptr [i].reg >= 0) {
-                               locals [i].index = ptr [i].reg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
-                               locals [i].offset = 0;
-                       } else
-                               locals [i].offset = ptr [i].offset;
-
-                       locals [i].size = ptr [i].size;
-
-                       begin_offset = il_offset_from_position (cfg, &ptr [i].range.first_use);
-                       end_offset = il_offset_from_position (cfg, &ptr [i].range.last_use);
-                       if (end_offset >= 0)
-                               end_offset++;
-
-                       begin_scope = address_from_il_offset (minfo, begin_offset);
-                       end_scope = address_from_il_offset (minfo, end_offset);
-
-                       if (begin_scope > 0)
-                               locals [i].begin_scope = begin_scope;
-                       else
-                               locals [i].begin_scope = jit->prologue_end;
-                       if (end_scope > 0)
-                               locals [i].end_scope = end_scope;
-                       else
-                               locals [i].end_scope = jit->epilogue_begin;
-               }
+       mono_debug_handle->dirty = TRUE;
 
-               jit->num_locals = header->num_locals;
-               jit->locals = locals;
+       minfo->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
+       jit->code_start = winfo->code_start;
+       jit->code_size = winfo->code_size;
+       jit->prologue_end = 0;
+       jit->epilogue_begin = winfo->code_size;
+       jit->num_params = 0;
+       jit->wrapper_addr = method->addr;
+
+       if (info->symfile) {
+               mono_debug_symfile_add_method (info->symfile, method);
+               mono_debugger_event (MONO_DEBUGGER_EVENT_METHOD_ADDED, info->symfile, method);
        }
 
-       if (info->symfile)
-               mono_debug_symfile_add_method (info->symfile, method);
+       mono_debug_unlock ();
 }
 
 gchar *
 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number)
 {
-       MonoDebugMethodInfo *minfo = lookup_method (method);
+       MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
 
        if (!minfo)
                return NULL;
@@ -969,7 +932,7 @@ mono_debug_il_offset_from_address (MonoMethod *method, gint32 address)
        if (address < 0)
                return -1;
 
-       minfo = lookup_method (method);
+       minfo = _mono_debug_lookup_method (method);
        if (!minfo || !minfo->il_offsets)
                return -1;
 
@@ -984,11 +947,11 @@ mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset)
        if (il_offset < 0)
                return -1;
 
-       minfo = lookup_method (method);
+       minfo = _mono_debug_lookup_method (method);
        if (!minfo || !minfo->il_offsets)
                return -1;
 
-       return address_from_il_offset (minfo, il_offset);
+       return _mono_debug_address_from_il_offset (minfo, il_offset);
 }
 
 static void
@@ -999,8 +962,6 @@ release_symbol_file_table ()
        if (!mono_debugger_symbol_file_table)
                return;
 
-       g_message (G_STRLOC);
-
        /*
         * Caution: The debugger may access the memory pointed to by this variable
         *          at any time.  It is very important to set the pointer to NULL
@@ -1012,30 +973,53 @@ release_symbol_file_table ()
        g_free (mono_debugger_symbol_file_table);
 }
 
-int
-mono_debugger_update_symbol_file_table (void)
+static void
+update_symbol_file_table_count_func (gpointer key, gpointer value, gpointer user_data)
+{
+       AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
+
+       if (!info->symfile)
+               return;
+       if (info->format != MONO_DEBUG_FORMAT_MONO)
+               return;
+
+       ++ (* (int *) user_data);
+}
+
+struct SymfileTableData
 {
-       MonoDebugHandle *debug;
-       int count = 0, index;
        MonoDebuggerSymbolFileTable *symfile_table;
-       guint32 size;
+       int index;
+};
 
-       for (debug = mono_debug_handles; debug; debug = debug->next) {
-               GList *tmp;
+static void
+update_symbol_file_table_func (gpointer key, gpointer value, gpointer user_data)
+{
+       AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
+       struct SymfileTableData *data = (struct SymfileTableData *) user_data;
 
-               if (debug->format != MONO_DEBUG_FORMAT_MONO)
-                       continue;
+       if (!info->symfile)
+               return;
+       if (info->format != MONO_DEBUG_FORMAT_MONO)
+               return;
 
-               for (tmp = debug->info; tmp; tmp = tmp->next) {
-                       AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
-                       MonoSymbolFile *symfile = info->symfile;
+       data->symfile_table->symfiles [data->index++] = info->symfile;
+}
 
-                       if (!symfile)
-                               continue;
+int
+mono_debug_update_symbol_file_table (void)
+{
+       int count = 0;
+       MonoDebuggerSymbolFileTable *symfile_table;
+       struct SymfileTableData data;
+       guint32 size;
 
-                       count++;
-               }
-       }
+       if (!mono_debug_handle)
+               return FALSE;
+
+       mono_debug_lock ();
+
+       g_hash_table_foreach (mono_debug_handle->images, update_symbol_file_table_count_func, &count);
 
        release_symbol_file_table ();
 
@@ -1046,27 +1030,101 @@ mono_debugger_update_symbol_file_table (void)
        symfile_table->total_size = size;
        symfile_table->count = count;
        symfile_table->generation = mono_debugger_symbol_file_table_generation;
+       symfile_table->global_symfile = mono_debugger_global_symbol_file;
+
+       data.symfile_table = symfile_table;
+       data.index = 0;
+
+       g_hash_table_foreach (mono_debug_handle->images, update_symbol_file_table_func, &data);
+
+       mono_debugger_symbol_file_table = symfile_table;
+
+       mono_debug_unlock ();
+
+       return TRUE;
+}
+
+static GPtrArray *breakpoints = NULL;
+
+int
+mono_insert_breakpoint_full (MonoMethodDesc *desc, gboolean use_trampoline)
+{
+       static int last_breakpoint_id = 0;
+       MonoDebuggerBreakpointInfo *info;
+
+       info = g_new0 (MonoDebuggerBreakpointInfo, 1);
+       info->desc = desc;
+       info->use_trampoline = use_trampoline;
+       info->index = ++last_breakpoint_id;
+
+       if (!breakpoints)
+               breakpoints = g_ptr_array_new ();
+
+       g_ptr_array_add (breakpoints, info);
+
+       return info->index;
+}
+
+int
+mono_remove_breakpoint (int breakpoint_id)
+{
+       int i;
+
+       if (!breakpoints)
+               return 0;
 
-       index = 0;
-       for (debug = mono_debug_handles; debug; debug = debug->next) {
-               GList *tmp;
+       for (i = 0; i < breakpoints->len; i++) {
+               MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
 
-               if (debug->format != MONO_DEBUG_FORMAT_MONO)
+               if (info->index != breakpoint_id)
                        continue;
 
-               for (tmp = debug->info; tmp; tmp = tmp->next) {
-                       AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
-                       MonoSymbolFile *symfile = info->symfile;
+               mono_method_desc_free (info->desc);
+               g_ptr_array_remove (breakpoints, info);
+               g_free (info);
+               return 1;
+       }
 
-                       if (!symfile)
-                               continue;
+       return 0;
+}
 
-                       symfile_table->symfiles [index++] = symfile;
-               }
+int
+mono_insert_breakpoint (const gchar *method_name, gboolean include_namespace)
+{
+       MonoMethodDesc *desc;
+
+       desc = mono_method_desc_new (method_name, include_namespace);
+       if (!desc)
+               return 0;
+
+       return mono_insert_breakpoint_full (desc, running_in_the_mono_debugger);
+}
+
+int
+mono_method_has_breakpoint (MonoMethod* method, gboolean use_trampoline)
+{
+       int i;
+
+       if (!breakpoints || (method->wrapper_type != MONO_WRAPPER_NONE))
+               return 0;
+
+       for (i = 0; i < breakpoints->len; i++) {
+               MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
+
+               if (info->use_trampoline != use_trampoline)
+                       continue;
+
+               if (!mono_method_desc_full_match (info->desc, method))
+                       continue;
+
+               return info->index;
        }
 
-       g_message (G_STRLOC ": %p", symfile_table);
+       return 0;
+}
 
-       mono_debugger_symbol_file_table = symfile_table;
-       return TRUE;
+void
+mono_debugger_trampoline_breakpoint_callback (void)
+{
+       mono_debugger_event (MONO_DEBUGGER_EVENT_BREAKPOINT_TRAMPOLINE, NULL, NULL);
 }