+/*
+ * mono-debug.c:
+ *
+ * Author:
+ * Mono Project (http://www.mono-project.com)
+ *
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ */
+
#include <config.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/mono-endian.h>
#include <string.h>
-#define SYMFILE_TABLE_CHUNK_SIZE 16
-#define DATA_TABLE_PTR_CHUNK_SIZE 256
-#define DATA_TABLE_CHUNK_SIZE 32768
+#define DATA_TABLE_CHUNK_SIZE 16384
#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
}
#define WRITE_UNALIGNED(type, addr, val) \
memcpy(addr, &val, sizeof(type))
+#define READ_UNALIGNED(type, addr, val) \
+ memcpy(&val, addr, sizeof(type))
#else
#define RETURN_UNALIGNED(type, addr) \
return *(type*)(p + offset);
#define WRITE_UNALIGNED(type, addr, val) \
(*(type *)(addr) = (val))
+#define READ_UNALIGNED(type, addr, val) \
+ val = (*(type *)(addr))
#endif
+typedef enum {
+ MONO_DEBUG_DATA_ITEM_UNKNOWN = 0,
+ MONO_DEBUG_DATA_ITEM_CLASS,
+ MONO_DEBUG_DATA_ITEM_METHOD,
+ MONO_DEBUG_DATA_ITEM_DELEGATE_TRAMPOLINE
+} MonoDebugDataItemType;
+
+typedef struct _MonoDebugDataChunk MonoDebugDataChunk;
+
+struct _MonoDebugDataChunk {
+ guint32 total_size;
+ guint32 allocated_size;
+ guint32 current_offset;
+ guint32 dummy;
+ MonoDebugDataChunk *next;
+ guint8 data [MONO_ZERO_LEN_ARRAY];
+};
+
+struct _MonoDebugDataTable {
+ gint32 domain;
+ gint32 _dummy; /* alignment for next field. */
+ MonoDebugDataChunk *first_chunk;
+ MonoDebugDataChunk *current_chunk;
+ GHashTable *method_hash;
+ GHashTable *method_address_hash;
+};
+
+typedef struct {
+ const gchar *method_name;
+ const gchar *cil_code;
+ guint32 wrapper_type;
+} MonoDebugWrapperData;
+
+typedef struct {
+ guint32 size;
+ guint32 symfile_id;
+ guint32 domain_id;
+ guint32 method_id;
+ MonoDebugWrapperData *wrapper_data;
+ MonoMethod *method;
+ GSList *address_list;
+} MonoDebugMethodHeader;
+
+struct _MonoDebugMethodAddress {
+ MonoDebugMethodHeader header;
+ const guint8 *code_start;
+ const guint8 *wrapper_addr;
+ guint32 code_size;
+ guint8 data [MONO_ZERO_LEN_ARRAY];
+};
+
+struct _MonoDebugClassEntry {
+ guint32 size;
+ guint8 data [MONO_ZERO_LEN_ARRAY];
+};
+
+typedef struct {
+ gpointer code;
+ guint32 size;
+} MonoDebugDelegateTrampolineEntry;
+
MonoSymbolTable *mono_symbol_table = NULL;
MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
+gint32 mono_debug_debugger_version = 5;
+gint32 _mono_debug_using_mono_debugger = 0;
-static gboolean in_the_mono_debugger = FALSE;
static gboolean mono_debug_initialized = FALSE;
GHashTable *mono_debug_handles = NULL;
-static GHashTable *method_hash = NULL;
+static GHashTable *data_table_hash = NULL;
+static int next_symbol_file_id = 0;
-static MonoDebugHandle *mono_debug_open_image (MonoImage *image);
-static void mono_debug_close_image (MonoDebugHandle *debug);
+static MonoDebugHandle *mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size);
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);
+void _mono_debug_init_corlib (MonoDomain *domain);
+
extern void (*mono_debugger_class_init_func) (MonoClass *klass);
-extern void (*mono_debugger_start_class_init_func) (MonoClass *klass);
+extern void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass);
-typedef struct {
- guint32 symfile_id;
- guint32 domain_id;
- guint32 method_id;
-} MethodHashEntry;
+static MonoDebugDataTable *
+create_data_table (MonoDomain *domain)
+{
+ MonoDebugDataTable *table;
+ MonoDebugDataChunk *chunk;
+
+ table = g_new0 (MonoDebugDataTable, 1);
+ table->domain = domain ? mono_domain_get_id (domain) : -1;
+
+ table->method_address_hash = g_hash_table_new (NULL, NULL);
+ table->method_hash = g_hash_table_new (NULL, NULL);
+
+ chunk = g_malloc0 (sizeof (MonoDebugDataChunk) + DATA_TABLE_CHUNK_SIZE);
+ chunk->total_size = DATA_TABLE_CHUNK_SIZE;
+
+ table->first_chunk = table->current_chunk = chunk;
+
+ if (domain) {
+ mono_debug_list_add (&mono_symbol_table->data_tables, table);
+ g_hash_table_insert (data_table_hash, domain, table);
+ }
+
+ return table;
+}
+
+static void
+free_header_data (gpointer key, gpointer value, gpointer user_data)
+{
+ MonoDebugMethodHeader *header = (MonoDebugMethodHeader*)value;
+
+ if (header->wrapper_data) {
+ g_free ((gpointer)header->wrapper_data->method_name);
+ g_free ((gpointer)header->wrapper_data->cil_code);
+ g_slist_free (header->address_list);
+ g_free (header->wrapper_data);
+ }
+}
-static guint
-method_hash_hash (gconstpointer data)
+static void
+free_data_table (MonoDebugDataTable *table)
{
- const MethodHashEntry *entry = (const MethodHashEntry *) data;
- return entry->symfile_id | (entry->domain_id << 16);
+ MonoDebugDataChunk *chunk, *next_chunk;
+
+ g_hash_table_foreach (table->method_hash, free_header_data, NULL);
+ g_hash_table_destroy (table->method_hash);
+ g_hash_table_destroy (table->method_address_hash);
+
+ table->method_hash = NULL;
+ table->method_address_hash = NULL;
+
+ chunk = table->first_chunk;
+ while (chunk) {
+ next_chunk = chunk->next;
+ g_free (chunk);
+ chunk = next_chunk;
+ }
+
+ table->first_chunk = table->current_chunk = NULL;
+ mono_debug_list_remove (&mono_symbol_table->data_tables, table);
+ g_free (table);
}
-static gint
-method_hash_equal (gconstpointer ka, gconstpointer kb)
+static MonoDebugDataTable *
+lookup_data_table (MonoDomain *domain)
{
- const MethodHashEntry *a = (const MethodHashEntry *) ka;
- const MethodHashEntry *b = (const MethodHashEntry *) kb;
+ MonoDebugDataTable *table;
- if ((a->symfile_id != b->symfile_id) || (a->method_id != b->method_id) || (a->domain_id != b->domain_id))
- return 0;
- return 1;
+ table = g_hash_table_lookup (data_table_hash, domain);
+ g_assert (table);
+ return table;
+}
+
+static void
+free_debug_handle (MonoDebugHandle *handle)
+{
+ if (handle->symfile)
+ mono_debug_close_mono_symbol_file (handle->symfile);
+ /* decrease the refcount added with mono_image_addref () */
+ free_data_table (handle->type_table);
+ mono_image_close (handle->image);
+ g_free (handle->image_file);
+ g_free (handle);
}
/*
{
g_assert (!mono_debug_initialized);
+ if (_mono_debug_using_mono_debugger)
+ format = MONO_DEBUG_FORMAT_DEBUGGER;
+
mono_debug_initialized = TRUE;
mono_debug_format = format;
- in_the_mono_debugger = format == MONO_DEBUG_FORMAT_DEBUGGER;
- mono_debugger_initialize (in_the_mono_debugger);
+ mono_debugger_initialize (_mono_debug_using_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->version = MONO_DEBUGGER_MAJOR_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);
+ (NULL, NULL, NULL, (GDestroyNotify) free_debug_handle);
+
+ data_table_hash = g_hash_table_new_full (
+ NULL, NULL, NULL, (GDestroyNotify) free_data_table);
- mono_debugger_start_class_init_func = mono_debug_start_add_type;
mono_debugger_class_init_func = mono_debug_add_type;
+ mono_debugger_class_loaded_methods_func = mono_debugger_class_initialized;
mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
- if (!in_the_mono_debugger)
- mono_debugger_unlock ();
+ mono_symbol_table->global_data_table = create_data_table (NULL);
+
+ mono_debugger_unlock ();
}
+/*
+ * INTERNAL USE ONLY !
+ */
void
-mono_debug_init_1 (MonoDomain *domain)
+_mono_debug_init_corlib (MonoDomain *domain)
{
- MonoDebugHandle *handle = mono_debug_open_image (mono_get_corlib ());
+ if (!mono_debug_initialized)
+ return;
- mono_symbol_table->corlib = handle;
+ mono_symbol_table->corlib = mono_debug_open_image (mono_defaults.corlib, NULL, 0);
+ mono_debugger_event (MONO_DEBUGGER_EVENT_INITIALIZE_CORLIB,
+ (guint64) (gsize) mono_symbol_table->corlib, 0);
}
-/*
- * Initialize debugging support - part 2.
- *
- * This method must be called after loading the application's main assembly.
- */
void
-mono_debug_init_2 (MonoAssembly *assembly)
+mono_debug_open_image_from_memory (MonoImage *image, const guint8 *raw_contents, int size)
{
- mono_debug_open_image (mono_assembly_get_image (assembly));
+ mono_debug_open_image (image, raw_contents, size);
}
+
gboolean
mono_debug_using_mono_debugger (void)
{
- return in_the_mono_debugger;
+ return _mono_debug_using_mono_debugger;
}
void
mono_debug_cleanup (void)
{
- mono_debugger_cleanup ();
-
if (mono_debug_handles)
g_hash_table_destroy (mono_debug_handles);
mono_debug_handles = NULL;
+
+ if (data_table_hash) {
+ g_hash_table_destroy (data_table_hash);
+ data_table_hash = NULL;
+ }
+
+ g_free (mono_symbol_table);
+ mono_symbol_table = NULL;
+}
+
+void
+mono_debug_domain_create (MonoDomain *domain)
+{
+ MonoDebugDataTable *table;
+
+ if (!mono_debug_initialized)
+ return;
+
+ mono_debugger_lock ();
+
+ table = create_data_table (domain);
+
+ mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_CREATE, (guint64) (gsize) table,
+ mono_domain_get_id (domain));
+
+ mono_debugger_unlock ();
}
+void
+mono_debug_domain_unload (MonoDomain *domain)
+{
+ MonoDebugDataTable *table;
+
+ if (!mono_debug_initialized)
+ return;
+
+ mono_debugger_lock ();
+
+ table = g_hash_table_lookup (data_table_hash, domain);
+ if (!table) {
+ g_warning (G_STRLOC ": unloading unknown domain %p / %d",
+ domain, mono_domain_get_id (domain));
+ mono_debugger_unlock ();
+ return;
+ }
+
+ mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_UNLOAD, (guint64) (gsize) table,
+ mono_domain_get_id (domain));
+
+ g_hash_table_remove (data_table_hash, domain);
+
+ mono_debugger_unlock ();
+}
+
+/*
+ * LOCKING: Assumes the debug lock is held.
+ */
static MonoDebugHandle *
_mono_debug_get_image (MonoImage *image)
{
return g_hash_table_lookup (mono_debug_handles, image);
}
-static MonoDebugHandle *
-allocate_debug_handle (MonoSymbolTable *table)
+void
+mono_debug_close_image (MonoImage *image)
{
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);
+ if (!mono_debug_initialized)
+ return;
+
+ mono_debugger_lock ();
- table->symbol_files = g_realloc (table->symbol_files, size);
+ handle = _mono_debug_get_image (image);
+ if (!handle) {
+ mono_debugger_unlock ();
+ return;
}
- handle = g_new0 (MonoDebugHandle, 1);
- handle->index = table->num_symbol_files;
- table->symbol_files [table->num_symbol_files++] = handle;
- return handle;
+ mono_debugger_event (MONO_DEBUGGER_EVENT_UNLOAD_MODULE, (guint64) (gsize) handle,
+ handle->index);
+
+ mono_debug_list_remove (&mono_symbol_table->symbol_files, handle);
+ g_hash_table_remove (mono_debug_handles, image);
+
+ mono_debugger_unlock ();
}
static MonoDebugHandle *
-mono_debug_open_image (MonoImage *image)
+mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
{
MonoDebugHandle *handle;
if (mono_image_is_dynamic (image))
return NULL;
+ mono_debugger_lock ();
+
handle = _mono_debug_get_image (image);
- if (handle != NULL)
+ if (handle != NULL) {
+ mono_debugger_unlock ();
return handle;
+ }
- handle = allocate_debug_handle (mono_symbol_table);
+ handle = g_new0 (MonoDebugHandle, 1);
+ handle->index = ++next_symbol_file_id;
handle->image = image;
mono_image_addref (image);
handle->image_file = g_strdup (mono_image_get_filename (image));
+ handle->type_table = create_data_table (NULL);
+
+ handle->symfile = mono_debug_open_mono_symbols (
+ handle, raw_contents, size, _mono_debug_using_mono_debugger);
+
+ mono_debug_list_add (&mono_symbol_table->symbol_files, handle);
+
g_hash_table_insert (mono_debug_handles, image, handle);
- handle->symfile = mono_debug_open_mono_symbol_file (handle, in_the_mono_debugger);
- if (in_the_mono_debugger)
- mono_debugger_add_symbol_file (handle);
+ if (mono_symbol_table->corlib)
+ mono_debugger_event (MONO_DEBUGGER_EVENT_LOAD_MODULE,
+ (guint64) (gsize) handle, 0);
- return handle;
-}
+ mono_debugger_unlock ();
-static void
-mono_debug_close_image (MonoDebugHandle *handle)
-{
- if (handle->symfile)
- mono_debug_close_mono_symbol_file (handle->symfile);
- /* 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);
+ return handle;
}
static void
mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
{
mono_debugger_lock ();
- mono_debug_open_image (mono_assembly_get_image (assembly));
+ mono_debug_open_image (mono_assembly_get_image (assembly), NULL, 0);
mono_debugger_unlock ();
}
-/*
- * 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 guint8 *
-allocate_data_item (MonoDebugDataItemType type, guint32 size)
+allocate_data_item (MonoDebugDataTable *table, MonoDebugDataItemType type, guint32 size)
{
guint32 chunk_size;
guint8 *data;
- g_assert (mono_symbol_table);
-
size = ALIGN_TO (size, sizeof (gpointer));
if (size + 16 < 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);
+ g_assert (table->current_chunk->current_offset == table->current_chunk->allocated_size);
- * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size;
- }
+ if (table->current_chunk->allocated_size + size + 8 >= table->current_chunk->total_size) {
+ MonoDebugDataChunk *new_chunk;
- 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;
- }
+ new_chunk = g_malloc0 (sizeof (MonoDebugDataChunk) + chunk_size);
+ new_chunk->total_size = chunk_size;
- /* 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);
+ table->current_chunk->next = new_chunk;
+ table->current_chunk = new_chunk;
}
- 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);
+ data = &table->current_chunk->data [table->current_chunk->allocated_size];
+ table->current_chunk->allocated_size += size + 8;
- 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;
+ * ((guint32 *) data) = size;
+ data += 4;
+ * ((guint32 *) data) = type;
+ data += 4;
+ return data;
+}
- /* .... 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;
+static void
+write_data_item (MonoDebugDataTable *table, const guint8 *data)
+{
+ MonoDebugDataChunk *current_chunk = table->current_chunk;
+ guint32 size = * ((guint32 *) (data - 8));
- goto again;
+ g_assert (current_chunk->current_offset + size + 8 == current_chunk->allocated_size);
+ current_chunk->current_offset = current_chunk->allocated_size;
}
struct LookupMethodData
write_leb128 (var->size, ptr, &ptr);
write_leb128 (var->begin_scope, ptr, &ptr);
write_leb128 (var->end_scope, ptr, &ptr);
+ WRITE_UNALIGNED (gpointer, ptr, var->type);
+ ptr += sizeof (gpointer);
*rptr = ptr;
}
-static MonoDebugWrapperData *
-mono_debug_add_wrapper (MonoMethod *method, MonoDebugMethodJitInfo *jit)
+MonoDebugMethodAddress *
+mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
{
- MonoMethodHeader *header;
- MonoDebugWrapperData *wrapper;
- char buffer [BUFSIZ];
+ MonoMethod *declaring;
+ MonoDebugDataTable *table;
+ MonoDebugMethodHeader *header;
+ MonoDebugMethodAddress *address;
+ MonoDebugMethodInfo *minfo;
+ MonoDebugHandle *handle;
+ guint8 buffer [BUFSIZ];
guint8 *ptr, *oldptr;
guint32 i, size, total_size, max_size;
- gint32 last_il_offset = 0, last_native_offset = 0;
- const unsigned char* il_code;
- guint32 il_codesize;
-
- if (!in_the_mono_debugger)
- return NULL;
+ gboolean is_wrapper = FALSE;
mono_debugger_lock ();
- header = mono_method_get_header (method);
-
- 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);
-
- il_code = mono_method_header_get_code (header, &il_codesize, NULL);
- wrapper->cil_code = mono_disasm_code (
- NULL, method, il_code, il_code + il_codesize);
-
- memcpy (&wrapper->data, oldptr, size);
+ table = lookup_data_table (domain);
- 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.
- */
-MonoDebugMethodAddress *
-mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
-{
- 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;
- MethodHashEntry *hash;
+ handle = _mono_debug_get_image (method->klass->image);
+ minfo = _mono_debug_lookup_method (method);
- if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
+ if (!minfo || (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->wrapper_type != MONO_WRAPPER_NONE)) {
- mono_debug_add_wrapper (method, jit);
- return NULL;
+ is_wrapper = TRUE;
}
- mono_debugger_lock ();
+ max_size = (5 * 5) + 1 + (10 * jit->num_line_numbers) +
+ (25 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
- 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;
- }
-
- 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
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 = read32 (&(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 = read32 (&(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;
+ write_sleb128 (lne->il_offset, ptr, &ptr);
+ write_sleb128 (lne->native_offset, ptr, &ptr);
}
*ptr++ = jit->this_var ? 1 : 0;
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 (
+ table, MONO_DEBUG_DATA_ITEM_METHOD, total_size);
- address = (MonoDebugMethodAddress *) allocate_data_item (MONO_DEBUG_DATA_ITEM_METHOD, total_size);
+ address->header.size = total_size;
+ address->header.symfile_id = handle ? handle->index : 0;
+ address->header.domain_id = mono_domain_get_id (domain);
+ address->header.method_id = is_wrapper ? 0 : minfo->index;
+ address->header.method = method;
- 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;
+ declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
+ header = g_hash_table_lookup (table->method_hash, declaring);
- g_hash_table_insert (method_hash, hash, address);
+ if (!header) {
+ header = &address->header;
+ g_hash_table_insert (table->method_hash, declaring, header);
- mono_debugger_unlock ();
+ if (is_wrapper) {
+ const unsigned char* il_code;
+ MonoMethodHeader *mheader;
+ MonoDebugWrapperData *wrapper;
+ guint32 il_codesize;
+
+ mheader = mono_method_get_header (declaring);
+ il_code = mono_method_header_get_code (mheader, &il_codesize, NULL);
+
+ header->wrapper_data = wrapper = g_new0 (MonoDebugWrapperData, 1);
+
+ wrapper->wrapper_type = method->wrapper_type;
+ wrapper->method_name = mono_method_full_name (declaring, TRUE);
+ wrapper->cil_code = mono_disasm_code (
+ NULL, declaring, il_code, il_code + il_codesize);
+ }
+ } else {
+ address->header.wrapper_data = header->wrapper_data;
+ header->address_list = g_slist_prepend (header->address_list, address);
+ }
+
+ g_hash_table_insert (table->method_address_hash, method, address);
+
+ write_data_item (table, (guint8 *) address);
+ mono_debugger_unlock ();
return address;
}
+void
+mono_debug_add_delegate_trampoline (gpointer code, int size)
+{
+ MonoDebugDelegateTrampolineEntry *entry;
+
+ if (!mono_debug_initialized)
+ return;
+
+ mono_debugger_lock ();
+
+ entry = (MonoDebugDelegateTrampolineEntry *) allocate_data_item (
+ mono_symbol_table->global_data_table, MONO_DEBUG_DATA_ITEM_DELEGATE_TRAMPOLINE,
+ sizeof (MonoDebugDelegateTrampolineEntry));
+ entry->code = code;
+ entry->size = size;
+
+ write_data_item (mono_symbol_table->global_data_table, (guint8 *) entry);
+
+ mono_debugger_unlock ();
+}
+
static inline guint32
read_leb128 (guint8 *ptr, guint8 **rptr)
{
var->size = read_leb128 (ptr, &ptr);
var->begin_scope = read_leb128 (ptr, &ptr);
var->end_scope = read_leb128 (ptr, &ptr);
+ READ_UNALIGNED (gpointer, ptr, var->type);
+ ptr += sizeof (gpointer);
*rptr = ptr;
}
-MonoDebugMethodJitInfo *
+void
+mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
+{
+ if (!jit)
+ return;
+ g_free (jit->line_numbers);
+ g_free (jit->this_var);
+ g_free (jit->params);
+ g_free (jit->locals);
+ g_free (jit);
+}
+
+static MonoDebugMethodJitInfo *
mono_debug_read_method (MonoDebugMethodAddress *address)
{
MonoDebugMethodJitInfo *jit;
- guint32 i, il_offset = 0, native_offset = 0;
+ guint32 i;
guint8 *ptr;
- if (address->jit)
- return address->jit;
-
- jit = address->jit = g_new0 (MonoDebugMethodJitInfo, 1);
+ jit = g_new0 (MonoDebugMethodJitInfo, 1);
jit->code_start = address->code_start;
jit->code_size = address->code_size;
jit->wrapper_addr = address->wrapper_addr;
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;
+ lne->il_offset = read_sleb128 (ptr, &ptr);
+ lne->native_offset = read_sleb128 (ptr, &ptr);
}
if (*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 void
mono_debug_add_type (MonoClass *klass)
{
MonoDebugHandle *handle;
MonoDebugClassEntry *entry;
- char buffer [BUFSIZ];
+ guint8 buffer [BUFSIZ];
guint8 *ptr, *oldptr;
guint32 size, total_size, max_size;
int base_offset = 0;
- handle = _mono_debug_get_image (klass->image);
- if (!handle)
- return;
-
if (klass->generic_class || klass->rank ||
(klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
return;
+ mono_debugger_lock ();
+
+ handle = _mono_debug_get_image (klass->image);
+ if (!handle) {
+ mono_debugger_unlock ();
+ return;
+ }
+
max_size = 12 + sizeof (gpointer);
if (max_size > BUFSIZ)
ptr = oldptr = g_malloc (max_size);
g_assert (total_size + 9 < DATA_TABLE_CHUNK_SIZE);
- entry = (MonoDebugClassEntry *) allocate_data_item (MONO_DEBUG_DATA_ITEM_CLASS, total_size);
+ entry = (MonoDebugClassEntry *) allocate_data_item (
+ handle->type_table, MONO_DEBUG_DATA_ITEM_CLASS, total_size);
entry->size = total_size;
- entry->symfile_id = handle->index;
memcpy (&entry->data, oldptr, size);
+ write_data_item (handle->type_table, (guint8 *) entry);
+
if (max_size > BUFSIZ)
g_free (oldptr);
- mono_debugger_start_add_type (handle, klass);
+ mono_debugger_unlock ();
}
static MonoDebugMethodJitInfo *
-find_method (MonoDebugMethodInfo *minfo, MonoDomain *domain)
+find_method (MonoMethod *method, MonoDomain *domain)
{
- MethodHashEntry lookup;
+ MonoDebugDataTable *table;
MonoDebugMethodAddress *address;
- lookup.symfile_id = minfo->handle->index;
- lookup.domain_id = mono_domain_get_id (domain);
- lookup.method_id = minfo->index;
+ table = lookup_data_table (domain);
+ address = g_hash_table_lookup (table->method_address_hash, method);
- address = g_hash_table_lookup (method_hash, &lookup);
if (!address)
return NULL;
return mono_debug_read_method (address);
}
+MonoDebugMethodJitInfo *
+mono_debug_find_method (MonoMethod *method, MonoDomain *domain)
+{
+ MonoDebugMethodJitInfo *res;
+
+ if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
+ return NULL;
+
+ mono_debugger_lock ();
+ res = find_method (method, domain);
+ mono_debugger_unlock ();
+ return res;
+}
+
+struct LookupMethodAddressData
+{
+ MonoMethod *method;
+ MonoDebugMethodHeader *result;
+};
+
+static void
+lookup_method_address_func (gpointer key, gpointer value, gpointer user_data)
+{
+ MonoDebugDataTable *table = (MonoDebugDataTable *) value;
+ struct LookupMethodAddressData *data = (struct LookupMethodAddressData *) user_data;
+ MonoDebugMethodHeader *header;
+
+ header = g_hash_table_lookup (table->method_hash, data->method);
+ if (header)
+ data->result = header;
+}
+
+MonoDebugMethodAddressList *
+mono_debug_lookup_method_addresses (MonoMethod *method)
+{
+ MonoDebugMethodAddressList *info;
+ MonoDebugMethodHeader *header = NULL;
+ struct LookupMethodAddressData data;
+ MonoMethod *declaring;
+ int count, size;
+ GSList *list;
+ guint8 *ptr;
+
+ g_assert ((mono_debug_debugger_version == 4) || (mono_debug_debugger_version == 5));
+
+ mono_debugger_lock ();
+
+ declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
+
+ data.method = declaring;
+ data.result = NULL;
+
+ g_hash_table_foreach (data_table_hash, lookup_method_address_func, &data);
+ header = data.result;
+
+ if (!header) {
+ mono_debugger_unlock ();
+ return NULL;
+ }
+
+ count = g_slist_length (header->address_list) + 1;
+ size = sizeof (MonoDebugMethodAddressList) + count * sizeof (gpointer);
+
+ info = g_malloc0 (size);
+ info->size = size;
+ info->count = count;
+
+ ptr = info->data;
+
+ WRITE_UNALIGNED (gpointer, ptr, header);
+ ptr += sizeof (gpointer);
+
+ for (list = header->address_list; list; list = list->next) {
+ WRITE_UNALIGNED (gpointer, ptr, list->data);
+ ptr += sizeof (gpointer);
+ }
+
+ mono_debugger_unlock ();
+ return info;
+}
+
static gint32
-il_offset_from_address (MonoDebugMethodInfo *minfo, MonoDomain *domain, guint32 native_offset)
+il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
{
MonoDebugMethodJitInfo *jit;
int i;
- jit = find_method (minfo, domain);
+ jit = find_method (method, domain);
if (!jit || !jit->line_numbers)
- return -1;
+ goto cleanup_and_fail;
for (i = jit->num_line_numbers - 1; i >= 0; i--) {
MonoDebugLineNumberEntry lne = jit->line_numbers [i];
- if (lne.native_offset <= native_offset)
+ if (lne.native_offset <= native_offset) {
+ mono_debug_free_method_jit_info (jit);
return lne.il_offset;
+ }
}
+cleanup_and_fail:
+ mono_debug_free_method_jit_info (jit);
return -1;
}
return NULL;
}
- offset = il_offset_from_address (minfo, domain, address);
+ offset = il_offset_from_address (method, domain, address);
if (offset < 0) {
mono_debugger_unlock ();
return NULL;
return location;
}
+/*
+ * mono_debug_lookup_locals:
+ *
+ * Return information about the local variables of MINFO.
+ * NAMES and INDEXES are set to g_malloc-ed arrays containing the local names and
+ * their IL indexes.
+ * Returns: the number of elements placed into the arrays, or -1 if there is no
+ * local variable info.
+ */
+int
+mono_debug_lookup_locals (MonoMethod *method, char ***names, int **indexes)
+{
+ MonoDebugMethodInfo *minfo;
+ int res;
+
+ *names = NULL;
+ *indexes = NULL;
+
+ if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
+ return -1;
+
+ 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 -1;
+ }
+
+ res = mono_debug_symfile_lookup_locals (minfo, names, indexes);
+ mono_debugger_unlock ();
+
+ return res;
+}
+
/**
* mono_debug_free_source_location:
* @location: A `MonoDebugSourceLocation'.
mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain)
{
MonoDebugSourceLocation *location;
- gchar *fname, *res;
+ gchar *fname, *ptr, *res;
+ int offset;
fname = mono_method_full_name (method, TRUE);
+ for (ptr = fname; *ptr; ptr++) {
+ if (*ptr == ':') *ptr = '.';
+ }
+
location = mono_debug_lookup_source_location (method, native_offset, domain);
if (!location) {
- res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
+ if (mono_debug_initialized) {
+ mono_debugger_lock ();
+ offset = il_offset_from_address (method, domain, native_offset);
+ mono_debugger_unlock ();
+ } else {
+ offset = -1;
+ }
+
+ if (offset < 0)
+ res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
+ else
+ res = g_strdup_printf ("at %s <IL 0x%05x, 0x%05x>", fname, offset, native_offset);
g_free (fname);
return res;
}
mono_debug_free_source_location (location);
return res;
}
+
+void
+mono_debug_list_add (MonoDebugList **list, gconstpointer data)
+{
+ MonoDebugList *element, **ptr;
+
+ element = g_new0 (MonoDebugList, 1);
+ element->data = data;
+
+ for (ptr = list; *ptr; ptr = &(*ptr)->next)
+ ;
+
+ *ptr = element;
+}
+
+void
+mono_debug_list_remove (MonoDebugList **list, gconstpointer data)
+{
+ MonoDebugList **ptr;
+ MonoDebugList *next;
+
+ for (ptr = list; *ptr; ptr = &(*ptr)->next) {
+ if ((*ptr)->data != data)
+ continue;
+
+ next = (*ptr)->next;
+ g_free ((*ptr));
+ *ptr = next;
+ break;
+ }
+}