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