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