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/os/gc_wrapper.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;
24 void (*mono_debugger_event_handler) (MonoDebuggerEvent event, guint64 data, guint64 arg) = NULL;
27 gpointer stack_pointer;
28 MonoObject *exception_obj;
30 } MonoDebuggerExceptionInfo;
36 MonoDebugMethodAddressList *address_list;
37 } MethodBreakpointInfo;
46 static GPtrArray *class_init_callbacks = NULL;
48 static int initialized = 0;
51 mono_debugger_lock (void)
53 g_assert (initialized);
54 EnterCriticalSection (&debugger_lock_mutex);
55 debugger_lock_level++;
59 mono_debugger_unlock (void)
61 g_assert (initialized);
62 debugger_lock_level--;
63 LeaveCriticalSection (&debugger_lock_mutex);
67 mono_debugger_initialize (gboolean use_debugger)
69 MONO_GC_REGISTER_ROOT (last_exception);
71 g_assert (!mono_debugger_use_debugger);
73 InitializeCriticalSection (&debugger_lock_mutex);
74 mono_debugger_use_debugger = use_debugger;
79 mono_debugger_event (MonoDebuggerEvent event, guint64 data, guint64 arg)
81 if (mono_debugger_event_handler)
82 (* mono_debugger_event_handler) (event, data, arg);
86 mono_debugger_cleanup (void)
88 mono_debugger_event (MONO_DEBUGGER_EVENT_FINALIZE_MANAGED_CODE, 0, 0);
89 mono_debugger_event_handler = NULL;
93 mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc)
97 if (!mono_debugger_use_debugger)
100 name = mono_class_get_name (mono_object_get_class (exc));
101 if (!strcmp (name, "ThreadAbortException"))
104 // Prevent the object from being finalized.
105 last_exception = exc;
107 mono_debugger_event (MONO_DEBUGGER_EVENT_UNHANDLED_EXCEPTION,
108 (guint64) (gsize) exc, (guint64) (gsize) addr);
113 mono_debugger_handle_exception (gpointer addr, gpointer stack, MonoObject *exc)
115 MonoDebuggerExceptionInfo info;
117 if (!mono_debugger_use_debugger)
120 // Prevent the object from being finalized.
121 last_exception = exc;
123 info.stack_pointer = stack;
124 info.exception_obj = exc;
127 mono_debugger_event (MONO_DEBUGGER_EVENT_HANDLE_EXCEPTION, (guint64) (gsize) &info,
128 (guint64) (gsize) addr);
132 mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc)
134 MonoDebuggerExceptionInfo info;
136 if (!mono_debugger_use_debugger)
139 // Prevent the object from being finalized.
140 last_exception = exc;
142 info.stack_pointer = stack;
143 info.exception_obj = exc;
146 mono_debugger_event (MONO_DEBUGGER_EVENT_THROW_EXCEPTION, (guint64) (gsize) &info,
147 (guint64) (gsize) addr);
148 return info.stop != 0;
152 get_exception_message (MonoObject *exc)
154 char *message = NULL;
160 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
161 klass = exc->vtable->klass;
163 while (klass && method == NULL) {
164 for (i = 0; i < klass->method.count; ++i) {
165 method = klass->methods [i];
166 if (!strcmp ("ToString", method->name) &&
167 mono_method_signature (method)->param_count == 0 &&
168 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
169 method->flags & METHOD_ATTRIBUTE_PUBLIC) {
176 klass = klass->parent;
181 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
183 message = mono_string_to_utf8 (str);
190 mono_debugger_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
195 if (!strcmp (method->name, ".ctor")) {
196 retval = obj = mono_object_new (mono_domain_get (), method->klass);
198 mono_runtime_invoke (method, obj, params, exc);
200 retval = mono_runtime_invoke (method, obj, params, exc);
202 if (!exc || (*exc == NULL))
205 message = get_exception_message (*exc);
207 *exc = (MonoObject *) mono_string_new_wrapper (message);
216 * Debugger breakpoint interface.
218 * This interface is used to insert breakpoints on methods which are not yet JITed.
219 * The debugging code keeps a list of all such breakpoints and automatically inserts the
220 * breakpoint when the method is JITed.
223 static GPtrArray *method_breakpoints = NULL;
225 MonoDebugMethodAddressList *
226 mono_debugger_insert_method_breakpoint (MonoMethod *method, guint64 index)
228 MethodBreakpointInfo *info;
230 info = g_new0 (MethodBreakpointInfo, 1);
231 info->method = method;
234 info->address_list = mono_debug_lookup_method_addresses (method);
236 if (!method_breakpoints)
237 method_breakpoints = g_ptr_array_new ();
239 g_ptr_array_add (method_breakpoints, info);
241 return info->address_list;
245 mono_debugger_remove_method_breakpoint (guint64 index)
249 if (!method_breakpoints)
252 for (i = 0; i < method_breakpoints->len; i++) {
253 MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
255 if (info->index != index)
258 g_ptr_array_remove (method_breakpoints, info);
259 g_free (info->address_list);
268 mono_debugger_check_breakpoints (MonoMethod *method, MonoDebugMethodAddress *debug_info)
272 if (!method_breakpoints)
275 if (method->is_inflated)
276 method = ((MonoMethodInflated *) method)->declaring;
278 for (i = 0; i < method_breakpoints->len; i++) {
279 MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
281 if (method != info->method)
284 mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
285 (guint64) (gsize) debug_info, info->index);
290 mono_debugger_register_class_init_callback (MonoImage *image, const gchar *full_name,
291 guint32 method_token, guint32 index)
293 ClassInitCallback *info;
295 gchar *name_space, *name, *pos;
297 name = g_strdup (full_name);
299 pos = strrchr (name, '.');
310 klass = mono_class_from_name (image, name_space ? name_space : "", name);
311 if (klass && klass->inited && klass->methods) {
312 mono_loader_unlock ();
316 info = g_new0 (ClassInitCallback, 1);
318 info->token = method_token;
319 info->name_space = name_space;
322 if (!class_init_callbacks)
323 class_init_callbacks = g_ptr_array_new ();
325 g_ptr_array_add (class_init_callbacks, info);
326 mono_loader_unlock ();
331 mono_debugger_remove_class_init_callback (int index)
335 if (!class_init_callbacks)
338 for (i = 0; i < class_init_callbacks->len; i++) {
339 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
341 if (info->index != index)
344 g_ptr_array_remove (class_init_callbacks, info);
345 if (info->name_space)
346 g_free (info->name_space);
354 mono_debugger_class_initialized (MonoClass *klass)
358 if (!class_init_callbacks)
362 for (i = 0; i < class_init_callbacks->len; i++) {
363 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
365 if (info->name_space && strcmp (info->name_space, klass->name_space))
367 if (strcmp (info->name, klass->name))
370 mono_debugger_event (MONO_DEBUGGER_EVENT_CLASS_INITIALIZED,
371 (guint64) (gsize) klass, info->index);
376 for (j = 0; j < klass->method.count; j++) {
377 if (klass->methods [j]->token != info->token)
380 mono_debugger_insert_method_breakpoint (klass->methods [j], info->index);
384 g_ptr_array_remove (class_init_callbacks, info);
385 if (info->name_space)
386 g_free (info->name_space);