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