+/*
+ * mono-debug-debugger.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 <stdlib.h>
#include <string.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/gc-internal.h>
#include <mono/metadata/threads.h>
-#include <mono/os/gc_wrapper.h>
+#include <mono/metadata/gc-internal.h>
#include <mono/metadata/object-internals.h>
#include <mono/metadata/class-internals.h>
+#include <mono/metadata/domain-internals.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/mono-debug-debugger.h>
static guint32 debugger_lock_level = 0;
static CRITICAL_SECTION debugger_lock_mutex;
-static gboolean must_reload_symtabs = FALSE;
static gboolean mono_debugger_use_debugger = FALSE;
static MonoObject *last_exception = NULL;
+volatile gint32 _mono_debugger_interruption_request = 0;
void (*mono_debugger_event_handler) (MonoDebuggerEvent event, guint64 data, guint64 arg) = NULL;
-#define WRITE_UINT32(ptr,value) G_STMT_START { \
- * ((guint32 *) ptr) = value; \
- ptr += 4; \
-} G_STMT_END
-
-#define WRITE_POINTER(ptr,value) G_STMT_START { \
- * ((gpointer *) ptr) = (gpointer) (value); \
- ptr += sizeof (gpointer); \
-} G_STMT_END
+typedef struct
+{
+ guint32 index;
+ MonoMethod *method;
+ MonoDebugMethodAddressList *address_list;
+} MethodBreakpointInfo;
-#define WRITE_STRING(ptr,value) G_STMT_START { \
- memcpy (ptr, value, strlen (value)+1); \
- ptr += strlen (value)+1; \
-} G_STMT_END
+typedef struct {
+ MonoImage *image;
+ guint64 index;
+ guint32 token;
+ gchar *name_space;
+ gchar *name;
+} ClassInitCallback;
typedef struct {
- gpointer stack_pointer;
- MonoObject *exception_obj;
- guint32 stop;
-} MonoDebuggerExceptionInfo;
+ guint32 id;
+ guint32 shadow_path_len;
+ gchar *shadow_path;
+ MonoDomain *domain;
+ MonoAppDomainSetup *setup;
+} AppDomainSetupInfo;
+
+static GPtrArray *class_init_callbacks = NULL;
static int initialized = 0;
mono_debugger_unlock (void)
{
g_assert (initialized);
- if (debugger_lock_level == 1) {
- if (must_reload_symtabs && mono_debugger_use_debugger) {
- mono_debugger_event (MONO_DEBUGGER_EVENT_RELOAD_SYMTABS, 0, 0);
- must_reload_symtabs = FALSE;
- }
- }
-
debugger_lock_level--;
LeaveCriticalSection (&debugger_lock_mutex);
}
}
void
-mono_debugger_add_symbol_file (MonoDebugHandle *handle)
+mono_debugger_event (MonoDebuggerEvent event, guint64 data, guint64 arg)
{
- g_assert (mono_debugger_use_debugger);
-
- mono_debugger_lock ();
- mono_debugger_event (MONO_DEBUGGER_EVENT_ADD_MODULE, (guint64) (gsize) handle, 0);
- mono_debugger_unlock ();
+ if (mono_debugger_event_handler)
+ (* mono_debugger_event_handler) (event, data, arg);
}
void
-mono_debugger_start_add_type (MonoDebugHandle *symfile, MonoClass *klass)
+mono_debugger_event_create_appdomain (MonoDomain *domain, gchar *shadow_path)
{
- must_reload_symtabs = TRUE;
+ AppDomainSetupInfo info;
+
+ info.id = mono_domain_get_id (domain);
+ info.shadow_path_len = shadow_path ? strlen (shadow_path) : 0;
+ info.shadow_path = shadow_path;
+
+ info.domain = domain;
+ info.setup = domain->setup;
+
+ mono_debugger_event (MONO_DEBUGGER_EVENT_CREATE_APPDOMAIN, (guint64) (gsize) &info, 0);
}
void
-mono_debugger_event (MonoDebuggerEvent event, guint64 data, guint64 arg)
+mono_debugger_event_unload_appdomain (MonoDomain *domain)
{
- if (mono_debugger_event_handler)
- (* mono_debugger_event_handler) (event, data, arg);
+ mono_debugger_event (MONO_DEBUGGER_EVENT_UNLOAD_APPDOMAIN,
+ (guint64) (gsize) domain, (guint64) mono_domain_get_id (domain));
}
void
mono_debugger_event_handler = NULL;
}
+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 ();
+}
+
/*
* Debugger breakpoint interface.
*
* breakpoint when the method is JITed.
*/
-static GPtrArray *breakpoints = NULL;
+static GPtrArray *method_breakpoints = NULL;
-int
-mono_debugger_insert_breakpoint_full (MonoMethodDesc *desc)
+MonoDebugMethodAddressList *
+mono_debugger_insert_method_breakpoint (MonoMethod *method, guint64 index)
{
- static int last_breakpoint_id = 0;
- MonoDebuggerBreakpointInfo *info;
+ MethodBreakpointInfo *info;
+
+ info = g_new0 (MethodBreakpointInfo, 1);
+ info->method = method;
+ info->index = index;
- info = g_new0 (MonoDebuggerBreakpointInfo, 1);
- info->desc = desc;
- info->index = ++last_breakpoint_id;
+ info->address_list = mono_debug_lookup_method_addresses (method);
- if (!breakpoints)
- breakpoints = g_ptr_array_new ();
+ if (!method_breakpoints)
+ method_breakpoints = g_ptr_array_new ();
- g_ptr_array_add (breakpoints, info);
+ g_ptr_array_add (method_breakpoints, info);
- return info->index;
+ return info->address_list;
}
int
-mono_debugger_remove_breakpoint (int breakpoint_id)
+mono_debugger_remove_method_breakpoint (guint64 index)
{
int i;
- if (!breakpoints)
+ if (!method_breakpoints)
return 0;
- for (i = 0; i < breakpoints->len; i++) {
- MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
+ for (i = 0; i < method_breakpoints->len; i++) {
+ MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
- if (info->index != breakpoint_id)
+ if (info->index != index)
continue;
- mono_method_desc_free (info->desc);
- g_ptr_array_remove (breakpoints, info);
+ g_ptr_array_remove (method_breakpoints, info);
+ g_free (info->address_list);
g_free (info);
return 1;
}
return 0;
}
-int
-mono_debugger_insert_breakpoint (const gchar *method_name, gboolean include_namespace)
-{
- MonoMethodDesc *desc;
-
- desc = mono_method_desc_new (method_name, include_namespace);
- if (!desc)
- return 0;
-
- return mono_debugger_insert_breakpoint_full (desc);
-}
-
-int
-mono_debugger_method_has_breakpoint (MonoMethod *method)
+void
+mono_debugger_check_breakpoints (MonoMethod *method, MonoDebugMethodAddress *debug_info)
{
int i;
- if (!breakpoints || (method->wrapper_type != MONO_WRAPPER_NONE))
- return 0;
+ if (method->is_inflated)
+ method = ((MonoMethodInflated *) method)->declaring;
- for (i = 0; i < breakpoints->len; i++) {
- MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
+ if (method_breakpoints) {
+ for (i = 0; i < method_breakpoints->len; i++) {
+ MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
- if (!mono_method_desc_full_match (info->desc, method))
- continue;
+ if (method != info->method)
+ continue;
- return info->index;
+ mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
+ (guint64) (gsize) debug_info, info->index);
+ }
}
- return 0;
-}
-
-void
-mono_debugger_breakpoint_callback (MonoMethod *method, guint32 index)
-{
- mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT, (guint64) (gsize) method, index);
-}
-
-gboolean
-mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc)
-{
- const gchar *name;
-
- if (!mono_debugger_use_debugger)
- return FALSE;
+ if (class_init_callbacks) {
+ for (i = 0; i < class_init_callbacks->len; i++) {
+ ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
- // Prevent the object from being finalized.
- last_exception = exc;
+ if ((method->token != info->token) || (method->klass->image != info->image))
+ continue;
- name = mono_class_get_name (mono_object_get_class (exc));
- if (!strcmp (name, "ThreadAbortException")) {
- MonoThread *thread = mono_thread_current ();
- mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_ABORT, 0, thread->tid);
- mono_thread_exit ();
+ mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
+ (guint64) (gsize) debug_info, info->index);
+ }
}
-
- mono_debugger_event (MONO_DEBUGGER_EVENT_UNHANDLED_EXCEPTION,
- (guint64) (gsize) exc, (guint64) (gsize) addr);
- return TRUE;
}
-void
-mono_debugger_handle_exception (gpointer addr, gpointer stack, MonoObject *exc)
+MonoClass *
+mono_debugger_register_class_init_callback (MonoImage *image, const gchar *full_name,
+ guint32 method_token, guint32 index)
{
- MonoDebuggerExceptionInfo info;
-
- if (!mono_debugger_use_debugger)
- return;
-
- // Prevent the object from being finalized.
- last_exception = exc;
-
- info.stack_pointer = stack;
- info.exception_obj = exc;
- info.stop = 0;
-
- mono_debugger_event (MONO_DEBUGGER_EVENT_HANDLE_EXCEPTION, (guint64) (gsize) &info,
- (guint64) (gsize) addr);
-}
-
-gboolean
-mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc)
-{
- MonoDebuggerExceptionInfo info;
-
- if (!mono_debugger_use_debugger)
- return FALSE;
-
- // Prevent the object from being finalized.
- last_exception = exc;
-
- info.stack_pointer = stack;
- info.exception_obj = exc;
- info.stop = 0;
-
- mono_debugger_event (MONO_DEBUGGER_EVENT_THROW_EXCEPTION, (guint64) (gsize) &info,
- (guint64) (gsize) addr);
- return info.stop != 0;
-}
-
-static gchar *
-get_exception_message (MonoObject *exc)
-{
- char *message = NULL;
- MonoString *str;
- MonoMethod *method;
+ ClassInitCallback *info;
MonoClass *klass;
- gint i;
-
- if (mono_object_isinst (exc, mono_defaults.exception_class)) {
- klass = exc->vtable->klass;
- method = NULL;
- while (klass && method == NULL) {
- for (i = 0; i < klass->method.count; ++i) {
- method = klass->methods [i];
- if (!strcmp ("ToString", method->name) &&
- mono_method_signature (method)->param_count == 0 &&
- method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
- method->flags & METHOD_ATTRIBUTE_PUBLIC) {
- break;
- }
- method = NULL;
- }
-
- if (method == NULL)
- klass = klass->parent;
- }
+ gchar *name_space, *name, *pos;
- g_assert (method);
+ name = g_strdup (full_name);
- str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
- if (str)
- message = mono_string_to_utf8 (str);
+ pos = strrchr (name, '.');
+ if (pos) {
+ name_space = name;
+ *pos = 0;
+ name = pos + 1;
+ } else {
+ name_space = NULL;
}
- return message;
-}
+ mono_loader_lock ();
-MonoObject *
-mono_debugger_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
-{
- MonoObject *retval;
- gchar *message;
+ klass = mono_class_from_name (image, name_space ? name_space : "", name);
- if (!strcmp (method->name, ".ctor")) {
- retval = obj = mono_object_new (mono_domain_get (), method->klass);
+ info = g_new0 (ClassInitCallback, 1);
+ info->image = image;
+ info->index = index;
+ info->token = method_token;
+ info->name_space = name_space;
+ info->name = name;
- mono_runtime_invoke (method, obj, params, exc);
- } else
- retval = mono_runtime_invoke (method, obj, params, exc);
+ if (!class_init_callbacks)
+ class_init_callbacks = g_ptr_array_new ();
- if (!exc || (*exc == NULL))
- return retval;
-
- message = get_exception_message (*exc);
- if (message) {
- *exc = (MonoObject *) mono_string_new_wrapper (message);
- g_free (message);
- }
-
- return retval;
+ g_ptr_array_add (class_init_callbacks, info);
+ mono_loader_unlock ();
+ return klass;
}
-gboolean
-mono_debugger_lookup_type (const gchar *type_name)
+void
+mono_debugger_remove_class_init_callback (int index)
{
int i;
- mono_debugger_lock ();
- for (i = 0; i < mono_symbol_table->num_symbol_files; i++) {
- MonoDebugHandle *symfile = mono_symbol_table->symbol_files [i];
- MonoType *type;
- MonoClass* klass;
- gchar *name;
+ if (!class_init_callbacks)
+ return;
- name = g_strdup (type_name);
- type = mono_reflection_type_from_name (name, symfile->image);
- g_free (name);
- if (!type)
- continue;
+ for (i = 0; i < class_init_callbacks->len; i++) {
+ ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
- klass = mono_class_from_mono_type (type);
- if (klass)
- mono_class_init (klass);
+ if (info->index != index)
+ continue;
- mono_debugger_unlock ();
- return TRUE;
+ g_ptr_array_remove (class_init_callbacks, info);
+ if (info->name_space)
+ g_free (info->name_space);
+ else
+ g_free (info->name);
+ g_free (info);
}
-
- mono_debugger_unlock ();
- return FALSE;
}
-gint32
-mono_debugger_lookup_assembly (const gchar *name)
+void
+mono_debugger_class_initialized (MonoClass *klass)
{
- MonoAssembly *assembly;
- MonoImageOpenStatus status;
int i;
- mono_debugger_lock ();
+ if (!class_init_callbacks)
+ return;
again:
- for (i = 0; i < mono_symbol_table->num_symbol_files; i++) {
- MonoDebugHandle *symfile = mono_symbol_table->symbol_files [i];
+ for (i = 0; i < class_init_callbacks->len; i++) {
+ ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
- if (!strcmp (symfile->image_file, name)) {
- mono_debugger_unlock ();
- return i;
- }
- }
+ if (info->name_space && strcmp (info->name_space, klass->name_space))
+ continue;
+ if (strcmp (info->name, klass->name))
+ continue;
- assembly = mono_assembly_open (name, &status);
+ mono_debugger_event (MONO_DEBUGGER_EVENT_CLASS_INITIALIZED,
+ (guint64) (gsize) klass, info->index);
- if (status != MONO_IMAGE_OK) {
- g_warning (G_STRLOC ": Cannot open image `%s'", name);
- mono_debugger_unlock ();
- return -1;
- }
+ if (info->token) {
+ int j;
- must_reload_symtabs = TRUE;
- goto again;
-}
+ for (j = 0; j < klass->method.count; j++) {
+ if (klass->methods [j]->token != info->token)
+ continue;
+ mono_debugger_insert_method_breakpoint (klass->methods [j], info->index);
+ }
+ }
+
+ g_ptr_array_remove (class_init_callbacks, info);
+ if (info->name_space)
+ g_free (info->name_space);
+ else
+ g_free (info->name);
+ g_free (info);
+ goto again;
+ }
+}