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