* reflection.c (inflate_mono_method): Reuse method instantiation
[mono.git] / mono / metadata / debug-mono-symfile.c
index a44c2748e185ea8f0bb868c74d9aa34e7efd53d1..6d703a57168f698a19bdb0e5905a209b27d18764 100644 (file)
@@ -1,8 +1,11 @@
 #include <config.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
 #include <string.h>
 #include <signal.h>
 #include <sys/param.h>
+#include <sys/stat.h>
 #include <mono/metadata/metadata.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/rawbuffer.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/debug-mono-symfile.h>
+#include <mono/metadata/mono-debug-debugger.h>
 #include <mono/metadata/mono-endian.h>
+#include <mono/metadata/metadata-internals.h>
+#include <mono/metadata/class-internals.h>
 
 #include <fcntl.h>
 #include <unistd.h>
@@ -46,9 +52,10 @@ get_class_name (MonoClass *klass)
 }
 
 static int
-load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile)
+load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile, gboolean in_the_debugger)
 {
        const char *ptr, *start;
+       gchar *guid;
        guint64 magic;
        long version;
 
@@ -59,69 +66,86 @@ load_symfile (MonoDebugHandle *handle, MonoSymbolFile *symfile)
        magic = read64(ptr);
        ptr += sizeof(guint64);
        if (magic != MONO_SYMBOL_FILE_MAGIC) {
-               g_warning ("Symbol file %s is not a mono symbol file", handle->image_file);
+               if (!in_the_debugger)
+                       g_warning ("Symbol file %s is not a mono symbol file", symfile->filename);
                return FALSE;
        }
 
        version = read32(ptr);
        ptr += sizeof(guint32);
        if (version != MONO_SYMBOL_FILE_VERSION) {
-               g_warning ("Symbol file %s has incorrect version "
-                          "(expected %d, got %ld)", handle->image_file,
-                          MONO_SYMBOL_FILE_VERSION, version);
+               if (!in_the_debugger)
+                       g_warning ("Symbol file %s has incorrect version "
+                                  "(expected %d, got %ld)", symfile->filename,
+                                  MONO_SYMBOL_FILE_VERSION, version);
                return FALSE;
        }
 
-       symfile->offset_table = (MonoSymbolFileOffsetTable *) ptr;
+       guid = mono_guid_to_string ((const guint8 *) ptr);
+       ptr += 16;
 
-       symfile->method_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
-                                                            (GDestroyNotify) free_method_info);
+       if (strcmp (handle->image->guid, guid)) {
+               if (!in_the_debugger)
+                       g_warning ("Symbol file %s doesn't match image %s", symfile->filename,
+                                  handle->image_file);
+               if (guid)
+                       g_free (guid);
+               return FALSE;
+       }
 
-       return TRUE;
-}
+       symfile->offset_table = (MonoSymbolFileOffsetTable *) ptr;
 
-static gconstpointer
-open_symfile (MonoImage *image, guint32 *size)
-{
-       MonoTableInfo *table = mono_image_get_table_info (image, MONO_TABLE_MANIFESTRESOURCE);
-       guint32 i, num_rows;
-       guint32 cols [MONO_MANIFEST_SIZE];
-       const char *val;
-
-       num_rows = mono_table_info_get_rows (table);
-       for (i = 0; i < num_rows; ++i) {
-               mono_metadata_decode_row (table, i, cols, MONO_MANIFEST_SIZE);
-               val = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
-               if (!strcmp (val, "MonoSymbolFile"))
-                       break;
-       }
-       if (i == num_rows)
-               return NULL;
-       g_assert (!cols [MONO_MANIFEST_IMPLEMENTATION]);
+       symfile->method_hash = g_hash_table_new_full (
+               g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) free_method_info);
 
-       return mono_image_get_resource (image, cols [MONO_MANIFEST_OFFSET], size);
+       g_free (guid);
+       return TRUE;
 }
 
 MonoSymbolFile *
-mono_debug_open_mono_symbol_file (MonoDebugHandle *handle, gboolean create_symfile)
+mono_debug_open_mono_symbols (MonoDebugHandle *handle, const guint8 *raw_contents,
+                             int size, gboolean in_the_debugger)
 {
        MonoSymbolFile *symfile;
+       FILE* f;
 
-       mono_loader_lock ();
+       mono_debugger_lock ();
        symfile = g_new0 (MonoSymbolFile, 1);
 
-       symfile->raw_contents = open_symfile (handle->image, &symfile->raw_contents_size);
-
-       if (load_symfile (handle, symfile)) {
-               mono_loader_unlock ();
+       if (raw_contents != NULL) {
+               symfile->raw_contents_size = size;
+               symfile->raw_contents = g_malloc (size);
+               memcpy(symfile->raw_contents, raw_contents, size);
+               symfile->filename = g_strdup_printf ("LoadedFromMemory");
+       } else {
+               symfile->filename = g_strdup_printf ("%s.mdb", mono_image_get_filename (handle->image));
+
+               if ((f = fopen (symfile->filename, "rb"))) {
+                       struct stat stat_buf;
+                       
+                       if (fstat (fileno (f), &stat_buf) < 0) {
+                               if (!in_the_debugger)
+                                       g_warning ("stat of %s failed: %s",
+                                                  symfile->filename,  g_strerror (errno));
+                       } else {
+                               symfile->raw_contents_size = stat_buf.st_size;
+                               symfile->raw_contents = mono_raw_buffer_load (fileno (f), FALSE, 0, stat_buf.st_size);
+                       }
+
+                       fclose (f);
+               }
+       }
+       
+       if (load_symfile (handle, symfile, in_the_debugger)) {
+               mono_debugger_unlock ();
                return symfile;
-       } else if (!create_symfile) {
+       } else if (!in_the_debugger) {
                mono_debug_close_mono_symbol_file (symfile);
-               mono_loader_unlock ();
+               mono_debugger_unlock ();
                return NULL;
        }
 
-       mono_loader_unlock ();
+       mono_debugger_unlock ();
        return symfile;
 }
 
@@ -131,43 +155,69 @@ mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
        if (!symfile)
                return;
 
-       mono_loader_lock ();
+       mono_debugger_lock ();
        if (symfile->method_hash)
                g_hash_table_destroy (symfile->method_hash);
 
+       if (symfile->raw_contents)
+               mono_raw_buffer_free ((gpointer) symfile->raw_contents);
+
+       if (symfile->filename)
+               g_free (symfile->filename);
        g_free (symfile);
-       mono_loader_unlock ();
+       mono_debugger_unlock ();
+}
+
+static int
+read_leb128 (const char *ptr, const char **rptr)
+{
+       int ret = 0;
+       int shift = 0;
+       char b;
+
+       do {
+               b = *ptr++;
+                               
+               ret = ret | ((b & 0x7f) << shift);
+               shift += 7;
+       } while ((b & 0x80) == 0x80);
+
+       if (rptr)
+               *rptr = ptr;
+
+       return ret;
 }
 
 static gchar *
 read_string (const char *ptr)
 {
-       int len = read32 (ptr);
-       ptr += sizeof(guint32);
+       int len = read_leb128 (ptr, &ptr);
        return g_filename_from_utf8 (ptr, len, NULL, NULL, NULL);
 }
 
-gchar *
-mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
-                                guint32 *line_number)
+/**
+ * mono_debug_symfile_lookup_location:
+ * @minfo: A `MonoDebugMethodInfo' which can be retrieved by
+ *         mono_debug_lookup_method().
+ * @offset: IL offset within the corresponding method's CIL code.
+ *
+ * This function is similar to mono_debug_lookup_location(), but we
+ * already looked up the method and also already did the
+ * `native address -> IL offset' mapping.
+ */
+MonoDebugSourceLocation *
+mono_debug_symfile_lookup_location (MonoDebugMethodInfo *minfo, guint32 offset)
 {
        MonoSymbolFileLineNumberEntry *lne;
-       MonoDebugMethodInfo *minfo;
+       MonoSymbolFile *symfile;
        gchar *source_file = NULL;
        const char *ptr;
-       int i;
+       int count, i;
 
-       mono_loader_lock ();
-       if (!symfile->method_hash) {
-               mono_loader_unlock ();
+       if ((symfile = minfo->handle->symfile) == NULL)
                return NULL;
-       }
 
-       minfo = g_hash_table_lookup (symfile->method_hash, method);
-       if (!minfo) {
-               mono_loader_unlock ();
-               return NULL;
-       }
+       mono_debugger_lock ();
 
        if (read32(&(minfo->entry->_source_index))) {
                int offset = read32(&(symfile->offset_table->_source_table_offset)) +
@@ -179,32 +229,25 @@ mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, gu
 
        ptr = symfile->raw_contents + read32(&(minfo->entry->_line_number_table_offset));
 
-       lne = (MonoSymbolFileLineNumberEntry *) ptr;
+       count = read32(&(minfo->entry->_num_line_numbers));
+       lne = ((MonoSymbolFileLineNumberEntry *) ptr) + count - 1;
 
-       for (i = 0; i < read32(&(minfo->entry->_num_line_numbers)); i++, lne++) {
-               if (read32(&(lne->_offset)) < offset)
+       for (i = count - 1; i >= 0; i--, lne--) {
+               MonoDebugSourceLocation *location;
+
+               if (read32(&(lne->_offset)) > offset)
                        continue;
 
-               if (line_number) {
-                       *line_number = read32(&(lne->_row));
-                       mono_loader_unlock ();
-                       if (source_file)
-                               return source_file;
-                       else
-                               return NULL;
-               } else if (source_file) {
-                       gchar *retval = g_strdup_printf ("%s:%d", source_file, read32(&(lne->_row)));
-                       g_free (source_file);
-                       mono_loader_unlock ();
-                       return retval;
-               } else {
-                       gchar* retval = g_strdup_printf ("%d", read32(&(lne->_row)));
-                       mono_loader_unlock ();
-                       return retval;
-               }
+               location = g_new0 (MonoDebugSourceLocation, 1);
+               location->source_file = source_file;
+               location->row = read32(&(lne->_row));
+               location->il_offset = read32(&(lne->_offset));
+
+               mono_debugger_unlock ();
+               return location;
        }
 
-       mono_loader_unlock ();
+       mono_debugger_unlock ();
        return NULL;
 }
 
@@ -216,12 +259,11 @@ _mono_debug_address_from_il_offset (MonoDebugMethodJitInfo *jit, guint32 il_offs
        if (!jit || !jit->line_numbers)
                return -1;
 
-       for (i = jit->line_numbers->len - 1; i >= 0; i--) {
-               MonoDebugLineNumberEntry lne = g_array_index (
-                       jit->line_numbers, MonoDebugLineNumberEntry, i);
+       for (i = jit->num_line_numbers - 1; i >= 0; i--) {
+               MonoDebugLineNumberEntry lne = jit->line_numbers [i];
 
-               if (lne.offset <= il_offset)
-                       return lne.address;
+               if (lne.il_offset <= il_offset)
+                       return lne.native_offset;
        }
 
        return -1;
@@ -237,7 +279,7 @@ compare_method (const void *key, const void *object)
 }
 
 MonoDebugMethodInfo *
-mono_debug_find_method (MonoDebugHandle *handle, MonoMethod *method)
+mono_debug_symfile_lookup_method (MonoDebugHandle *handle, MonoMethod *method)
 {
        MonoSymbolFileMethodEntry *me;
        MonoSymbolFileMethodIndexEntry *first_ie, *ie;
@@ -250,7 +292,7 @@ mono_debug_find_method (MonoDebugHandle *handle, MonoMethod *method)
        if (handle->image != mono_class_get_image (mono_method_get_class (method)))
                return NULL;
 
-       mono_loader_lock ();
+       mono_debugger_lock ();
        first_ie = (MonoSymbolFileMethodIndexEntry *)
                (symfile->raw_contents + read32(&(symfile->offset_table->_method_table_offset)));
 
@@ -259,7 +301,7 @@ mono_debug_find_method (MonoDebugHandle *handle, MonoMethod *method)
                                   sizeof (MonoSymbolFileMethodIndexEntry), compare_method);
 
        if (!ie) {
-               mono_loader_unlock ();
+               mono_debugger_unlock ();
                return NULL;
        }
 
@@ -272,10 +314,13 @@ mono_debug_find_method (MonoDebugHandle *handle, MonoMethod *method)
        minfo->num_il_offsets = read32(&(me->_num_line_numbers));
        minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
                (symfile->raw_contents + read32(&(me->_line_number_table_offset)));
+       minfo->num_lexical_blocks = read32(&(me->_num_lexical_blocks));
+       minfo->lexical_blocks = (MonoSymbolFileLexicalBlockEntry *)
+               (symfile->raw_contents + read32(&(me->_lexical_block_table_offset)));
        minfo->entry = me;
 
        g_hash_table_insert (symfile->method_hash, method, minfo);
 
-       mono_loader_unlock ();
+       mono_debugger_unlock ();
        return minfo;
 }