New test.
[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/metadata/threads.h>
11 #include <mono/os/gc_wrapper.h>
12 #include <mono/metadata/object-internals.h>
13 #include <mono/metadata/class-internals.h>
14 #include <mono/metadata/exception.h>
15 #include <mono/metadata/mono-debug.h>
16 #include <mono/metadata/mono-debug-debugger.h>
17 #include <mono/metadata/mono-endian.h>
18
19 static guint32 debugger_lock_level = 0;
20 static CRITICAL_SECTION debugger_lock_mutex;
21 static gboolean must_reload_symtabs = FALSE;
22 static gboolean mono_debugger_use_debugger = FALSE;
23 static MonoObject *last_exception = NULL;
24
25 void (*mono_debugger_event_handler) (MonoDebuggerEvent event, guint64 data, guint64 arg) = NULL;
26
27 #define WRITE_UINT32(ptr,value) G_STMT_START {  \
28         * ((guint32 *) ptr) = value;            \
29         ptr += 4;                               \
30 } G_STMT_END
31
32 #define WRITE_POINTER(ptr,value) G_STMT_START { \
33         * ((gpointer *) ptr) = (gpointer) (value); \
34         ptr += sizeof (gpointer);               \
35 } G_STMT_END
36
37 #define WRITE_STRING(ptr,value) G_STMT_START {  \
38         memcpy (ptr, value, strlen (value)+1);  \
39         ptr += strlen (value)+1;                \
40 } G_STMT_END
41
42 typedef struct {
43         gpointer stack_pointer;
44         MonoObject *exception_obj;
45         guint32 stop;
46 } MonoDebuggerExceptionInfo;
47
48 static int initialized = 0;
49
50 void
51 mono_debugger_lock (void)
52 {
53         g_assert (initialized);
54         EnterCriticalSection (&debugger_lock_mutex);
55         debugger_lock_level++;
56 }
57
58 void
59 mono_debugger_unlock (void)
60 {
61         g_assert (initialized);
62         if (debugger_lock_level == 1) {
63                 if (must_reload_symtabs && mono_debugger_use_debugger) {
64                         mono_debugger_event (MONO_DEBUGGER_EVENT_RELOAD_SYMTABS, 0, 0);
65                         must_reload_symtabs = FALSE;
66                 }
67         }
68
69         debugger_lock_level--;
70         LeaveCriticalSection (&debugger_lock_mutex);
71 }
72
73 void
74 mono_debugger_initialize (gboolean use_debugger)
75 {
76         MONO_GC_REGISTER_ROOT (last_exception);
77         
78         g_assert (!mono_debugger_use_debugger);
79
80         InitializeCriticalSection (&debugger_lock_mutex);
81         mono_debugger_use_debugger = use_debugger;
82         initialized = 1;
83 }
84
85 void
86 mono_debugger_add_symbol_file (MonoDebugHandle *handle)
87 {
88         g_assert (mono_debugger_use_debugger);
89
90         mono_debugger_lock ();
91         mono_debugger_event (MONO_DEBUGGER_EVENT_ADD_MODULE, (guint64) (gsize) handle, 0);
92         mono_debugger_unlock ();
93 }
94
95 void
96 mono_debugger_start_add_type (MonoDebugHandle *symfile, MonoClass *klass)
97 {
98         must_reload_symtabs = TRUE;
99 }
100
101 void
102 mono_debugger_event (MonoDebuggerEvent event, guint64 data, guint64 arg)
103 {
104         if (mono_debugger_event_handler)
105                 (* mono_debugger_event_handler) (event, data, arg);
106 }
107
108 void
109 mono_debugger_cleanup (void)
110 {
111         mono_debugger_event (MONO_DEBUGGER_EVENT_FINALIZE_MANAGED_CODE, 0, 0);
112         mono_debugger_event_handler = NULL;
113 }
114
115 /*
116  * Debugger breakpoint interface.
117  *
118  * This interface is used to insert breakpoints on methods which are not yet JITed.
119  * The debugging code keeps a list of all such breakpoints and automatically inserts the
120  * breakpoint when the method is JITed.
121  */
122
123 static GPtrArray *breakpoints = NULL;
124
125 int
126 mono_debugger_insert_breakpoint_full (MonoMethodDesc *desc)
127 {
128         static int last_breakpoint_id = 0;
129         MonoDebuggerBreakpointInfo *info;
130
131         info = g_new0 (MonoDebuggerBreakpointInfo, 1);
132         info->desc = desc;
133         info->index = ++last_breakpoint_id;
134
135         if (!breakpoints)
136                 breakpoints = g_ptr_array_new ();
137
138         g_ptr_array_add (breakpoints, info);
139
140         return info->index;
141 }
142
143 int
144 mono_debugger_remove_breakpoint (int breakpoint_id)
145 {
146         int i;
147
148         if (!breakpoints)
149                 return 0;
150
151         for (i = 0; i < breakpoints->len; i++) {
152                 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
153
154                 if (info->index != breakpoint_id)
155                         continue;
156
157                 mono_method_desc_free (info->desc);
158                 g_ptr_array_remove (breakpoints, info);
159                 g_free (info);
160                 return 1;
161         }
162
163         return 0;
164 }
165
166 int
167 mono_debugger_insert_breakpoint (const gchar *method_name, gboolean include_namespace)
168 {
169         MonoMethodDesc *desc;
170
171         desc = mono_method_desc_new (method_name, include_namespace);
172         if (!desc)
173                 return 0;
174
175         return mono_debugger_insert_breakpoint_full (desc);
176 }
177
178 int
179 mono_debugger_method_has_breakpoint (MonoMethod *method)
180 {
181         int i;
182
183         if (!breakpoints || (method->wrapper_type != MONO_WRAPPER_NONE))
184                 return 0;
185
186         for (i = 0; i < breakpoints->len; i++) {
187                 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
188
189                 if (!mono_method_desc_full_match (info->desc, method))
190                         continue;
191
192                 return info->index;
193         }
194
195         return 0;
196 }
197
198 void
199 mono_debugger_breakpoint_callback (MonoMethod *method, guint32 index)
200 {
201         mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT, (guint64) (gsize) method, index);
202 }
203
204 gboolean
205 mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc)
206 {
207         const gchar *name;
208
209         if (!mono_debugger_use_debugger)
210                 return FALSE;
211
212         // Prevent the object from being finalized.
213         last_exception = exc;
214
215         name = mono_class_get_name (mono_object_get_class (exc));
216         if (!strcmp (name, "ThreadAbortException")) {
217                 MonoThread *thread = mono_thread_current ();
218                 mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_ABORT, 0, thread->tid);
219                 mono_thread_exit ();
220         }
221
222         mono_debugger_event (MONO_DEBUGGER_EVENT_UNHANDLED_EXCEPTION,
223                              (guint64) (gsize) exc, (guint64) (gsize) addr);
224         return TRUE;
225 }
226
227 void
228 mono_debugger_handle_exception (gpointer addr, gpointer stack, MonoObject *exc)
229 {
230         MonoDebuggerExceptionInfo info;
231
232         if (!mono_debugger_use_debugger)
233                 return;
234
235         // Prevent the object from being finalized.
236         last_exception = exc;
237
238         info.stack_pointer = stack;
239         info.exception_obj = exc;
240         info.stop = 0;
241
242         mono_debugger_event (MONO_DEBUGGER_EVENT_HANDLE_EXCEPTION, (guint64) (gsize) &info,
243                              (guint64) (gsize) addr);
244 }
245
246 gboolean
247 mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc)
248 {
249         MonoDebuggerExceptionInfo info;
250
251         if (!mono_debugger_use_debugger)
252                 return FALSE;
253
254         // Prevent the object from being finalized.
255         last_exception = exc;
256
257         info.stack_pointer = stack;
258         info.exception_obj = exc;
259         info.stop = 0;
260
261         mono_debugger_event (MONO_DEBUGGER_EVENT_THROW_EXCEPTION, (guint64) (gsize) &info,
262                              (guint64) (gsize) addr);
263         return info.stop != 0;
264 }
265
266 static gchar *
267 get_exception_message (MonoObject *exc)
268 {
269         char *message = NULL;
270         MonoString *str; 
271         MonoMethod *method;
272         MonoClass *klass;
273         gint i;
274
275         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
276                 klass = exc->vtable->klass;
277                 method = NULL;
278                 while (klass && method == NULL) {
279                         for (i = 0; i < klass->method.count; ++i) {
280                                 method = klass->methods [i];
281                                 if (!strcmp ("ToString", method->name) &&
282                                     mono_method_signature (method)->param_count == 0 &&
283                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
284                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
285                                         break;
286                                 }
287                                 method = NULL;
288                         }
289                         
290                         if (method == NULL)
291                                 klass = klass->parent;
292                 }
293
294                 g_assert (method);
295
296                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
297                 if (str)
298                         message = mono_string_to_utf8 (str);
299         }
300
301         return message;
302 }
303
304 MonoObject *
305 mono_debugger_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
306 {
307         MonoObject *retval;
308         gchar *message;
309
310         if (!strcmp (method->name, ".ctor")) {
311                 retval = obj = mono_object_new (mono_domain_get (), method->klass);
312
313                 mono_runtime_invoke (method, obj, params, exc);
314         } else
315                 retval = mono_runtime_invoke (method, obj, params, exc);
316
317         if (!exc || (*exc == NULL))
318                 return retval;
319
320         message = get_exception_message (*exc);
321         if (message) {
322                 *exc = (MonoObject *) mono_string_new_wrapper (message);
323                 g_free (message);
324         }
325
326         return retval;
327 }
328
329 gboolean
330 mono_debugger_lookup_type (const gchar *type_name)
331 {
332         int i;
333         mono_debugger_lock ();
334
335         for (i = 0; i < mono_symbol_table->num_symbol_files; i++) {
336                 MonoDebugHandle *symfile = mono_symbol_table->symbol_files [i];
337                 MonoType *type;
338                 MonoClass* klass;
339                 gchar *name;
340
341                 name = g_strdup (type_name);
342                 type = mono_reflection_type_from_name (name, symfile->image);
343                 g_free (name);
344                 if (!type)
345                         continue;
346
347                 klass = mono_class_from_mono_type (type);
348                 if (klass)
349                         mono_class_init (klass);
350
351                 mono_debugger_unlock ();
352                 return TRUE;
353         }
354
355         mono_debugger_unlock ();
356         return FALSE;
357 }
358
359 gint32
360 mono_debugger_lookup_assembly (const gchar *name)
361 {
362         MonoAssembly *assembly;
363         MonoImageOpenStatus status;
364         int i;
365
366         mono_debugger_lock ();
367
368  again:
369         for (i = 0; i < mono_symbol_table->num_symbol_files; i++) {
370                 MonoDebugHandle *symfile = mono_symbol_table->symbol_files [i];
371
372                 if (!strcmp (symfile->image_file, name)) {
373                         mono_debugger_unlock ();
374                         return i;
375                 }
376         }
377
378         assembly = mono_assembly_open (name, &status);
379
380         if (status != MONO_IMAGE_OK) {
381                 g_warning (G_STRLOC ": Cannot open image `%s'", name);
382                 mono_debugger_unlock ();
383                 return -1;
384         }
385
386         must_reload_symtabs = TRUE;
387         goto again;
388 }
389