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 must_reload_symtabs = FALSE;
22 static gboolean mono_debugger_use_debugger = FALSE;
23 static MonoObject *last_exception = NULL;
25 void (*mono_debugger_event_handler) (MonoDebuggerEvent event, guint64 data, guint64 arg) = NULL;
27 #define WRITE_UINT32(ptr,value) G_STMT_START { \
28 * ((guint32 *) ptr) = value; \
32 #define WRITE_POINTER(ptr,value) G_STMT_START { \
33 * ((gpointer *) ptr) = (gpointer) (value); \
34 ptr += sizeof (gpointer); \
37 #define WRITE_STRING(ptr,value) G_STMT_START { \
38 memcpy (ptr, value, strlen (value)+1); \
39 ptr += strlen (value)+1; \
43 gpointer stack_pointer;
44 MonoObject *exception_obj;
46 } MonoDebuggerExceptionInfo;
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 if (debugger_lock_level == 1) {
63 if (must_reload_symtabs && mono_debugger_use_debugger) {
64 mono_debugger_event (MONO_DEBUGGER_EVENT_RELOAD_SYMTABS, 0, 0);
65 must_reload_symtabs = FALSE;
69 debugger_lock_level--;
70 LeaveCriticalSection (&debugger_lock_mutex);
74 mono_debugger_initialize (gboolean use_debugger)
76 MONO_GC_REGISTER_ROOT (last_exception);
78 g_assert (!mono_debugger_use_debugger);
80 InitializeCriticalSection (&debugger_lock_mutex);
81 mono_debugger_use_debugger = use_debugger;
86 mono_debugger_add_symbol_file (MonoDebugHandle *handle)
88 g_assert (mono_debugger_use_debugger);
90 mono_debugger_lock ();
91 mono_debugger_event (MONO_DEBUGGER_EVENT_ADD_MODULE, (guint64) (gsize) handle, 0);
92 mono_debugger_unlock ();
96 mono_debugger_start_add_type (MonoDebugHandle *symfile, MonoClass *klass)
98 must_reload_symtabs = TRUE;
102 mono_debugger_event (MonoDebuggerEvent event, guint64 data, guint64 arg)
104 if (mono_debugger_event_handler)
105 (* mono_debugger_event_handler) (event, data, arg);
109 mono_debugger_cleanup (void)
111 mono_debugger_event (MONO_DEBUGGER_EVENT_FINALIZE_MANAGED_CODE, 0, 0);
112 mono_debugger_event_handler = NULL;
116 * Debugger breakpoint interface.
118 * This interface is used to insert breakpoints on methods which are not yet JITed.
119 * The debugging code keeps a list of all such breakpoints and automatically inserts the
120 * breakpoint when the method is JITed.
123 static GPtrArray *breakpoints = NULL;
126 mono_debugger_insert_breakpoint_full (MonoMethodDesc *desc)
128 static int last_breakpoint_id = 0;
129 MonoDebuggerBreakpointInfo *info;
131 info = g_new0 (MonoDebuggerBreakpointInfo, 1);
133 info->index = ++last_breakpoint_id;
136 breakpoints = g_ptr_array_new ();
138 g_ptr_array_add (breakpoints, info);
144 mono_debugger_remove_breakpoint (int breakpoint_id)
151 for (i = 0; i < breakpoints->len; i++) {
152 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
154 if (info->index != breakpoint_id)
157 mono_method_desc_free (info->desc);
158 g_ptr_array_remove (breakpoints, info);
167 mono_debugger_insert_breakpoint (const gchar *method_name, gboolean include_namespace)
169 MonoMethodDesc *desc;
171 desc = mono_method_desc_new (method_name, include_namespace);
175 return mono_debugger_insert_breakpoint_full (desc);
179 mono_debugger_method_has_breakpoint (MonoMethod *method)
183 if (!breakpoints || (method->wrapper_type != MONO_WRAPPER_NONE))
186 for (i = 0; i < breakpoints->len; i++) {
187 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
189 if (!mono_method_desc_full_match (info->desc, method))
199 mono_debugger_breakpoint_callback (MonoMethod *method, guint32 index)
201 mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT, (guint64) (gsize) method, index);
205 mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc)
209 if (!mono_debugger_use_debugger)
212 // Prevent the object from being finalized.
213 last_exception = exc;
215 name = mono_class_get_name (mono_object_get_class (exc));
216 if (!strcmp (name, "ThreadAbortException")) {
217 MonoThread *thread = mono_thread_current ();
218 mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_ABORT, 0, thread->tid);
222 mono_debugger_event (MONO_DEBUGGER_EVENT_UNHANDLED_EXCEPTION,
223 (guint64) (gsize) exc, (guint64) (gsize) addr);
228 mono_debugger_handle_exception (gpointer addr, gpointer stack, MonoObject *exc)
230 MonoDebuggerExceptionInfo info;
232 if (!mono_debugger_use_debugger)
235 // Prevent the object from being finalized.
236 last_exception = exc;
238 info.stack_pointer = stack;
239 info.exception_obj = exc;
242 mono_debugger_event (MONO_DEBUGGER_EVENT_HANDLE_EXCEPTION, (guint64) (gsize) &info,
243 (guint64) (gsize) addr);
247 mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc)
249 MonoDebuggerExceptionInfo info;
251 if (!mono_debugger_use_debugger)
254 // Prevent the object from being finalized.
255 last_exception = exc;
257 info.stack_pointer = stack;
258 info.exception_obj = exc;
261 mono_debugger_event (MONO_DEBUGGER_EVENT_THROW_EXCEPTION, (guint64) (gsize) &info,
262 (guint64) (gsize) addr);
263 return info.stop != 0;
267 get_exception_message (MonoObject *exc)
269 char *message = NULL;
275 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
276 klass = exc->vtable->klass;
278 while (klass && method == NULL) {
279 for (i = 0; i < klass->method.count; ++i) {
280 method = klass->methods [i];
281 if (!strcmp ("ToString", method->name) &&
282 mono_method_signature (method)->param_count == 0 &&
283 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
284 method->flags & METHOD_ATTRIBUTE_PUBLIC) {
291 klass = klass->parent;
296 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
298 message = mono_string_to_utf8 (str);
305 mono_debugger_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
310 if (!strcmp (method->name, ".ctor")) {
311 retval = obj = mono_object_new (mono_domain_get (), method->klass);
313 mono_runtime_invoke (method, obj, params, exc);
315 retval = mono_runtime_invoke (method, obj, params, exc);
317 if (!exc || (*exc == NULL))
320 message = get_exception_message (*exc);
322 *exc = (MonoObject *) mono_string_new_wrapper (message);
330 mono_debugger_lookup_type (const gchar *type_name)
333 mono_debugger_lock ();
335 for (i = 0; i < mono_symbol_table->num_symbol_files; i++) {
336 MonoDebugHandle *symfile = mono_symbol_table->symbol_files [i];
341 name = g_strdup (type_name);
342 type = mono_reflection_type_from_name (name, symfile->image);
347 klass = mono_class_from_mono_type (type);
349 mono_class_init (klass);
351 mono_debugger_unlock ();
355 mono_debugger_unlock ();
360 mono_debugger_lookup_assembly (const gchar *name)
362 MonoAssembly *assembly;
363 MonoImageOpenStatus status;
366 mono_debugger_lock ();
369 for (i = 0; i < mono_symbol_table->num_symbol_files; i++) {
370 MonoDebugHandle *symfile = mono_symbol_table->symbol_files [i];
372 if (!strcmp (symfile->image_file, name)) {
373 mono_debugger_unlock ();
378 assembly = mono_assembly_open (name, &status);
380 if (status != MONO_IMAGE_OK) {
381 g_warning (G_STRLOC ": Cannot open image `%s'", name);
382 mono_debugger_unlock ();
386 must_reload_symtabs = TRUE;