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