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