2007-06-22 Atsushi Enomoto <atsushi@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 <libgc/include/libgc-mono-debugger.h>
10 #include "mini.h"
11 #include <unistd.h>
12 #include <locale.h>
13 #include <string.h>
14
15 /*
16  * This file is only compiled on platforms where the debugger is supported - see the conditional
17  * definition of `debugger_sources' in Makefile.am.
18  *
19  * configure.in checks whether we're using the included libgc and disables the debugger if not.
20  */
21
22 #if !defined(MONO_DEBUGGER_SUPPORTED)
23 #error "Some clown tried to compile debug-debugger.c on an unsupported platform - fix Makefile.am!"
24 #elif !defined(USE_INCLUDED_LIBGC)
25 #error "Some clown #defined MONO_DEBUGGER_SUPPORTED without USE_INCLUDED_GC - fix configure.in!"
26 #endif
27
28 static guint64 debugger_insert_breakpoint (guint64 method_argument, const gchar *string_argument);
29 static guint64 debugger_remove_breakpoint (guint64 breakpoint);
30 static guint64 debugger_compile_method (guint64 method_arg);
31 static guint64 debugger_get_virtual_method (guint64 class_arg, guint64 method_arg);
32 static guint64 debugger_get_boxed_object (guint64 klass_arg, guint64 val_arg);
33 static guint64 debugger_create_string (guint64 dummy_argument, const gchar *string_argument);
34 static guint64 debugger_class_get_static_field_data (guint64 klass);
35 static guint64 debugger_lookup_class (guint64 image_argument, guint64 token_arg);
36 static guint64 debugger_lookup_type (guint64 dummy_argument, const gchar *string_argument);
37 static guint64 debugger_lookup_assembly (guint64 dummy_argument, const gchar *string_argument);
38 static guint64 debugger_run_finally (guint64 argument1, guint64 argument2);
39 static guint64 debugger_get_current_thread (void);
40 static void debugger_attach (void);
41 static void debugger_detach (void);
42 static void debugger_initialize (void);
43
44 static void (*mono_debugger_notification_function) (guint64 command, guint64 data, guint64 data2);
45
46 static MonoDebuggerMetadataInfo debugger_metadata_info = {
47         sizeof (MonoDebuggerMetadataInfo),
48         sizeof (MonoDefaults),
49         &mono_defaults,
50         sizeof (MonoType),
51         sizeof (MonoArrayType),
52         sizeof (MonoClass),
53         sizeof (MonoThread),
54         G_STRUCT_OFFSET (MonoThread, tid),
55         G_STRUCT_OFFSET (MonoThread, stack_ptr),
56         G_STRUCT_OFFSET (MonoThread, end_stack),
57         G_STRUCT_OFFSET (MonoClass, instance_size),
58         G_STRUCT_OFFSET (MonoClass, parent),
59         G_STRUCT_OFFSET (MonoClass, type_token),
60         G_STRUCT_OFFSET (MonoClass, fields),
61         G_STRUCT_OFFSET (MonoClass, methods),
62         G_STRUCT_OFFSET (MonoClass, method.count),
63         G_STRUCT_OFFSET (MonoClass, this_arg),
64         G_STRUCT_OFFSET (MonoClass, byval_arg),
65         G_STRUCT_OFFSET (MonoClass, generic_class),
66         G_STRUCT_OFFSET (MonoClass, generic_container),
67         sizeof (MonoClassField),
68         G_STRUCT_OFFSET (MonoDefaults, corlib),
69         G_STRUCT_OFFSET (MonoDefaults, object_class),
70         G_STRUCT_OFFSET (MonoDefaults, byte_class),
71         G_STRUCT_OFFSET (MonoDefaults, void_class),
72         G_STRUCT_OFFSET (MonoDefaults, boolean_class),
73         G_STRUCT_OFFSET (MonoDefaults, sbyte_class),
74         G_STRUCT_OFFSET (MonoDefaults, int16_class),
75         G_STRUCT_OFFSET (MonoDefaults, uint16_class),
76         G_STRUCT_OFFSET (MonoDefaults, int32_class),
77         G_STRUCT_OFFSET (MonoDefaults, uint32_class),
78         G_STRUCT_OFFSET (MonoDefaults, int_class),
79         G_STRUCT_OFFSET (MonoDefaults, uint_class),
80         G_STRUCT_OFFSET (MonoDefaults, int64_class),
81         G_STRUCT_OFFSET (MonoDefaults, uint64_class),
82         G_STRUCT_OFFSET (MonoDefaults, single_class),
83         G_STRUCT_OFFSET (MonoDefaults, double_class),
84         G_STRUCT_OFFSET (MonoDefaults, char_class),
85         G_STRUCT_OFFSET (MonoDefaults, string_class),
86         G_STRUCT_OFFSET (MonoDefaults, enum_class),
87         G_STRUCT_OFFSET (MonoDefaults, array_class),
88         G_STRUCT_OFFSET (MonoDefaults, delegate_class),
89         G_STRUCT_OFFSET (MonoDefaults, exception_class)
90 };
91
92 /*
93  * This is a global data symbol which is read by the debugger.
94  */
95 MonoDebuggerInfo MONO_DEBUGGER__debugger_info = {
96         MONO_DEBUGGER_MAGIC,
97         MONO_DEBUGGER_VERSION,
98         sizeof (MonoDebuggerInfo),
99         sizeof (MonoSymbolTable),
100         0,
101         &mono_debugger_notification_function,
102         mono_trampoline_code,
103         &mono_symbol_table,
104         &debugger_metadata_info,
105         &debugger_compile_method,
106         &debugger_get_virtual_method,
107         &debugger_get_boxed_object,
108         &debugger_insert_breakpoint,
109         &debugger_remove_breakpoint,
110         &mono_debugger_runtime_invoke,
111         &debugger_create_string,
112         &debugger_class_get_static_field_data,
113         &debugger_lookup_class,
114         &debugger_lookup_type,
115         &debugger_lookup_assembly,
116         &debugger_run_finally,
117         &debugger_get_current_thread,
118         &debugger_attach,
119         &debugger_detach,
120         &debugger_initialize,
121         (void*)&mono_get_lmf_addr
122 };
123
124 static guint64
125 debugger_insert_breakpoint (guint64 method_argument, const gchar *string_argument)
126 {
127         MonoMethodDesc *desc;
128
129         desc = mono_method_desc_new (string_argument, TRUE);
130         if (!desc)
131                 return 0;
132
133         return (guint64) mono_debugger_insert_breakpoint_full (desc);
134 }
135
136 static guint64
137 debugger_remove_breakpoint (guint64 breakpoint)
138 {
139         return mono_debugger_remove_breakpoint (breakpoint);
140 }
141
142 static gpointer
143 debugger_compile_method_cb (MonoMethod *method)
144 {
145         gpointer retval;
146
147         mono_debugger_lock ();
148         retval = mono_compile_method (method);
149         mono_debugger_unlock ();
150
151         mono_debugger_notification_function (
152                 MONO_DEBUGGER_EVENT_METHOD_COMPILED, (guint64) (gsize) retval, 0);
153
154         return retval;
155 }
156
157 static guint64
158 debugger_compile_method (guint64 method_arg)
159 {
160         MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg);
161
162         return (guint64) (gsize) debugger_compile_method_cb (method);
163 }
164
165 static guint64
166 debugger_get_virtual_method (guint64 object_arg, guint64 method_arg)
167 {
168         MonoObject *object = (MonoObject *) GUINT_TO_POINTER ((gsize) object_arg);
169         MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg);
170
171         if (mono_class_is_valuetype (mono_method_get_class (method)))
172                 return method_arg;
173
174         return (guint64) (gsize) mono_object_get_virtual_method (object, method);
175 }
176
177 static guint64
178 debugger_get_boxed_object (guint64 klass_arg, guint64 val_arg)
179 {
180         static MonoObject *last_boxed_object = NULL;
181         MonoClass *klass = (MonoClass *) GUINT_TO_POINTER ((gsize) klass_arg);
182         gpointer val = (gpointer) GUINT_TO_POINTER ((gsize) val_arg);
183         MonoObject *boxed;
184
185         if (!mono_class_is_valuetype (klass))
186                 return val_arg;
187
188         boxed = mono_value_box (mono_domain_get (), klass, val);
189         last_boxed_object = boxed; // Protect the object from being garbage collected
190
191         return (guint64) (gsize) boxed;
192 }
193
194 static guint64
195 debugger_create_string (guint64 dummy_argument, const gchar *string_argument)
196 {
197         return (guint64) (gsize) mono_string_new_wrapper (string_argument);
198 }
199
200 static guint64
201 debugger_lookup_type (guint64 dummy_argument, const gchar *string_argument)
202 {
203         guint64 retval;
204
205         mono_debugger_lock ();
206         // retval = mono_debugger_lookup_type (string_argument);
207         retval = -1;
208         mono_debugger_unlock ();
209         return retval;
210 }
211
212 static guint64
213 debugger_lookup_class (guint64 image_argument, guint64 token_argument)
214 {
215         MonoImage *image = (MonoImage *) GUINT_TO_POINTER ((gsize) image_argument);
216         guint32 token = (guint32) token_argument;
217         MonoClass *klass;
218
219         klass = mono_class_get (image, token);
220         if (klass)
221                 mono_class_init (klass);
222
223         return (guint64) (gsize) klass;
224 }
225
226 static guint64
227 debugger_lookup_assembly (guint64 dummy_argument, const gchar *string_argument)
228 {
229         gint64 retval;
230
231         mono_debugger_lock ();
232         retval = mono_debugger_lookup_assembly (string_argument);
233         mono_debugger_unlock ();
234         return retval;
235 }
236
237 static guint64
238 debugger_run_finally (guint64 context_argument, guint64 dummy)
239 {
240         mono_debugger_run_finally (GUINT_TO_POINTER ((gsize)context_argument));
241         return 0;
242 }
243
244 static guint64
245 debugger_class_get_static_field_data (guint64 value)
246 {
247         MonoClass *klass = GUINT_TO_POINTER ((gsize) value);
248         MonoVTable *vtable = mono_class_vtable (mono_domain_get (), klass);
249         return (guint64) (gsize) mono_vtable_get_static_field_data (vtable);
250 }
251
252 static void
253 debugger_event_handler (MonoDebuggerEvent event, guint64 data, guint64 arg)
254 {
255         mono_debugger_notification_function (event, data, arg);
256 }
257
258 static guint64
259 debugger_get_current_thread (void)
260 {
261         return (guint64) (gsize) mono_thread_current ();
262 }
263
264 static void
265 debugger_gc_thread_created (pthread_t thread, void *stack_ptr)
266 {
267         mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CREATED,
268                              (guint64) (gsize) stack_ptr, thread);
269 }
270
271 static void
272 debugger_gc_thread_exited (pthread_t thread, void *stack_ptr)
273 {
274         mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_EXITED,
275                              (guint64) (gsize) stack_ptr, thread);
276 }
277
278 static void
279 debugger_gc_stop_world (void)
280 {
281         mono_debugger_event (
282                 MONO_DEBUGGER_EVENT_ACQUIRE_GLOBAL_THREAD_LOCK, 0, 0);
283 }
284
285 static void
286 debugger_gc_start_world (void)
287 {
288         mono_debugger_event (
289                 MONO_DEBUGGER_EVENT_RELEASE_GLOBAL_THREAD_LOCK, 0, 0);
290 }
291
292 static GCThreadFunctions debugger_thread_vtable = {
293         NULL,
294
295         debugger_gc_thread_created,
296         debugger_gc_thread_exited,
297
298         debugger_gc_stop_world,
299         debugger_gc_start_world
300 };
301
302 static void
303 debugger_init_threads (void)
304 {
305         gc_thread_vtable = &debugger_thread_vtable;
306 }
307
308 static void
309 debugger_finalize_threads (void)
310 {
311         gc_thread_vtable = NULL;
312 }
313
314 static void
315 debugger_attach (void)
316 {
317         mono_debugger_init ();
318
319         mono_debugger_event_handler = debugger_event_handler;
320         mono_debugger_notification_function (MONO_DEBUGGER_EVENT_INITIALIZE_MANAGED_CODE, 0, 0);
321
322         debugger_init_threads ();
323         GC_mono_debugger_add_all_threads ();
324 }
325
326 static void
327 debugger_detach (void)
328 {
329         mono_debugger_event_handler = NULL;
330         mono_debugger_notification_function = NULL;
331         debugger_finalize_threads ();
332 }
333
334 extern MonoDebuggerInfo *MONO_DEBUGGER__debugger_info_ptr;
335
336 static void
337 debugger_initialize (void)
338 {
339 }
340
341 void
342 mono_debugger_init (void)
343 {
344         mono_debugger_notification_function = mono_debugger_create_notification_function ();
345         mono_debugger_event_handler = debugger_event_handler;
346
347         /*
348          * Use an indirect call so gcc can't optimize it away.
349          */
350         MONO_DEBUGGER__debugger_info.initialize ();
351
352         debugger_init_threads ();
353
354         /*
355          * Initialize the thread manager.
356          */
357
358         mono_debugger_notification_function (MONO_DEBUGGER_EVENT_INITIALIZE_THREAD_MANAGER,
359                                              GetCurrentThreadId (), 0);
360 }
361
362 typedef struct 
363 {
364         MonoDomain *domain;
365         const char *file;
366 } DebuggerThreadArgs;
367
368 typedef struct
369 {
370         MonoDomain *domain;
371         MonoMethod *method;
372         int argc;
373         char **argv;
374 } MainThreadArgs;
375
376 static guint32
377 main_thread_handler (gpointer user_data)
378 {
379         MainThreadArgs *main_args = (MainThreadArgs *) user_data;
380         int retval;
381
382         mono_debugger_notification_function (MONO_DEBUGGER_EVENT_REACHED_MAIN,
383                                              (guint64) (gsize) main_args->method, 0);
384
385         retval = mono_runtime_run_main (main_args->method, main_args->argc, main_args->argv, NULL);
386
387         /*
388          * This will never return.
389          */
390         mono_debugger_notification_function (MONO_DEBUGGER_EVENT_MAIN_EXITED, 0,
391                                              (guint64) (gsize) retval);
392
393         return retval;
394 }
395
396 int
397 mono_debugger_main (MonoDomain *domain, MonoAssembly *assembly, int argc, char **argv)
398 {
399         MainThreadArgs main_args;
400         MonoImage *image;
401         MonoMethod *main_method;
402
403         /*
404          * Get and compile the main function.
405          */
406
407         image = mono_assembly_get_image (assembly);
408         main_method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
409
410         /*
411          * Reload symbol tables.
412          *
413          * NOTE: We only reference the `MONO_DEBUGGER__debugger_info_ptr' here to prevent the
414          * linker from removing the .mdb_debug_info section.
415          */
416         mono_debugger_notification_function (MONO_DEBUGGER_EVENT_INITIALIZE_MANAGED_CODE,
417                                              (guint64) (gssize) MONO_DEBUGGER__debugger_info_ptr, 0);
418         mono_debugger_unlock ();
419
420         /*
421          * Start the main thread and wait until it's ready.
422          */
423
424         main_args.domain = domain;
425         main_args.method = main_method;
426         main_args.argc = argc;
427         main_args.argv = argv;
428
429 #if RUN_IN_SUBTHREAD
430         mono_thread_create (domain, main_thread_handler, &main_args);
431 #else
432         main_thread_handler (&main_args);
433 #endif
434
435         mono_thread_manage ();
436
437         /*
438          * This will never return.
439          */
440         mono_debugger_notification_function (MONO_DEBUGGER_EVENT_WRAPPER_MAIN, 0, 0);
441
442         return 0;
443 }