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