file-io.c: Don't consider sockets as directory and avoid an endless loop. Fix bug...
[mono.git] / mono / metadata / mono-debug.c
index 64032f18bcbaadf3a65ad05812d9f8ee03228372..b3816d22ea23c26752843fa875f6f990d73b7eb2 100644 (file)
 #define DATA_TABLE_PTR_CHUNK_SIZE      256
 #define DATA_TABLE_CHUNK_SIZE          32768
 
+#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
+
+#if NO_UNALIGNED_ACCESS
+#define RETURN_UNALIGNED(type, addr) \
+       { \
+               type val; \
+               memcpy(&val, p + offset, sizeof(val)); \
+               return val; \
+       }
+#define WRITE_UNALIGNED(type, addr, val) \
+       memcpy(addr, &val, sizeof(type))
+#else
+#define RETURN_UNALIGNED(type, addr) \
+       return *(type*)(p + offset);
+#define WRITE_UNALIGNED(type, addr, val) \
+       (*(type *)(addr) = (val))
+#endif
+
 MonoSymbolTable *mono_symbol_table = NULL;
 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
 
@@ -74,8 +92,7 @@ mono_debug_init (MonoDebugFormat format)
        mono_debug_format = format;
        in_the_mono_debugger = format == MONO_DEBUG_FORMAT_DEBUGGER;
 
-       if (in_the_mono_debugger)
-               mono_debugger_initialize ();
+       mono_debugger_initialize (in_the_mono_debugger);
 
        mono_debugger_lock ();
 
@@ -91,6 +108,9 @@ mono_debug_init (MonoDebugFormat format)
        mono_debugger_start_class_init_func = mono_debug_start_add_type;
        mono_debugger_class_init_func = mono_debug_add_type;
        mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
+
+       if (!in_the_mono_debugger)
+               mono_debugger_unlock ();
 }
 
 void
@@ -113,6 +133,12 @@ mono_debug_init_2 (MonoAssembly *assembly)
        mono_debug_open_image (mono_assembly_get_image (assembly));
 }
 
+gboolean
+mono_debug_using_mono_debugger (void)
+{
+       return in_the_mono_debugger;
+}
+
 void
 mono_debug_cleanup (void)
 {
@@ -209,16 +235,18 @@ allocate_data_item (MonoDebugDataItemType type, guint32 size)
 
        g_assert (mono_symbol_table);
 
-       if (size + 12 < DATA_TABLE_CHUNK_SIZE)
+       size = ALIGN_TO (size, sizeof (gpointer));
+
+       if (size + 16 < DATA_TABLE_CHUNK_SIZE)
                chunk_size = DATA_TABLE_CHUNK_SIZE;
        else
-               chunk_size = size + 12;
+               chunk_size = size + 16;
 
        /* Initialize things if necessary. */
        if (!mono_symbol_table->current_data_table) {
                mono_symbol_table->current_data_table = g_malloc0 (chunk_size);
                mono_symbol_table->current_data_table_size = chunk_size;
-               mono_symbol_table->current_data_table_offset = 4;
+               mono_symbol_table->current_data_table_offset = sizeof (gpointer);
 
                * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size;
        }
@@ -254,7 +282,7 @@ allocate_data_item (MonoDebugDataItemType type, guint32 size)
        /* .... allocate a new current_data_table. */
        mono_symbol_table->current_data_table = g_malloc0 (chunk_size);
        mono_symbol_table->current_data_table_size = chunk_size;
-       mono_symbol_table->current_data_table_offset = 4;
+       mono_symbol_table->current_data_table_offset = sizeof (gpointer);
        * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size;
 
        goto again;
@@ -338,6 +366,78 @@ write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
        *rptr = ptr;
 }
 
+static MonoDebugWrapperData *
+mono_debug_add_wrapper (MonoMethod *method, MonoDebugMethodJitInfo *jit)
+{
+       MonoMethodHeader *header;
+       MonoDebugWrapperData *wrapper;
+       char buffer [BUFSIZ];
+       guint8 *ptr, *oldptr;
+       guint32 i, size, total_size, max_size;
+       gint32 last_il_offset = 0, last_native_offset = 0;
+
+       if (!in_the_mono_debugger)
+               return NULL;
+
+       mono_debugger_lock ();
+
+       header = ((MonoMethodNormal *) method)->header;
+
+       max_size = 28 * jit->num_line_numbers;
+       if (max_size > BUFSIZ)
+               ptr = oldptr = g_malloc (max_size);
+       else
+               ptr = oldptr = buffer;
+
+       write_leb128 (jit->prologue_end, ptr, &ptr);
+       write_leb128 (jit->epilogue_begin, ptr, &ptr);
+       write_leb128 (jit->num_line_numbers, ptr, &ptr);
+       for (i = 0; i < jit->num_line_numbers; i++) {
+               MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
+
+               write_sleb128 (lne->il_offset - last_il_offset, ptr, &ptr);
+               write_sleb128 (lne->native_offset - last_native_offset, ptr, &ptr);
+
+               last_il_offset = lne->il_offset;
+               last_native_offset = lne->native_offset;
+       }
+
+       write_leb128 (method->wrapper_type, ptr, &ptr);
+
+       size = ptr - oldptr;
+       g_assert (size < max_size);
+       total_size = size + sizeof (MonoDebugWrapperData);
+
+       if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
+               // FIXME: Maybe we should print a warning here.
+               //        This should only happen for very big methods, for instance
+               //        with more than 40.000 line numbers and more than 5.000
+               //        local variables.
+               mono_debugger_unlock ();
+               return NULL;
+       }
+
+       wrapper = (MonoDebugWrapperData *) allocate_data_item (MONO_DEBUG_DATA_ITEM_WRAPPER, total_size);
+
+       wrapper->method = method;
+       wrapper->size = total_size;
+       wrapper->code_start = jit->code_start;
+       wrapper->code_size = jit->code_size;
+       wrapper->name = mono_method_full_name (method, TRUE);
+
+       wrapper->cil_code = mono_disasm_code (
+               NULL, method, header->code, header->code + header->code_size);
+
+       memcpy (&wrapper->data, oldptr, size);
+
+       if (max_size > BUFSIZ)
+               g_free (oldptr);
+
+       mono_debugger_unlock ();
+
+       return wrapper;
+}
+
 /*
  * This is called by the JIT to tell the debugging code about a newly
  * compiled method.
@@ -354,19 +454,23 @@ mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDoma
        MonoDebugMethodInfo *minfo;
        MethodHashEntry *hash;
 
+       if (method->is_inflated)
+               return NULL;
+
        if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
            (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
            (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
-           (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
-               return NULL;
-
-       if (method->wrapper_type != MONO_WRAPPER_NONE)
+           (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
+           (method->wrapper_type != MONO_WRAPPER_NONE)) {
+               mono_debug_add_wrapper (method, jit);
                return NULL;
+       }
 
        mono_debugger_lock ();
 
        handle = _mono_debug_get_image (method->klass->image);
        if (!handle || !handle->symfile || !handle->symfile->offset_table) {
+               mono_debug_add_wrapper (method, jit);
                mono_debugger_unlock ();
                return NULL;
        }
@@ -377,7 +481,7 @@ mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDoma
                return NULL;
        }
 
-       max_size = 24 + 8 * jit->num_line_numbers + 20 * (1 + jit->num_params + jit->num_locals);
+       max_size = 24 + 8 * jit->num_line_numbers + 16 * minfo->num_lexical_blocks + 20 * (1 + jit->num_params + jit->num_locals);
        if (max_size > BUFSIZ)
                ptr = oldptr = g_malloc (max_size);
        else
@@ -397,6 +501,37 @@ mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDoma
                last_native_offset = lne->native_offset;
        }
 
+       jit->num_lexical_blocks = minfo->num_lexical_blocks;
+       jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
+       for (i = 0; i < jit->num_lexical_blocks; i ++) {
+               MonoDebugLexicalBlockEntry *jit_lbe = &jit->lexical_blocks [i];
+               MonoSymbolFileLexicalBlockEntry *minfo_lbe = &minfo->lexical_blocks [i];
+               jit_lbe->il_start_offset = minfo_lbe->_start_offset;
+               jit_lbe->native_start_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_start_offset);
+
+               jit_lbe->il_end_offset = minfo_lbe->_end_offset;
+               jit_lbe->native_end_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_end_offset);
+       }
+
+       last_il_offset = 0;
+       last_native_offset = 0;
+       write_leb128 (jit->num_lexical_blocks, ptr, &ptr);
+       for (i = 0; i < jit->num_lexical_blocks; i++) {
+               MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
+
+               write_sleb128 (lbe->il_start_offset - last_il_offset, ptr, &ptr);
+               write_sleb128 (lbe->native_start_offset - last_native_offset, ptr, &ptr);
+
+               last_il_offset = lbe->il_start_offset;
+               last_native_offset = lbe->native_start_offset;
+
+               write_sleb128 (lbe->il_end_offset - last_il_offset, ptr, &ptr);
+               write_sleb128 (lbe->native_end_offset - last_native_offset, ptr, &ptr);
+
+               last_il_offset = lbe->il_end_offset;
+               last_native_offset = lbe->native_end_offset;
+       }
+
        *ptr++ = jit->this_var ? 1 : 0;
        if (jit->this_var)
                write_variable (jit->this_var, ptr, &ptr);
@@ -418,6 +553,7 @@ mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDoma
                //        This should only happen for very big methods, for instance
                //        with more than 40.000 line numbers and more than 5.000
                //        local variables.
+               mono_debugger_unlock ();
                return NULL;
        }
 
@@ -443,9 +579,6 @@ mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDoma
 
        g_hash_table_insert (method_hash, hash, address);
 
-       if (in_the_mono_debugger)
-               mono_debugger_add_method (jit);
-
        mono_debugger_unlock ();
 
        return address;
@@ -511,7 +644,10 @@ mono_debug_read_method (MonoDebugMethodAddress *address)
        guint32 i, il_offset = 0, native_offset = 0;
        guint8 *ptr;
 
-       jit = g_new0 (MonoDebugMethodJitInfo, 1);
+       if (address->jit)
+               return address->jit;
+
+       jit = address->jit = g_new0 (MonoDebugMethodJitInfo, 1);
        jit->code_start = address->code_start;
        jit->code_size = address->code_size;
        jit->wrapper_addr = address->wrapper_addr;
@@ -533,6 +669,26 @@ mono_debug_read_method (MonoDebugMethodAddress *address)
                lne->native_offset = native_offset;
        }
 
+       il_offset = 0;
+       native_offset = 0;
+       jit->num_lexical_blocks = read_leb128 (ptr, &ptr);
+       jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
+       for (i = 0; i < jit->num_lexical_blocks; i ++) {
+               MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
+
+               il_offset += read_sleb128 (ptr, &ptr);
+               native_offset += read_sleb128 (ptr, &ptr);
+
+               lbe->il_start_offset = il_offset;
+               lbe->native_start_offset = native_offset;
+
+               il_offset += read_sleb128 (ptr, &ptr);
+               native_offset += read_sleb128 (ptr, &ptr);
+
+               lbe->il_end_offset = il_offset;
+               lbe->native_end_offset = native_offset;
+       }
+
        if (*ptr++) {
                jit->this_var = g_new0 (MonoDebugVarInfo, 1);
                read_variable (jit->this_var, ptr, &ptr);
@@ -551,6 +707,19 @@ mono_debug_read_method (MonoDebugMethodAddress *address)
        return jit;
 }
 
+void
+mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
+{
+       if (jit->address)
+               jit->address->jit = NULL;
+
+       g_free (jit->line_numbers);
+       g_free (jit->this_var);
+       g_free (jit->params);
+       g_free (jit->locals);
+       g_free (jit);
+}
+
 /*
  * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
  * a new class is initialized.
@@ -563,18 +732,6 @@ mono_debug_start_add_type (MonoClass *klass)
        handle = _mono_debug_get_image (klass->image);
        if (!handle)
                return;
-
-       if (in_the_mono_debugger)
-               mono_debugger_add_type (handle, klass);
-}
-
-static guint32
-get_token (MonoClass *klass)
-{
-       while (klass->rank)
-               klass = klass->element_class;
-
-       return klass->type_token;
 }
 
 static void
@@ -584,14 +741,14 @@ mono_debug_add_type (MonoClass *klass)
        MonoDebugClassEntry *entry;
        char buffer [BUFSIZ];
        guint8 *ptr, *oldptr;
-       guint32 token, size, total_size, max_size;
+       guint32 size, total_size, max_size;
        int base_offset = 0;
 
        handle = _mono_debug_get_image (klass->image);
        if (!handle)
                return;
 
-       if (klass->generic_class ||
+       if (klass->generic_class || klass->rank ||
            (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
                return;
 
@@ -601,30 +758,19 @@ mono_debug_add_type (MonoClass *klass)
        else
                ptr = oldptr = buffer;
 
-       token = get_token (klass);
-       if (!token)
-               return;
-
        if (klass->valuetype)
                base_offset = - (int)(sizeof (MonoObject));
 
-       write_leb128 (token, ptr, &ptr);
-       write_leb128 (klass->rank, ptr, &ptr);
+       write_leb128 (klass->type_token, ptr, &ptr);
        write_leb128 (klass->instance_size + base_offset, ptr, &ptr);
-       * ((gpointer *) ptr) = klass;
+       WRITE_UNALIGNED (gpointer, ptr, klass);
        ptr += sizeof (gpointer);
 
        size = ptr - oldptr;
        g_assert (size < max_size);
        total_size = size + sizeof (MonoDebugClassEntry);
 
-       if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
-               // FIXME: Maybe we should print a warning here.
-               //        This should only happen for very big methods, for instance
-               //        with more than 40.000 line numbers and more than 5.000
-               //        local variables.
-               return;
-       }
+       g_assert (total_size + 9 < DATA_TABLE_CHUNK_SIZE);
 
        entry = (MonoDebugClassEntry *) allocate_data_item (MONO_DEBUG_DATA_ITEM_CLASS, total_size);
 
@@ -700,10 +846,13 @@ mono_debug_source_location_from_address (MonoMethod *method, guint32 address, gu
        char *res = NULL;
        gint32 offset;
 
-       mono_loader_lock ();
+       if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
+               return NULL;
+
+       mono_debugger_lock ();
        minfo = _mono_debug_lookup_method (method);
        if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
-               mono_loader_unlock ();
+               mono_debugger_unlock ();
                return NULL;
        }
 
@@ -712,7 +861,7 @@ mono_debug_source_location_from_address (MonoMethod *method, guint32 address, gu
        if (offset >= 0)
                res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
 
-       mono_loader_unlock ();
+       mono_debugger_unlock ();
        return res;
 }
 
@@ -737,15 +886,18 @@ mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, g
        char *res;
        MonoDebugMethodInfo *minfo;
 
-       mono_loader_lock ();
+       if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
+               return NULL;
+
+       mono_debugger_lock ();
        minfo = _mono_debug_lookup_method (method);
        if (!minfo || !minfo->handle || !minfo->handle->symfile) {
-               mono_loader_unlock ();
+               mono_debugger_unlock ();
                return NULL;
        }
 
        res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
-       mono_loader_unlock ();
+       mono_debugger_unlock ();
        return res;
 }
 
@@ -764,19 +916,19 @@ mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomai
        MonoDebugMethodInfo *minfo;
        gint32 res;
 
-       if (address < 0)
+       if ((address < 0) || (mono_debug_format == MONO_DEBUG_FORMAT_NONE))
                return -1;
 
-       mono_loader_lock ();
+       mono_debugger_lock ();
        minfo = _mono_debug_lookup_method (method);
        if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
            !minfo->handle->symfile->offset_table) {
-               mono_loader_unlock ();
+               mono_debugger_unlock ();
                return -1;
        }
 
        res = il_offset_from_address (minfo, domain, address);
-       mono_loader_unlock ();
+       mono_debugger_unlock ();
        return res;
 }
 
@@ -796,24 +948,24 @@ mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDom
        MonoDebugMethodJitInfo *jit;
        gint32 res;
 
-       if (il_offset < 0)
+       if ((il_offset < 0) || (mono_debug_format == MONO_DEBUG_FORMAT_NONE))
                return -1;
 
-       mono_loader_lock ();
+       mono_debugger_lock ();
        minfo = _mono_debug_lookup_method (method);
        if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
            !minfo->handle->symfile->offset_table) {
-               mono_loader_unlock ();
+               mono_debugger_unlock ();
                return -1;
        }
 
        jit = find_method (minfo, domain);
        if (!jit) {
-               mono_loader_unlock ();
+               mono_debugger_unlock ();
                return -1;
        }
 
        res = _mono_debug_address_from_il_offset (jit, il_offset);
-       mono_loader_unlock ();
+       mono_debugger_unlock ();
        return res;
 }