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