2 * debug-debugger.c: Hard debugger support (mdb)
6 * Copyright 2006-2010 Novell, Inc.
8 #if MONO_DEBUGGER_SUPPORTED
11 #include <mono/io-layer/io-layer.h>
12 #include <mono/metadata/threads.h>
13 #include <mono/metadata/assembly.h>
14 #include <mono/metadata/mono-debug.h>
15 #include <mono/metadata/mono-config.h>
16 #define _IN_THE_MONO_DEBUGGER
17 #include "debug-debugger.h"
18 #include "debug-mini.h"
19 #include <libgc/include/libgc-mono-debugger.h>
26 * This file is only compiled on platforms where the debugger is supported - see the conditional
27 * definition of `debugger_sources' in Makefile.am.
29 * configure.in checks whether we're using the included libgc and disables the debugger if not.
32 #if !defined(USE_INCLUDED_LIBGC)
33 #error "Inconsistency detected: #defined MONO_DEBUGGER_SUPPORTED without USE_INCLUDED_GC - fix configure.in!"
36 static guint64 debugger_compile_method (guint64 method_arg);
37 static guint64 debugger_get_virtual_method (guint64 class_arg, guint64 method_arg);
38 static guint64 debugger_get_boxed_object (guint64 klass_arg, guint64 val_arg);
39 static guint64 debugger_class_get_static_field_data (guint64 klass);
41 static guint64 debugger_run_finally (guint64 argument1, guint64 argument2);
42 static void debugger_initialize (void);
43 static guint64 debugger_init_code_buffer (void);
45 static void debugger_event_handler (MonoDebuggerEvent event, guint64 data, guint64 arg);
47 static guint64 debugger_create_string (G_GNUC_UNUSED guint64 dummy, G_GNUC_UNUSED guint64 dummy2,
48 G_GNUC_UNUSED guint64 dummy3, const gchar *string_argument);
49 static gint64 debugger_lookup_class (guint64 image_argument, G_GNUC_UNUSED guint64 dummy,
50 G_GNUC_UNUSED guint64 dummy2, gchar *full_name);
51 static guint64 debugger_insert_method_breakpoint (guint64 method_argument, guint64 index);
52 static guint64 debugger_insert_source_breakpoint (guint64 image_argument, guint64 token,
53 guint64 index, const gchar *class_name);
54 static void debugger_remove_breakpoint (guint64 index, G_GNUC_UNUSED guint64 dummy);
55 static guint64 debugger_register_class_init_callback (guint64 image_argument, guint64 token,
56 guint64 index, const gchar *class_name);
57 static void debugger_remove_class_init_callback (guint64 index, G_GNUC_UNUSED guint64 dummy);
58 static guint64 debugger_get_method_signature (guint64 argument1, G_GNUC_UNUSED guint64 argument2);
60 static guint64 debugger_abort_runtime_invoke (G_GNUC_UNUSED guint64 dummy1, G_GNUC_UNUSED guint64 dummy2);
62 #define EXECUTABLE_CODE_BUFFER_SIZE 4096
63 static guint8 *debugger_executable_code_buffer = NULL;
65 static GCThreadFunctions debugger_thread_vtable;
67 static guint32 debugger_thread_abort_signal = 0;
69 static MonoDebuggerMetadataInfo debugger_metadata_info = {
70 sizeof (MonoDebuggerMetadataInfo),
71 sizeof (MonoDefaults),
74 sizeof (MonoArrayType),
76 sizeof (MonoInternalThread),
77 G_STRUCT_OFFSET (MonoInternalThread, tid),
78 G_STRUCT_OFFSET (MonoInternalThread, stack_ptr),
79 G_STRUCT_OFFSET (MonoInternalThread, end_stack),
80 G_STRUCT_OFFSET (MonoClass, image),
81 G_STRUCT_OFFSET (MonoClass, instance_size),
82 G_STRUCT_OFFSET (MonoClass, parent),
83 G_STRUCT_OFFSET (MonoClass, type_token),
84 G_STRUCT_OFFSET (MonoClass, fields),
85 G_STRUCT_OFFSET (MonoClass, methods),
86 G_STRUCT_OFFSET (MonoClass, method.count),
87 G_STRUCT_OFFSET (MonoClass, this_arg),
88 G_STRUCT_OFFSET (MonoClass, byval_arg),
89 G_STRUCT_OFFSET (MonoClass, generic_class),
90 G_STRUCT_OFFSET (MonoClass, generic_container),
91 G_STRUCT_OFFSET (MonoClass, vtable),
92 sizeof (MonoClassField),
93 G_STRUCT_OFFSET (MonoClassField, type),
94 G_STRUCT_OFFSET (MonoClassField, offset),
95 G_STRUCT_OFFSET (MonoDefaults, corlib),
96 G_STRUCT_OFFSET (MonoDefaults, object_class),
97 G_STRUCT_OFFSET (MonoDefaults, byte_class),
98 G_STRUCT_OFFSET (MonoDefaults, void_class),
99 G_STRUCT_OFFSET (MonoDefaults, boolean_class),
100 G_STRUCT_OFFSET (MonoDefaults, sbyte_class),
101 G_STRUCT_OFFSET (MonoDefaults, int16_class),
102 G_STRUCT_OFFSET (MonoDefaults, uint16_class),
103 G_STRUCT_OFFSET (MonoDefaults, int32_class),
104 G_STRUCT_OFFSET (MonoDefaults, uint32_class),
105 G_STRUCT_OFFSET (MonoDefaults, int_class),
106 G_STRUCT_OFFSET (MonoDefaults, uint_class),
107 G_STRUCT_OFFSET (MonoDefaults, int64_class),
108 G_STRUCT_OFFSET (MonoDefaults, uint64_class),
109 G_STRUCT_OFFSET (MonoDefaults, single_class),
110 G_STRUCT_OFFSET (MonoDefaults, double_class),
111 G_STRUCT_OFFSET (MonoDefaults, char_class),
112 G_STRUCT_OFFSET (MonoDefaults, string_class),
113 G_STRUCT_OFFSET (MonoDefaults, enum_class),
114 G_STRUCT_OFFSET (MonoDefaults, array_class),
115 G_STRUCT_OFFSET (MonoDefaults, delegate_class),
116 G_STRUCT_OFFSET (MonoDefaults, exception_class),
117 G_STRUCT_OFFSET (MonoMethod, klass),
118 G_STRUCT_OFFSET (MonoMethod, token),
119 G_STRUCT_OFFSET (MonoMethod, name) + sizeof (void *),
120 G_STRUCT_OFFSET (MonoMethodInflated, declaring),
121 G_STRUCT_OFFSET (MonoVTable, klass),
122 G_STRUCT_OFFSET (MonoVTable, vtable)
125 extern void MONO_DEBUGGER__notification_function (guint64 command, guint64 data, guint64 data2);
128 * This is a global data symbol which is read by the debugger.
130 MonoDebuggerInfo MONO_DEBUGGER__debugger_info = {
132 MONO_DEBUGGER_MAJOR_VERSION,
133 MONO_DEBUGGER_MINOR_VERSION,
134 0, /* runtime_flags */
135 sizeof (MonoDebuggerInfo),
136 sizeof (MonoSymbolTable),
138 mono_trampoline_code,
139 &MONO_DEBUGGER__notification_function,
141 &debugger_metadata_info,
142 &mono_debug_debugger_version,
144 &debugger_compile_method,
145 &debugger_get_virtual_method,
146 &debugger_get_boxed_object,
147 &mono_debugger_runtime_invoke,
148 &debugger_class_get_static_field_data,
149 &debugger_run_finally,
150 &debugger_initialize,
152 &debugger_create_string,
153 &debugger_lookup_class,
155 &debugger_insert_method_breakpoint,
156 &debugger_insert_source_breakpoint,
157 &debugger_remove_breakpoint,
159 &debugger_register_class_init_callback,
160 &debugger_remove_class_init_callback,
162 &mono_debugger_thread_table,
164 &debugger_executable_code_buffer,
165 mono_breakpoint_info,
166 mono_breakpoint_info_index,
168 EXECUTABLE_CODE_BUFFER_SIZE,
169 MONO_BREAKPOINT_ARRAY_SIZE,
171 debugger_get_method_signature,
172 debugger_init_code_buffer,
175 &debugger_thread_vtable,
177 &mono_debugger_event_handler,
178 debugger_event_handler,
180 &_mono_debug_using_mono_debugger,
181 (gint32*)&_mono_debugger_interruption_request,
183 &debugger_abort_runtime_invoke,
185 &debugger_thread_abort_signal
189 debugger_abort_runtime_invoke (G_GNUC_UNUSED guint64 dummy1, G_GNUC_UNUSED guint64 dummy2)
191 return mono_debugger_abort_runtime_invoke ();
195 debugger_compile_method (guint64 method_arg)
197 MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg);
200 mono_debugger_lock ();
201 addr = mono_compile_method (method);
202 mono_debugger_unlock ();
204 return (guint64) (gsize) addr;
208 debugger_get_virtual_method (guint64 object_arg, guint64 method_arg)
210 MonoObject *object = (MonoObject *) GUINT_TO_POINTER ((gsize) object_arg);
211 MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg);
213 if (mono_class_is_valuetype (mono_method_get_class (method)))
216 return (guint64) (gsize) mono_object_get_virtual_method (object, method);
220 debugger_get_boxed_object (guint64 klass_arg, guint64 val_arg)
222 static MonoObject *last_boxed_object = NULL;
223 MonoClass *klass = (MonoClass *) GUINT_TO_POINTER ((gsize) klass_arg);
224 gpointer val = (gpointer) GUINT_TO_POINTER ((gsize) val_arg);
227 if (!mono_class_is_valuetype (klass))
230 boxed = mono_value_box (mono_domain_get (), klass, val);
231 last_boxed_object = boxed; // Protect the object from being garbage collected
233 return (guint64) (gsize) boxed;
237 debugger_create_string (G_GNUC_UNUSED guint64 dummy, G_GNUC_UNUSED guint64 dummy2,
238 G_GNUC_UNUSED guint64 dummy3, const gchar *string_argument)
240 return (guint64) (gsize) mono_string_new_wrapper (string_argument);
244 debugger_lookup_class (guint64 image_argument, G_GNUC_UNUSED guint64 dummy,
245 G_GNUC_UNUSED guint64 dummy2, gchar *full_name)
247 MonoImage *image = (MonoImage *) GUINT_TO_POINTER ((gsize) image_argument);
248 gchar *name_space, *name, *pos;
251 pos = strrchr (full_name, '.');
253 name_space = full_name;
261 klass = mono_class_from_name (image, name_space ? name_space : "", name);
265 mono_class_init (klass);
266 mono_class_setup_methods (klass);
267 return (gint64) (gssize) klass;
271 debugger_run_finally (guint64 context_argument, G_GNUC_UNUSED guint64 dummy)
273 mono_debugger_run_finally (GUINT_TO_POINTER ((gsize)context_argument));
278 debugger_class_get_static_field_data (guint64 value)
280 MonoClass *klass = GUINT_TO_POINTER ((gsize) value);
281 MonoVTable *vtable = mono_class_vtable (mono_domain_get (), klass);
282 return (guint64) (gsize) mono_vtable_get_static_field_data (vtable);
286 debugger_insert_method_breakpoint (guint64 method_argument, guint64 index)
288 MonoMethod *method = GUINT_TO_POINTER ((gsize) method_argument);
289 MonoDebugMethodAddressList *info;
291 mono_debugger_lock ();
293 if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
294 const char *name = method->name;
295 MonoMethod *nm = NULL;
297 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
298 if (*name == 'I' && (strcmp (name, "Invoke") == 0))
299 nm = mono_marshal_get_delegate_invoke (method, NULL);
300 else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0))
301 nm = mono_marshal_get_delegate_begin_invoke (method);
302 else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0))
303 nm = mono_marshal_get_delegate_end_invoke (method);
307 mono_debugger_unlock ();
314 info = mono_debugger_insert_method_breakpoint (method, index);
316 mono_debugger_unlock ();
317 return (guint64) (gsize) info;
321 debugger_insert_source_breakpoint (guint64 image_argument, guint64 token, guint64 index,
322 const gchar *class_name)
324 MonoImage *image = GUINT_TO_POINTER ((gsize) image_argument);
325 MonoDebugMethodAddressList *info;
329 mono_debugger_lock ();
331 klass = mono_debugger_register_class_init_callback (image, class_name, token, index);
332 if (!klass || !klass->inited || !klass->methods) {
333 mono_debugger_unlock ();
337 for (i = 0; i < klass->method.count; i++) {
338 MonoMethod *method = klass->methods [i];
340 if (method->token != token)
343 if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
344 const char *name = method->name;
345 MonoMethod *nm = NULL;
347 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
348 if (*name == 'I' && (strcmp (name, "Invoke") == 0))
349 nm = mono_marshal_get_delegate_invoke (method, NULL);
350 else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0))
351 nm = mono_marshal_get_delegate_begin_invoke (method);
352 else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0))
353 nm = mono_marshal_get_delegate_end_invoke (method);
357 mono_debugger_unlock ();
364 info = mono_debug_lookup_method_addresses (method);
365 mono_debugger_unlock ();
366 return (guint64) (gsize) info;
369 mono_debugger_unlock ();
374 debugger_remove_breakpoint (guint64 index, G_GNUC_UNUSED guint64 dummy)
376 mono_debugger_lock ();
377 mono_debugger_remove_method_breakpoint (index);
378 mono_debugger_remove_class_init_callback (index);
379 mono_debugger_unlock ();
383 debugger_register_class_init_callback (guint64 image_argument, guint64 token, guint64 index,
384 const gchar *class_name)
386 MonoImage *image = GUINT_TO_POINTER ((gsize) image_argument);
389 mono_debugger_lock ();
390 klass = mono_debugger_register_class_init_callback (image, class_name, token, index);
391 mono_debugger_unlock ();
392 return (guint64) (gsize) klass;
396 debugger_remove_class_init_callback (guint64 index, G_GNUC_UNUSED guint64 dummy)
398 mono_debugger_lock ();
399 mono_debugger_remove_class_init_callback (index);
400 mono_debugger_unlock ();
404 debugger_get_method_signature (guint64 method_arg, G_GNUC_UNUSED guint64 dummy)
406 MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg);
407 MonoMethodSignature *sig;
409 sig = mono_method_signature (method);
410 return (guint64) (gsize) sig;
414 debugger_event_handler (MonoDebuggerEvent event, guint64 data, guint64 arg)
416 MONO_DEBUGGER__notification_function (event, data, arg);
420 debugger_gc_thread_created (pthread_t thread, void *stack_ptr)
422 mono_debugger_event (MONO_DEBUGGER_EVENT_GC_THREAD_CREATED,
423 (guint64) (gsize) stack_ptr, thread);
427 debugger_gc_thread_exited (pthread_t thread, void *stack_ptr)
429 mono_debugger_event (MONO_DEBUGGER_EVENT_GC_THREAD_EXITED,
430 (guint64) (gsize) stack_ptr, thread);
434 debugger_gc_stop_world (void)
436 mono_debugger_event (MONO_DEBUGGER_EVENT_ACQUIRE_GLOBAL_THREAD_LOCK, 0, 0);
440 debugger_gc_start_world (void)
442 mono_debugger_event (MONO_DEBUGGER_EVENT_RELEASE_GLOBAL_THREAD_LOCK, 0, 0);
445 static GCThreadFunctions debugger_thread_vtable = {
448 debugger_gc_thread_created,
449 debugger_gc_thread_exited,
451 debugger_gc_stop_world,
452 debugger_gc_start_world
456 debugger_init_threads (void)
458 gc_thread_vtable = &debugger_thread_vtable;
464 debugger_finalize_threads (void)
466 gc_thread_vtable = NULL;
472 debugger_init_code_buffer (void)
474 if (!debugger_executable_code_buffer)
475 debugger_executable_code_buffer = mono_global_codeman_reserve (EXECUTABLE_CODE_BUFFER_SIZE);
476 return (guint64) (gsize) debugger_executable_code_buffer;
479 extern MonoDebuggerInfo *MONO_DEBUGGER__debugger_info_ptr;
480 extern long MONO_DEBUGGER__using_debugger;
483 debugger_initialize (void)
488 * Check whether we're running inside the debugger.
490 * There seems to be a bug in some versions of glibc which causes _dl_debug_state() being called with
491 * RT_CONSISTENT before relocations are done.
493 * If that happens, the debugger cannot read the `MONO_DEBUGGER__debugger_info' structure at the time
494 * the `libmono.so' library is loaded.
496 * As a workaround, the `mdb_debug_info' now also contains a global variable called
497 * `MONO_DEBUGGER__using_debugger' which may we set to 1 by the debugger to tell us that we're running
498 * inside the debugger.
500 * mini_init() checks this and calls mini_debugger_init() if necessary.
505 mini_debug_running_inside_mdb (void)
507 return MONO_DEBUGGER__using_debugger || mono_debug_using_mono_debugger ();
511 mini_debugger_init (void)
513 if (mono_debugger_event_handler) {
514 g_warning (G_STRLOC ": duplicate call to mono_debugger_init()!");
518 debugger_executable_code_buffer = mono_global_codeman_reserve (EXECUTABLE_CODE_BUFFER_SIZE);
519 mono_debugger_event_handler = debugger_event_handler;
521 debugger_thread_abort_signal = mono_thread_get_abort_signal ();
524 * Use an indirect call so gcc can't optimize it away.
526 MONO_DEBUGGER__debugger_info.initialize ();
528 debugger_init_threads ();
531 * Initialize the thread manager.
533 * NOTE: We only reference the `MONO_DEBUGGER__debugger_info_ptr' here to prevent the
534 * linker from removing the .mdb_debug_info section.
537 mono_debugger_event (MONO_DEBUGGER_EVENT_INITIALIZE_THREAD_MANAGER,
538 (guint64) (gssize) MONO_DEBUGGER__debugger_info_ptr, 0);
542 mini_debugger_set_attach_ok (void)
544 debugger_thread_abort_signal = mono_thread_get_abort_signal ();
545 MONO_DEBUGGER__debugger_info.runtime_flags |= DEBUGGER_RUNTIME_FLAGS_ATTACH_OK;
552 } DebuggerThreadArgs;
563 main_thread_handler (gpointer user_data)
565 MainThreadArgs *main_args = (MainThreadArgs *) user_data;
567 return mono_runtime_run_main (main_args->method, main_args->argc, main_args->argv, NULL);
571 mini_debugger_main (MonoDomain *domain, MonoAssembly *assembly, int argc, char **argv)
573 MainThreadArgs main_args;
575 MonoMethod *main_method;
578 * Get and compile the main function.
581 image = mono_assembly_get_image (assembly);
582 main_method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
585 * Initialize managed code.
587 mono_debugger_event (MONO_DEBUGGER_EVENT_INITIALIZE_MANAGED_CODE,
588 (guint64) (gssize) main_method, 0);
591 * Start the main thread and wait until it's ready.
594 main_args.domain = domain;
595 main_args.method = main_method;
596 main_args.argc = argc;
597 main_args.argv = argv;
600 mono_thread_create (domain, main_thread_handler, &main_args);
602 main_thread_handler (&main_args);
605 mono_thread_manage ();
608 * This will never return.
610 mono_debugger_event (MONO_DEBUGGER_EVENT_WRAPPER_MAIN, 0, 0);
614 #endif /* MONO_DEBUGGER_SUPPORTED */