Patch for bug #62532 implemention of a kqueue/kevent based FileSystemWatcher.
[mono.git] / mono / metadata / mono-debug.c
1 #include <config.h>
2 #include <mono/metadata/assembly.h>
3 #include <mono/metadata/tabledefs.h>
4 #include <mono/metadata/tokentype.h>
5 #include <mono/metadata/appdomain.h>
6 #include <mono/metadata/class-internals.h>
7 #include <mono/metadata/mono-debug.h>
8 #include <mono/metadata/mono-debug-debugger.h>
9 #include <mono/metadata/mono-endian.h>
10
11 struct _MonoDebugHandlePriv
12 {
13         MonoDebuggerSymbolFile *debugger_info;
14         MonoDebugDomainData *domain_table;
15 };
16
17 struct _MonoDebugDomainDataPriv
18 {
19         GHashTable *wrapper_info;
20         MonoDebugDomainData *next;
21 };
22
23 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
24
25 static gboolean in_the_mono_debugger = FALSE;
26 static gboolean mono_debug_initialized = FALSE;
27 GHashTable *mono_debug_handles = NULL;
28
29 static MonoDebugHandle     *mono_debug_open_image      (MonoImage *image);
30 static void                 mono_debug_close_image     (MonoDebugHandle *debug);
31
32 static MonoDebugHandle     *_mono_debug_get_image      (MonoImage *image);
33 static void                 mono_debug_add_assembly    (MonoAssembly *assembly,
34                                                         gpointer user_data);
35 static void                 mono_debug_start_add_type  (MonoClass *klass);
36 static void                 mono_debug_add_type        (MonoClass *klass);
37 static MonoDebugDomainData *mono_debug_get_domain_data (MonoDebugHandle *handle,
38                                                         MonoDomain *domain);
39
40 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
41 extern void (*mono_debugger_start_class_init_func) (MonoClass *klass);
42
43 /*
44  * Initialize debugging support.
45  *
46  * This method must be called after loading corlib,
47  * but before opening the application's main assembly because we need to set some
48  * callbacks here.
49  */
50 void
51 mono_debug_init (MonoDebugFormat format)
52 {
53         g_assert (!mono_debug_initialized);
54
55         mono_debug_initialized = TRUE;
56         mono_debug_format = format;
57         in_the_mono_debugger = format == MONO_DEBUG_FORMAT_DEBUGGER;
58
59         if (in_the_mono_debugger)
60                 mono_debugger_initialize ();
61
62         mono_debugger_lock ();
63
64         mono_debug_handles = g_hash_table_new_full
65                 (NULL, NULL, NULL, (GDestroyNotify) mono_debug_close_image);
66
67         mono_debugger_start_class_init_func = mono_debug_start_add_type;
68         mono_debugger_class_init_func = mono_debug_add_type;
69         mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
70 }
71
72 void
73 mono_debug_init_1 (MonoDomain *domain)
74 {
75         MonoDebugHandle *handle = mono_debug_open_image (mono_get_corlib ());
76
77         if (in_the_mono_debugger)
78                 mono_debugger_add_builtin_types (handle->_priv->debugger_info);
79 }
80
81 /*
82  * Initialize debugging support - part 2.
83  *
84  * This method must be called after loading the application's main assembly.
85  */
86 void
87 mono_debug_init_2 (MonoAssembly *assembly)
88 {
89         mono_debug_open_image (mono_assembly_get_image (assembly));
90 }
91
92 void
93 mono_debug_cleanup (void)
94 {
95         mono_debugger_cleanup ();
96
97         if (mono_debug_handles)
98                 g_hash_table_destroy (mono_debug_handles);
99         mono_debug_handles = NULL;
100 }
101
102 static MonoDebugHandle *
103 _mono_debug_get_image (MonoImage *image)
104 {
105         return g_hash_table_lookup (mono_debug_handles, image);
106 }
107
108 static MonoDebugHandle *
109 mono_debug_open_image (MonoImage *image)
110 {
111         MonoDebugHandle *handle;
112
113         handle = _mono_debug_get_image (image);
114         if (handle != NULL)
115                 return handle;
116
117         handle = g_new0 (MonoDebugHandle, 1);
118         handle->image = image;
119         mono_image_addref (image);
120         handle->image_file = g_strdup (mono_image_get_filename (image));
121         handle->_priv = g_new0 (MonoDebugHandlePriv, 1);
122
123         g_hash_table_insert (mono_debug_handles, image, handle);
124
125         if (mono_image_is_dynamic (image))
126                 return handle;
127
128         handle->symfile = mono_debug_open_mono_symbol_file (handle, in_the_mono_debugger);
129         if (in_the_mono_debugger)
130                 handle->_priv->debugger_info = mono_debugger_add_symbol_file (handle);
131
132         return handle;
133 }
134
135 static void
136 mono_debug_close_image (MonoDebugHandle *handle)
137 {
138         if (handle->symfile)
139                 mono_debug_close_mono_symbol_file (handle->symfile);
140         /* decrease the refcount added with mono_image_addref () */
141         mono_image_close (handle->image);
142         /* FIXME: should also free handle->image_file? */
143         g_free (handle->_priv);
144         g_free (handle);
145 }
146
147 static void
148 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
149 {
150         mono_debugger_lock ();
151         mono_debug_open_image (mono_assembly_get_image (assembly));
152         mono_debugger_unlock ();
153 }
154
155 /*
156  * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
157  * a new class is initialized.
158  */
159 MonoDebuggerSymbolFile *
160 _mono_debugger_get_symfile (MonoImage *image)
161 {
162         MonoDebugHandle *handle = _mono_debug_get_image (image);
163         if (!handle)
164                 return NULL;
165
166         return handle->_priv->debugger_info;
167 }
168
169 static void
170 mono_debug_start_add_type (MonoClass *klass)
171 {
172         MonoDebugHandle *handle;
173
174         handle = _mono_debug_get_image (klass->image);
175         if (!handle)
176                 return;
177
178         if (handle->_priv->debugger_info)
179                 mono_debugger_start_add_type (handle->_priv->debugger_info, klass);
180 }
181
182 static void
183 mono_debug_add_type (MonoClass *klass)
184 {
185         MonoDebugHandle *handle;
186
187         handle = _mono_debug_get_image (klass->image);
188         if (!handle)
189                 return;
190
191         if (handle->_priv->debugger_info)
192                 mono_debugger_add_type (handle->_priv->debugger_info, klass);
193 }
194
195
196 struct LookupMethodData
197 {
198         MonoDebugMethodInfo *minfo;
199         MonoMethod *method;
200 };
201
202 static void
203 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
204 {
205         MonoDebugHandle *handle = (MonoDebugHandle *) value;
206         struct LookupMethodData *data = (struct LookupMethodData *) user_data;
207
208         if (data->minfo)
209                 return;
210
211         if (handle->symfile)
212                 data->minfo = mono_debug_find_method (handle, data->method);
213 }
214
215 static MonoDebugMethodInfo *
216 _mono_debug_lookup_method (MonoMethod *method)
217 {
218         struct LookupMethodData data;
219
220         data.minfo = NULL;
221         data.method = method;
222
223         if (!mono_debug_handles)
224                 return NULL;
225
226         g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
227         return data.minfo;
228 }
229
230 /*
231  * This is called by the JIT to tell the debugging code about a newly compiled
232  * wrapper method.
233  */
234 void
235 mono_debug_add_wrapper (MonoMethod *method, gpointer wrapper, MonoDomain *domain)
236 {
237         MonoClass *klass = method->klass;
238         MonoDebugDomainData *domain_data;
239         MonoDebugHandle *handle;
240         MonoDebugMethodJitInfo *jit;
241
242         mono_debugger_lock ();
243
244         mono_class_init (klass);
245
246         handle = _mono_debug_get_image (klass->image);
247         if (!handle || !handle->symfile || !handle->symfile->offset_table) {
248                 mono_debugger_unlock ();
249                 return;
250         }
251
252         domain_data = mono_debug_get_domain_data (handle, domain);
253         jit = g_hash_table_lookup (domain_data->_priv->wrapper_info, method);
254         g_assert (jit);
255
256         mono_debugger_add_wrapper (method, jit, wrapper);
257
258         mono_debugger_unlock ();
259 }
260
261 /*
262  * This is called by the JIT to tell the debugging code about a newly
263  * compiled method.
264  */
265 void
266 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
267 {
268         MonoClass *klass = method->klass;
269         MonoDebugDomainData *domain_data;
270         MonoDebugHandle *handle;
271         MonoDebugMethodInfo *minfo;
272
273         mono_debugger_lock ();
274
275         mono_class_init (klass);
276
277         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
278             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
279             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
280             (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
281                 mono_debugger_unlock ();
282                 return;
283         }
284
285         handle = _mono_debug_get_image (klass->image);
286         if (!handle || !handle->symfile || !handle->symfile->offset_table) {
287                 mono_debugger_unlock ();
288                 return;
289         }
290
291         domain_data = mono_debug_get_domain_data (handle, domain);
292         if (method->wrapper_type != MONO_WRAPPER_NONE) {
293                 g_hash_table_insert (domain_data->_priv->wrapper_info, method, jit);
294                 mono_debugger_unlock ();
295                 return;
296         }
297
298         minfo = _mono_debug_lookup_method (method);
299         if (!minfo) {
300                 mono_debugger_unlock ();
301                 return;
302         }
303
304         if (domain_data->jit [minfo->index]) {
305                 /* FIXME FIXME FIXME
306                 // This is bug #48591.
307                 */
308                 mono_debugger_unlock ();
309                 return;
310         }
311
312         domain_data->jit [minfo->index] = jit;
313
314         if (handle->_priv->debugger_info && (domain == mono_get_root_domain ()))
315                 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
316
317         mono_debugger_unlock ();
318 }
319
320 static gint32
321 il_offset_from_address (MonoDebugMethodJitInfo *jit, guint32 address)
322 {
323         int i;
324
325         if (!jit || !jit->line_numbers)
326                 return -1;
327
328         for (i = jit->line_numbers->len - 1; i >= 0; i--) {
329                 MonoDebugLineNumberEntry lne = g_array_index (
330                         jit->line_numbers, MonoDebugLineNumberEntry, i);
331
332                 if (lne.address <= address)
333                         return lne.offset;
334         }
335
336         return -1;
337 }
338
339 /*
340  * Used by the exception code to get a source location from a machine address.
341  *
342  * Returns a textual representation of the specified address which is suitable to be displayed to
343  * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
344  *
345  * If the optional @line_number argument is not NULL, the line number is stored there and just the
346  * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
347  * line number 8 in the variable pointed to by @line_number).
348  */
349 gchar *
350 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
351                                          MonoDomain *domain)
352 {
353         MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
354         MonoDebugDomainData *domain_data;
355
356         if (!minfo || !minfo->handle || !minfo->handle->symfile ||
357             !minfo->handle->symfile->offset_table)
358                 return NULL;
359
360         domain_data = mono_debug_get_domain_data (minfo->handle, domain);
361         if (!domain_data->jit [minfo->index])
362                 return NULL;
363
364         if (minfo->handle && minfo->handle->symfile) {
365                 gint32 offset = il_offset_from_address (domain_data->jit [minfo->index], address);
366                 
367                 if (offset < 0)
368                         return NULL;
369
370                 return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
371         }
372
373         return NULL;
374 }
375
376 /*
377  * Used by the exception code to get a source location from an IL offset.
378  *
379  * Returns a textual representation of the specified address which is suitable to be displayed to
380  * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
381  *
382  * If the optional @line_number argument is not NULL, the line number is stored there and just the
383  * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
384  * line number 8 in the variable pointed to by @line_number).
385  */
386 gchar *
387 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
388 {
389         MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
390
391         if (!minfo || !minfo->handle || !minfo->handle->symfile)
392                 return NULL;
393
394         return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
395 }
396
397 /*
398  * Returns the IL offset corresponding to machine address @address which is an offset
399  * relative to the beginning of the method @method.
400  */
401 gint32
402 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
403 {
404         MonoDebugMethodInfo *minfo;
405         MonoDebugDomainData *domain_data;
406
407         if (address < 0)
408                 return -1;
409
410         minfo = _mono_debug_lookup_method (method);
411         if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
412             !minfo->handle->symfile->offset_table)
413                 return -1;
414
415         domain_data = mono_debug_get_domain_data (minfo->handle, domain);
416
417         return il_offset_from_address (domain_data->jit [minfo->index], address);
418 }
419
420 /*
421  * Returns the machine address corresponding to IL offset @il_offset.
422  * The returned value is an offset relative to the beginning of the method @method.
423  */
424 gint32
425 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
426 {
427         MonoDebugMethodInfo *minfo;
428         MonoDebugDomainData *domain_data;
429
430         if (il_offset < 0)
431                 return -1;
432
433         minfo = _mono_debug_lookup_method (method);
434         if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
435             !minfo->handle->symfile->offset_table)
436                 return -1;
437
438         domain_data = mono_debug_get_domain_data (minfo->handle, domain);
439
440         return _mono_debug_address_from_il_offset (domain_data->jit [minfo->index], il_offset);
441 }
442
443 static MonoDebugDomainData *
444 mono_debug_get_domain_data (MonoDebugHandle *handle, MonoDomain *domain)
445 {
446         MonoDebugDomainData *data;
447         int domain_id = mono_domain_get_id (domain);
448
449         /* We checked this earlier. */
450         g_assert (handle->symfile);
451
452         for (data = handle->_priv->domain_table; data; data = data->_priv->next)
453                 if (data->domain_id == domain_id)
454                         return data;
455
456         data = g_new0 (MonoDebugDomainData, 1);
457         data->domain_id = domain_id;
458         data->jit = g_new0 (MonoDebugMethodJitInfo *, read32(&(handle->symfile->offset_table->_method_count)) + 1);
459
460         data->_priv = g_new0 (MonoDebugDomainDataPriv, 1);
461         data->_priv->next = handle->_priv->domain_table;
462         data->_priv->wrapper_info = g_hash_table_new (g_direct_hash, g_direct_equal);
463         handle->_priv->domain_table = data;
464
465         return data;
466 }