Fri Jun 6 11:41:18 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 = { NULL, method };
227
228         if (!mono_debug_handles)
229                 return NULL;
230
231         g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
232         return data.minfo;
233 }
234
235 /*
236  * This is called by the JIT to tell the debugging code about a newly compiled
237  * wrapper method.
238  */
239 void
240 mono_debug_add_wrapper (MonoMethod *method, MonoMethod *wrapper_method, MonoDomain *domain)
241 {
242         MonoClass *klass = method->klass;
243         MonoDebugHandle *handle;
244         MonoDebugMethodInfo *minfo;
245         MonoDebugMethodJitInfo *jit;
246         MonoDebugDomainData *domain_data;
247
248         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
249                 return;
250
251         mono_class_init (klass);
252
253         handle = _mono_debug_get_image (klass->image);
254         g_assert (handle);
255
256         minfo = _mono_debug_lookup_method (method);
257         if (!minfo)
258                 return;
259
260         domain_data = mono_debug_get_domain_data (handle, domain);
261         g_assert (!domain_data->jit [minfo->index]);
262
263         jit = g_hash_table_lookup (domain_data->_priv->wrapper_info, wrapper_method);
264         g_assert (jit);
265
266         mono_debugger_lock ();
267
268         domain_data->jit [minfo->index] = jit;
269         jit->wrapper_addr = method->addr;
270
271         if (handle->_priv->debugger_info && (domain == mono_root_domain))
272                 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
273
274         mono_debugger_unlock ();
275 }
276
277 /*
278  * This is called by the JIT to tell the debugging code about a newly
279  * compiled method.
280  */
281 void
282 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
283 {
284         MonoClass *klass = method->klass;
285         MonoDebugDomainData *domain_data;
286         MonoDebugHandle *handle;
287         MonoDebugMethodInfo *minfo;
288
289         mono_class_init (klass);
290
291         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
292             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
293             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
294             (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
295                 return;
296
297         handle = _mono_debug_get_image (klass->image);
298         g_assert (handle);
299
300         minfo = _mono_debug_lookup_method (method);
301         if (!minfo)
302                 return;
303
304         mono_debugger_lock ();
305
306         domain_data = mono_debug_get_domain_data (handle, domain);
307         g_assert (!domain_data->jit [minfo->index]);
308
309         if (method->wrapper_type != MONO_WRAPPER_NONE) {
310                 g_hash_table_insert (domain_data->_priv->wrapper_info, method, jit);
311                 mono_debugger_unlock ();
312                 return;
313         }
314
315         domain_data->jit [minfo->index] = jit;
316
317         if (handle->_priv->debugger_info && (domain == mono_root_domain))
318                 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
319
320         mono_debugger_unlock ();
321 }
322
323 static gint32
324 il_offset_from_address (MonoDebugMethodJitInfo *jit, guint32 address)
325 {
326         int i;
327
328         if (!jit || !jit->line_numbers)
329                 return -1;
330
331         for (i = jit->line_numbers->len - 1; i >= 0; i--) {
332                 MonoDebugLineNumberEntry lne = g_array_index (
333                         jit->line_numbers, MonoDebugLineNumberEntry, i);
334
335                 if (lne.address <= address)
336                         return lne.offset;
337         }
338
339         return -1;
340 }
341
342 /*
343  * Used by the exception code to get a source location from a machine address.
344  *
345  * Returns a textual representation of the specified address which is suitable to be displayed to
346  * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
347  *
348  * If the optional @line_number argument is not NULL, the line number is stored there and just the
349  * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
350  * line number 8 in the variable pointed to by @line_number).
351  */
352 gchar *
353 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
354                                          MonoDomain *domain)
355 {
356         MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
357         MonoDebugDomainData *domain_data;
358
359         if (!minfo)
360                 return NULL;
361
362         domain_data = mono_debug_get_domain_data (minfo->handle, domain);
363         if (!domain_data->jit [minfo->index])
364                 return NULL;
365
366         if (minfo->handle) {
367                 gint32 offset = il_offset_from_address (domain_data->jit [minfo->index], address);
368                 
369                 if (offset < 0)
370                         return NULL;
371
372                 return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
373         }
374
375         return NULL;
376 }
377
378 /*
379  * Used by the exception code to get a source location from an IL offset.
380  *
381  * Returns a textual representation of the specified address which is suitable to be displayed to
382  * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
383  *
384  * If the optional @line_number argument is not NULL, the line number is stored there and just the
385  * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
386  * line number 8 in the variable pointed to by @line_number).
387  */
388 gchar *
389 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
390 {
391         MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
392
393         if (!minfo || !minfo->handle)
394                 return NULL;
395
396         return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
397 }
398
399 /*
400  * Returns the IL offset corresponding to machine address @address which is an offset
401  * relative to the beginning of the method @method.
402  */
403 gint32
404 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
405 {
406         MonoDebugMethodInfo *minfo;
407         MonoDebugDomainData *domain_data;
408
409         if (address < 0)
410                 return -1;
411
412         minfo = _mono_debug_lookup_method (method);
413         if (!minfo || !minfo->il_offsets)
414                 return -1;
415
416         domain_data = mono_debug_get_domain_data (minfo->handle, domain);
417
418         return il_offset_from_address (domain_data->jit [minfo->index], address);
419 }
420
421 /*
422  * Returns the machine address corresponding to IL offset @il_offset.
423  * The returned value is an offset relative to the beginning of the method @method.
424  */
425 gint32
426 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
427 {
428         MonoDebugMethodInfo *minfo;
429         MonoDebugDomainData *domain_data;
430
431         if (il_offset < 0)
432                 return -1;
433
434         minfo = _mono_debug_lookup_method (method);
435         if (!minfo || !minfo->il_offsets)
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 MonoDebugDomainData *
444 mono_debug_get_domain_data (MonoDebugHandle *handle, MonoDomain *domain)
445 {
446         MonoDebugDomainData *data;
447
448         for (data = handle->_priv->domain_table; data; data = data->_priv->next)
449                 if (data->domain_id == domain->domain_id)
450                         return data;
451
452         data = g_new0 (MonoDebugDomainData, 1);
453         data->domain_id = domain->domain_id;
454         data->jit = g_new0 (MonoDebugMethodJitInfo *, handle->symfile->offset_table->method_count + 1);
455
456         data->_priv = g_new0 (MonoDebugDomainDataPriv, 1);
457         data->_priv->next = handle->_priv->domain_table;
458         data->_priv->wrapper_info = g_hash_table_new (g_direct_hash, g_direct_equal);
459         handle->_priv->domain_table = data;
460
461         return data;
462 }