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>
11 struct _MonoDebugHandlePriv
13 MonoDebuggerSymbolFile *debugger_info;
14 MonoDebugDomainData *domain_table;
17 struct _MonoDebugDomainDataPriv
19 GHashTable *wrapper_info;
20 MonoDebugDomainData *next;
23 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
25 static gboolean in_the_mono_debugger = FALSE;
26 static gboolean mono_debug_initialized = FALSE;
27 GHashTable *mono_debug_handles = NULL;
29 static MonoDebugHandle *mono_debug_open_image (MonoImage *image);
30 static void mono_debug_close_image (MonoDebugHandle *debug);
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);
36 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
39 * Initialize debugging support.
41 * This method must be called after loading corlib,
42 * but before opening the application's main assembly because we need to set some
46 mono_debug_init (MonoDomain *domain, MonoDebugFormat format)
50 g_assert (!mono_debug_initialized);
52 mono_debug_initialized = TRUE;
53 mono_debug_format = format;
54 in_the_mono_debugger = format == MONO_DEBUG_FORMAT_DEBUGGER;
56 if (in_the_mono_debugger)
57 mono_debugger_initialize (domain);
59 mono_debugger_lock ();
61 mono_debug_handles = g_hash_table_new_full
62 (NULL, NULL, NULL, (GDestroyNotify) mono_debug_close_image);
64 mono_debugger_class_init_func = mono_debug_add_type;
65 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
67 mono_debug_open_image (mono_get_corlib ());
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);
76 * Initialize debugging support - part 2.
78 * This method must be called after loading the application's main assembly.
81 mono_debug_init_2 (MonoAssembly *assembly)
83 MonoDebugHandle *handle;
85 mono_debug_open_image (mono_assembly_get_image (assembly));
87 handle = _mono_debug_get_image (mono_get_corlib ());
92 mono_debug_cleanup (void)
94 mono_debugger_cleanup ();
96 if (mono_debug_handles)
97 g_hash_table_destroy (mono_debug_handles);
98 mono_debug_handles = NULL;
101 static MonoDebugHandle *
102 _mono_debug_get_image (MonoImage *image)
104 return g_hash_table_lookup (mono_debug_handles, image);
107 static MonoDebugHandle *
108 mono_debug_open_image (MonoImage *image)
110 MonoDebugHandle *handle;
112 handle = _mono_debug_get_image (image);
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);
122 g_hash_table_insert (mono_debug_handles, image, handle);
124 if (mono_image_is_dynamic (image))
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);
138 mono_debug_close_image (MonoDebugHandle *handle)
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);
150 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
152 mono_debugger_lock ();
153 mono_debug_open_image (mono_assembly_get_image (assembly));
154 mono_debugger_unlock ();
158 * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
159 * a new class is initialized.
162 mono_debug_add_type (MonoClass *klass)
164 MonoDebugHandle *handle;
166 handle = _mono_debug_get_image (klass->image);
170 if (handle->_priv->debugger_info)
171 mono_debugger_add_type (handle->_priv->debugger_info, klass);
174 struct LookupMethodData
176 MonoDebugMethodInfo *minfo;
181 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
183 MonoDebugHandle *handle = (MonoDebugHandle *) value;
184 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
190 data->minfo = mono_debug_find_method (handle, data->method);
193 static MonoDebugMethodInfo *
194 _mono_debug_lookup_method (MonoMethod *method)
196 struct LookupMethodData data;
199 data.method = method;
201 if (!mono_debug_handles)
204 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
209 * This is called by the JIT to tell the debugging code about a newly compiled
213 mono_debug_add_wrapper (MonoMethod *method, MonoMethod *wrapper_method, MonoDomain *domain)
215 MonoClass *klass = mono_method_get_class (method);
216 MonoDebugHandle *handle;
217 MonoDebugMethodInfo *minfo;
218 MonoDebugMethodJitInfo *jit;
219 MonoDebugDomainData *domain_data;
222 mono_method_get_flags (method, &iflags);
223 if (!(iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
226 mono_class_init (klass);
228 handle = _mono_debug_get_image (klass->image);
231 minfo = _mono_debug_lookup_method (method);
235 domain_data = mono_debug_get_domain_data (handle, domain);
236 if (domain_data->jit [minfo->index]) {
238 // This is bug #48591.
242 jit = g_hash_table_lookup (domain_data->_priv->wrapper_info, wrapper_method);
245 mono_debugger_lock ();
247 domain_data->jit [minfo->index] = jit;
248 jit->wrapper_addr = method->addr;
250 if (handle->_priv->debugger_info && (domain == mono_get_root_domain ()))
251 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
253 mono_debugger_unlock ();
257 * This is called by the JIT to tell the debugging code about a newly
261 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
263 MonoClass *klass = method->klass;
264 MonoDebugDomainData *domain_data;
265 MonoDebugHandle *handle;
266 MonoDebugMethodInfo *minfo;
268 mono_class_init (klass);
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))
276 handle = _mono_debug_get_image (klass->image);
280 minfo = _mono_debug_lookup_method (method);
284 mono_debugger_lock ();
286 domain_data = mono_debug_get_domain_data (handle, domain);
287 if (domain_data->jit [minfo->index]) {
289 // This is bug #48591.
290 mono_debugger_unlock ();
294 if (method->wrapper_type != MONO_WRAPPER_NONE) {
295 g_hash_table_insert (domain_data->_priv->wrapper_info, method, jit);
296 mono_debugger_unlock ();
300 domain_data->jit [minfo->index] = jit;
302 if (handle->_priv->debugger_info && (domain == mono_get_root_domain ()))
303 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
305 mono_debugger_unlock ();
309 il_offset_from_address (MonoDebugMethodJitInfo *jit, guint32 address)
313 if (!jit || !jit->line_numbers)
316 for (i = jit->line_numbers->len - 1; i >= 0; i--) {
317 MonoDebugLineNumberEntry lne = g_array_index (
318 jit->line_numbers, MonoDebugLineNumberEntry, i);
320 if (lne.address <= address)
328 * Used by the exception code to get a source location from a machine address.
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").
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).
338 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
341 MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
342 MonoDebugDomainData *domain_data;
347 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
348 if (!domain_data->jit [minfo->index])
352 gint32 offset = il_offset_from_address (domain_data->jit [minfo->index], address);
357 return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
364 * Used by the exception code to get a source location from an IL offset.
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").
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).
374 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
376 MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
378 if (!minfo || !minfo->handle)
381 return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
385 * Returns the IL offset corresponding to machine address @address which is an offset
386 * relative to the beginning of the method @method.
389 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
391 MonoDebugMethodInfo *minfo;
392 MonoDebugDomainData *domain_data;
397 minfo = _mono_debug_lookup_method (method);
398 if (!minfo || !minfo->il_offsets)
401 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
403 return il_offset_from_address (domain_data->jit [minfo->index], address);
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.
411 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
413 MonoDebugMethodInfo *minfo;
414 MonoDebugDomainData *domain_data;
419 minfo = _mono_debug_lookup_method (method);
420 if (!minfo || !minfo->il_offsets)
423 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
425 return _mono_debug_address_from_il_offset (domain_data->jit [minfo->index], il_offset);
428 MonoDebugDomainData *
429 mono_debug_get_domain_data (MonoDebugHandle *handle, MonoDomain *domain)
431 MonoDebugDomainData *data;
432 int domain_id = mono_domain_get_id (domain);
434 for (data = handle->_priv->domain_table; data; data = data->_priv->next)
435 if (data->domain_id == domain_id)
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);
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;