2007-11-20 Martin Baulig <martin@ximian.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_attach (void);
36 static void debugger_detach (void);
37 static void debugger_initialize (void);
38
39 static guint64 debugger_create_string (G_GNUC_UNUSED guint64 dummy, G_GNUC_UNUSED guint64 dummy2,
40                                        G_GNUC_UNUSED guint64 dummy3, const gchar *string_argument);
41 static gint64 debugger_lookup_class (guint64 image_argument, G_GNUC_UNUSED guint64 dummy,
42                                      G_GNUC_UNUSED guint64 dummy2, gchar *full_name);
43 static guint64 debugger_insert_method_breakpoint (guint64 method_argument, guint64 index);
44 static guint64 debugger_insert_source_breakpoint (guint64 image_argument, guint64 token,
45                                                   guint64 index, const gchar *class_name);
46 static void debugger_remove_breakpoint (guint64 index, G_GNUC_UNUSED guint64 dummy);
47 static guint64 debugger_register_class_init_callback (guint64 image_argument, guint64 token,
48                                                       guint64 index, const gchar *class_name);
49 static void debugger_remove_class_init_callback (guint64 index, G_GNUC_UNUSED guint64 dummy);
50
51 static void (*mono_debugger_notification_function) (guint64 command, guint64 data, guint64 data2);
52
53 #define EXECUTABLE_CODE_BUFFER_SIZE 4096
54 static guint8 *debugger_executable_code_buffer = NULL;
55
56 static MonoDebuggerMetadataInfo debugger_metadata_info = {
57         sizeof (MonoDebuggerMetadataInfo),
58         sizeof (MonoDefaults),
59         &mono_defaults,
60         sizeof (MonoType),
61         sizeof (MonoArrayType),
62         sizeof (MonoClass),
63         sizeof (MonoThread),
64         G_STRUCT_OFFSET (MonoThread, tid),
65         G_STRUCT_OFFSET (MonoThread, stack_ptr),
66         G_STRUCT_OFFSET (MonoThread, end_stack),
67         G_STRUCT_OFFSET (MonoClass, image),
68         G_STRUCT_OFFSET (MonoClass, instance_size),
69         G_STRUCT_OFFSET (MonoClass, parent),
70         G_STRUCT_OFFSET (MonoClass, type_token),
71         G_STRUCT_OFFSET (MonoClass, fields),
72         G_STRUCT_OFFSET (MonoClass, methods),
73         G_STRUCT_OFFSET (MonoClass, method.count),
74         G_STRUCT_OFFSET (MonoClass, this_arg),
75         G_STRUCT_OFFSET (MonoClass, byval_arg),
76         G_STRUCT_OFFSET (MonoClass, generic_class),
77         G_STRUCT_OFFSET (MonoClass, generic_container),
78         G_STRUCT_OFFSET (MonoClass, vtable),
79         sizeof (MonoClassField),
80         G_STRUCT_OFFSET (MonoClassField, type),
81         G_STRUCT_OFFSET (MonoClassField, offset),
82         G_STRUCT_OFFSET (MonoDefaults, corlib),
83         G_STRUCT_OFFSET (MonoDefaults, object_class),
84         G_STRUCT_OFFSET (MonoDefaults, byte_class),
85         G_STRUCT_OFFSET (MonoDefaults, void_class),
86         G_STRUCT_OFFSET (MonoDefaults, boolean_class),
87         G_STRUCT_OFFSET (MonoDefaults, sbyte_class),
88         G_STRUCT_OFFSET (MonoDefaults, int16_class),
89         G_STRUCT_OFFSET (MonoDefaults, uint16_class),
90         G_STRUCT_OFFSET (MonoDefaults, int32_class),
91         G_STRUCT_OFFSET (MonoDefaults, uint32_class),
92         G_STRUCT_OFFSET (MonoDefaults, int_class),
93         G_STRUCT_OFFSET (MonoDefaults, uint_class),
94         G_STRUCT_OFFSET (MonoDefaults, int64_class),
95         G_STRUCT_OFFSET (MonoDefaults, uint64_class),
96         G_STRUCT_OFFSET (MonoDefaults, single_class),
97         G_STRUCT_OFFSET (MonoDefaults, double_class),
98         G_STRUCT_OFFSET (MonoDefaults, char_class),
99         G_STRUCT_OFFSET (MonoDefaults, string_class),
100         G_STRUCT_OFFSET (MonoDefaults, enum_class),
101         G_STRUCT_OFFSET (MonoDefaults, array_class),
102         G_STRUCT_OFFSET (MonoDefaults, delegate_class),
103         G_STRUCT_OFFSET (MonoDefaults, exception_class),
104         G_STRUCT_OFFSET (MonoMethod, klass),
105         G_STRUCT_OFFSET (MonoMethod, token),
106         G_STRUCT_OFFSET (MonoMethod, name) + sizeof (void *),
107         G_STRUCT_OFFSET (MonoMethodInflated, declaring),
108         G_STRUCT_OFFSET (MonoVTable, klass),
109         G_STRUCT_OFFSET (MonoVTable, vtable)
110 };
111
112 /*
113  * This is a global data symbol which is read by the debugger.
114  */
115 MonoDebuggerInfo MONO_DEBUGGER__debugger_info = {
116         MONO_DEBUGGER_MAGIC,
117         MONO_DEBUGGER_VERSION,
118         sizeof (MonoDebuggerInfo),
119         sizeof (MonoSymbolTable),
120         MONO_TRAMPOLINE_NUM,
121         mono_trampoline_code,
122         &mono_debugger_notification_function,
123         &mono_symbol_table,
124         &debugger_metadata_info,
125         &debugger_compile_method,
126         &debugger_get_virtual_method,
127         &debugger_get_boxed_object,
128         &mono_debugger_runtime_invoke,
129         &debugger_class_get_static_field_data,
130         &debugger_run_finally,
131         &debugger_attach,
132         &debugger_detach,
133         &debugger_initialize,
134         (void*)&mono_get_lmf_addr,
135
136         &debugger_create_string,
137         &debugger_lookup_class,
138
139         &debugger_insert_method_breakpoint,
140         &debugger_insert_source_breakpoint,
141         &debugger_remove_breakpoint,
142
143         &debugger_register_class_init_callback,
144         &debugger_remove_class_init_callback,
145
146         &mono_debug_debugger_version,
147         &mono_debugger_thread_table,
148
149         &debugger_executable_code_buffer,
150         mono_breakpoint_info,
151         mono_breakpoint_info_index,
152
153         EXECUTABLE_CODE_BUFFER_SIZE,
154         MONO_BREAKPOINT_ARRAY_SIZE
155 };
156
157 static guint64
158 debugger_compile_method (guint64 method_arg)
159 {
160         MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg);
161         gpointer addr;
162
163         mono_debugger_lock ();
164         addr = mono_compile_method (method);
165         mono_debugger_unlock ();
166
167         return (guint64) (gsize) addr;
168 }
169
170 static guint64
171 debugger_get_virtual_method (guint64 object_arg, guint64 method_arg)
172 {
173         MonoObject *object = (MonoObject *) GUINT_TO_POINTER ((gsize) object_arg);
174         MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg);
175
176         if (mono_class_is_valuetype (mono_method_get_class (method)))
177                 return method_arg;
178
179         return (guint64) (gsize) mono_object_get_virtual_method (object, method);
180 }
181
182 static guint64
183 debugger_get_boxed_object (guint64 klass_arg, guint64 val_arg)
184 {
185         static MonoObject *last_boxed_object = NULL;
186         MonoClass *klass = (MonoClass *) GUINT_TO_POINTER ((gsize) klass_arg);
187         gpointer val = (gpointer) GUINT_TO_POINTER ((gsize) val_arg);
188         MonoObject *boxed;
189
190         if (!mono_class_is_valuetype (klass))
191                 return val_arg;
192
193         boxed = mono_value_box (mono_domain_get (), klass, val);
194         last_boxed_object = boxed; // Protect the object from being garbage collected
195
196         return (guint64) (gsize) boxed;
197 }
198
199 static guint64
200 debugger_create_string (G_GNUC_UNUSED guint64 dummy, G_GNUC_UNUSED guint64 dummy2,
201                         G_GNUC_UNUSED guint64 dummy3, const gchar *string_argument)
202 {
203         return (guint64) (gsize) mono_string_new_wrapper (string_argument);
204 }
205
206 static gint64
207 debugger_lookup_class (guint64 image_argument, G_GNUC_UNUSED guint64 dummy,
208                        G_GNUC_UNUSED guint64 dummy2, gchar *full_name)
209 {
210         MonoImage *image = (MonoImage *) GUINT_TO_POINTER ((gsize) image_argument);
211         gchar *name_space, *name, *pos;
212         MonoClass *klass;
213
214         pos = strrchr (full_name, '.');
215         if (pos) {
216                 name_space = full_name;
217                 *pos = 0;
218                 name = pos + 1;
219         } else {
220                 name = full_name;
221                 name_space = NULL;
222         }
223
224         klass = mono_class_from_name (image, name_space ? name_space : "", name);
225         if (!klass)
226                 return -1;
227
228         mono_class_init (klass);
229         return (gint64) (gssize) klass;
230 }
231
232 static guint64
233 debugger_run_finally (guint64 context_argument, G_GNUC_UNUSED guint64 dummy)
234 {
235         mono_debugger_run_finally (GUINT_TO_POINTER ((gsize)context_argument));
236         return 0;
237 }
238
239 static guint64
240 debugger_class_get_static_field_data (guint64 value)
241 {
242         MonoClass *klass = GUINT_TO_POINTER ((gsize) value);
243         MonoVTable *vtable = mono_class_vtable (mono_domain_get (), klass);
244         return (guint64) (gsize) mono_vtable_get_static_field_data (vtable);
245 }
246
247 static guint64
248 debugger_insert_method_breakpoint (guint64 method_argument, guint64 index)
249 {
250         MonoMethod *method = GUINT_TO_POINTER ((gsize) method_argument);
251         MonoDebugMethodAddressList *info;
252
253         mono_debugger_lock ();
254
255         if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
256                 const char *name = method->name;
257                 MonoMethod *nm = NULL;
258
259                 if (method->klass->parent == mono_defaults.multicastdelegate_class) {
260                         if (*name == 'I' && (strcmp (name, "Invoke") == 0))
261                                 nm = mono_marshal_get_delegate_invoke (method, NULL);
262                         else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0))
263                                 nm = mono_marshal_get_delegate_begin_invoke (method);
264                         else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0))
265                                 nm = mono_marshal_get_delegate_end_invoke (method);
266                 }
267
268                 if (!nm) {
269                         mono_debugger_unlock ();
270                         return 0;
271                 }
272
273                 method = nm;
274         }
275
276         info = mono_debugger_insert_method_breakpoint (method, index);
277
278         mono_debugger_unlock ();
279         return (guint64) (gsize) info;
280 }
281
282 static guint64
283 debugger_insert_source_breakpoint (guint64 image_argument, guint64 token, guint64 index,
284                                    const gchar *class_name)
285 {
286         MonoImage *image = GUINT_TO_POINTER ((gsize) image_argument);
287         MonoDebugMethodAddressList *info;
288         MonoClass *klass;
289         int i;
290
291         mono_debugger_lock ();
292
293         klass = mono_debugger_register_class_init_callback (image, class_name, token, index);
294         if (!klass) {
295                 mono_debugger_unlock ();
296                 return 0;
297         }
298
299         for (i = 0; i < klass->method.count; i++) {
300                 MonoMethod *method = klass->methods [i];
301
302                 if (method->token != token)
303                         continue;
304
305                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
306                         const char *name = method->name;
307                         MonoMethod *nm = NULL;
308
309                         if (method->klass->parent == mono_defaults.multicastdelegate_class) {
310                                 if (*name == 'I' && (strcmp (name, "Invoke") == 0))
311                                         nm = mono_marshal_get_delegate_invoke (method, NULL);
312                                 else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0))
313                                         nm = mono_marshal_get_delegate_begin_invoke (method);
314                                 else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0))
315                                         nm = mono_marshal_get_delegate_end_invoke (method);
316                         }
317
318                         if (!nm) {
319                                 mono_debugger_unlock ();
320                                 return 0;
321                         }
322
323                         method = nm;
324                 }
325
326                 info = mono_debugger_insert_method_breakpoint (method, index);
327                 mono_debugger_unlock ();
328                 return (guint64) (gsize) info;
329         }
330
331         mono_debugger_unlock ();
332         return 0;
333 }
334
335 static void
336 debugger_remove_breakpoint (guint64 index, G_GNUC_UNUSED guint64 dummy)
337 {
338         mono_debugger_lock ();
339         mono_debugger_remove_method_breakpoint (index);
340         mono_debugger_unlock ();
341 }
342
343 static guint64
344 debugger_register_class_init_callback (guint64 image_argument, guint64 token, guint64 index,
345                                        const gchar *class_name)
346 {
347         MonoImage *image = GUINT_TO_POINTER ((gsize) image_argument);
348         MonoClass *klass;
349
350         mono_debugger_lock ();
351         klass = mono_debugger_register_class_init_callback (image, class_name, token, index);
352         mono_debugger_unlock ();
353         return (guint64) (gsize) klass;
354 }
355
356 static void
357 debugger_remove_class_init_callback (guint64 index, G_GNUC_UNUSED guint64 dummy)
358 {
359         mono_debugger_lock ();
360         mono_debugger_remove_class_init_callback (index);
361         mono_debugger_unlock ();
362 }
363
364 static void
365 debugger_event_handler (MonoDebuggerEvent event, guint64 data, guint64 arg)
366 {
367         mono_debugger_notification_function (event, data, arg);
368 }
369
370 static void
371 debugger_gc_thread_created (pthread_t thread, void *stack_ptr)
372 {
373         mono_debugger_event (MONO_DEBUGGER_EVENT_GC_THREAD_CREATED,
374                              (guint64) (gsize) stack_ptr, thread);
375 }
376
377 static void
378 debugger_gc_thread_exited (pthread_t thread, void *stack_ptr)
379 {
380         mono_debugger_event (MONO_DEBUGGER_EVENT_GC_THREAD_EXITED,
381                              (guint64) (gsize) stack_ptr, thread);
382 }
383
384 static void
385 debugger_gc_stop_world (void)
386 {
387         mono_debugger_event (
388                 MONO_DEBUGGER_EVENT_ACQUIRE_GLOBAL_THREAD_LOCK, 0, 0);
389 }
390
391 static void
392 debugger_gc_start_world (void)
393 {
394         mono_debugger_event (
395                 MONO_DEBUGGER_EVENT_RELEASE_GLOBAL_THREAD_LOCK, 0, 0);
396 }
397
398 static GCThreadFunctions debugger_thread_vtable = {
399         NULL,
400
401         debugger_gc_thread_created,
402         debugger_gc_thread_exited,
403
404         debugger_gc_stop_world,
405         debugger_gc_start_world
406 };
407
408 static void
409 debugger_init_threads (void)
410 {
411         gc_thread_vtable = &debugger_thread_vtable;
412 }
413
414 static void
415 debugger_finalize_threads (void)
416 {
417         gc_thread_vtable = NULL;
418 }
419
420 static void
421 debugger_attach (void)
422 {
423         mono_debugger_init ();
424
425         mono_debugger_event_handler = debugger_event_handler;
426         debugger_executable_code_buffer = mono_global_codeman_reserve (EXECUTABLE_CODE_BUFFER_SIZE);
427         debugger_init_threads ();
428 }
429
430 static void
431 debugger_detach (void)
432 {
433         mono_debugger_event_handler = NULL;
434         mono_debugger_notification_function = NULL;
435         debugger_finalize_threads ();
436 }
437
438 extern MonoDebuggerInfo *MONO_DEBUGGER__debugger_info_ptr;
439
440 static void
441 debugger_initialize (void)
442 {
443 }
444
445 void
446 mono_debugger_init (void)
447 {
448         mono_debugger_notification_function = mono_debugger_create_notification_function ();
449         debugger_executable_code_buffer = mono_global_codeman_reserve (EXECUTABLE_CODE_BUFFER_SIZE);
450         mono_debugger_event_handler = debugger_event_handler;
451
452         /*
453          * Use an indirect call so gcc can't optimize it away.
454          */
455         MONO_DEBUGGER__debugger_info.initialize ();
456
457         debugger_init_threads ();
458
459         /*
460          * Initialize the thread manager.
461          *
462          * NOTE: We only reference the `MONO_DEBUGGER__debugger_info_ptr' here to prevent the
463          * linker from removing the .mdb_debug_info section.
464          */
465
466         mono_debugger_notification_function (MONO_DEBUGGER_EVENT_INITIALIZE_THREAD_MANAGER,
467                                              (guint64) (gssize) MONO_DEBUGGER__debugger_info_ptr, 0);
468 }
469
470 typedef struct 
471 {
472         MonoDomain *domain;
473         const char *file;
474 } DebuggerThreadArgs;
475
476 typedef struct
477 {
478         MonoDomain *domain;
479         MonoMethod *method;
480         int argc;
481         char **argv;
482 } MainThreadArgs;
483
484 static guint32
485 main_thread_handler (gpointer user_data)
486 {
487         MainThreadArgs *main_args = (MainThreadArgs *) user_data;
488         int retval;
489
490         mono_debugger_notification_function (MONO_DEBUGGER_EVENT_REACHED_MAIN,
491                                              (guint64) (gsize) main_args->method, 0);
492
493         retval = mono_runtime_run_main (main_args->method, main_args->argc, main_args->argv, NULL);
494
495         /*
496          * This will never return.
497          */
498         mono_debugger_notification_function (MONO_DEBUGGER_EVENT_MAIN_EXITED, 0,
499                                              (guint64) (gsize) retval);
500
501         return retval;
502 }
503
504 int
505 mono_debugger_main (MonoDomain *domain, MonoAssembly *assembly, int argc, char **argv)
506 {
507         MainThreadArgs main_args;
508         MonoImage *image;
509         MonoMethod *main_method;
510
511         /*
512          * Get and compile the main function.
513          */
514
515         image = mono_assembly_get_image (assembly);
516         main_method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
517
518         /*
519          * Initialize managed code.
520          */
521         mono_debugger_notification_function (MONO_DEBUGGER_EVENT_INITIALIZE_MANAGED_CODE,
522                                              (guint64) (gssize) main_method, 0);
523
524         /*
525          * Start the main thread and wait until it's ready.
526          */
527
528         main_args.domain = domain;
529         main_args.method = main_method;
530         main_args.argc = argc;
531         main_args.argv = argv;
532
533 #if RUN_IN_SUBTHREAD
534         mono_thread_create (domain, main_thread_handler, &main_args);
535 #else
536         main_thread_handler (&main_args);
537 #endif
538
539         mono_thread_manage ();
540
541         /*
542          * This will never return.
543          */
544         mono_debugger_notification_function (MONO_DEBUGGER_EVENT_WRAPPER_MAIN, 0, 0);
545
546         return 0;
547 }