+/*
+ * 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)
+ * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
+ */
+
#include <config.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/mono-debug-debugger.h>
#include <mono/metadata/mono-endian.h>
+#include <mono/metadata/gc-internal.h>
#include <string.h>
-#define DATA_TABLE_CHUNK_SIZE 16384
+#define DATA_TABLE_CHUNK_SIZE (16384-sizeof (MonoDebugDataChunk))
#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
typedef struct {
const gchar *method_name;
- const gchar *cil_code;
+ const gchar *obsolete_cil_code;
guint32 wrapper_type;
} MonoDebugWrapperData;
MonoSymbolTable *mono_symbol_table = NULL;
MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
-gint32 mono_debug_debugger_version = 3;
+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 *mono_debug_handles = NULL;
static GHashTable *data_table_hash = NULL;
static int next_symbol_file_id = 0;
gpointer user_data);
static void mono_debug_add_type (MonoClass *klass);
+static MonoDebugHandle *open_symfile_from_bundle (MonoImage *image);
+
void _mono_debug_init_corlib (MonoDomain *domain);
extern void (*mono_debugger_class_init_func) (MonoClass *klass);
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);
}
+ g_slist_free (header->address_list);
}
static void
MonoDebugDataTable *table;
table = g_hash_table_lookup (data_table_hash, domain);
- g_assert (table);
+ if (!table) {
+ g_error ("lookup_data_table () failed for %p\n", domain);
+ g_assert (table);
+ }
return table;
}
{
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);
+ /*
+ * This must be called before mono_debugger_initialize(), because the
+ * latter registers GC roots.
+ */
+ mono_gc_base_init ();
+
+ 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
void
mono_debug_open_image_from_memory (MonoImage *image, const guint8 *raw_contents, int size)
{
+ if (!mono_debug_initialized)
+ return;
+
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
data_table_hash = NULL;
}
- g_free (mono_symbol_table);
- mono_symbol_table = NULL;
+ if (mono_symbol_table) {
+ if (mono_symbol_table->global_data_table)
+ free_data_table (mono_symbol_table->global_data_table);
+
+ g_free (mono_symbol_table);
+ mono_symbol_table = NULL;
+ }
}
void
mono_debugger_unlock ();
}
+/*
+ * LOCKING: Assumes the debug lock is held.
+ */
static MonoDebugHandle *
_mono_debug_get_image (MonoImage *image)
{
if (!mono_debug_initialized)
return;
+ mono_debugger_lock ();
+
handle = _mono_debug_get_image (image);
- if (!handle)
+ if (!handle) {
+ mono_debugger_unlock ();
return;
-
- mono_debugger_lock ();
+ }
mono_debugger_event (MONO_DEBUGGER_EVENT_UNLOAD_MODULE, (guint64) (gsize) handle,
handle->index);
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;
-
- mono_debugger_lock ();
+ }
handle = g_new0 (MonoDebugHandle, 1);
handle->index = ++next_symbol_file_id;
handle->type_table = create_data_table (NULL);
- handle->symfile = mono_debug_open_mono_symbols (handle, raw_contents, size, in_the_mono_debugger);
+ 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);
static void
mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
{
+ MonoDebugHandle *handle;
+ MonoImage *image;
+
mono_debugger_lock ();
- mono_debug_open_image (mono_assembly_get_image (assembly), NULL, 0);
+ image = mono_assembly_get_image (assembly);
+ handle = open_symfile_from_bundle (image);
+ if (!handle)
+ mono_debug_open_image (image, NULL, 0);
mono_debugger_unlock ();
}
guint8 buffer [BUFSIZ];
guint8 *ptr, *oldptr;
guint32 i, size, total_size, max_size;
- gint32 last_il_offset = 0, last_native_offset = 0;
gboolean is_wrapper = FALSE;
mono_debugger_lock ();
is_wrapper = TRUE;
}
- jit->num_lexical_blocks = minfo ? minfo->num_lexical_blocks : 0;
-
- max_size = 24 + 8 * jit->num_line_numbers + 16 * jit->num_lexical_blocks +
- (20 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
+ max_size = (5 * 5) + 1 + (10 * jit->num_line_numbers) +
+ (25 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
if (max_size > BUFSIZ)
ptr = oldptr = g_malloc (max_size);
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->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;
for (i = 0; i < jit->num_locals; i++)
write_variable (&jit->locals [i], ptr, &ptr);
+ *ptr++ = jit->gsharedvt_info_var ? 1 : 0;
+ if (jit->gsharedvt_info_var) {
+ write_variable (jit->gsharedvt_info_var, ptr, &ptr);
+ write_variable (jit->gsharedvt_locals_var, ptr, &ptr);
+ }
+
size = ptr - oldptr;
g_assert (size < max_size);
total_size = size + sizeof (MonoDebugMethodAddress);
- address = (MonoDebugMethodAddress *) allocate_data_item (
- table, MONO_DEBUG_DATA_ITEM_METHOD, total_size);
+ if (method->dynamic) {
+ address = g_malloc0 (total_size);
+ } else {
+ address = (MonoDebugMethodAddress *) allocate_data_item (
+ table, MONO_DEBUG_DATA_ITEM_METHOD, total_size);
+ }
address->header.size = total_size;
address->header.symfile_id = handle ? handle->index : 0;
g_hash_table_insert (table->method_hash, declaring, header);
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);
+ wrapper->obsolete_cil_code = "";
}
} else {
address->header.wrapper_data = header->wrapper_data;
g_hash_table_insert (table->method_address_hash, method, address);
- write_data_item (table, (guint8 *) address);
+ if (!method->dynamic)
+ write_data_item (table, (guint8 *) address);
mono_debugger_unlock ();
return address;
}
+void
+mono_debug_remove_method (MonoMethod *method, MonoDomain *domain)
+{
+ MonoMethod *declaring;
+ MonoDebugDataTable *table;
+ MonoDebugMethodHeader *header;
+ MonoDebugMethodAddress *address;
+
+ if (!mono_debug_initialized)
+ return;
+
+ g_assert (method->dynamic);
+
+ mono_debugger_lock ();
+
+ table = lookup_data_table (domain);
+
+ declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
+ g_hash_table_remove (table->method_hash, declaring);
+
+ address = g_hash_table_lookup (table->method_address_hash, method);
+ if (address) {
+ header = &address->header;
+
+ if (header->wrapper_data) {
+ g_free ((char*)header->wrapper_data->method_name);
+ g_free (header->wrapper_data);
+ }
+ g_free (address);
+ }
+
+ g_hash_table_remove (table->method_address_hash, method);
+
+ mono_debugger_unlock ();
+}
+
void
mono_debug_add_delegate_trampoline (gpointer code, int size)
{
*rptr = ptr;
}
+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->gsharedvt_info_var);
+ g_free (jit->gsharedvt_locals_var);
+ 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;
jit = g_new0 (MonoDebugMethodJitInfo, 1);
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++) {
for (i = 0; i < jit->num_locals; i++)
read_variable (&jit->locals [i], ptr, &ptr);
+ if (*ptr++) {
+ jit->gsharedvt_info_var = g_new0 (MonoDebugVarInfo, 1);
+ jit->gsharedvt_locals_var = g_new0 (MonoDebugVarInfo, 1);
+ read_variable (jit->gsharedvt_info_var, ptr, &ptr);
+ read_variable (jit->gsharedvt_locals_var, ptr, &ptr);
+ }
+
return jit;
}
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);
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 ();
GSList *list;
guint8 *ptr;
- g_assert (mono_debug_debugger_version == 3);
+ g_assert ((mono_debug_debugger_version == 4) || (mono_debug_debugger_version == 5));
mono_debugger_lock ();
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;
}
+/**
+ * mono_debug_il_offset_from_address:
+ *
+ * Compute the IL offset corresponding to NATIVE_OFFSET inside the native
+ * code of METHOD in DOMAIN.
+ */
+gint32
+mono_debug_il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
+{
+ gint32 res;
+
+ mono_debugger_lock ();
+
+ res = il_offset_from_address (method, domain, native_offset);
+
+ mono_debugger_unlock ();
+
+ return res;
+}
+
/**
* mono_debug_lookup_source_location:
* @address: Native offset within the @method's machine code.
mono_debugger_lock ();
minfo = _mono_debug_lookup_method (method);
- if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
+ if (!minfo || !minfo->handle || !minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile)) {
mono_debugger_unlock ();
return NULL;
}
return location;
}
+/*
+ * mono_debug_lookup_locals:
+ *
+ * Return information about the local variables of MINFO.
+ * The result should be freed using mono_debug_symfile_free_locals ().
+ */
+MonoDebugLocalsInfo*
+mono_debug_lookup_locals (MonoMethod *method)
+{
+ MonoDebugMethodInfo *minfo;
+ MonoDebugLocalsInfo *res;
+
+ 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_debug_symfile_is_loaded (minfo->handle->symfile)) {
+ mono_debugger_unlock ();
+ return NULL;
+ }
+
+ res = mono_debug_symfile_lookup_locals (minfo);
+ mono_debugger_unlock ();
+
+ return res;
+}
+
/**
* mono_debug_free_source_location:
* @location: A `MonoDebugSourceLocation'.
{
MonoDebugSourceLocation *location;
gchar *fname, *ptr, *res;
+ int offset;
fname = mono_method_full_name (method, TRUE);
for (ptr = fname; *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;
}
break;
}
}
+
+static gboolean is_attached = FALSE;
+
+void
+mono_set_is_debugger_attached (gboolean attached)
+{
+ is_attached = attached;
+}
+
+gboolean
+mono_is_debugger_attached (void)
+{
+ return is_attached;
+}
+
+/*
+ * Bundles
+ */
+
+typedef struct _BundledSymfile BundledSymfile;
+
+struct _BundledSymfile {
+ BundledSymfile *next;
+ const char *aname;
+ const mono_byte *raw_contents;
+ int size;
+};
+
+static BundledSymfile *bundled_symfiles = NULL;
+
+void
+mono_register_symfile_for_assembly (const char *assembly_name, const mono_byte *raw_contents, int size)
+{
+ BundledSymfile *bsymfile;
+
+ bsymfile = g_new0 (BundledSymfile, 1);
+ bsymfile->aname = assembly_name;
+ bsymfile->raw_contents = raw_contents;
+ bsymfile->size = size;
+ bsymfile->next = bundled_symfiles;
+ bundled_symfiles = bsymfile;
+}
+
+static MonoDebugHandle *
+open_symfile_from_bundle (MonoImage *image)
+{
+ BundledSymfile *bsymfile;
+
+ for (bsymfile = bundled_symfiles; bsymfile; bsymfile = bsymfile->next) {
+ if (strcmp (bsymfile->aname, image->module_name))
+ continue;
+
+ return mono_debug_open_image (image, bsymfile->raw_contents, bsymfile->size);
+ }
+
+ return NULL;
+}