2002-08-16 Nick Drochak <ndrochak@gol.com>
[mono.git] / mono / metadata / debug-symfile.c
index f1a18f422da43c5a597195a352fccc26d7d79ebe..4cf9fa90029866d512595d6c19613d927b399496 100644 (file)
@@ -1,6 +1,7 @@
 #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>
 #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
@@ -52,6 +60,7 @@
 #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
@@ -137,6 +146,13 @@ get_sections_elf32 (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
                        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;
                }
        }
 
@@ -211,16 +227,91 @@ read_line_numbers (MonoDebugSymbolFile *symfile)
 }
 
 static MonoClass *
-mono_debug_class_get (MonoDebugSymbolFile *symfile, guint32 type_token)
+find_class_by_name (MonoDebugSymbolFile *symfile, const char *nspace, const char *name)
 {
+       MonoAssembly **assembly;
        MonoClass *klass;
 
-       if ((klass = g_hash_table_lookup (symfile->image->class_cache, GUINT_TO_POINTER (type_token))))
+       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)
 {
@@ -264,6 +355,8 @@ mono_debug_open_symbol_file (MonoImage *image, const char *filename, gboolean em
                return NULL;
        }
 
+       read_symbol_table (symfile);
+
        read_line_numbers (symfile);
 
        return symfile;
@@ -378,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;
 
@@ -807,6 +902,108 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
                        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",
@@ -819,7 +1016,8 @@ mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
 }
 
 gchar *
-mono_debug_find_source_location (MonoDebugSymbolFile *symfile, MonoMethod *method, guint32 offset)
+mono_debug_find_source_location (MonoDebugSymbolFile *symfile, MonoMethod *method, guint32 offset,
+                                guint32 *line_number)
 {
        MonoDebugLineNumberBlock *lnb;
        const char *ptr;
@@ -847,8 +1045,13 @@ mono_debug_find_source_location (MonoDebugSymbolFile *symfile, MonoMethod *metho
                if (!row)
                        continue;
 
-               if (iloffset >= offset)
-                       return g_strdup_printf ("%s:%d", lnb->source_file, row);
+               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 NULL;