2007-07-22 Zoltan Varga <vargaz@gmail.com>
[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_event (MonoDebuggerEvent event, guint64 data, guint64 arg)
97 {
98         if (mono_debugger_event_handler)
99                 (* mono_debugger_event_handler) (event, data, arg);
100 }
101
102 void
103 mono_debugger_cleanup (void)
104 {
105         mono_debugger_event (MONO_DEBUGGER_EVENT_FINALIZE_MANAGED_CODE, 0, 0);
106         mono_debugger_event_handler = NULL;
107 }
108
109 gboolean
110 mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc)
111 {
112         const gchar *name;
113
114         if (!mono_debugger_use_debugger)
115                 return FALSE;
116
117         // Prevent the object from being finalized.
118         last_exception = exc;
119
120         name = mono_class_get_name (mono_object_get_class (exc));
121         if (!strcmp (name, "ThreadAbortException")) {
122                 MonoThread *thread = mono_thread_current ();
123                 mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_ABORT, 0, thread->tid);
124                 mono_thread_exit ();
125         }
126
127         mono_debugger_event (MONO_DEBUGGER_EVENT_UNHANDLED_EXCEPTION,
128                              (guint64) (gsize) exc, (guint64) (gsize) addr);
129         return TRUE;
130 }
131
132 void
133 mono_debugger_handle_exception (gpointer addr, gpointer stack, MonoObject *exc)
134 {
135         MonoDebuggerExceptionInfo info;
136
137         if (!mono_debugger_use_debugger)
138                 return;
139
140         // Prevent the object from being finalized.
141         last_exception = exc;
142
143         info.stack_pointer = stack;
144         info.exception_obj = exc;
145         info.stop = 0;
146
147         mono_debugger_event (MONO_DEBUGGER_EVENT_HANDLE_EXCEPTION, (guint64) (gsize) &info,
148                              (guint64) (gsize) addr);
149 }
150
151 gboolean
152 mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc)
153 {
154         MonoDebuggerExceptionInfo info;
155
156         if (!mono_debugger_use_debugger)
157                 return FALSE;
158
159         // Prevent the object from being finalized.
160         last_exception = exc;
161
162         info.stack_pointer = stack;
163         info.exception_obj = exc;
164         info.stop = 0;
165
166         mono_debugger_event (MONO_DEBUGGER_EVENT_THROW_EXCEPTION, (guint64) (gsize) &info,
167                              (guint64) (gsize) addr);
168         return info.stop != 0;
169 }
170
171 static gchar *
172 get_exception_message (MonoObject *exc)
173 {
174         char *message = NULL;
175         MonoString *str; 
176         MonoMethod *method;
177         MonoClass *klass;
178         gint i;
179
180         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
181                 klass = exc->vtable->klass;
182                 method = NULL;
183                 while (klass && method == NULL) {
184                         for (i = 0; i < klass->method.count; ++i) {
185                                 method = klass->methods [i];
186                                 if (!strcmp ("ToString", method->name) &&
187                                     mono_method_signature (method)->param_count == 0 &&
188                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
189                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
190                                         break;
191                                 }
192                                 method = NULL;
193                         }
194                         
195                         if (method == NULL)
196                                 klass = klass->parent;
197                 }
198
199                 g_assert (method);
200
201                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
202                 if (str)
203                         message = mono_string_to_utf8 (str);
204         }
205
206         return message;
207 }
208
209 MonoObject *
210 mono_debugger_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
211 {
212         MonoObject *retval;
213         gchar *message;
214
215         if (!strcmp (method->name, ".ctor")) {
216                 retval = obj = mono_object_new (mono_domain_get (), method->klass);
217
218                 mono_runtime_invoke (method, obj, params, exc);
219         } else
220                 retval = mono_runtime_invoke (method, obj, params, exc);
221
222         if (!exc || (*exc == NULL))
223                 return retval;
224
225         message = get_exception_message (*exc);
226         if (message) {
227                 *exc = (MonoObject *) mono_string_new_wrapper (message);
228                 g_free (message);
229         }
230
231         return retval;
232 }
233
234 gboolean
235 mono_debugger_lookup_type (const gchar *type_name)
236 {
237         int i;
238         mono_debugger_lock ();
239
240         for (i = 0; i < mono_symbol_table->num_symbol_files; i++) {
241                 MonoDebugHandle *symfile = mono_symbol_table->symbol_files [i];
242                 MonoType *type;
243                 MonoClass* klass;
244                 gchar *name;
245
246                 name = g_strdup (type_name);
247                 type = mono_reflection_type_from_name (name, symfile->image);
248                 g_free (name);
249                 if (!type)
250                         continue;
251
252                 klass = mono_class_from_mono_type (type);
253                 if (klass)
254                         mono_class_init (klass);
255
256                 mono_debugger_unlock ();
257                 return TRUE;
258         }
259
260         mono_debugger_unlock ();
261         return FALSE;
262 }
263
264 gint32
265 mono_debugger_lookup_assembly (const gchar *name)
266 {
267         MonoAssembly *assembly;
268         MonoImageOpenStatus status;
269         int i;
270
271         mono_debugger_lock ();
272
273  again:
274         for (i = 0; i < mono_symbol_table->num_symbol_files; i++) {
275                 MonoDebugHandle *symfile = mono_symbol_table->symbol_files [i];
276
277                 if (!strcmp (symfile->image_file, name)) {
278                         mono_debugger_unlock ();
279                         return i;
280                 }
281         }
282
283         assembly = mono_assembly_open (name, &status);
284
285         if (status != MONO_IMAGE_OK) {
286                 g_warning (G_STRLOC ": Cannot open image `%s'", name);
287                 mono_debugger_unlock ();
288                 return -1;
289         }
290
291         must_reload_symtabs = TRUE;
292         goto again;
293 }
294
295 void
296 mono_debugger_add_type (MonoDebugHandle *symfile, MonoClass *klass)
297 {
298         must_reload_symtabs = TRUE;
299
300 }