2 * mono-debug-debugger.c:
5 * Mono Project (http://www.mono-project.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
14 #include <mono/metadata/assembly.h>
15 #include <mono/metadata/metadata.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/gc-internal.h>
20 #include <mono/metadata/threads.h>
21 #include <mono/metadata/gc-internal.h>
22 #include <mono/metadata/object-internals.h>
23 #include <mono/metadata/class-internals.h>
24 #include <mono/metadata/exception.h>
25 #include <mono/metadata/mono-debug.h>
26 #include <mono/metadata/mono-debug-debugger.h>
27 #include <mono/metadata/mono-endian.h>
29 static guint32 debugger_lock_level = 0;
30 static CRITICAL_SECTION debugger_lock_mutex;
31 static gboolean mono_debugger_use_debugger = FALSE;
32 static MonoObject *last_exception = NULL;
33 volatile gint32 _mono_debugger_interruption_request = 0;
35 void (*mono_debugger_event_handler) (MonoDebuggerEvent event, guint64 data, guint64 arg) = NULL;
38 gpointer stack_pointer;
39 MonoObject *exception_obj;
41 } MonoDebuggerExceptionInfo;
47 MonoDebugMethodAddressList *address_list;
48 } MethodBreakpointInfo;
58 static GPtrArray *class_init_callbacks = NULL;
60 static int initialized = 0;
63 mono_debugger_lock (void)
65 g_assert (initialized);
66 EnterCriticalSection (&debugger_lock_mutex);
67 debugger_lock_level++;
71 mono_debugger_unlock (void)
73 g_assert (initialized);
74 debugger_lock_level--;
75 LeaveCriticalSection (&debugger_lock_mutex);
79 mono_debugger_initialize (gboolean use_debugger)
81 MONO_GC_REGISTER_ROOT (last_exception);
83 g_assert (!mono_debugger_use_debugger);
85 InitializeCriticalSection (&debugger_lock_mutex);
86 mono_debugger_use_debugger = use_debugger;
91 mono_debugger_event (MonoDebuggerEvent event, guint64 data, guint64 arg)
93 if (mono_debugger_event_handler)
94 (* mono_debugger_event_handler) (event, data, arg);
98 mono_debugger_cleanup (void)
100 mono_debugger_event (MONO_DEBUGGER_EVENT_FINALIZE_MANAGED_CODE, 0, 0);
101 mono_debugger_event_handler = NULL;
105 mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc)
109 if (!mono_debugger_use_debugger)
112 name = mono_class_get_name (mono_object_get_class (exc));
113 if (!strcmp (name, "ThreadAbortException"))
116 // Prevent the object from being finalized.
117 last_exception = exc;
119 mono_debugger_event (MONO_DEBUGGER_EVENT_UNHANDLED_EXCEPTION,
120 (guint64) (gsize) exc, (guint64) (gsize) addr);
125 mono_debugger_handle_exception (gpointer addr, gpointer stack, MonoObject *exc)
127 MonoDebuggerExceptionInfo info;
129 if (!mono_debugger_use_debugger)
132 // Prevent the object from being finalized.
133 last_exception = exc;
135 info.stack_pointer = stack;
136 info.exception_obj = exc;
139 mono_debugger_event (MONO_DEBUGGER_EVENT_HANDLE_EXCEPTION, (guint64) (gsize) &info,
140 (guint64) (gsize) addr);
144 mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc)
146 MonoDebuggerExceptionInfo info;
148 if (!mono_debugger_use_debugger)
151 // Prevent the object from being finalized.
152 last_exception = exc;
154 info.stack_pointer = stack;
155 info.exception_obj = exc;
158 mono_debugger_event (MONO_DEBUGGER_EVENT_THROW_EXCEPTION, (guint64) (gsize) &info,
159 (guint64) (gsize) addr);
160 return info.stop != 0;
164 get_exception_message (MonoObject *exc)
166 char *message = NULL;
172 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
173 klass = exc->vtable->klass;
175 while (klass && method == NULL) {
176 for (i = 0; i < klass->method.count; ++i) {
177 method = klass->methods [i];
178 if (!strcmp ("ToString", method->name) &&
179 mono_method_signature (method)->param_count == 0 &&
180 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
181 method->flags & METHOD_ATTRIBUTE_PUBLIC) {
188 klass = klass->parent;
193 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
195 message = mono_string_to_utf8 (str);
202 mono_debugger_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
207 if (!strcmp (method->name, ".ctor")) {
208 retval = obj = mono_object_new (mono_domain_get (), method->klass);
210 mono_runtime_invoke (method, obj, params, exc);
212 retval = mono_runtime_invoke (method, obj, params, exc);
214 if (!exc || (*exc == NULL))
218 message = get_exception_message (*exc);
220 *exc = (MonoObject *) mono_string_new_wrapper (message);
228 mono_debugger_check_interruption (void)
230 if (!_mono_debugger_interruption_request)
233 mono_debugger_lock ();
234 mono_debugger_event (MONO_DEBUGGER_EVENT_INTERRUPTION_REQUEST, 0, 0);
235 mono_debugger_unlock ();
239 * Debugger breakpoint interface.
241 * This interface is used to insert breakpoints on methods which are not yet JITed.
242 * The debugging code keeps a list of all such breakpoints and automatically inserts the
243 * breakpoint when the method is JITed.
246 static GPtrArray *method_breakpoints = NULL;
248 MonoDebugMethodAddressList *
249 mono_debugger_insert_method_breakpoint (MonoMethod *method, guint64 index)
251 MethodBreakpointInfo *info;
253 info = g_new0 (MethodBreakpointInfo, 1);
254 info->method = method;
257 info->address_list = mono_debug_lookup_method_addresses (method);
259 if (!method_breakpoints)
260 method_breakpoints = g_ptr_array_new ();
262 g_ptr_array_add (method_breakpoints, info);
264 return info->address_list;
268 mono_debugger_remove_method_breakpoint (guint64 index)
272 if (!method_breakpoints)
275 for (i = 0; i < method_breakpoints->len; i++) {
276 MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
278 if (info->index != index)
281 g_ptr_array_remove (method_breakpoints, info);
282 g_free (info->address_list);
291 mono_debugger_check_breakpoints (MonoMethod *method, MonoDebugMethodAddress *debug_info)
295 if (!method_breakpoints)
298 if (method->is_inflated)
299 method = ((MonoMethodInflated *) method)->declaring;
301 for (i = 0; i < method_breakpoints->len; i++) {
302 MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
304 if (method != info->method)
307 mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
308 (guint64) (gsize) debug_info, info->index);
311 if (!class_init_callbacks)
314 for (i = 0; i < class_init_callbacks->len; i++) {
315 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
317 if ((method->token != info->token) || (method->klass->image != info->image))
320 mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
321 (guint64) (gsize) debug_info, info->index);
326 mono_debugger_register_class_init_callback (MonoImage *image, const gchar *full_name,
327 guint32 method_token, guint32 index)
329 ClassInitCallback *info;
331 gchar *name_space, *name, *pos;
333 name = g_strdup (full_name);
335 pos = strrchr (name, '.');
346 klass = mono_class_from_name (image, name_space ? name_space : "", name);
347 if (klass && klass->inited && klass->methods) {
348 mono_loader_unlock ();
352 info = g_new0 (ClassInitCallback, 1);
355 info->token = method_token;
356 info->name_space = name_space;
359 if (!class_init_callbacks)
360 class_init_callbacks = g_ptr_array_new ();
362 g_ptr_array_add (class_init_callbacks, info);
363 mono_loader_unlock ();
368 mono_debugger_remove_class_init_callback (int index)
372 if (!class_init_callbacks)
375 for (i = 0; i < class_init_callbacks->len; i++) {
376 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
378 if (info->index != index)
381 g_ptr_array_remove (class_init_callbacks, info);
382 if (info->name_space)
383 g_free (info->name_space);
391 mono_debugger_class_initialized (MonoClass *klass)
395 if (!class_init_callbacks)
399 for (i = 0; i < class_init_callbacks->len; i++) {
400 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
402 if (info->name_space && strcmp (info->name_space, klass->name_space))
404 if (strcmp (info->name, klass->name))
407 mono_debugger_event (MONO_DEBUGGER_EVENT_CLASS_INITIALIZED,
408 (guint64) (gsize) klass, info->index);
413 for (j = 0; j < klass->method.count; j++) {
414 if (klass->methods [j]->token != info->token)
417 mono_debugger_insert_method_breakpoint (klass->methods [j], info->index);
421 g_ptr_array_remove (class_init_callbacks, info);
422 if (info->name_space)
423 g_free (info->name_space);