2002-08-16 Nick Drochak <ndrochak@gol.com>
[mono.git] / mono / metadata / debug-symfile.c
index c0cf4a59cc195a229e35ba2952577fca76971ad4..4cf9fa90029866d512595d6c19613d927b399496 100644 (file)
@@ -1,8 +1,10 @@
 #include <config.h>
 #include <stdlib.h>
 #include <string.h>
+#include <signal.h>
 #include <mono/metadata/metadata.h>
 #include <mono/metadata/rawbuffer.h>
+#include <mono/metadata/tokentype.h>
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/exception.h>
 #include <mono/metadata/debug-symfile.h>
 #define MRT_method_end_address         0x04
 #define MRT_local_variable             0x05
 #define MRT_method_parameter           0x06
+#define MRT_type_sizeof                        0x07
+#define MRT_type_field_offset          0x08
+#define MRT_mono_string_sizeof         0x09
+#define MRT_mono_string_offset         0x0a
+#define MRT_mono_array_sizeof          0x0b
+#define MRT_mono_array_offset          0x0c
+#define MRT_mono_array_bounds_sizeof   0x0d
+#define MRT_mono_array_bounds_offset   0x0e
+#define MRT_variable_start_scope       0x0f
+#define MRT_variable_end_scope         0x10
+#define MRT_mono_string_fieldsize      0x11
+#define MRT_mono_array_fieldsize       0x12
+#define MRT_type_field_fieldsize       0x13
+#define MRT_mono_string_string_length  0x14
+#define MRT_mono_string_byte_size      0x15
+#define MRT_mono_string_data_location  0x16
+#define MRT_static_type_field_offset   0x17
+#define MRT_mono_array_data_location   0x18
+#define MRT_mono_array_max_length      0x19
+#define MRT_mono_array_length_byte_size        0x1a
+
+#define MRI_string_offset_length       0x00
+#define MRI_string_offset_chars                0x01
+
+#define MRI_array_offset_bounds                0x00
+#define MRI_array_offset_max_length    0x01
+#define MRI_array_offset_vector                0x02
+
+#define MRI_array_bounds_offset_lower  0x00
+#define MRI_array_bounds_offset_length 0x01
 
 #define MRS_debug_info                 0x01
 #define MRS_debug_abbrev               0x02
 #define MRS_debug_line                 0x03
 #define MRS_mono_reloc_table           0x04
 
+#define DW_OP_const4u                  0x0c
+#define DW_OP_const4s                  0x0d
+#define DW_OP_plus                     0x22
+#define DW_OP_reg0                     0x50
+#define DW_OP_breg0                    0x70
+#define DW_OP_fbreg                    0x91
+#define DW_OP_piece                    0x93
+#define DW_OP_nop                      0x96
+
 #ifdef HAVE_ELF_H
 
 static gboolean
@@ -38,7 +79,7 @@ get_sections_elf32 (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
        const char *strtab;
        int i;
 
-       header = symfile->raw_contents;
+       header = (Elf32_Ehdr *)symfile->raw_contents;
        if (header->e_version != EV_CURRENT) {
                if (emit_warnings)
                        g_warning ("Symbol file %s has unknown ELF version %d",
@@ -63,7 +104,7 @@ get_sections_elf32 (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
 
        symfile->section_offsets = g_new0 (MonoDebugSymbolFileSection, MONO_DEBUG_SYMBOL_SECTION_MAX);
 
-       section = symfile->raw_contents + header->e_shoff;
+       section = (Elf32_Shdr *)(symfile->raw_contents + header->e_shoff);
        strtab_section = section + header->e_shstrndx;
        strtab = symfile->raw_contents + strtab_section->sh_offset;
 
@@ -98,6 +139,20 @@ get_sections_elf32 (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
                        sfs->type = MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE;
                        sfs->file_offset = section->sh_offset;
                        sfs->size = section->sh_size;
+               } else if (!strcmp (name, ".mono_line_numbers")) {
+                       MonoDebugSymbolFileSection *sfs;
+
+                       sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS];
+                       sfs->type = MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS;
+                       sfs->file_offset = section->sh_offset;
+                       sfs->size = section->sh_size;
+               } else if (!strcmp (name, ".mono_symbol_table")) {
+                       MonoDebugSymbolFileSection *sfs;
+
+                       sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_SYMBOL_TABLE];
+                       sfs->type = MONO_DEBUG_SYMBOL_SECTION_MONO_SYMBOL_TABLE;
+                       sfs->file_offset = section->sh_offset;
+                       sfs->size = section->sh_size;
                }
        }
 
@@ -110,6 +165,9 @@ static gboolean
 get_sections (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
 {
 #ifdef HAVE_ELF_H
+#ifdef __FreeBSD__
+       static const char ELFMAG[] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, 0 };
+#endif
        if (!strncmp (symfile->raw_contents, ELFMAG, strlen (ELFMAG)))
                return get_sections_elf32 (symfile, emit_warnings);
 #endif
@@ -120,6 +178,140 @@ get_sections (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
        return FALSE;
 }
 
+static void
+read_line_numbers (MonoDebugSymbolFile *symfile)
+{
+       const char *ptr, *start, *end;
+       int version;
+       long section_size;
+
+       if (!symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset)
+               return;
+
+       ptr = start = symfile->raw_contents +
+               symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset;
+
+       version = *((guint16 *) ptr)++;
+       if (version != MONO_DEBUG_SYMBOL_FILE_VERSION) {
+               g_warning ("Symbol file %s has incorrect line number table version "
+                          "(expected %d, got %d)", symfile->file_name,
+                          MONO_DEBUG_SYMBOL_FILE_VERSION, version);
+               return;
+       }
+
+       section_size = *((guint32 *) ptr)++;
+       end = ptr + section_size;
+
+       symfile->line_number_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+                                                           NULL, (GDestroyNotify) g_free);
+
+       while (ptr < end) {
+               MonoDebugLineNumberBlock *lnb;
+               guint32 token, source_offset;
+               MonoMethod *method;
+
+               token = * ((guint32 *) ptr)++;
+               method = mono_get_method (symfile->image, token, NULL);
+               if (!method)
+                       continue;
+
+               lnb = g_new0 (MonoDebugLineNumberBlock, 1);
+               lnb->token = token;
+               source_offset = * ((guint32 *) ptr)++;
+               lnb->source_file = (const char *) start + source_offset;
+               lnb->start_line = * ((guint32 *) ptr)++;
+               lnb->file_offset = * ((guint32 *) ptr)++;
+
+               g_hash_table_insert (symfile->line_number_table, method, lnb);
+       }
+}
+
+static MonoClass *
+find_class_by_name (MonoDebugSymbolFile *symfile, const char *nspace, const char *name)
+{
+       MonoAssembly **assembly;
+       MonoClass *klass;
+
+       klass = mono_class_from_name (symfile->image, nspace, name);
+
+       if (klass)
+               return klass;
+
+       for (assembly = symfile->image->references; assembly && *assembly; assembly++) {
+               klass = mono_class_from_name ((*assembly)->image, nspace, name);
+
+               if (klass)
+                       return klass;
+       }
+
+       g_message (G_STRLOC ": Can't find class %s.%s", nspace, name);
+
+       return NULL;
+}
+
+static void
+read_symbol_table (MonoDebugSymbolFile *symfile)
+{
+       const char *ptr, *start, *end;
+       int version, i;
+       long section_size;
+
+       if (!symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_SYMBOL_TABLE].file_offset)
+               return;
+
+       ptr = start = symfile->raw_contents +
+               symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_SYMBOL_TABLE].file_offset;
+
+       version = *((guint16 *) ptr)++;
+       if (version != MONO_DEBUG_SYMBOL_FILE_VERSION) {
+               g_warning ("Symbol file %s has incorrect line number table version "
+                          "(expected %d, got %d)", symfile->file_name,
+                          MONO_DEBUG_SYMBOL_FILE_VERSION, version);
+               return;
+       }
+
+       section_size = *((guint32 *) ptr)++;
+       end = ptr + section_size;
+
+       g_free (symfile->type_table);
+
+       symfile->num_types = * ((guint32 *) ptr)++;
+       symfile->type_table = g_new0 (MonoClass *, symfile->num_types);
+
+       for (i = 0; i < symfile->num_types; i++) {
+               const char *name, *namespace;
+               MonoClass *klass;
+
+               namespace = ptr;
+               ptr += strlen (namespace) + 1;
+
+               name = ptr;
+               ptr += strlen (name) + 1;
+
+               klass = find_class_by_name (symfile, namespace, name);
+
+               if (klass)
+                       symfile->type_table [i] = klass;
+       }
+}
+
+static MonoClass *
+mono_debug_class_get (MonoDebugSymbolFile *symfile, guint32 type_token)
+{
+       MonoClass *klass;
+
+       if (!type_token)
+               return mono_defaults.object_class;
+
+       if (type_token <= symfile->num_types)
+               return symfile->type_table [type_token - 1];
+
+       if ((klass = g_hash_table_lookup (symfile->image->class_cache, GUINT_TO_POINTER (type_token))))
+                return klass;
+
+        return NULL;
+}
+
 MonoDebugSymbolFile *
 mono_debug_open_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
 {
@@ -163,6 +355,10 @@ mono_debug_open_symbol_file (MonoImage *image, const char *filename, gboolean em
                return NULL;
        }
 
+       read_symbol_table (symfile);
+
+       read_line_numbers (symfile);
+
        return symfile;
 }
 
@@ -177,11 +373,95 @@ mono_debug_close_symbol_file (MonoDebugSymbolFile *symfile)
        if (symfile->fd)
                close (symfile->fd);
 
+       if (symfile->line_number_table)
+               g_hash_table_destroy (symfile->line_number_table);
        g_free (symfile->file_name);
        g_free (symfile->section_offsets);
        g_free (symfile);
 }
 
+static void
+relocate_variable (MonoDebugVarInfo *var, void *base_ptr)
+{
+       if (!var) {
+               * ((guint8 *) base_ptr)++ = DW_OP_nop;
+               * ((guint8 *) base_ptr)++ = DW_OP_nop;
+               * ((guint8 *) base_ptr)++ = DW_OP_nop;
+               * ((guint8 *) base_ptr)++ = DW_OP_nop;
+               * ((guint8 *) base_ptr)++ = DW_OP_nop;
+               * ((guint8 *) base_ptr)++ = DW_OP_nop;
+               * ((guint8 *) base_ptr)++ = DW_OP_nop;
+               * ((guint8 *) base_ptr)++ = DW_OP_nop;
+               return;
+       }
+               
+       /*
+        * Update the location description for a local variable or method parameter.
+        * MCS always reserves 8 bytes for us to do this, if we don't need them all
+        * we just fill up the rest with DW_OP_nop's.
+        */
+
+       switch (var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) {
+       case MONO_DEBUG_VAR_ADDRESS_MODE_STACK:
+               /*
+                * Variable is on the stack.
+                *
+                * If `index' is zero, use the normal frame register.  Otherwise, bits
+                * 0..4 of `index' contain the frame register.
+                *
+                * Both DW_OP_fbreg and DW_OP_breg0 ... DW_OP_breg31 take an ULeb128
+                * argument - since this has an variable size, we set it to zero and
+                * manually add a 4 byte constant using DW_OP_plus.
+                */
+               if (!var->index)
+                       /* Use the normal frame register (%ebp on the i386). */
+                       * ((guint8 *) base_ptr)++ = DW_OP_fbreg;
+               else
+                       /* Use a custom frame register. */
+                       * ((guint8 *) base_ptr)++ = DW_OP_breg0 + (var->index & 0x001f);
+               * ((guint8 *) base_ptr)++ = 0;
+               * ((guint8 *) base_ptr)++ = DW_OP_const4s;
+               * ((gint32 *) base_ptr)++ = var->offset;
+               * ((guint8 *) base_ptr)++ = DW_OP_plus;
+               break;
+
+       case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
+               /*
+                * Variable is in the register whose number is contained in bits 0..4
+                * of `index'.
+                *
+                * We need to write exactly 8 bytes in this location description, so instead
+                * of filling up the rest with DW_OP_nop's just add the `offset' even if
+                * it's zero.
+                */
+               * ((guint8 *) base_ptr)++ = DW_OP_reg0 + (var->index & 0x001f);
+               * ((guint8 *) base_ptr)++ = DW_OP_nop;
+               * ((guint8 *) base_ptr)++ = DW_OP_const4s;
+               * ((gint32 *) base_ptr)++ = var->offset;
+               * ((guint8 *) base_ptr)++ = DW_OP_plus;
+               break;
+
+       case MONO_DEBUG_VAR_ADDRESS_MODE_TWO_REGISTERS:
+               /*
+                * Variable is in two registers whose numbers are in bits 0..4 and 5..9 of 
+                * the `index' field.  Don't add `offset' since we have only two bytes left,
+                * fill them up with DW_OP_nop's.
+                */
+               * ((guint8 *) base_ptr)++ = DW_OP_reg0 + (var->index & 0x001f);
+               * ((guint8 *) base_ptr)++ = DW_OP_piece;
+               * ((guint8 *) base_ptr)++ = sizeof (int);
+               * ((guint8 *) base_ptr)++ = DW_OP_reg0 + ((var->index & 0x1f0) >> 5);
+               * ((guint8 *) base_ptr)++ = DW_OP_piece;
+               * ((guint8 *) base_ptr)++ = sizeof (int);
+               * ((guint8 *) base_ptr)++ = DW_OP_nop;
+               * ((guint8 *) base_ptr)++ = DW_OP_nop;
+               break;
+
+       default:
+               g_assert_not_reached ();
+       }
+}
+
 void
 mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
                               MonoDebugMethodInfoFunc method_info_func,
@@ -191,6 +471,8 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
        int version, already_relocated = 0;
        long reloc_size;
 
+       read_symbol_table (symfile);
+
        if (!symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE].file_offset)
                return;
 
@@ -214,7 +496,7 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
        while (reloc_ptr < reloc_end) {
                int type, size, section, offset;
                const char *tmp_ptr;
-               void *base_ptr;
+               char *base_ptr;
 
                type = *reloc_ptr++;
                size = * ((guint32 *) reloc_ptr)++;
@@ -238,7 +520,7 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
                }
 
                base_ptr = symfile->raw_contents + symfile->section_offsets [section].file_offset;
-               base_ptr += offset;
+               base_ptr = base_ptr + offset;
 
                switch (type) {
                case MRT_target_address_size:
@@ -255,7 +537,10 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
                                continue;
                        }
 
-                       g_message ("Start of `%s' relocated to %p", minfo->method->name, minfo->code_start);
+#if 0
+                       g_message ("Start of `%s' (%ld) relocated to %p", minfo->method->name,
+                                  token, minfo->code_start);
+#endif
 
                        * (void **) base_ptr = minfo->code_start;
 
@@ -272,7 +557,7 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
                                continue;
                        }
 
-                       * (void **) base_ptr = minfo->code_start + minfo->code_size;
+                       * (void **) base_ptr = (char *)minfo->code_start + minfo->code_size;
 
                        break;
                }
@@ -301,9 +586,11 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
                                }
                        }
 
-                       g_message ("Relocating IL offset %d in `%s' to %d (%p)",
+#if 0
+                       g_message ("Relocating IL offset %04x in `%s' to %d (%p)",
                                   original, minfo->method->name, address,
                                   minfo->code_start + address);
+#endif
 
                        * (void **) base_ptr = minfo->code_start + address;
 
@@ -313,12 +600,11 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
                        guint32 token = *((guint32 *) tmp_ptr)++;
                        guint32 original = *((guint32 *) tmp_ptr)++;
                        MonoDebugMethodInfo *minfo;
-                       gint32 address;
 
                        minfo = method_info_func (symfile, token, user_data);
 
                        if (!minfo) {
-                               * (void **) base_ptr = 0;
+                               relocate_variable (NULL, base_ptr);
                                continue;
                        }
 
@@ -327,15 +613,12 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
                                           "local variable %d, but method %s only has %d local variables.",
                                           symfile->file_name, original, minfo->method->name,
                                           minfo->num_locals);
+                               g_message (G_STRLOC ": %d", token);
+                               G_BREAKPOINT ();
                                continue;
                        }
 
-                       address = minfo->local_offsets [original];
-
-                       g_message ("Relocating local variable %d (%s) to stack offset %d",
-                                  original, minfo->method->name, address);
-
-                       * (gint32 *) base_ptr = address;
+                       relocate_variable (&minfo->locals [original], base_ptr);
 
                        break;
                }
@@ -343,15 +626,23 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
                        guint32 token = *((guint32 *) tmp_ptr)++;
                        guint32 original = *((guint32 *) tmp_ptr)++;
                        MonoDebugMethodInfo *minfo;
-                       gint32 address;
 
                        minfo = method_info_func (symfile, token, user_data);
 
                        if (!minfo) {
-                               * (void **) base_ptr = 0;
+                               relocate_variable (NULL, base_ptr);
                                continue;
                        }
 
+                       if (minfo->method->signature->hasthis) {
+                               if (original == 0) {
+                                       relocate_variable (minfo->this_var, base_ptr);
+                                       continue;
+                               }
+
+                               original--;
+                       }
+
                        if (original > minfo->num_params) {
                                g_warning ("Symbol file %s contains relocation entry for non-existing "
                                           "parameter %d, but method %s only has %d parameters.",
@@ -360,15 +651,360 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
                                continue;
                        }
 
-                       address = minfo->param_offsets [original];
+                       relocate_variable (&minfo->params [original], base_ptr);
+
+                       break;
+               }
+               case MRT_type_sizeof: {
+                       guint32 token = *((guint32 *) tmp_ptr)++;
+                       MonoClass *klass = mono_debug_class_get (symfile, token);
+
+                       if (!klass)
+                               continue;
+
+                       mono_class_init (klass);
+
+                       if (klass->enumtype || klass->valuetype)
+                               * (gint8 *) base_ptr = klass->instance_size - sizeof (MonoObject);
+                       else
+                               * (gint8 *) base_ptr = klass->instance_size;
+
+                       break;
+               }
+               case MRT_type_field_offset: {
+                       guint32 token = *((guint32 *) tmp_ptr)++;
+                       guint32 original = *((guint32 *) tmp_ptr)++;
+                       MonoClass *klass = mono_debug_class_get (symfile, token);
+                       guint32 off;
+
+                       if (!klass)
+                               continue;
+
+                       mono_class_init (klass);
+
+                       if (original > klass->field.count) {
+                               g_warning ("Symbol file %s contains invalid field offset entry.",
+                                          symfile->file_name);
+                               g_message (G_STRLOC ": %d", token);
+                               /* G_BREAKPOINT (); */
+                               continue;
+                       }
+
+                       if (!klass->fields)
+                               continue;
+
+                       off = klass->fields [original].offset;
+                       if (klass->byval_arg.type == MONO_TYPE_VALUETYPE)
+                               off -= sizeof (MonoObject);
 
-                       g_message ("Relocating parameter %d (%s) to stack offset %d",
-                                  original, minfo->method->name, address);
+#if 0
+                       g_message ("Setting field %d of type %u to offset %d", original,
+                                  token, off);
+#endif
 
-                       * (gint32 *) base_ptr = address;
+                       * (guint32 *) base_ptr = off;
 
                        break;
                }
+               case MRT_mono_string_sizeof:
+                       * (gint8 *) base_ptr = sizeof (MonoString);
+                       break;
+
+               case MRT_mono_string_offset: {
+                       guint32 idx = *((guint32 *) tmp_ptr)++;
+                       MonoString string;
+                       guint32 off;
+
+                       switch (idx) {
+                       case MRI_string_offset_length:
+                               off = (guchar *) &string.length - (guchar *) &string;
+                               break;
+
+                       case MRI_string_offset_chars:
+                               off = (guchar *) &string.chars - (guchar *) &string;
+                               break;
+
+                       default:
+                               g_warning ("Symbol file %s contains invalid string offset entry",
+                                          symfile->file_name);
+                               continue;
+                       }
+
+                       * (guint32 *) base_ptr = off;
+
+                       break;
+               }
+               case MRT_mono_array_sizeof:
+                       * (gint8 *) base_ptr = sizeof (MonoArray);
+                       break;
+
+               case MRT_mono_array_offset: {
+                       guint32 idx = *((guint32 *) tmp_ptr)++;
+                       MonoArray array;
+                       guint32 off;
+
+                       switch (idx) {
+                       case MRI_array_offset_bounds:
+                               off = (guchar *) &array.bounds - (guchar *) &array;
+                               break;
+
+                       case MRI_array_offset_max_length:
+                               off = (guchar *) &array.max_length - (guchar *) &array;
+                               break;
+
+                       case MRI_array_offset_vector:
+                               off = (guchar *) &array.vector - (guchar *) &array;
+                               break;
+
+                       default:
+                               g_warning ("Symbol file %s contains invalid array offset entry",
+                                          symfile->file_name);
+                               continue;
+                       }
+
+                       * (guint32 *) base_ptr = off;
+
+                       break;
+               }
+
+               case MRT_mono_array_bounds_sizeof:
+                       * (gint8 *) base_ptr = sizeof (MonoArrayBounds);
+                       break;
+
+               case MRT_mono_array_bounds_offset: {
+                       guint32 idx = *((guint32 *) tmp_ptr)++;
+                       MonoArrayBounds bounds;
+                       guint32 off;
+
+                       switch (idx) {
+                       case MRI_array_bounds_offset_lower:
+                               off = (guchar *) &bounds.lower_bound - (guchar *) &bounds;
+                               break;
+
+                       case MRI_array_bounds_offset_length:
+                               off = (guchar *) &bounds.length - (guchar *) &bounds;
+                               break;
+
+                       default:
+                               g_warning ("Symbol file %s contains invalid array bounds offset entry",
+                                          symfile->file_name);
+                               continue;
+                       }
+
+                       * (guint32 *) base_ptr = off;
+
+                       break;
+               }
+
+               case MRT_variable_start_scope:  {
+                       guint32 token = *((guint32 *) tmp_ptr)++;
+                       guint32 original = *((guint32 *) tmp_ptr)++;
+                       MonoDebugMethodInfo *minfo;
+                       gint32 address;
+
+                       minfo = method_info_func (symfile, token, user_data);
+
+                       if (!minfo || !minfo->locals) {
+                               * (void **) base_ptr = 0;
+                               continue;
+                       }
+
+                       if (original > minfo->num_locals) {
+                               g_warning ("Symbol file %s contains relocation entry for non-existing "
+                                          "local variable %d, but method %s only has %d local variables.",
+                                          symfile->file_name, original, minfo->method->name,
+                                          minfo->num_locals);
+                               continue;
+                       }
+
+                       address = minfo->locals [original].begin_scope;
+
+                       * (void **) base_ptr = minfo->code_start + address;
+
+                       break;
+               }
+
+               case MRT_variable_end_scope:  {
+                       guint32 token = *((guint32 *) tmp_ptr)++;
+                       guint32 original = *((guint32 *) tmp_ptr)++;
+                       MonoDebugMethodInfo *minfo;
+                       gint32 address;
+
+                       minfo = method_info_func (symfile, token, user_data);
+
+                       if (!minfo || !minfo->locals) {
+                               * (void **) base_ptr = 0;
+                               continue;
+                       }
+
+                       if (original > minfo->num_locals) {
+                               g_warning ("Symbol file %s contains relocation entry for non-existing "
+                                          "local variable %d, but method %s only has %d local variables.",
+                                          symfile->file_name, original, minfo->method->name,
+                                          minfo->num_locals);
+                               continue;
+                       }
+
+                       address = minfo->locals [original].end_scope;
+
+                       * (void **) base_ptr = minfo->code_start + address;
+
+                       break;
+               }
+
+               case MRT_mono_string_fieldsize: {
+                       guint32 idx = *((guint32 *) tmp_ptr)++;
+                       MonoString string;
+                       guint32 fieldsize;
+
+                       switch (idx) {
+                       case MRI_string_offset_length:
+                               fieldsize = sizeof (string.length);
+                               break;
+
+                       default:
+                               g_warning ("Symbol file %s contains invalid string fieldsize entry",
+                                          symfile->file_name);
+                               continue;
+                       }
+
+                       * (guint32 *) base_ptr = fieldsize;
+
+                       break;
+               }
+
+               case MRT_mono_array_fieldsize: {
+                       guint32 idx = *((guint32 *) tmp_ptr)++;
+                       MonoArray array;
+                       guint32 fieldsize;
+
+                       switch (idx) {
+                       case MRI_array_offset_bounds:
+                               fieldsize = sizeof (array.bounds);
+                               break;
+
+                       case MRI_array_offset_max_length:
+                               fieldsize = sizeof (array.max_length);
+                               break;
+
+                       case MRI_array_offset_vector:
+                               fieldsize = sizeof (array.vector);
+                               break;
+
+                       default:
+                               g_warning ("Symbol file %s contains invalid array fieldsize entry",
+                                          symfile->file_name);
+                               continue;
+                       }
+
+                       * (guint32 *) base_ptr = fieldsize;
+
+                       break;
+               }
+
+               case MRT_mono_string_string_length: {
+                       MonoString string;
+                       guint32 offset = (guchar *) &string.length - (guchar *) &string;
+
+                       * ((guint8 *) base_ptr)++ = DW_OP_const4u;
+                       * ((gint32 *) base_ptr)++ = offset;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+
+                       break;
+               }
+
+               case MRT_mono_string_byte_size: {
+                       MonoString string;
+
+                       * (guint32 *) base_ptr = sizeof (string.length);
+
+                       break;
+               }
+
+               case MRT_mono_string_data_location: {
+                       MonoString string;
+                       guint32 offset = (guchar *) &string.chars - (guchar *) &string;
+
+                       * ((guint8 *) base_ptr)++ = DW_OP_const4u;
+                       * ((gint32 *) base_ptr)++ = offset;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+
+                       break;
+               }
+
+               case MRT_static_type_field_offset: {
+                       guint32 token = *((guint32 *) tmp_ptr)++;
+                       guint32 original = *((guint32 *) tmp_ptr)++;
+                       MonoClass *klass = mono_debug_class_get (symfile, token);
+                       MonoVTable *vtable;
+                       guint32 off;
+
+                       if (!klass)
+                               continue;
+
+                       mono_class_init (klass);
+
+                       if (original > klass->field.count) {
+                               g_warning ("Symbol file %s contains invalid field offset entry.",
+                                          symfile->file_name);
+                               continue;
+                       }
+
+                       if (!klass->fields)
+                               continue;
+
+                       vtable = mono_class_vtable (mono_domain_get (), klass);
+
+                       off = klass->fields [original].offset;
+
+#if 0
+                       g_message ("Setting field %d of type %u (%p) to offset %d", original,
+                                  token, klass, off);
+#endif
+
+                       * (void **) base_ptr = (char *) vtable->data + off;
+
+                       break;
+               }
+
+               case MRT_mono_array_data_location: {
+                       MonoArray array;
+                       guint32 offset = (guchar *) &array.vector - (guchar *) &array;
+
+                       * ((guint8 *) base_ptr)++ = DW_OP_const4u;
+                       * ((gint32 *) base_ptr)++ = offset;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+
+                       break;
+               }
+
+               case MRT_mono_array_max_length: {
+                       MonoArray array;
+                       guint32 offset = (guchar *) &array.max_length - (guchar *) &array;
+
+                       * ((guint8 *) base_ptr)++ = DW_OP_const4u;
+                       * ((gint32 *) base_ptr)++ = offset;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+                       * ((guint8 *) base_ptr)++ = DW_OP_nop;
+
+                       break;
+               }
+
+               case MRT_mono_array_length_byte_size: {
+                       MonoArray array;
+
+                       * (guint32 *) base_ptr = sizeof (array.max_length);
+
+                       break;
+               }
+
                default:
                        g_warning ("Symbol file %s contains unknown relocation entry %d",
                                   symfile->file_name, type);
@@ -379,49 +1015,44 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
        mono_raw_buffer_update (symfile->raw_contents, symfile->raw_contents_size);
 }
 
-MonoReflectionType *
-mono_debug_local_type_from_signature (MonoReflectionAssembly *assembly, MonoArray *signature)
+gchar *
+mono_debug_find_source_location (MonoDebugSymbolFile *symfile, MonoMethod *method, guint32 offset,
+                                guint32 *line_number)
 {
-       MonoDomain *domain; 
-       MonoImage *image;
-       MonoClass *klass;
-       MonoType *type;
+       MonoDebugLineNumberBlock *lnb;
        const char *ptr;
-       int len = 0;
-
-       MONO_CHECK_ARG_NULL (assembly);
-       MONO_CHECK_ARG_NULL (signature);
 
-       domain = mono_domain_get();
-       image = assembly->assembly->image;
-
-       ptr = mono_array_addr (signature, char, 0);
-       g_assert (*ptr++ == 0x07);
-       len = mono_metadata_decode_value (ptr, &ptr);
-       g_assert (len == 1);
-
-       type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
+       if (!symfile->line_number_table)
+               return NULL;
 
-       klass = mono_class_from_mono_type (type);
+       lnb = g_hash_table_lookup (symfile->line_number_table, method);
+       if (!lnb)
+               return NULL;
 
-       mono_class_init (klass);
+       ptr = symfile->raw_contents +
+               symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset;
 
-       return mono_type_get_object (domain, type);
-}
+       ptr += lnb->file_offset;
 
-MonoReflectionMethod *
-mono_debug_method_from_token (MonoReflectionAssembly *assembly, guint32 token)
-{
-       MonoDomain *domain; 
-       MonoImage *image;
-       MonoMethod *method;
+       do {
+               guint32 row, iloffset;
 
-       MONO_CHECK_ARG_NULL (assembly);
+               row = * ((guint32 *) ptr)++;
+               iloffset = * ((guint32 *) ptr)++;
 
-       domain = mono_domain_get();
-       image = assembly->assembly->image;
+               if (!row && !offset)
+                       return NULL;
+               if (!row)
+                       continue;
 
-       method = mono_get_method (image, token, NULL);
+               if (iloffset >= offset) {
+                       if (line_number) {
+                               *line_number = row;
+                               return g_strdup (lnb->source_file);
+                       } else
+                               return g_strdup_printf ("%s:%d", lnb->source_file, row);
+               }
+       } while (1);
 
-       return mono_method_get_object (domain, method);
+       return NULL;
 }