2009-06-12 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mono / mini / debug-debugger.c
1 #include <config.h>
2 #include <mono/io-layer/io-layer.h>
3 #include <mono/metadata/threads.h>
4 #include <mono/metadata/assembly.h>
5 #include <mono/metadata/mono-debug.h>
6 #include <mono/metadata/mono-config.h>
7 #define _IN_THE_MONO_DEBUGGER
8 #include "debug-debugger.h"
9 #include "debug-mini.h"
10 #include <libgc/include/libgc-mono-debugger.h>
11 #include "mini.h"
12 #include <unistd.h>
13 #include <locale.h>
14 #include <string.h>
15
16 /*
17  * This file is only compiled on platforms where the debugger is supported - see the conditional
18  * definition of `debugger_sources' in Makefile.am.
19  *
20  * configure.in checks whether we're using the included libgc and disables the debugger if not.
21  */
22
23 #if !defined(MONO_DEBUGGER_SUPPORTED)
24 #error "Some clown tried to compile debug-debugger.c on an unsupported platform - fix Makefile.am!"
25 #elif !defined(USE_INCLUDED_LIBGC)
26 #error "Some clown #defined MONO_DEBUGGER_SUPPORTED without USE_INCLUDED_GC - fix configure.in!"
27 #endif
28
29 static guint64 debugger_compile_method (guint64 method_arg);
30 static guint64 debugger_get_virtual_method (guint64 class_arg, guint64 method_arg);
31 static guint64 debugger_get_boxed_object (guint64 klass_arg, guint64 val_arg);
32 static guint64 debugger_class_get_static_field_data (guint64 klass);
33
34 static guint64 debugger_run_finally (guint64 argument1, guint64 argument2);
35 static void debugger_initialize (void);
36 static guint64 debugger_init_code_buffer (void);
37
38 static void debugger_event_handler (MonoDebuggerEvent event, guint64 data, guint64 arg);
39
40 static guint64 debugger_create_string (G_GNUC_UNUSED guint64 dummy, G_GNUC_UNUSED guint64 dummy2,
41                                        G_GNUC_UNUSED guint64 dummy3, const gchar *string_argument);
42 static gint64 debugger_lookup_class (guint64 image_argument, G_GNUC_UNUSED guint64 dummy,
43                                      G_GNUC_UNUSED guint64 dummy2, gchar *full_name);
44 static guint64 debugger_insert_method_breakpoint (guint64 method_argument, guint64 index);
45 static guint64 debugger_insert_source_breakpoint (guint64 image_argument, guint64 token,
46                                                   guint64 index, const gchar *class_name);
47 static void debugger_remove_breakpoint (guint64 index, G_GNUC_UNUSED guint64 dummy);
48 static guint64 debugger_register_class_init_callback (guint64 image_argument, guint64 token,
49                                                       guint64 index, const gchar *class_name);
50 static void debugger_remove_class_init_callback (guint64 index, G_GNUC_UNUSED guint64 dummy);
51 static guint64 debugger_get_method_signature (guint64 argument1, G_GNUC_UNUSED guint64 argument2);
52
53 #define EXECUTABLE_CODE_BUFFER_SIZE 4096
54 static guint8 *debugger_executable_code_buffer = NULL;
55
56 static GCThreadFunctions debugger_thread_vtable;
57
58 static MonoDebuggerMetadataInfo debugger_metadata_info = {
59         sizeof (MonoDebuggerMetadataInfo),
60         sizeof (MonoDefaults),
61         &mono_defaults,
62         sizeof (MonoType),
63         sizeof (MonoArrayType),
64         sizeof (MonoClass),
65         sizeof (MonoThread),
66         G_STRUCT_OFFSET (MonoThread, tid),
67         G_STRUCT_OFFSET (MonoThread, stack_ptr),
68         G_STRUCT_OFFSET (MonoThread, end_stack),
69         G_STRUCT_OFFSET (MonoClass, image),
70         G_STRUCT_OFFSET (MonoClass, instance_size),
71         G_STRUCT_OFFSET (MonoClass, parent),
72         G_STRUCT_OFFSET (MonoClass, type_token),
73         G_STRUCT_OFFSET (MonoClass, fields),
74         G_STRUCT_OFFSET (MonoClass, methods),
75         G_STRUCT_OFFSET (MonoClass, method.count),
76         G_STRUCT_OFFSET (MonoClass, this_arg),
77         G_STRUCT_OFFSET (MonoClass, byval_arg),
78         G_STRUCT_OFFSET (MonoClass, generic_class),
79         G_STRUCT_OFFSET (MonoClass, generic_container),
80         G_STRUCT_OFFSET (MonoClass, vtable),
81         sizeof (MonoClassField),
82         G_STRUCT_OFFSET (MonoClassField, type),
83         G_STRUCT_OFFSET (MonoClassField, offset),
84         G_STRUCT_OFFSET (MonoDefaults, corlib),
85         G_STRUCT_OFFSET (MonoDefaults, object_class),
86         G_STRUCT_OFFSET (MonoDefaults, byte_class),
87         G_STRUCT_OFFSET (MonoDefaults, void_class),
88         G_STRUCT_OFFSET (MonoDefaults, boolean_class),
89         G_STRUCT_OFFSET (MonoDefaults, sbyte_class),
90         G_STRUCT_OFFSET (MonoDefaults, int16_class),
91         G_STRUCT_OFFSET (MonoDefaults, uint16_class),
92         G_STRUCT_OFFSET (MonoDefaults, int32_class),
93         G_STRUCT_OFFSET (MonoDefaults, uint32_class),
94         G_STRUCT_OFFSET (MonoDefaults, int_class),
95         G_STRUCT_OFFSET (MonoDefaults, uint_class),
96         G_STRUCT_OFFSET (MonoDefaults, int64_class),
97         G_STRUCT_OFFSET (MonoDefaults, uint64_class),
98         G_STRUCT_OFFSET (MonoDefaults, single_class),
99         G_STRUCT_OFFSET (MonoDefaults, double_class),
100         G_STRUCT_OFFSET (MonoDefaults, char_class),
101         G_STRUCT_OFFSET (MonoDefaults, string_class),
102         G_STRUCT_OFFSET (MonoDefaults, enum_class),
103         G_STRUCT_OFFSET (MonoDefaults, array_class),
104         G_STRUCT_OFFSET (MonoDefaults, delegate_class),
105         G_STRUCT_OFFSET (MonoDefaults, exception_class),
106         G_STRUCT_OFFSET (MonoMethod, klass),
107         G_STRUCT_OFFSET (MonoMethod, token),
108         G_STRUCT_OFFSET (MonoMethod, name) + sizeof (void *),
109         G_STRUCT_OFFSET (MonoMethodInflated, declaring),
110         G_STRUCT_OFFSET (MonoVTable, klass),
111         G_STRUCT_OFFSET (MonoVTable, vtable)
112 };
113
114 extern void MONO_DEBUGGER__notification_function (guint64 command, guint64 data, guint64 data2);
115
116 /*
117  * This is a global data symbol which is read by the debugger.
118  */
119 MonoDebuggerInfo MONO_DEBUGGER__debugger_info = {
120         MONO_DEBUGGER_MAGIC,
121         MONO_DEBUGGER_MAJOR_VERSION,
122         MONO_DEBUGGER_MINOR_VERSION,
123         0, /* dummy */
124         sizeof (MonoDebuggerInfo),
125         sizeof (MonoSymbolTable),
126         MONO_TRAMPOLINE_NUM,
127         mono_trampoline_code,
128         &MONO_DEBUGGER__notification_function,
129         &mono_symbol_table,
130         &debugger_metadata_info,
131         &mono_debug_debugger_version,
132
133         &debugger_compile_method,
134         &debugger_get_virtual_method,
135         &debugger_get_boxed_object,
136         &mono_debugger_runtime_invoke,
137         &debugger_class_get_static_field_data,
138         &debugger_run_finally,
139         &debugger_initialize,
140
141         &debugger_create_string,
142         &debugger_lookup_class,
143
144         &debugger_insert_method_breakpoint,
145         &debugger_insert_source_breakpoint,
146         &debugger_remove_breakpoint,
147
148         &debugger_register_class_init_callback,
149         &debugger_remove_class_init_callback,
150
151         &mono_debugger_thread_table,
152
153         &debugger_executable_code_buffer,
154         mono_breakpoint_info,
155         mono_breakpoint_info_index,
156
157         EXECUTABLE_CODE_BUFFER_SIZE,
158         MONO_BREAKPOINT_ARRAY_SIZE,
159
160         debugger_get_method_signature,
161         debugger_init_code_buffer,
162
163         &gc_thread_vtable,
164         &debugger_thread_vtable,
165
166         &mono_debugger_event_handler,
167         debugger_event_handler,
168
169         &_mono_debug_using_mono_debugger,
170         (gint32*)&_mono_debugger_interruption_request
171 };
172
173 static guint64
174 debugger_compile_method (guint64 method_arg)
175 {
176         MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg);
177         gpointer addr;
178
179         mono_debugger_lock ();
180         addr = mono_compile_method (method);
181         mono_debugger_unlock ();
182
183         return (guint64) (gsize) addr;
184 }
185
186 static guint64
187 debugger_get_virtual_method (guint64 object_arg, guint64 method_arg)
188 {
189         MonoObject *object = (MonoObject *) GUINT_TO_POINTER ((gsize) object_arg);
190         MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg);
191
192         if (mono_class_is_valuetype (mono_method_get_class (method)))
193                 return method_arg;
194
195         return (guint64) (gsize) mono_object_get_virtual_method (object, method);
196 }
197
198 static guint64
199 debugger_get_boxed_object (guint64 klass_arg, guint64 val_arg)
200 {
201         static MonoObject *last_boxed_object = NULL;
202         MonoClass *klass = (MonoClass *) GUINT_TO_POINTER ((gsize) klass_arg);
203         gpointer val = (gpointer) GUINT_TO_POINTER ((gsize) val_arg);
204         MonoObject *boxed;
205
206         if (!mono_class_is_valuetype (klass))
207                 return val_arg;
208
209         boxed = mono_value_box (mono_domain_get (), klass, val);
210         last_boxed_object = boxed; // Protect the object from being garbage collected
211
212         return (guint64) (gsize) boxed;
213 }
214
215 static guint64
216 debugger_create_string (G_GNUC_UNUSED guint64 dummy, G_GNUC_UNUSED guint64 dummy2,
217                         G_GNUC_UNUSED guint64 dummy3, const gchar *string_argument)
218 {
219         return (guint64) (gsize) mono_string_new_wrapper (string_argument);
220 }
221
222 static gint64
223 debugger_lookup_class (guint64 image_argument, G_GNUC_UNUSED guint64 dummy,
224                        G_GNUC_UNUSED guint64 dummy2, gchar *full_name)
225 {
226         MonoImage *image = (MonoImage *) GUINT_TO_POINTER ((gsize) image_argument);
227         gchar *name_space, *name, *pos;
228         MonoClass *klass;
229
230         pos = strrchr (full_name, '.');
231         if (pos) {
232                 name_space = full_name;
233                 *pos = 0;
234                 name = pos + 1;
235         } else {
236                 name = full_name;
237                 name_space = NULL;
238         }
239
240         klass = mono_class_from_name (image, name_space ? name_space : "", name);
241         if (!klass)
242                 return -1;
243
244         mono_class_init (klass);
245         mono_class_setup_methods (klass);
246         return (gint64) (gssize) klass;
247 }
248
249 static guint64
250 debugger_run_finally (guint64 context_argument, G_GNUC_UNUSED guint64 dummy)
251 {
252         mono_debugger_run_finally (GUINT_TO_POINTER ((gsize)context_argument));
253         return 0;
254 }
255
256 static guint64
257 debugger_class_get_static_field_data (guint64 value)
258 {
259         MonoClass *klass = GUINT_TO_POINTER ((gsize) value);
260         MonoVTable *vtable = mono_class_vtable (mono_domain_get (), klass);
261         return (guint64) (gsize) mono_vtable_get_static_field_data (vtable);
262 }
263
264 static guint64
265 debugger_insert_method_breakpoint (guint64 method_argument, guint64 index)
266 {
267         MonoMethod *method = GUINT_TO_POINTER ((gsize) method_argument);
268         MonoDebugMethodAddressList *info;
269
270         mono_debugger_lock ();
271
272         if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
273                 const char *name = method->name;
274                 MonoMethod *nm = NULL;
275
276                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
277                         if (*name == 'I' && (strcmp (name, "Invoke") == 0))
278                                 nm = mono_marshal_get_delegate_invoke (method, NULL);
279                         else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0))
280                                 nm = mono_marshal_get_delegate_begin_invoke (method);
281                         else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0))
282                                 nm = mono_marshal_get_delegate_end_invoke (method);
283                 }
284
285                 if (!nm) {
286                         mono_debugger_unlock ();
287                         return 0;
288                 }
289
290                 method = nm;
291         }
292
293         info = mono_debugger_insert_method_breakpoint (method, index);
294
295         mono_debugger_unlock ();
296         return (guint64) (gsize) info;
297 }
298
299 static guint64
300 debugger_insert_source_breakpoint (guint64 image_argument, guint64 token, guint64 index,
301                                    const gchar *class_name)
302 {
303         MonoImage *image = GUINT_TO_POINTER ((gsize) image_argument);
304         MonoDebugMethodAddressList *info;
305         MonoClass *klass;
306         int i;
307
308         mono_debugger_lock ();
309
310         klass = mono_debugger_register_class_init_callback (image, class_name, token, index);
311         if (!klass || !klass->inited || !klass->methods) {
312                 mono_debugger_unlock ();
313                 return 0;
314         }
315
316         for (i = 0; i < klass->method.count; i++) {
317                 MonoMethod *method = klass->methods [i];
318
319                 if (method->token != token)
320                         continue;
321
322                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
323                         const char *name = method->name;
324                         MonoMethod *nm = NULL;
325
326                         if (method->klass->parent == mono_defaults.multicastdelegate_class) {
327                                 if (*name == 'I' && (strcmp (name, "Invoke") == 0))
328                                         nm = mono_marshal_get_delegate_invoke (method, NULL);
329                                 else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0))
330                                         nm = mono_marshal_get_delegate_begin_invoke (method);
331                                 else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0))
332                                         nm = mono_marshal_get_delegate_end_invoke (method);
333                         }
334
335                         if (!nm) {
336                                 mono_debugger_unlock ();
337                                 return 0;
338                         }
339
340                         method = nm;
341                 }
342
343                 info = mono_debug_lookup_method_addresses (method);
344                 mono_debugger_unlock ();
345                 return (guint64) (gsize) info;
346         }
347
348         mono_debugger_unlock ();
349         return 0;
350 }
351
352 static void
353 debugger_remove_breakpoint (guint64 index, G_GNUC_UNUSED guint64 dummy)
354 {
355         mono_debugger_lock ();
356         mono_debugger_remove_method_breakpoint (index);
357         mono_debugger_remove_class_init_callback (index);
358         mono_debugger_unlock ();
359 }
360
361 static guint64
362 debugger_register_class_init_callback (guint64 image_argument, guint64 token, guint64 index,
363                                        const gchar *class_name)
364 {
365         MonoImage *image = GUINT_TO_POINTER ((gsize) image_argument);
366         MonoClass *klass;
367
368         mono_debugger_lock ();
369         klass = mono_debugger_register_class_init_callback (image, class_name, token, index);
370         mono_debugger_unlock ();
371         return (guint64) (gsize) klass;
372 }
373
374 static void
375 debugger_remove_class_init_callback (guint64 index, G_GNUC_UNUSED guint64 dummy)
376 {
377         mono_debugger_lock ();
378         mono_debugger_remove_class_init_callback (index);
379         mono_debugger_unlock ();
380 }
381
382 static guint64
383 debugger_get_method_signature (guint64 method_arg, G_GNUC_UNUSED guint64 dummy)
384 {
385         MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg);
386         MonoMethodSignature *sig;
387
388         sig = mono_method_signature (method);
389         return (guint64) (gsize) sig;
390 }
391
392 static void
393 debugger_event_handler (MonoDebuggerEvent event, guint64 data, guint64 arg)
394 {
395         MONO_DEBUGGER__notification_function (event, data, arg);
396 }
397
398 static void
399 debugger_gc_thread_created (pthread_t thread, void *stack_ptr)
400 {
401         mono_debugger_event (MONO_DEBUGGER_EVENT_GC_THREAD_CREATED,
402                              (guint64) (gsize) stack_ptr, thread);
403 }
404
405 static void
406 debugger_gc_thread_exited (pthread_t thread, void *stack_ptr)
407 {
408         mono_debugger_event (MONO_DEBUGGER_EVENT_GC_THREAD_EXITED,
409                              (guint64) (gsize) stack_ptr, thread);
410 }
411
412 static void
413 debugger_gc_stop_world (void)
414 {
415         mono_debugger_event (MONO_DEBUGGER_EVENT_ACQUIRE_GLOBAL_THREAD_LOCK, 0, 0);
416 }
417
418 static void
419 debugger_gc_start_world (void)
420 {
421         mono_debugger_event (MONO_DEBUGGER_EVENT_RELEASE_GLOBAL_THREAD_LOCK, 0, 0);
422 }
423
424 static GCThreadFunctions debugger_thread_vtable = {
425         NULL,
426
427         debugger_gc_thread_created,
428         debugger_gc_thread_exited,
429
430         debugger_gc_stop_world,
431         debugger_gc_start_world
432 };
433
434 static void
435 debugger_init_threads (void)
436 {
437         gc_thread_vtable = &debugger_thread_vtable;
438 }
439
440 #if 0
441
442 static void
443 debugger_finalize_threads (void)
444 {
445         gc_thread_vtable = NULL;
446 }
447
448 #endif
449
450 static guint64
451 debugger_init_code_buffer (void)
452 {
453         if (!debugger_executable_code_buffer)
454                 debugger_executable_code_buffer = mono_global_codeman_reserve (EXECUTABLE_CODE_BUFFER_SIZE);
455         return (guint64) (gsize) debugger_executable_code_buffer;
456 }
457
458 extern MonoDebuggerInfo *MONO_DEBUGGER__debugger_info_ptr;
459 extern long MONO_DEBUGGER__using_debugger;
460
461 static void
462 debugger_initialize (void)
463 {
464 }
465
466 /**
467  * Check whether we're running inside the debugger.
468  *
469  * There seems to be a bug in some versions of glibc which causes _dl_debug_state() being called with
470  * RT_CONSISTENT before relocations are done.
471  *
472  * If that happens, the debugger cannot read the `MONO_DEBUGGER__debugger_info' structure at the time
473  * the `libmono.so' library is loaded.
474  *
475  * As a workaround, the `mdb_debug_info' now also contains a global variable called
476  * `MONO_DEBUGGER__using_debugger' which may we set to 1 by the debugger to tell us that we're running
477  * inside the debugger.
478  *
479  * mini_init() checks this and calls mini_debugger_init() if necessary.
480  *
481  */
482
483 gboolean
484 mini_debug_running_inside_mdb (void)
485 {
486         return MONO_DEBUGGER__using_debugger || mono_debug_using_mono_debugger ();
487 }
488
489 void
490 mini_debugger_init (void)
491 {
492         if (mono_debugger_event_handler) {
493                 g_warning (G_STRLOC ": duplicate call to mono_debugger_init()!");
494                 return;
495         }
496
497         debugger_executable_code_buffer = mono_global_codeman_reserve (EXECUTABLE_CODE_BUFFER_SIZE);
498         mono_debugger_event_handler = debugger_event_handler;
499
500         /*
501          * Use an indirect call so gcc can't optimize it away.
502          */
503         MONO_DEBUGGER__debugger_info.initialize ();
504
505         debugger_init_threads ();
506
507         /*
508          * Initialize the thread manager.
509          *
510          * NOTE: We only reference the `MONO_DEBUGGER__debugger_info_ptr' here to prevent the
511          * linker from removing the .mdb_debug_info section.
512          */
513
514         mono_debugger_event (MONO_DEBUGGER_EVENT_INITIALIZE_THREAD_MANAGER,
515                              (guint64) (gssize) MONO_DEBUGGER__debugger_info_ptr, 0);
516 }
517
518 typedef struct 
519 {
520         MonoDomain *domain;
521         const char *file;
522 } DebuggerThreadArgs;
523
524 typedef struct
525 {
526         MonoDomain *domain;
527         MonoMethod *method;
528         int argc;
529         char **argv;
530 } MainThreadArgs;
531
532 static guint32
533 main_thread_handler (gpointer user_data)
534 {
535         MainThreadArgs *main_args = (MainThreadArgs *) user_data;
536
537         return mono_runtime_run_main (main_args->method, main_args->argc, main_args->argv, NULL);
538 }
539
540 int
541 mini_debugger_main (MonoDomain *domain, MonoAssembly *assembly, int argc, char **argv)
542 {
543         MainThreadArgs main_args;
544         MonoImage *image;
545         MonoMethod *main_method;
546
547         /*
548          * Get and compile the main function.
549          */
550
551         image = mono_assembly_get_image (assembly);
552         main_method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
553
554         /*
555          * Initialize managed code.
556          */
557         mono_debugger_event (MONO_DEBUGGER_EVENT_INITIALIZE_MANAGED_CODE,
558                              (guint64) (gssize) main_method, 0);
559
560         /*
561          * Start the main thread and wait until it's ready.
562          */
563
564         main_args.domain = domain;
565         main_args.method = main_method;
566         main_args.argc = argc;
567         main_args.argv = argv;
568
569 #if RUN_IN_SUBTHREAD
570         mono_thread_create (domain, main_thread_handler, &main_args);
571 #else
572         main_thread_handler (&main_args);
573 #endif
574
575         mono_thread_manage ();
576
577         /*
578          * This will never return.
579          */
580         mono_debugger_event (MONO_DEBUGGER_EVENT_WRAPPER_MAIN, 0, 0);
581
582         return 0;
583 }