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