X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmono-debug.c;h=f93cdbffbae7c145563612bc495c2452fd21567b;hb=4e4851142302b80c66174d23dffb42a87cb7948c;hp=8cf61e5719d668a249d97867fafb92396d114695;hpb=b90f596a18204b46ee98a0bd4c9ef31ceea10a97;p=mono.git diff --git a/mono/metadata/mono-debug.c b/mono/metadata/mono-debug.c index 8cf61e5719d..f93cdbffbae 100644 --- a/mono/metadata/mono-debug.c +++ b/mono/metadata/mono-debug.c @@ -3,36 +3,78 @@ #include #include #include +#include #include #include #include +#include -struct _MonoDebugHandlePriv -{ - MonoDebuggerSymbolFile *debugger_info; - MonoDebugDomainData *domain_table; -}; +#define SYMFILE_TABLE_CHUNK_SIZE 16 +#define DATA_TABLE_PTR_CHUNK_SIZE 256 +#define DATA_TABLE_CHUNK_SIZE 32768 -struct _MonoDebugDomainDataPriv -{ - GHashTable *wrapper_info; - MonoDebugDomainData *next; -}; +#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; static gboolean in_the_mono_debugger = FALSE; static gboolean mono_debug_initialized = FALSE; GHashTable *mono_debug_handles = NULL; -static MonoDebugHandle *mono_debug_open_image (MonoImage *image); -static void mono_debug_close_image (MonoDebugHandle *debug); +static GHashTable *method_hash = NULL; -static MonoDebugHandle *_mono_debug_get_image (MonoImage *image); -static void mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data); -static void mono_debug_add_type (MonoClass *klass); +static MonoDebugHandle *mono_debug_open_image (MonoImage *image); +static void mono_debug_close_image (MonoDebugHandle *debug); + +static MonoDebugHandle *_mono_debug_get_image (MonoImage *image); +static void mono_debug_add_assembly (MonoAssembly *assembly, + gpointer user_data); +static void mono_debug_start_add_type (MonoClass *klass); +static void mono_debug_add_type (MonoClass *klass); extern void (*mono_debugger_class_init_func) (MonoClass *klass); +extern void (*mono_debugger_start_class_init_func) (MonoClass *klass); + +typedef struct { + guint32 symfile_id; + guint32 domain_id; + guint32 method_id; +} MethodHashEntry; + +static guint +method_hash_hash (gconstpointer data) +{ + const MethodHashEntry *entry = (const MethodHashEntry *) data; + return entry->symfile_id | (entry->domain_id << 16); +} + +static gint +method_hash_equal (gconstpointer ka, gconstpointer kb) +{ + const MethodHashEntry *a = (const MethodHashEntry *) ka; + const MethodHashEntry *b = (const MethodHashEntry *) kb; + + if ((a->symfile_id != b->symfile_id) || (a->method_id != b->method_id) || (a->domain_id != b->domain_id)) + return 0; + return 1; +} /* * Initialize debugging support. @@ -42,30 +84,42 @@ extern void (*mono_debugger_class_init_func) (MonoClass *klass); * callbacks here. */ void -mono_debug_init (MonoDomain *domain, MonoDebugFormat format) +mono_debug_init (MonoDebugFormat format) { - MonoAssembly **ass; - g_assert (!mono_debug_initialized); mono_debug_initialized = TRUE; mono_debug_format = format; in_the_mono_debugger = format == MONO_DEBUG_FORMAT_DEBUGGER; - if (in_the_mono_debugger) - mono_debugger_initialize (domain); + mono_debugger_initialize (in_the_mono_debugger); mono_debugger_lock (); + mono_symbol_table = g_new0 (MonoSymbolTable, 1); + mono_symbol_table->magic = MONO_DEBUGGER_MAGIC; + mono_symbol_table->version = MONO_DEBUGGER_VERSION; + mono_symbol_table->total_size = sizeof (MonoSymbolTable); + mono_debug_handles = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) mono_debug_close_image); + method_hash = g_hash_table_new (method_hash_hash, method_hash_equal); + 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); - mono_debug_open_image (mono_defaults.corlib); - for (ass = mono_defaults.corlib->references; ass && *ass; ass++) - mono_debug_open_image ((*ass)->image); + if (!in_the_mono_debugger) + mono_debugger_unlock (); +} + +void +mono_debug_init_1 (MonoDomain *domain) +{ + MonoDebugHandle *handle = mono_debug_open_image (mono_get_corlib ()); + + if (in_the_mono_debugger) + mono_debugger_add_builtin_types (handle); } /* @@ -76,12 +130,7 @@ mono_debug_init (MonoDomain *domain, MonoDebugFormat format) void mono_debug_init_2 (MonoAssembly *assembly) { - MonoDebugHandle *handle; - - mono_debug_open_image (assembly->image); - - handle = _mono_debug_get_image (mono_defaults.corlib); - g_assert (handle); + mono_debug_open_image (mono_assembly_get_image (assembly)); } void @@ -100,32 +149,49 @@ _mono_debug_get_image (MonoImage *image) return g_hash_table_lookup (mono_debug_handles, image); } +static MonoDebugHandle * +allocate_debug_handle (MonoSymbolTable *table) +{ + MonoDebugHandle *handle; + + if (!table->symbol_files) + table->symbol_files = g_new0 (MonoDebugHandle *, SYMFILE_TABLE_CHUNK_SIZE); + else if (!((table->num_symbol_files + 1) % SYMFILE_TABLE_CHUNK_SIZE)) { + guint32 chunks = (table->num_symbol_files + 1) / SYMFILE_TABLE_CHUNK_SIZE; + guint32 size = sizeof (MonoDebugHandle *) * SYMFILE_TABLE_CHUNK_SIZE * (chunks + 1); + + table->symbol_files = g_realloc (table->symbol_files, size); + } + + handle = g_new0 (MonoDebugHandle, 1); + handle->index = table->num_symbol_files; + table->symbol_files [table->num_symbol_files++] = handle; + return handle; +} + static MonoDebugHandle * mono_debug_open_image (MonoImage *image) { MonoDebugHandle *handle; + if (mono_image_is_dynamic (image)) + return NULL; + handle = _mono_debug_get_image (image); if (handle != NULL) return handle; - handle = g_new0 (MonoDebugHandle, 1); + handle = allocate_debug_handle (mono_symbol_table); + handle->image = image; - handle->image->ref_count++; - handle->image_file = g_strdup (image->name); - handle->_priv = g_new0 (MonoDebugHandlePriv, 1); + mono_image_addref (image); + handle->image_file = g_strdup (mono_image_get_filename (image)); g_hash_table_insert (mono_debug_handles, image, handle); - if (image->assembly->dynamic) - return handle; - handle->symfile = mono_debug_open_mono_symbol_file (handle, in_the_mono_debugger); - if (in_the_mono_debugger) { - handle->_priv->debugger_info = mono_debugger_add_symbol_file (handle); - if (image == mono_defaults.corlib) - mono_debugger_add_builtin_types (handle->_priv->debugger_info); - } + if (in_the_mono_debugger) + mono_debugger_add_symbol_file (handle); return handle; } @@ -135,7 +201,9 @@ mono_debug_close_image (MonoDebugHandle *handle) { if (handle->symfile) mono_debug_close_mono_symbol_file (handle->symfile); - handle->image->ref_count--; + /* decrease the refcount added with mono_image_addref () */ + mono_image_close (handle->image); + g_free (handle->image_file); g_free (handle->_priv); g_free (handle); } @@ -144,25 +212,74 @@ static void mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data) { mono_debugger_lock (); - mono_debug_open_image (assembly->image); + mono_debug_open_image (mono_assembly_get_image (assembly)); mono_debugger_unlock (); } /* - * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time - * a new class is initialized. + * Allocate a new data item of size `size'. + * Returns the global offset which is to be used to reference this data item and + * a pointer (in the `ptr' argument) which is to be used to write it. */ -static void -mono_debug_add_type (MonoClass *klass) +static guint8 * +allocate_data_item (MonoDebugDataItemType type, guint32 size) { - MonoDebugHandle *handle; + guint32 chunk_size; + guint8 *data; - handle = _mono_debug_get_image (klass->image); - if (!handle) - return; + g_assert (mono_symbol_table); - if (handle->_priv->debugger_info) - mono_debugger_add_type (handle->_priv->debugger_info, klass); + size = ALIGN_TO (size, sizeof (gpointer)); + + if (size + 16 < DATA_TABLE_CHUNK_SIZE) + chunk_size = DATA_TABLE_CHUNK_SIZE; + else + 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 = sizeof (gpointer); + + * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size; + } + + again: + /* First let's check whether there's still enough room in the current_data_table. */ + if (mono_symbol_table->current_data_table_offset + size + 8 < mono_symbol_table->current_data_table_size) { + data = ((guint8 *) mono_symbol_table->current_data_table) + mono_symbol_table->current_data_table_offset; + mono_symbol_table->current_data_table_offset += size + 8; + + * ((guint32 *) data) = size; + data += 4; + * ((guint32 *) data) = type; + data += 4; + return data; + } + + /* Add the current_data_table to the data_tables vector and ... */ + if (!mono_symbol_table->data_tables) { + guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE; + mono_symbol_table->data_tables = g_malloc0 (tsize); + } + + if (!((mono_symbol_table->num_data_tables + 1) % DATA_TABLE_PTR_CHUNK_SIZE)) { + guint32 chunks = (mono_symbol_table->num_data_tables + 1) / DATA_TABLE_PTR_CHUNK_SIZE; + guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE * (chunks + 1); + + mono_symbol_table->data_tables = g_realloc (mono_symbol_table->data_tables, tsize); + } + + mono_symbol_table->data_tables [mono_symbol_table->num_data_tables++] = mono_symbol_table->current_data_table; + + /* .... 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 = sizeof (gpointer); + * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size; + + goto again; } struct LookupMethodData @@ -199,127 +316,532 @@ _mono_debug_lookup_method (MonoMethod *method) return data.minfo; } -/* - * This is called by the JIT to tell the debugging code about a newly compiled - * wrapper method. - */ -void -mono_debug_add_wrapper (MonoMethod *method, MonoMethod *wrapper_method, MonoDomain *domain) +static inline void +write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr) { - MonoClass *klass = method->klass; - MonoDebugHandle *handle; - MonoDebugMethodInfo *minfo; - MonoDebugMethodJitInfo *jit; - MonoDebugDomainData *domain_data; + do { + guint8 byte = value & 0x7f; + value >>= 7; + if (value) + byte |= 0x80; + *ptr++ = byte; + } while (value); + + *rptr = ptr; +} - if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) - return; +static inline void +write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr) +{ + gboolean more = 1; - mono_class_init (klass); + while (more) { + guint8 byte = value & 0x7f; + value >>= 7; - handle = _mono_debug_get_image (klass->image); - g_assert (handle); + if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40))) + more = 0; + else + byte |= 0x80; + *ptr++ = byte; + } - minfo = _mono_debug_lookup_method (method); - if (!minfo) - return; + *rptr = ptr; +} - domain_data = mono_debug_get_domain_data (handle, domain); - if (domain_data->jit [minfo->index]) { - // FIXME FIXME FIXME - // This is bug #48591. - return; - } +static void +write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr) +{ + write_leb128 (var->index, ptr, &ptr); + write_sleb128 (var->offset, ptr, &ptr); + write_leb128 (var->size, ptr, &ptr); + write_leb128 (var->begin_scope, ptr, &ptr); + write_leb128 (var->end_scope, ptr, &ptr); + *rptr = ptr; +} - jit = g_hash_table_lookup (domain_data->_priv->wrapper_info, wrapper_method); - g_assert (jit); +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 (); - domain_data->jit [minfo->index] = jit; - jit->wrapper_addr = method->addr; + 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; - if (handle->_priv->debugger_info && (domain == mono_root_domain)) - mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit); + 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. */ -void +MonoDebugMethodAddress * mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain) { - MonoClass *klass = method->klass; - MonoDebugDomainData *domain_data; + MonoDebugMethodAddress *address; + char buffer [BUFSIZ]; + guint8 *ptr, *oldptr; + guint32 i, size, total_size, max_size; + gint32 last_il_offset = 0, last_native_offset = 0; MonoDebugHandle *handle; MonoDebugMethodInfo *minfo; - - mono_class_init (klass); + MethodHashEntry *hash; 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)) + (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_debugger_unlock (); + return NULL; + } + + minfo = _mono_debug_lookup_method (method); + if (!minfo) { + mono_debugger_unlock (); + return NULL; + } + + 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 + 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; + } + + 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); + + write_leb128 (jit->num_params, ptr, &ptr); + for (i = 0; i < jit->num_params; i++) + write_variable (&jit->params [i], ptr, &ptr); + + write_leb128 (jit->num_locals, ptr, &ptr); + for (i = 0; i < jit->num_locals; i++) + write_variable (&jit->locals [i], ptr, &ptr); + + size = ptr - oldptr; + g_assert (size < max_size); + total_size = size + sizeof (MonoDebugMethodAddress); + + 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; + } + + address = (MonoDebugMethodAddress *) allocate_data_item (MONO_DEBUG_DATA_ITEM_METHOD, total_size); + + address->size = total_size; + address->symfile_id = handle->index; + address->domain_id = mono_domain_get_id (domain); + address->method_id = minfo->index; + address->code_start = jit->code_start; + address->code_size = jit->code_size; + address->wrapper_addr = jit->wrapper_addr; + + memcpy (&address->data, oldptr, size); + + if (max_size > BUFSIZ) + g_free (oldptr); + + hash = g_new0 (MethodHashEntry, 1); + hash->symfile_id = address->symfile_id; + hash->domain_id = address->domain_id; + hash->method_id = address->method_id; + + g_hash_table_insert (method_hash, hash, address); + + mono_debugger_unlock (); + + return address; +} + +static inline guint32 +read_leb128 (guint8 *ptr, guint8 **rptr) +{ + guint32 result = 0, shift = 0; + + while (TRUE) { + guint8 byte = *ptr++; + + result |= (byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + break; + shift += 7; + } + + *rptr = ptr; + return result; +} + +static inline gint32 +read_sleb128 (guint8 *ptr, guint8 **rptr) +{ + gint32 result = 0; + guint32 shift = 0; + + while (TRUE) { + guint8 byte = *ptr++; + + result |= (byte & 0x7f) << shift; + shift += 7; + + if (byte & 0x80) + continue; + + if ((shift < 32) && (byte & 0x40)) + result |= - (1 << shift); + break; + } + + *rptr = ptr; + return result; +} + +static void +read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr) +{ + var->index = read_leb128 (ptr, &ptr); + var->offset = read_sleb128 (ptr, &ptr); + var->size = read_leb128 (ptr, &ptr); + var->begin_scope = read_leb128 (ptr, &ptr); + var->end_scope = read_leb128 (ptr, &ptr); + *rptr = ptr; +} + +MonoDebugMethodJitInfo * +mono_debug_read_method (MonoDebugMethodAddress *address) +{ + MonoDebugMethodJitInfo *jit; + guint32 i, il_offset = 0, native_offset = 0; + guint8 *ptr; + + 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; + + ptr = (guint8 *) &address->data; + + jit->prologue_end = read_leb128 (ptr, &ptr); + jit->epilogue_begin = read_leb128 (ptr, &ptr); + + jit->num_line_numbers = read_leb128 (ptr, &ptr); + jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers); + for (i = 0; i < jit->num_line_numbers; i++) { + MonoDebugLineNumberEntry *lne = &jit->line_numbers [i]; + + il_offset += read_sleb128 (ptr, &ptr); + native_offset += read_sleb128 (ptr, &ptr); + + lne->il_offset = il_offset; + 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); + } + + jit->num_params = read_leb128 (ptr, &ptr); + jit->params = g_new0 (MonoDebugVarInfo, jit->num_params); + for (i = 0; i < jit->num_params; i++) + read_variable (&jit->params [i], ptr, &ptr); + + jit->num_locals = read_leb128 (ptr, &ptr); + jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals); + for (i = 0; i < jit->num_locals; i++) + read_variable (&jit->locals [i], ptr, &ptr); + + 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. + */ +static void +mono_debug_start_add_type (MonoClass *klass) +{ + MonoDebugHandle *handle; + + handle = _mono_debug_get_image (klass->image); + if (!handle) return; +} + +static guint32 +get_token (MonoClass *klass) +{ + while (klass->rank) + klass = klass->element_class; + + return klass->type_token; +} + +static void +mono_debug_add_type (MonoClass *klass) +{ + MonoDebugHandle *handle; + MonoDebugClassEntry *entry; + char buffer [BUFSIZ]; + guint8 *ptr, *oldptr; + guint32 token, size, total_size, max_size; + int base_offset = 0; handle = _mono_debug_get_image (klass->image); if (!handle) return; - minfo = _mono_debug_lookup_method (method); - if (!minfo) + if (klass->generic_class || + (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR)) return; - mono_debugger_lock (); + max_size = 12 + sizeof (gpointer); + if (max_size > BUFSIZ) + ptr = oldptr = g_malloc (max_size); + else + ptr = oldptr = buffer; - domain_data = mono_debug_get_domain_data (handle, domain); - if (domain_data->jit [minfo->index]) { - // FIXME FIXME FIXME - // This is bug #48591. - mono_debugger_unlock (); + token = get_token (klass); + if (!token) return; - } - if (method->wrapper_type != MONO_WRAPPER_NONE) { - g_hash_table_insert (domain_data->_priv->wrapper_info, method, jit); - mono_debugger_unlock (); + if (klass->valuetype) + base_offset = - (int)(sizeof (MonoObject)); + + write_leb128 (token, ptr, &ptr); + write_leb128 (klass->rank, ptr, &ptr); + write_leb128 (klass->instance_size + base_offset, ptr, &ptr); + 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; } - domain_data->jit [minfo->index] = jit; + entry = (MonoDebugClassEntry *) allocate_data_item (MONO_DEBUG_DATA_ITEM_CLASS, total_size); - if (handle->_priv->debugger_info && (domain == mono_root_domain)) - mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit); + entry->size = total_size; + entry->symfile_id = handle->index; - mono_debugger_unlock (); + memcpy (&entry->data, oldptr, size); + + if (max_size > BUFSIZ) + g_free (oldptr); + + mono_debugger_start_add_type (handle, klass); +} + +static MonoDebugMethodJitInfo * +find_method (MonoDebugMethodInfo *minfo, MonoDomain *domain) +{ + MethodHashEntry lookup; + MonoDebugMethodAddress *address; + + lookup.symfile_id = minfo->handle->index; + lookup.domain_id = mono_domain_get_id (domain); + lookup.method_id = minfo->index; + + address = g_hash_table_lookup (method_hash, &lookup); + if (!address) + return NULL; + + return mono_debug_read_method (address); } static gint32 -il_offset_from_address (MonoDebugMethodJitInfo *jit, guint32 address) +il_offset_from_address (MonoDebugMethodInfo *minfo, MonoDomain *domain, guint32 native_offset) { + MonoDebugMethodJitInfo *jit; int i; + jit = find_method (minfo, domain); 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.address <= address) - return lne.offset; + if (lne.native_offset <= native_offset) + return lne.il_offset; } return -1; } -/* +/** + * mono_debug_source_location_from_address: + * @method: + * @address: + * @line_number: + * @domain: + * * Used by the exception code to get a source location from a machine address. * - * Returns a textual representation of the specified address which is suitable to be displayed to + * Returns: a textual representation of the specified address which is suitable to be displayed to * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8"). * * If the optional @line_number argument is not NULL, the line number is stored there and just the @@ -330,29 +852,35 @@ gchar * mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number, MonoDomain *domain) { - MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method); - MonoDebugDomainData *domain_data; + MonoDebugMethodInfo *minfo; + char *res = NULL; + gint32 offset; - if (!minfo) + if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) return NULL; - domain_data = mono_debug_get_domain_data (minfo->handle, domain); - if (!domain_data->jit [minfo->index]) + mono_debugger_lock (); + minfo = _mono_debug_lookup_method (method); + if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) { + mono_debugger_unlock (); return NULL; + } - if (minfo->handle) { - gint32 offset = il_offset_from_address (domain_data->jit [minfo->index], address); + offset = il_offset_from_address (minfo, domain, address); - if (offset < 0) - return NULL; - - return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number); - } + if (offset >= 0) + res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number); - return NULL; + mono_debugger_unlock (); + return res; } -/* +/** + * mono_debug_source_location_from_il_offset: + * @method: + * @offset: + * @line_number: + * * Used by the exception code to get a source location from an IL offset. * * Returns a textual representation of the specified address which is suitable to be displayed to @@ -365,76 +893,89 @@ mono_debug_source_location_from_address (MonoMethod *method, guint32 address, gu gchar * mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number) { - MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method); + char *res; + MonoDebugMethodInfo *minfo; - if (!minfo || !minfo->handle) + 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_debugger_unlock (); return NULL; + } - return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number); + res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number); + mono_debugger_unlock (); + return res; } -/* - * Returns the IL offset corresponding to machine address @address which is an offset +/** + * mono_debug_il_offset_from_address: + * @method: + * @address: + * @domain: + * + * Returns: the IL offset corresponding to machine address @address which is an offset * relative to the beginning of the method @method. */ gint32 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain) { MonoDebugMethodInfo *minfo; - MonoDebugDomainData *domain_data; + gint32 res; - if (address < 0) + if ((address < 0) || (mono_debug_format == MONO_DEBUG_FORMAT_NONE)) return -1; + mono_debugger_lock (); minfo = _mono_debug_lookup_method (method); - if (!minfo || !minfo->il_offsets) + if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile || + !minfo->handle->symfile->offset_table) { + mono_debugger_unlock (); return -1; + } - domain_data = mono_debug_get_domain_data (minfo->handle, domain); - - return il_offset_from_address (domain_data->jit [minfo->index], address); + res = il_offset_from_address (minfo, domain, address); + mono_debugger_unlock (); + return res; } -/* - * Returns the machine address corresponding to IL offset @il_offset. +/** + * mono_debug_address_from_il_offset: + * @method: + * @il_offset: + * @domain: + * + * Returns: the machine address corresponding to IL offset @il_offset. * The returned value is an offset relative to the beginning of the method @method. */ gint32 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain) { MonoDebugMethodInfo *minfo; - MonoDebugDomainData *domain_data; + MonoDebugMethodJitInfo *jit; + gint32 res; - if (il_offset < 0) + if ((il_offset < 0) || (mono_debug_format == MONO_DEBUG_FORMAT_NONE)) return -1; + mono_debugger_lock (); minfo = _mono_debug_lookup_method (method); - if (!minfo || !minfo->il_offsets) + if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile || + !minfo->handle->symfile->offset_table) { + mono_debugger_unlock (); return -1; + } - domain_data = mono_debug_get_domain_data (minfo->handle, domain); - - return _mono_debug_address_from_il_offset (domain_data->jit [minfo->index], il_offset); -} - -MonoDebugDomainData * -mono_debug_get_domain_data (MonoDebugHandle *handle, MonoDomain *domain) -{ - MonoDebugDomainData *data; - int domain_id = mono_domain_get_id (domain); - - for (data = handle->_priv->domain_table; data; data = data->_priv->next) - if (data->domain_id == domain_id) - return data; - - data = g_new0 (MonoDebugDomainData, 1); - data->domain_id = domain_id; - data->jit = g_new0 (MonoDebugMethodJitInfo *, read32(&(handle->symfile->offset_table->_method_count)) + 1); - - data->_priv = g_new0 (MonoDebugDomainDataPriv, 1); - data->_priv->next = handle->_priv->domain_table; - data->_priv->wrapper_info = g_hash_table_new (g_direct_hash, g_direct_equal); - handle->_priv->domain_table = data; + jit = find_method (minfo, domain); + if (!jit) { + mono_debugger_unlock (); + return -1; + } - return data; + res = _mono_debug_address_from_il_offset (jit, il_offset); + mono_debugger_unlock (); + return res; }