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