2010-04-19 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / mono-debug-debugger.c
blob6755f63630980bd65f60e80a3cea1df44182be44
1 /*
2 * mono-debug-debugger.c:
4 * Author:
5 * Mono Project (http://www.mono-project.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 */
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>
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;
36 void (*mono_debugger_event_handler) (MonoDebuggerEvent event, guint64 data, guint64 arg) = NULL;
38 typedef struct
40 guint32 index;
41 MonoMethod *method;
42 MonoDebugMethodAddressList *address_list;
43 } MethodBreakpointInfo;
45 typedef struct {
46 MonoImage *image;
47 guint64 index;
48 guint32 token;
49 gchar *name_space;
50 gchar *name;
51 } ClassInitCallback;
53 typedef struct {
54 guint32 id;
55 guint32 shadow_path_len;
56 gchar *shadow_path;
57 MonoDomain *domain;
58 MonoAppDomainSetup *setup;
59 } AppDomainSetupInfo;
61 static GPtrArray *class_init_callbacks = NULL;
63 static int initialized = 0;
65 void
66 mono_debugger_lock (void)
68 g_assert (initialized);
69 EnterCriticalSection (&debugger_lock_mutex);
70 debugger_lock_level++;
73 void
74 mono_debugger_unlock (void)
76 g_assert (initialized);
77 debugger_lock_level--;
78 LeaveCriticalSection (&debugger_lock_mutex);
81 void
82 mono_debugger_initialize (gboolean use_debugger)
84 MONO_GC_REGISTER_ROOT (last_exception);
86 g_assert (!mono_debugger_use_debugger);
88 InitializeCriticalSection (&debugger_lock_mutex);
89 mono_debugger_use_debugger = use_debugger;
90 initialized = 1;
93 void
94 mono_debugger_event (MonoDebuggerEvent event, guint64 data, guint64 arg)
96 if (mono_debugger_event_handler)
97 (* mono_debugger_event_handler) (event, data, arg);
100 void
101 mono_debugger_event_create_appdomain (MonoDomain *domain, gchar *shadow_path)
103 AppDomainSetupInfo info;
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;
109 info.domain = domain;
110 info.setup = domain->setup;
112 mono_debugger_event (MONO_DEBUGGER_EVENT_CREATE_APPDOMAIN, (guint64) (gsize) &info, 0);
115 void
116 mono_debugger_event_unload_appdomain (MonoDomain *domain)
118 mono_debugger_event (MONO_DEBUGGER_EVENT_UNLOAD_APPDOMAIN,
119 (guint64) (gsize) domain, (guint64) mono_domain_get_id (domain));
122 void
123 mono_debugger_cleanup (void)
125 mono_debugger_event (MONO_DEBUGGER_EVENT_FINALIZE_MANAGED_CODE, 0, 0);
126 mono_debugger_event_handler = NULL;
129 void
130 mono_debugger_check_interruption (void)
132 if (!_mono_debugger_interruption_request)
133 return;
135 mono_debugger_lock ();
136 mono_debugger_event (MONO_DEBUGGER_EVENT_INTERRUPTION_REQUEST, 0, 0);
137 mono_debugger_unlock ();
141 * Debugger breakpoint interface.
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.
148 static GPtrArray *method_breakpoints = NULL;
150 MonoDebugMethodAddressList *
151 mono_debugger_insert_method_breakpoint (MonoMethod *method, guint64 index)
153 MethodBreakpointInfo *info;
155 info = g_new0 (MethodBreakpointInfo, 1);
156 info->method = method;
157 info->index = index;
159 info->address_list = mono_debug_lookup_method_addresses (method);
161 if (!method_breakpoints)
162 method_breakpoints = g_ptr_array_new ();
164 g_ptr_array_add (method_breakpoints, info);
166 return info->address_list;
170 mono_debugger_remove_method_breakpoint (guint64 index)
172 int i;
174 if (!method_breakpoints)
175 return 0;
177 for (i = 0; i < method_breakpoints->len; i++) {
178 MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
180 if (info->index != index)
181 continue;
183 g_ptr_array_remove (method_breakpoints, info);
184 g_free (info->address_list);
185 g_free (info);
186 return 1;
189 return 0;
192 void
193 mono_debugger_check_breakpoints (MonoMethod *method, MonoDebugMethodAddress *debug_info)
195 int i;
197 if (method->is_inflated)
198 method = ((MonoMethodInflated *) method)->declaring;
200 if (method_breakpoints) {
201 for (i = 0; i < method_breakpoints->len; i++) {
202 MethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
204 if (method != info->method)
205 continue;
207 mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
208 (guint64) (gsize) debug_info, info->index);
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);
216 if ((method->token != info->token) || (method->klass->image != info->image))
217 continue;
219 mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
220 (guint64) (gsize) debug_info, info->index);
225 MonoClass *
226 mono_debugger_register_class_init_callback (MonoImage *image, const gchar *full_name,
227 guint32 method_token, guint32 index)
229 ClassInitCallback *info;
230 MonoClass *klass;
231 gchar *name_space, *name, *pos;
233 name = g_strdup (full_name);
235 pos = strrchr (name, '.');
236 if (pos) {
237 name_space = name;
238 *pos = 0;
239 name = pos + 1;
240 } else {
241 name_space = NULL;
244 mono_loader_lock ();
246 klass = mono_class_from_name (image, name_space ? name_space : "", name);
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;
255 if (!class_init_callbacks)
256 class_init_callbacks = g_ptr_array_new ();
258 g_ptr_array_add (class_init_callbacks, info);
259 mono_loader_unlock ();
260 return klass;
263 void
264 mono_debugger_remove_class_init_callback (int index)
266 int i;
268 if (!class_init_callbacks)
269 return;
271 for (i = 0; i < class_init_callbacks->len; i++) {
272 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
274 if (info->index != index)
275 continue;
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);
286 void
287 mono_debugger_class_initialized (MonoClass *klass)
289 int i;
291 if (!class_init_callbacks)
292 return;
294 again:
295 for (i = 0; i < class_init_callbacks->len; i++) {
296 ClassInitCallback *info = g_ptr_array_index (class_init_callbacks, i);
298 if (info->name_space && strcmp (info->name_space, klass->name_space))
299 continue;
300 if (strcmp (info->name, klass->name))
301 continue;
303 mono_debugger_event (MONO_DEBUGGER_EVENT_CLASS_INITIALIZED,
304 (guint64) (gsize) klass, info->index);
306 if (info->token) {
307 int j;
309 for (j = 0; j < klass->method.count; j++) {
310 if (klass->methods [j]->token != info->token)
311 continue;
313 mono_debugger_insert_method_breakpoint (klass->methods [j], info->index);
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;