[runtime] Remove mono_debug_using_mono_debugger. This would only return true under...
[mono.git] / mono / metadata / mono-debug-debugger.c
1 /*
2  * mono-debug-debugger.c: 
3  *
4  * Author:
5  *      Mono Project (http://www.mono-project.com)
6  *
7  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9  */
10
11 #include <config.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <mono/metadata/assembly.h>
15 #include <mono/metadata/metadata.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/gc-internal.h>
20 #include <mono/metadata/threads.h>
21 #include <mono/metadata/gc-internal.h>
22 #include <mono/metadata/object-internals.h>
23 #include <mono/metadata/class-internals.h>
24 #include <mono/metadata/domain-internals.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/mono-debug.h>
27 #include <mono/metadata/mono-debug-debugger.h>
28 #include <mono/metadata/mono-endian.h>
29
30 static guint32 debugger_lock_level = 0;
31 static CRITICAL_SECTION debugger_lock_mutex;
32 static MonoObject *last_exception = NULL;
33 volatile gint32 _mono_debugger_interruption_request = 0;
34
35 void (*mono_debugger_event_handler) (MonoDebuggerEvent event, guint64 data, guint64 arg) = NULL;
36
37 typedef struct
38 {
39         guint32 index;
40         MonoMethod *method;
41         MonoDebugMethodAddressList *address_list;
42 } MethodBreakpointInfo;
43
44 typedef struct {
45         MonoImage *image;
46         guint64 index;
47         guint32 token;
48         gchar *name_space;
49         gchar *name;
50 } ClassInitCallback;
51
52 typedef struct {
53         guint32 id;
54         guint32 shadow_path_len;
55         gchar *shadow_path;
56         MonoDomain *domain;
57         MonoAppDomainSetup *setup;
58 } AppDomainSetupInfo;
59
60 static GPtrArray *class_init_callbacks = NULL;
61
62 static int initialized = 0;
63
64 void
65 mono_debugger_lock (void)
66 {
67         g_assert (initialized);
68         EnterCriticalSection (&debugger_lock_mutex);
69         debugger_lock_level++;
70 }
71
72 void
73 mono_debugger_unlock (void)
74 {
75         g_assert (initialized);
76         debugger_lock_level--;
77         LeaveCriticalSection (&debugger_lock_mutex);
78 }
79
80 void
81 mono_debugger_initialize ()
82 {
83         MONO_GC_REGISTER_ROOT_SINGLE (last_exception);
84         
85         InitializeCriticalSection (&debugger_lock_mutex);
86         initialized = 1;
87 }
88
89 void
90 mono_debugger_event (MonoDebuggerEvent event, guint64 data, guint64 arg)
91 {
92         if (mono_debugger_event_handler)
93                 (* mono_debugger_event_handler) (event, data, arg);
94 }
95
96 void
97 mono_debugger_event_create_appdomain (MonoDomain *domain, gchar *shadow_path)
98 {
99         AppDomainSetupInfo info;
100
101         info.id = mono_domain_get_id (domain);
102         info.shadow_path_len = shadow_path ? strlen (shadow_path) : 0;
103         info.shadow_path = shadow_path;
104
105         info.domain = domain;
106         info.setup = domain->setup;
107
108         mono_debugger_event (MONO_DEBUGGER_EVENT_CREATE_APPDOMAIN, (guint64) (gsize) &info, 0);
109 }
110
111 void
112 mono_debugger_event_unload_appdomain (MonoDomain *domain)
113 {
114         mono_debugger_event (MONO_DEBUGGER_EVENT_UNLOAD_APPDOMAIN,
115                              (guint64) (gsize) domain, (guint64) mono_domain_get_id (domain));
116 }
117
118 void
119 mono_debugger_cleanup (void)
120 {
121         mono_debugger_event (MONO_DEBUGGER_EVENT_FINALIZE_MANAGED_CODE, 0, 0);
122         mono_debugger_event_handler = NULL;
123 }
124
125 void
126 mono_debugger_check_interruption (void)
127 {
128         if (!_mono_debugger_interruption_request)
129                 return;
130
131         mono_debugger_lock ();
132         mono_debugger_event (MONO_DEBUGGER_EVENT_INTERRUPTION_REQUEST, 0, 0);
133         mono_debugger_unlock ();
134 }
135
136 /*
137  * Debugger breakpoint interface.
138  *
139  * This interface is used to insert breakpoints on methods which are not yet JITed.
140  * The debugging code keeps a list of all such breakpoints and automatically inserts the
141  * breakpoint when the method is JITed.
142  */
143
144 static GPtrArray *method_breakpoints = NULL;
145
146 MonoDebugMethodAddressList *
147 mono_debugger_insert_method_breakpoint (MonoMethod *method, guint64 index)
148 {
149         MethodBreakpointInfo *info;
150
151         info = g_new0 (MethodBreakpointInfo, 1);
152         info->method = method;
153         info->index = index;
154
155         info->address_list = mono_debug_lookup_method_addresses (method);
156
157         if (!method_breakpoints)
158                 method_breakpoints = g_ptr_array_new ();
159
160         g_ptr_array_add (method_breakpoints, info);
161
162         return info->address_list;
163 }
164
165 int
166 mono_debugger_remove_method_breakpoint (guint64 index)
167 {
168         int i;
169
170         if (!method_breakpoints)
171                 return 0;
172
173         for (i = 0; i < method_breakpoints->len; i++) {
174                 MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
175
176                 if (info->index != index)
177                         continue;
178
179                 g_ptr_array_remove (method_breakpoints, info);
180                 g_free (info->address_list);
181                 g_free (info);
182                 return 1;
183         }
184
185         return 0;
186 }
187
188 void
189 mono_debugger_check_breakpoints (MonoMethod *method, MonoDebugMethodAddress *debug_info)
190 {
191         int i;
192
193         if (method->is_inflated)
194                 method = ((MonoMethodInflated *) method)->declaring;
195
196         if (method_breakpoints) {
197                 for (i = 0; i < method_breakpoints->len; i++) {
198                         MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
199
200                         if (method != info->method)
201                                 continue;
202
203                         mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
204                                              (guint64) (gsize) debug_info, info->index);
205                 }
206         }
207
208         if (class_init_callbacks) {
209                 for (i = 0; i < class_init_callbacks->len; i++) {
210                         ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
211
212                         if ((method->token != info->token) || (method->klass->image != info->image))
213                                 continue;
214
215                         mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
216                                              (guint64) (gsize) debug_info, info->index);
217                 }
218         }
219 }
220
221 MonoClass *
222 mono_debugger_register_class_init_callback (MonoImage *image, const gchar *full_name,
223                                             guint32 method_token, guint32 index)
224 {
225         ClassInitCallback *info;
226         MonoClass *klass;
227         gchar *name_space, *name, *pos;
228
229         name = g_strdup (full_name);
230
231         pos = strrchr (name, '.');
232         if (pos) {
233                 name_space = name;
234                 *pos = 0;
235                 name = pos + 1;
236         } else {
237                 name_space = NULL;
238         }
239
240         mono_loader_lock ();
241
242         klass = mono_class_from_name (image, name_space ? name_space : "", name);
243
244         info = g_new0 (ClassInitCallback, 1);
245         info->image = image;
246         info->index = index;
247         info->token = method_token;
248         info->name_space = name_space;
249         info->name = name;
250
251         if (!class_init_callbacks)
252                 class_init_callbacks = g_ptr_array_new ();
253
254         g_ptr_array_add (class_init_callbacks, info);
255         mono_loader_unlock ();
256         return klass;
257 }
258
259 void
260 mono_debugger_remove_class_init_callback (int index)
261 {
262         int i;
263
264         if (!class_init_callbacks)
265                 return;
266
267         for (i = 0; i < class_init_callbacks->len; i++) {
268                 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
269
270                 if (info->index != index)
271                         continue;
272
273                 g_ptr_array_remove (class_init_callbacks, info);
274                 if (info->name_space)
275                         g_free (info->name_space);
276                 else
277                         g_free (info->name);
278                 g_free (info);
279         }
280 }
281
282 void
283 mono_debugger_class_initialized (MonoClass *klass)
284 {
285         int i;
286
287         if (!class_init_callbacks)
288                 return;
289
290  again:
291         for (i = 0; i < class_init_callbacks->len; i++) {
292                 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
293
294                 if (info->name_space && strcmp (info->name_space, klass->name_space))
295                         continue;
296                 if (strcmp (info->name, klass->name))
297                         continue;
298
299                 mono_debugger_event (MONO_DEBUGGER_EVENT_CLASS_INITIALIZED,
300                                      (guint64) (gsize) klass, info->index);
301
302                 if (info->token) {
303                         int j;
304
305                         for (j = 0; j < klass->method.count; j++) {
306                                 if (klass->methods [j]->token != info->token)
307                                         continue;
308
309                                 mono_debugger_insert_method_breakpoint (klass->methods [j], info->index);
310                         }
311                 }
312
313                 g_ptr_array_remove (class_init_callbacks, info);
314                 if (info->name_space)
315                         g_free (info->name_space);
316                 else
317                         g_free (info->name);
318                 g_free (info);
319                 goto again;
320         }
321 }