static guint64 debugger_insert_method_breakpoint (guint64 method_argument, guint64 index) { MonoMethod *method = GUINT_TO_POINTER ((gsize) method_argument); MonoDebugMethodAddressList *info; mono_debugger_lock (); if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) { const char *name = method->name; MonoMethod *nm = NULL; if (method->klass->parent == mono_defaults.multicastdelegate_class) { if (*name == 'I' && (strcmp (name, "Invoke") == 0)) nm = mono_marshal_get_delegate_invoke (method, NULL); else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) nm = mono_marshal_get_delegate_begin_invoke (method); else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) nm = mono_marshal_get_delegate_end_invoke (method); } if (!nm) { mono_debugger_unlock (); return 0; } method = nm; } info = mono_debugger_insert_method_breakpoint (method, index); mono_debugger_unlock (); return (guint64) (gsize) info; }
/* * mono_debug_lookup_locals: * * Return information about the local variables of MINFO. * The result should be freed using mono_debug_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_internal (method); if (!minfo || !minfo->handle) { mono_debugger_unlock (); return NULL; } if (minfo->handle->ppdb) { res = mono_ppdb_lookup_locals (minfo); } else { if (!minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile)) res = NULL; else res = mono_debug_symfile_lookup_locals (minfo); } mono_debugger_unlock (); return res; }
static void mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data) { mono_debugger_lock (); mono_debug_open_image (mono_assembly_get_image (assembly), NULL, 0); mono_debugger_unlock (); }
/** * mono_debug_lookup_source_location_by_il: * * Same as mono_debug_lookup_source_location but take an IL_OFFSET argument. */ MonoDebugSourceLocation * mono_debug_lookup_source_location_by_il (MonoMethod *method, guint32 il_offset, MonoDomain *domain) { MonoDebugMethodInfo *minfo; MonoDebugSourceLocation *location; if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) return NULL; mono_debugger_lock (); minfo = mono_debug_lookup_method_internal (method); if (!minfo || !minfo->handle) { mono_debugger_unlock (); return NULL; } if (!minfo->handle->ppdb && (!minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile))) { mono_debugger_unlock (); return NULL; } if (minfo->handle->ppdb) location = mono_ppdb_lookup_location (minfo, il_offset); else location = mono_debug_symfile_lookup_location (minfo, il_offset); mono_debugger_unlock (); return location; }
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_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 (); }
/** * mono_debug_lookup_source_location: * @address: Native offset within the @method's machine code. * * Lookup the source code corresponding to the machine instruction located at * native offset @address within @method. * * The returned `MonoDebugSourceLocation' contains both file / line number * information and the corresponding IL offset. It must be freed by * mono_debug_free_source_location(). */ MonoDebugSourceLocation * mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDomain *domain) { MonoDebugMethodInfo *minfo; MonoDebugSourceLocation *location; gint32 offset; 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; } offset = il_offset_from_address (method, domain, address); if (offset < 0) { mono_debugger_unlock (); return NULL; } location = mono_debug_symfile_lookup_location (minfo, offset); mono_debugger_unlock (); return location; }
static void debugger_remove_class_init_callback (guint64 index, G_GNUC_UNUSED guint64 dummy) { mono_debugger_lock (); mono_debugger_remove_class_init_callback (index); mono_debugger_unlock (); }
static MonoDebugHandle * 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) { mono_debugger_unlock (); return handle; } handle = g_new0 (MonoDebugHandle, 1); handle->image = image; mono_image_addref (image); /* Try a ppdb file first */ handle->ppdb = mono_ppdb_load_file (handle->image, raw_contents, size); if (!handle->ppdb) handle->symfile = mono_debug_open_mono_symbols (handle, raw_contents, size, FALSE); g_hash_table_insert (mono_debug_handles, image, handle); mono_debugger_unlock (); return handle; }
/* * Initialize debugging support. * * This method must be called after loading corlib, * but before opening the application's main assembly because we need to set some * callbacks here. */ void mono_debug_init (MonoDebugFormat format) { g_assert (!mono_debug_initialized); if (_mono_debug_using_mono_debugger) format = MONO_DEBUG_FORMAT_DEBUGGER; mono_debug_initialized = TRUE; mono_debug_format = format; 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_MAJOR_VERSION; mono_symbol_table->total_size = sizeof (MonoSymbolTable); mono_debug_handles = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) free_debug_handle); data_table_hash = g_hash_table_new_full ( NULL, NULL, NULL, (GDestroyNotify) free_data_table); 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); mono_symbol_table->global_data_table = create_data_table (NULL); mono_debugger_unlock (); }
MonoDebugMethodInfo * mono_ppdb_lookup_method (MonoDebugHandle *handle, MonoMethod *method) { MonoDebugMethodInfo *minfo; MonoPPDBFile *ppdb = handle->ppdb; if (handle->image != mono_class_get_image (mono_method_get_class (method))) return NULL; mono_debugger_lock (); minfo = (MonoDebugMethodInfo *)g_hash_table_lookup (ppdb->method_hash, method); if (minfo) { mono_debugger_unlock (); return minfo; } minfo = g_new0 (MonoDebugMethodInfo, 1); minfo->index = 0; minfo->method = method; minfo->handle = handle; g_hash_table_insert (ppdb->method_hash, method, minfo); mono_debugger_unlock (); return minfo; }
static void mono_debug_add_type (MonoClass *klass) { MonoDebugHandle *handle; MonoDebugClassEntry *entry; guint8 buffer [BUFSIZ]; guint8 *ptr, *oldptr; guint32 size, total_size, max_size; int base_offset = 0; 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); else ptr = oldptr = buffer; if (klass->valuetype) base_offset = - (int)(sizeof (MonoObject)); write_leb128 (klass->type_token, 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); g_assert (total_size + 9 < DATA_TABLE_CHUNK_SIZE); entry = (MonoDebugClassEntry *) allocate_data_item ( handle->type_table, MONO_DEBUG_DATA_ITEM_CLASS, total_size); entry->size = total_size; memcpy (&entry->data, oldptr, size); write_data_item (handle->type_table, (guint8 *) entry); if (max_size > BUFSIZ) g_free (oldptr); mono_debugger_unlock (); }
/** * mono_debug_lookup_method: * * Lookup symbol file information for the method @method. The returned * `MonoDebugMethodInfo' is a private structure, but it can be passed to * mono_debug_symfile_lookup_location(). */ MonoDebugMethodInfo * mono_debug_lookup_method (MonoMethod *method) { MonoDebugMethodInfo *minfo; mono_debugger_lock (); minfo = _mono_debug_lookup_method (method); mono_debugger_unlock (); return minfo; }
void mono_debugger_check_interruption (void) { if (!_mono_debugger_interruption_request) return; mono_debugger_lock (); mono_debugger_event (MONO_DEBUGGER_EVENT_INTERRUPTION_REQUEST, 0, 0); mono_debugger_unlock (); }
/** * mono_debug_domain_create: */ void mono_debug_domain_create (MonoDomain *domain) { if (!mono_debug_initialized) return; mono_debugger_lock (); create_data_table (domain); mono_debugger_unlock (); }
static guint64 debugger_register_class_init_callback (guint64 image_argument, guint64 token, guint64 index, const gchar *class_name) { MonoImage *image = GUINT_TO_POINTER ((gsize) image_argument); MonoClass *klass; mono_debugger_lock (); klass = mono_debugger_register_class_init_callback (image, class_name, token, index); mono_debugger_unlock (); return (guint64) (gsize) klass; }
static guint64 debugger_compile_method (guint64 method_arg) { MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg); gpointer addr; mono_debugger_lock (); addr = mono_compile_method (method); mono_debugger_unlock (); return (guint64) (gsize) addr; }
static guint64 debugger_insert_source_breakpoint (guint64 image_argument, guint64 token, guint64 index, const gchar *class_name) { MonoImage *image = GUINT_TO_POINTER ((gsize) image_argument); MonoDebugMethodAddressList *info; MonoClass *klass; int i; mono_debugger_lock (); klass = mono_debugger_register_class_init_callback (image, class_name, token, index); if (!klass || !klass->inited || !klass->methods) { mono_debugger_unlock (); return 0; } for (i = 0; i < klass->method.count; i++) { MonoMethod *method = klass->methods [i]; if (method->token != token) continue; if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) { const char *name = method->name; MonoMethod *nm = NULL; if (method->klass->parent == mono_defaults.multicastdelegate_class) { if (*name == 'I' && (strcmp (name, "Invoke") == 0)) nm = mono_marshal_get_delegate_invoke (method, NULL); else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) nm = mono_marshal_get_delegate_begin_invoke (method); else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) nm = mono_marshal_get_delegate_end_invoke (method); } if (!nm) { mono_debugger_unlock (); return 0; } method = nm; } info = mono_debug_lookup_method_addresses (method); mono_debugger_unlock (); return (guint64) (gsize) info; } mono_debugger_unlock (); return 0; }
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; }
/** * mono_debug_lookup_method: * * Lookup symbol file information for the method \p method. The returned * \c MonoDebugMethodInfo is a private structure, but it can be passed to * \c mono_debug_symfile_lookup_location. */ MonoDebugMethodInfo * mono_debug_lookup_method (MonoMethod *method) { MonoDebugMethodInfo *minfo; if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) return NULL; mono_debugger_lock (); minfo = mono_debug_lookup_method_internal (method); mono_debugger_unlock (); return minfo; }
static void mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data) { MonoDebugHandle *handle; MonoImage *image; mono_debugger_lock (); image = mono_assembly_get_image (assembly); handle = open_symfile_from_bundle (image); if (!handle) mono_debug_open_image (image, NULL, 0); mono_debugger_unlock (); }
/** * 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; }
MonoDebugSourceLocation * mono_debug_method_lookup_location (MonoDebugMethodInfo *minfo, int il_offset) { MonoDebugSourceLocation *location; mono_debugger_lock (); if (minfo->handle->ppdb) location = mono_ppdb_lookup_location (minfo, il_offset); else location = mono_debug_symfile_lookup_location (minfo, il_offset); mono_debugger_unlock (); return location; }
void mono_debug_domain_create (MonoDomain *domain) { MonoDebugDataTable *table; if (!mono_debug_initialized) return; mono_debugger_lock (); table = create_data_table (domain); mono_debugger_unlock (); }
/** * mono_debug_print_stack_frame: * \param native_offset Native offset within the \p method's machine code. * Conventient wrapper around \c mono_debug_lookup_source_location which can be * used if you only want to use the location to print a stack frame. */ gchar * mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain) { MonoDebugSourceLocation *location; 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) { 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 && get_seq_point) offset = get_seq_point (domain, method, native_offset); if (offset < 0) res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset); else { char *mvid = mono_guid_to_string_minimal ((uint8_t*)m_class_get_image (method->klass)->heap_guid.data); char *aotid = mono_runtime_get_aotid (); if (aotid) res = g_strdup_printf ("at %s [0x%05x] in <%s#%s>:0" , fname, offset, mvid, aotid); else res = g_strdup_printf ("at %s [0x%05x] in <%s>:0" , fname, offset, mvid); g_free (aotid); g_free (mvid); } g_free (fname); return res; } res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset, location->source_file, location->row); g_free (fname); mono_debug_free_source_location (location); return res; }
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; }
gboolean mono_debug_image_has_debug_info (MonoImage *image) { LookupImageData data; if (!mono_debug_handles) return FALSE; memset (&data, 0, sizeof (data)); data.image = image; mono_debugger_lock (); g_hash_table_foreach (mono_debug_handles, lookup_image_func, &data); mono_debugger_unlock (); return data.found; }
MonoSymbolFile * mono_debug_open_mono_symbols (MonoDebugHandle *handle, const uint8_t *raw_contents, int size, gboolean in_the_debugger) { MonoSymbolFile *symfile; mono_debugger_lock (); symfile = g_new0 (MonoSymbolFile, 1); if (raw_contents != NULL) { unsigned char *p; symfile->raw_contents_size = size; symfile->raw_contents = p = (unsigned char *)g_malloc (size); memcpy (p, raw_contents, size); symfile->filename = g_strdup_printf ("LoadedFromMemory"); symfile->was_loaded_from_memory = TRUE; } else { MonoFileMap *f; symfile->filename = g_strdup_printf ("%s.mdb", mono_image_get_filename (handle->image)); symfile->was_loaded_from_memory = FALSE; if ((f = mono_file_map_open (symfile->filename))) { symfile->raw_contents_size = mono_file_map_size (f); if (symfile->raw_contents_size == 0) { if (!in_the_debugger) g_warning ("stat of %s failed: %s", symfile->filename, g_strerror (errno)); } else { symfile->raw_contents = (const unsigned char *)mono_file_map (symfile->raw_contents_size, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (f), 0, &symfile->raw_contents_handle); } mono_file_map_close (f); } } if (load_symfile (handle, symfile, in_the_debugger)) { mono_debugger_unlock (); return symfile; } else if (!in_the_debugger) { mono_debug_close_mono_symbol_file (symfile); mono_debugger_unlock (); return NULL; } mono_debugger_unlock (); return symfile; }
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 (); }
MonoDebugMethodInfo * mono_debug_symfile_lookup_method (MonoDebugHandle *handle, MonoMethod *method) { MonoSymbolFileMethodEntry *first_ie, *ie; MonoDebugMethodInfo *minfo; MonoSymbolFile *symfile = handle->symfile; if (!symfile->method_hash) return NULL; if (handle->image != mono_class_get_image (mono_method_get_class (method))) return NULL; mono_debugger_lock (); minfo = g_hash_table_lookup (symfile->method_hash, method); if (minfo) { mono_debugger_unlock (); return minfo; } first_ie = (MonoSymbolFileMethodEntry *) (symfile->raw_contents + read32(&(symfile->offset_table->_method_table_offset))); ie = bsearch (GUINT_TO_POINTER (mono_method_get_token (method)), first_ie, read32(&(symfile->offset_table->_method_count)), sizeof (MonoSymbolFileMethodEntry), compare_method); if (!ie) { mono_debugger_unlock (); return NULL; } minfo = g_new0 (MonoDebugMethodInfo, 1); minfo->index = (ie - first_ie) + 1; minfo->method = method; minfo->handle = handle; minfo->data_offset = read32 (&(ie->_data_offset)); minfo->lnt_offset = read32 (&(ie->_line_number_table)); g_hash_table_insert (symfile->method_hash, method, minfo); mono_debugger_unlock (); return minfo; }