2005-08-21 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / mono-debug-debugger.c
1 #include <config.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <mono/metadata/assembly.h>
5 #include <mono/metadata/metadata.h>
6 #include <mono/metadata/tabledefs.h>
7 #include <mono/metadata/tokentype.h>
8 #include <mono/metadata/appdomain.h>
9 #include <mono/metadata/gc-internal.h>
10 #include <mono/os/gc_wrapper.h>
11 #include <mono/metadata/object-internals.h>
12 #include <mono/metadata/class-internals.h>
13 #include <mono/metadata/exception.h>
14 #include <mono/metadata/mono-debug.h>
15 #include <mono/metadata/mono-debug-debugger.h>
16 #include <mono/metadata/mono-endian.h>
17
18 static guint32 debugger_lock_level = 0;
19 static CRITICAL_SECTION debugger_lock_mutex;
20 static gboolean must_reload_symtabs = FALSE;
21 static gboolean mono_debugger_use_debugger = FALSE;
22 static MonoObject *last_exception = NULL;
23
24 struct _MonoDebuggerMetadataInfo {
25         int size;
26         int mono_defaults_size;
27         MonoDefaults *mono_defaults;
28         int klass_field_offset;
29         int klass_methods_offset;
30         int klass_method_count_offset;
31         int field_info_size;
32 };
33
34 void (*mono_debugger_event_handler) (MonoDebuggerEvent event, guint64 data, guint64 arg) = NULL;
35
36 #define WRITE_UINT32(ptr,value) G_STMT_START {  \
37         * ((guint32 *) ptr) = value;            \
38         ptr += 4;                               \
39 } G_STMT_END
40
41 #define WRITE_POINTER(ptr,value) G_STMT_START { \
42         * ((gpointer *) ptr) = (gpointer) (value); \
43         ptr += sizeof (gpointer);               \
44 } G_STMT_END
45
46 #define WRITE_STRING(ptr,value) G_STMT_START {  \
47         memcpy (ptr, value, strlen (value)+1);  \
48         ptr += strlen (value)+1;                \
49 } G_STMT_END
50
51 typedef struct {
52         gpointer stack_pointer;
53         MonoObject *exception_obj;
54         guint32 stop;
55 } MonoDebuggerExceptionInfo;
56
57 #ifndef PLATFORM_WIN32
58
59 MonoDebuggerIOLayer mono_debugger_io_layer = {
60         InitializeCriticalSection, DeleteCriticalSection, TryEnterCriticalSection,
61         EnterCriticalSection, LeaveCriticalSection, WaitForSingleObjectEx, SignalObjectAndWait,
62         WaitForMultipleObjectsEx, CreateSemaphore, ReleaseSemaphore, CreateThread,
63         GetCurrentThreadId
64 };
65
66 #endif
67
68 static int initialized = 0;
69
70 void
71 mono_debugger_lock (void)
72 {
73         g_assert (initialized);
74         EnterCriticalSection (&debugger_lock_mutex);
75         debugger_lock_level++;
76 }
77
78 void
79 mono_debugger_unlock (void)
80 {
81         g_assert (initialized);
82         if (debugger_lock_level == 1) {
83                 if (must_reload_symtabs && mono_debugger_use_debugger) {
84                         mono_debugger_event (MONO_DEBUGGER_EVENT_RELOAD_SYMTABS, 0, 0);
85                         must_reload_symtabs = FALSE;
86                 }
87         }
88
89         debugger_lock_level--;
90         LeaveCriticalSection (&debugger_lock_mutex);
91 }
92
93 void
94 mono_debugger_initialize (gboolean use_debugger)
95 {
96         MONO_GC_REGISTER_ROOT (last_exception);
97         
98         g_assert (!mono_debugger_use_debugger);
99
100         InitializeCriticalSection (&debugger_lock_mutex);
101         mono_debugger_use_debugger = use_debugger;
102         initialized = 1;
103 }
104
105 void
106 mono_debugger_add_symbol_file (MonoDebugHandle *handle)
107 {
108         g_assert (mono_debugger_use_debugger);
109
110         mono_debugger_lock ();
111         mono_debugger_event (MONO_DEBUGGER_EVENT_ADD_MODULE, GPOINTER_TO_UINT (handle), 0);
112         mono_debugger_unlock ();
113 }
114
115 void
116 mono_debugger_add_builtin_types (MonoDebugHandle *symfile)
117 {
118         MonoDebuggerMetadataInfo *info;
119         MonoClass klass;
120
121         mono_symbol_table->corlib = symfile;
122         mono_symbol_table->metadata_info = info = g_new0 (MonoDebuggerMetadataInfo, 1);
123
124         info->size = sizeof (MonoDebuggerMetadataInfo);
125         info->mono_defaults = &mono_defaults;
126         info->mono_defaults_size = sizeof (MonoDefaults);
127         info->klass_field_offset = (guint8*)&klass.fields - (guint8*)&klass;
128         info->klass_methods_offset = (guint8*)&klass.methods - (guint8*)&klass;
129         info->klass_method_count_offset = (guint8*)&klass.method.count - (guint8*)&klass;
130         info->field_info_size = sizeof (MonoClassField);
131 }
132
133 void
134 mono_debugger_start_add_type (MonoDebugHandle *symfile, MonoClass *klass)
135 {
136         must_reload_symtabs = TRUE;
137 }
138
139 MonoReflectionMethod *
140 ves_icall_MonoDebugger_GetMethod (MonoReflectionAssembly *assembly, guint32 token)
141 {
142         MonoMethod *method;
143
144         method = mono_get_method (mono_assembly_get_image (assembly->assembly), token, NULL);
145
146         return mono_method_get_object (mono_domain_get (), method, NULL);
147 }
148
149 int
150 ves_icall_MonoDebugger_GetMethodToken (MonoReflectionAssembly *assembly, MonoReflectionMethod *method)
151 {
152         return method->method->token;
153 }
154
155 MonoReflectionType *
156 ves_icall_MonoDebugger_GetType (MonoReflectionAssembly *assembly, guint32 token)
157 {
158         MonoClass *klass;
159
160         klass = mono_class_get (mono_assembly_get_image (assembly->assembly), token);
161         if (!klass) {
162                 g_warning (G_STRLOC ": %x", token);
163                 return NULL;
164         }
165
166         return mono_type_get_object (mono_domain_get (), &klass->byval_arg);
167 }
168
169 MonoReflectionType *
170 ves_icall_MonoDebugger_GetLocalTypeFromSignature (MonoReflectionAssembly *assembly, MonoArray *signature)
171 {
172         MonoDomain *domain; 
173         MonoImage *image;
174         MonoType *type;
175         const char *ptr;
176         int len = 0;
177
178         MONO_CHECK_ARG_NULL (assembly);
179         MONO_CHECK_ARG_NULL (signature);
180
181         domain = mono_domain_get();
182         image = mono_assembly_get_image (assembly->assembly);
183
184         ptr = mono_array_addr (signature, char, 0);
185         g_assert (*ptr++ == 0x07);
186         len = mono_metadata_decode_value (ptr, &ptr);
187         g_assert (len == 1);
188
189         type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
190
191         return mono_type_get_object (domain, type);
192 }
193
194 void
195 mono_debugger_event (MonoDebuggerEvent event, guint64 data, guint64 arg)
196 {
197         if (mono_debugger_event_handler)
198                 (* mono_debugger_event_handler) (event, data, arg);
199 }
200
201 void
202 mono_debugger_cleanup (void)
203 {
204         /* Do nothing yet. */
205 }
206
207 /*
208  * Debugger breakpoint interface.
209  *
210  * This interface is used to insert breakpoints on methods which are not yet JITed.
211  * The debugging code keeps a list of all such breakpoints and automatically inserts the
212  * breakpoint when the method is JITed.
213  */
214
215 static GPtrArray *breakpoints = NULL;
216
217 int
218 mono_debugger_insert_breakpoint_full (MonoMethodDesc *desc)
219 {
220         static int last_breakpoint_id = 0;
221         MonoDebuggerBreakpointInfo *info;
222
223         info = g_new0 (MonoDebuggerBreakpointInfo, 1);
224         info->desc = desc;
225         info->index = ++last_breakpoint_id;
226
227         if (!breakpoints)
228                 breakpoints = g_ptr_array_new ();
229
230         g_ptr_array_add (breakpoints, info);
231
232         return info->index;
233 }
234
235 int
236 mono_debugger_remove_breakpoint (int breakpoint_id)
237 {
238         int i;
239
240         if (!breakpoints)
241                 return 0;
242
243         for (i = 0; i < breakpoints->len; i++) {
244                 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
245
246                 if (info->index != breakpoint_id)
247                         continue;
248
249                 mono_method_desc_free (info->desc);
250                 g_ptr_array_remove (breakpoints, info);
251                 g_free (info);
252                 return 1;
253         }
254
255         return 0;
256 }
257
258 int
259 mono_debugger_insert_breakpoint (const gchar *method_name, gboolean include_namespace)
260 {
261         MonoMethodDesc *desc;
262
263         desc = mono_method_desc_new (method_name, include_namespace);
264         if (!desc)
265                 return 0;
266
267         return mono_debugger_insert_breakpoint_full (desc);
268 }
269
270 int
271 mono_debugger_method_has_breakpoint (MonoMethod *method)
272 {
273         int i;
274
275         if (!breakpoints || (method->wrapper_type != MONO_WRAPPER_NONE))
276                 return 0;
277
278         for (i = 0; i < breakpoints->len; i++) {
279                 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
280
281                 if (!mono_method_desc_full_match (info->desc, method))
282                         continue;
283
284                 return info->index;
285         }
286
287         return 0;
288 }
289
290 void
291 mono_debugger_breakpoint_callback (MonoMethod *method, guint32 index)
292 {
293         mono_debugger_event (MONO_DEBUGGER_EVENT_BREAKPOINT, GPOINTER_TO_UINT (method), index);
294 }
295
296 gboolean
297 mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc)
298 {
299         if (!mono_debugger_use_debugger)
300                 return FALSE;
301
302         // Prevent the object from being finalized.
303         last_exception = exc;
304         mono_debugger_event (MONO_DEBUGGER_EVENT_UNHANDLED_EXCEPTION,
305                              GPOINTER_TO_UINT (exc), GPOINTER_TO_UINT (addr));
306         return TRUE;
307 }
308
309 void
310 mono_debugger_handle_exception (gpointer addr, gpointer stack, MonoObject *exc)
311 {
312         MonoDebuggerExceptionInfo info;
313
314         if (!mono_debugger_use_debugger)
315                 return;
316
317         // Prevent the object from being finalized.
318         last_exception = exc;
319
320         info.stack_pointer = stack;
321         info.exception_obj = exc;
322         info.stop = 0;
323
324         mono_debugger_event (MONO_DEBUGGER_EVENT_EXCEPTION, GPOINTER_TO_UINT (&info),
325                              GPOINTER_TO_UINT (addr));
326 }
327
328 gboolean
329 mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc)
330 {
331         MonoDebuggerExceptionInfo info;
332
333         if (!mono_debugger_use_debugger)
334                 return FALSE;
335
336         // Prevent the object from being finalized.
337         last_exception = exc;
338
339         info.stack_pointer = stack;
340         info.exception_obj = exc;
341         info.stop = 0;
342
343         mono_debugger_event (MONO_DEBUGGER_EVENT_THROW_EXCEPTION, GPOINTER_TO_UINT (&info),
344                              GPOINTER_TO_UINT (addr));
345         return info.stop != 0;
346 }
347
348 static gchar *
349 get_exception_message (MonoObject *exc)
350 {
351         char *message = NULL;
352         MonoString *str; 
353         MonoMethod *method;
354         MonoClass *klass;
355         gint i;
356
357         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
358                 klass = exc->vtable->klass;
359                 method = NULL;
360                 while (klass && method == NULL) {
361                         for (i = 0; i < klass->method.count; ++i) {
362                                 method = klass->methods [i];
363                                 if (!strcmp ("ToString", method->name) &&
364                                     mono_method_signature (method)->param_count == 0 &&
365                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
366                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
367                                         break;
368                                 }
369                                 method = NULL;
370                         }
371                         
372                         if (method == NULL)
373                                 klass = klass->parent;
374                 }
375
376                 g_assert (method);
377
378                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
379                 if (str)
380                         message = mono_string_to_utf8 (str);
381         }
382
383         return message;
384 }
385
386 MonoObject *
387 mono_debugger_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
388 {
389         MonoObject *retval;
390         gchar *message;
391
392         if (!strcmp (method->name, ".ctor")) {
393                 retval = obj = mono_object_new (mono_domain_get (), method->klass);
394
395                 mono_runtime_invoke (method, obj, params, exc);
396         } else
397                 retval = mono_runtime_invoke (method, obj, params, exc);
398
399         if (!exc || (*exc == NULL))
400                 return retval;
401
402         message = get_exception_message (*exc);
403         if (message) {
404                 *exc = (MonoObject *) mono_string_new_wrapper (message);
405                 g_free (message);
406         }
407
408         return retval;
409 }
410
411 gboolean
412 mono_debugger_lookup_type (const gchar *type_name)
413 {
414         int i;
415         mono_debugger_lock ();
416
417         for (i = 0; i < mono_symbol_table->num_symbol_files; i++) {
418                 MonoDebugHandle *symfile = mono_symbol_table->symbol_files [i];
419                 MonoType *type;
420                 MonoClass* klass;
421                 gchar *name;
422
423                 name = g_strdup (type_name);
424                 type = mono_reflection_type_from_name (name, symfile->image);
425                 g_free (name);
426                 if (!type)
427                         continue;
428
429                 klass = mono_class_from_mono_type (type);
430                 if (klass)
431                         mono_class_init (klass);
432
433                 mono_debugger_unlock ();
434                 return TRUE;
435         }
436
437         mono_debugger_unlock ();
438         return FALSE;
439 }
440
441 gint32
442 mono_debugger_lookup_assembly (const gchar *name)
443 {
444         MonoAssembly *assembly;
445         MonoImageOpenStatus status;
446         int i;
447
448         mono_debugger_lock ();
449
450  again:
451         for (i = 0; i < mono_symbol_table->num_symbol_files; i++) {
452                 MonoDebugHandle *symfile = mono_symbol_table->symbol_files [i];
453
454                 if (!strcmp (symfile->image_file, name)) {
455                         mono_debugger_unlock ();
456                         return i;
457                 }
458         }
459
460         assembly = mono_assembly_open (name, &status);
461
462         if (status != MONO_IMAGE_OK) {
463                 g_warning (G_STRLOC ": Cannot open image `%s'", name);
464                 mono_debugger_unlock ();
465                 return -1;
466         }
467
468         must_reload_symtabs = TRUE;
469         goto again;
470 }
471