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