4 #include <mono/metadata/assembly.h>
5 #include <mono/metadata/metadata.h>
6 #include <mono/metadata/tabledefs.h>
7 #include <mono/metadata/tokentype.h>
8 #include <mono/metadata/appdomain.h>
9 #include <mono/metadata/gc-internal.h>
10 #include <mono/metadata/threads.h>
11 #include <mono/metadata/gc-internal.h>
12 #include <mono/metadata/object-internals.h>
13 #include <mono/metadata/class-internals.h>
14 #include <mono/metadata/exception.h>
15 #include <mono/metadata/mono-debug.h>
16 #include <mono/metadata/mono-debug-debugger.h>
17 #include <mono/metadata/mono-endian.h>
19 static guint32 debugger_lock_level = 0;
20 static CRITICAL_SECTION debugger_lock_mutex;
21 static gboolean mono_debugger_use_debugger = FALSE;
22 static MonoObject *last_exception = NULL;
23 volatile gint32 _mono_debugger_interruption_request = 0;
25 void (*mono_debugger_event_handler) (MonoDebuggerEvent event, guint64 data, guint64 arg) = NULL;
28 gpointer stack_pointer;
29 MonoObject *exception_obj;
31 } MonoDebuggerExceptionInfo;
37 MonoDebugMethodAddressList *address_list;
38 } MethodBreakpointInfo;
48 static GPtrArray *class_init_callbacks = NULL;
50 static int initialized = 0;
53 mono_debugger_lock (void)
55 g_assert (initialized);
56 EnterCriticalSection (&debugger_lock_mutex);
57 debugger_lock_level++;
61 mono_debugger_unlock (void)
63 g_assert (initialized);
64 debugger_lock_level--;
65 LeaveCriticalSection (&debugger_lock_mutex);
69 mono_debugger_initialize (gboolean use_debugger)
71 MONO_GC_REGISTER_ROOT (last_exception);
73 g_assert (!mono_debugger_use_debugger);
75 InitializeCriticalSection (&debugger_lock_mutex);
76 mono_debugger_use_debugger = use_debugger;
81 mono_debugger_event (MonoDebuggerEvent event, guint64 data, guint64 arg)
83 if (mono_debugger_event_handler)
84 (* mono_debugger_event_handler) (event, data, arg);
88 mono_debugger_cleanup (void)
90 mono_debugger_event (MONO_DEBUGGER_EVENT_FINALIZE_MANAGED_CODE, 0, 0);
91 mono_debugger_event_handler = NULL;
95 mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc)
99 if (!mono_debugger_use_debugger)
102 name = mono_class_get_name (mono_object_get_class (exc));
103 if (!strcmp (name, "ThreadAbortException"))
106 // Prevent the object from being finalized.
107 last_exception = exc;
109 mono_debugger_event (MONO_DEBUGGER_EVENT_UNHANDLED_EXCEPTION,
110 (guint64) (gsize) exc, (guint64) (gsize) addr);
115 mono_debugger_handle_exception (gpointer addr, gpointer stack, MonoObject *exc)
117 MonoDebuggerExceptionInfo info;
119 if (!mono_debugger_use_debugger)
122 // Prevent the object from being finalized.
123 last_exception = exc;
125 info.stack_pointer = stack;
126 info.exception_obj = exc;
129 mono_debugger_event (MONO_DEBUGGER_EVENT_HANDLE_EXCEPTION, (guint64) (gsize) &info,
130 (guint64) (gsize) addr);
134 mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc)
136 MonoDebuggerExceptionInfo info;
138 if (!mono_debugger_use_debugger)
141 // Prevent the object from being finalized.
142 last_exception = exc;
144 info.stack_pointer = stack;
145 info.exception_obj = exc;
148 mono_debugger_event (MONO_DEBUGGER_EVENT_THROW_EXCEPTION, (guint64) (gsize) &info,
149 (guint64) (gsize) addr);
150 return info.stop != 0;
154 get_exception_message (MonoObject *exc)
156 char *message = NULL;
162 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
163 klass = exc->vtable->klass;
165 while (klass && method == NULL) {
166 for (i = 0; i < klass->method.count; ++i) {
167 method = klass->methods [i];
168 if (!strcmp ("ToString", method->name) &&
169 mono_method_signature (method)->param_count == 0 &&
170 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
171 method->flags & METHOD_ATTRIBUTE_PUBLIC) {
178 klass = klass->parent;
183 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
185 message = mono_string_to_utf8 (str);
192 mono_debugger_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
197 if (!strcmp (method->name, ".ctor")) {
198 retval = obj = mono_object_new (mono_domain_get (), method->klass);
200 mono_runtime_invoke (method, obj, params, exc);
202 retval = mono_runtime_invoke (method, obj, params, exc);
204 if (!exc || (*exc == NULL))
207 message = get_exception_message (*exc);
209 *exc = (MonoObject *) mono_string_new_wrapper (message);
217 mono_debugger_check_interruption (void)
219 if (!_mono_debugger_interruption_request)
222 mono_debugger_lock ();
223 mono_debugger_event (MONO_DEBUGGER_EVENT_INTERRUPTION_REQUEST, 0, 0);
224 mono_debugger_unlock ();
228 * Debugger breakpoint interface.
230 * This interface is used to insert breakpoints on methods which are not yet JITed.
231 * The debugging code keeps a list of all such breakpoints and automatically inserts the
232 * breakpoint when the method is JITed.
235 static GPtrArray *method_breakpoints = NULL;
237 MonoDebugMethodAddressList *
238 mono_debugger_insert_method_breakpoint (MonoMethod *method, guint64 index)
240 MethodBreakpointInfo *info;
242 info = g_new0 (MethodBreakpointInfo, 1);
243 info->method = method;
246 info->address_list = mono_debug_lookup_method_addresses (method);
248 if (!method_breakpoints)
249 method_breakpoints = g_ptr_array_new ();
251 g_ptr_array_add (method_breakpoints, info);
253 return info->address_list;
257 mono_debugger_remove_method_breakpoint (guint64 index)
261 if (!method_breakpoints)
264 for (i = 0; i < method_breakpoints->len; i++) {
265 MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
267 if (info->index != index)
270 g_ptr_array_remove (method_breakpoints, info);
271 g_free (info->address_list);
280 mono_debugger_check_breakpoints (MonoMethod *method, MonoDebugMethodAddress *debug_info)
284 if (!method_breakpoints)
287 if (method->is_inflated)
288 method = ((MonoMethodInflated *) method)->declaring;
290 for (i = 0; i < method_breakpoints->len; i++) {
291 MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
293 if (method != info->method)
296 mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
297 (guint64) (gsize) debug_info, info->index);
300 if (!class_init_callbacks)
303 for (i = 0; i < class_init_callbacks->len; i++) {
304 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
306 if ((method->token != info->token) || (method->klass->image != info->image))
309 mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
310 (guint64) (gsize) debug_info, info->index);
315 mono_debugger_register_class_init_callback (MonoImage *image, const gchar *full_name,
316 guint32 method_token, guint32 index)
318 ClassInitCallback *info;
320 gchar *name_space, *name, *pos;
322 name = g_strdup (full_name);
324 pos = strrchr (name, '.');
335 klass = mono_class_from_name (image, name_space ? name_space : "", name);
336 if (klass && klass->inited && klass->methods) {
337 mono_loader_unlock ();
341 info = g_new0 (ClassInitCallback, 1);
344 info->token = method_token;
345 info->name_space = name_space;
348 if (!class_init_callbacks)
349 class_init_callbacks = g_ptr_array_new ();
351 g_ptr_array_add (class_init_callbacks, info);
352 mono_loader_unlock ();
357 mono_debugger_remove_class_init_callback (int index)
361 if (!class_init_callbacks)
364 for (i = 0; i < class_init_callbacks->len; i++) {
365 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
367 if (info->index != index)
370 g_ptr_array_remove (class_init_callbacks, info);
371 if (info->name_space)
372 g_free (info->name_space);
380 mono_debugger_class_initialized (MonoClass *klass)
384 if (!class_init_callbacks)
388 for (i = 0; i < class_init_callbacks->len; i++) {
389 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
391 if (info->name_space && strcmp (info->name_space, klass->name_space))
393 if (strcmp (info->name, klass->name))
396 mono_debugger_event (MONO_DEBUGGER_EVENT_CLASS_INITIALIZED,
397 (guint64) (gsize) klass, info->index);
402 for (j = 0; j < klass->method.count; j++) {
403 if (klass->methods [j]->token != info->token)
406 mono_debugger_insert_method_breakpoint (klass->methods [j], info->index);
410 g_ptr_array_remove (class_init_callbacks, info);
411 if (info->name_space)
412 g_free (info->name_space);