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,
35 static void mono_debug_start_add_type (MonoClass *klass);
36 static void mono_debug_add_type (MonoClass *klass);
37 static MonoDebugDomainData *mono_debug_get_domain_data (MonoDebugHandle *handle,
40 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
41 extern void (*mono_debugger_start_class_init_func) (MonoClass *klass);
44 * Initialize debugging support.
46 * This method must be called after loading corlib,
47 * but before opening the application's main assembly because we need to set some
51 mono_debug_init (MonoDebugFormat format)
53 g_assert (!mono_debug_initialized);
55 mono_debug_initialized = TRUE;
56 mono_debug_format = format;
57 in_the_mono_debugger = format == MONO_DEBUG_FORMAT_DEBUGGER;
59 if (in_the_mono_debugger)
60 mono_debugger_initialize ();
62 mono_debugger_lock ();
64 mono_debug_handles = g_hash_table_new_full
65 (NULL, NULL, NULL, (GDestroyNotify) mono_debug_close_image);
67 mono_debugger_start_class_init_func = mono_debug_start_add_type;
68 mono_debugger_class_init_func = mono_debug_add_type;
69 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
73 mono_debug_init_1 (MonoDomain *domain)
75 MonoDebugHandle *handle = mono_debug_open_image (mono_get_corlib ());
77 if (in_the_mono_debugger)
78 mono_debugger_add_builtin_types (handle->_priv->debugger_info);
82 * Initialize debugging support - part 2.
84 * This method must be called after loading the application's main assembly.
87 mono_debug_init_2 (MonoAssembly *assembly)
89 mono_debug_open_image (mono_assembly_get_image (assembly));
93 mono_debug_cleanup (void)
95 mono_debugger_cleanup ();
97 if (mono_debug_handles)
98 g_hash_table_destroy (mono_debug_handles);
99 mono_debug_handles = NULL;
102 static MonoDebugHandle *
103 _mono_debug_get_image (MonoImage *image)
105 return g_hash_table_lookup (mono_debug_handles, image);
108 static MonoDebugHandle *
109 mono_debug_open_image (MonoImage *image)
111 MonoDebugHandle *handle;
113 handle = _mono_debug_get_image (image);
117 handle = g_new0 (MonoDebugHandle, 1);
118 handle->image = image;
119 mono_image_addref (image);
120 handle->image_file = g_strdup (mono_image_get_filename (image));
121 handle->_priv = g_new0 (MonoDebugHandlePriv, 1);
123 g_hash_table_insert (mono_debug_handles, image, handle);
125 if (mono_image_is_dynamic (image))
128 handle->symfile = mono_debug_open_mono_symbol_file (handle, in_the_mono_debugger);
129 if (in_the_mono_debugger)
130 handle->_priv->debugger_info = mono_debugger_add_symbol_file (handle);
136 mono_debug_close_image (MonoDebugHandle *handle)
139 mono_debug_close_mono_symbol_file (handle->symfile);
140 /* decrease the refcount added with mono_image_addref () */
141 mono_image_close (handle->image);
142 /* FIXME: should also free handle->image_file? */
143 g_free (handle->_priv);
148 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
150 mono_debugger_lock ();
151 mono_debug_open_image (mono_assembly_get_image (assembly));
152 mono_debugger_unlock ();
156 * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
157 * a new class is initialized.
159 MonoDebuggerSymbolFile *
160 _mono_debugger_get_symfile (MonoImage *image)
162 MonoDebugHandle *handle = _mono_debug_get_image (image);
166 return handle->_priv->debugger_info;
170 mono_debug_start_add_type (MonoClass *klass)
172 MonoDebugHandle *handle;
174 handle = _mono_debug_get_image (klass->image);
178 if (handle->_priv->debugger_info)
179 mono_debugger_start_add_type (handle->_priv->debugger_info, klass);
183 mono_debug_add_type (MonoClass *klass)
185 MonoDebugHandle *handle;
187 handle = _mono_debug_get_image (klass->image);
191 if (handle->_priv->debugger_info)
192 mono_debugger_add_type (handle->_priv->debugger_info, klass);
196 struct LookupMethodData
198 MonoDebugMethodInfo *minfo;
203 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
205 MonoDebugHandle *handle = (MonoDebugHandle *) value;
206 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
212 data->minfo = mono_debug_find_method (handle, data->method);
215 static MonoDebugMethodInfo *
216 _mono_debug_lookup_method (MonoMethod *method)
218 struct LookupMethodData data;
221 data.method = method;
223 if (!mono_debug_handles)
226 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
231 * This is called by the JIT to tell the debugging code about a newly compiled
235 mono_debug_add_wrapper (MonoMethod *method, gpointer wrapper, MonoDomain *domain)
237 MonoClass *klass = method->klass;
238 MonoDebugDomainData *domain_data;
239 MonoDebugHandle *handle;
240 MonoDebugMethodJitInfo *jit;
242 mono_debugger_lock ();
244 mono_class_init (klass);
246 handle = _mono_debug_get_image (klass->image);
247 if (!handle || !handle->symfile || !handle->symfile->offset_table) {
248 mono_debugger_unlock ();
252 domain_data = mono_debug_get_domain_data (handle, domain);
253 jit = g_hash_table_lookup (domain_data->_priv->wrapper_info, method);
256 mono_debugger_add_wrapper (method, jit, wrapper);
258 mono_debugger_unlock ();
262 * This is called by the JIT to tell the debugging code about a newly
266 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
268 MonoClass *klass = method->klass;
269 MonoDebugDomainData *domain_data;
270 MonoDebugHandle *handle;
271 MonoDebugMethodInfo *minfo;
273 mono_debugger_lock ();
275 mono_class_init (klass);
277 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
278 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
279 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
280 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
281 mono_debugger_unlock ();
285 handle = _mono_debug_get_image (klass->image);
286 if (!handle || !handle->symfile || !handle->symfile->offset_table) {
287 mono_debugger_unlock ();
291 domain_data = mono_debug_get_domain_data (handle, domain);
292 if (method->wrapper_type != MONO_WRAPPER_NONE) {
293 g_hash_table_insert (domain_data->_priv->wrapper_info, method, jit);
294 mono_debugger_unlock ();
298 minfo = _mono_debug_lookup_method (method);
300 mono_debugger_unlock ();
304 if (domain_data->jit [minfo->index]) {
306 // This is bug #48591.
308 mono_debugger_unlock ();
312 domain_data->jit [minfo->index] = jit;
314 if (handle->_priv->debugger_info && (domain == mono_get_root_domain ()))
315 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
317 mono_debugger_unlock ();
321 il_offset_from_address (MonoDebugMethodJitInfo *jit, guint32 native_offset)
325 if (!jit || !jit->line_numbers)
328 for (i = jit->line_numbers->len - 1; i >= 0; i--) {
329 MonoDebugLineNumberEntry lne = g_array_index (
330 jit->line_numbers, MonoDebugLineNumberEntry, i);
332 if (lne.native_offset <= native_offset)
333 return lne.il_offset;
340 * mono_debug_source_location_from_address:
346 * Used by the exception code to get a source location from a machine address.
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").
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).
356 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
359 MonoDebugMethodInfo *minfo;
360 MonoDebugDomainData *domain_data;
363 minfo = _mono_debug_lookup_method (method);
364 if (!minfo || !minfo->handle || !minfo->handle->symfile ||
365 !minfo->handle->symfile->offset_table) {
366 mono_loader_unlock ();
370 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
371 if (!domain_data->jit [minfo->index]) {
372 mono_loader_unlock ();
376 if (minfo->handle && minfo->handle->symfile) {
377 gint32 offset = il_offset_from_address (domain_data->jit [minfo->index], address);
381 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
382 mono_loader_unlock ();
386 mono_loader_unlock ();
391 * mono_debug_source_location_from_il_offset:
396 * Used by the exception code to get a source location from an IL offset.
398 * Returns a textual representation of the specified address which is suitable to be displayed to
399 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
401 * If the optional @line_number argument is not NULL, the line number is stored there and just the
402 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
403 * line number 8 in the variable pointed to by @line_number).
406 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
409 MonoDebugMethodInfo *minfo;
412 minfo = _mono_debug_lookup_method (method);
413 if (!minfo || !minfo->handle || !minfo->handle->symfile) {
414 mono_loader_unlock ();
418 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
419 mono_loader_unlock ();
424 * mono_debug_il_offset_from_address:
429 * Returns: the IL offset corresponding to machine address @address which is an offset
430 * relative to the beginning of the method @method.
433 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
435 MonoDebugMethodInfo *minfo;
436 MonoDebugDomainData *domain_data;
443 minfo = _mono_debug_lookup_method (method);
444 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
445 !minfo->handle->symfile->offset_table) {
446 mono_loader_unlock ();
450 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
452 res = il_offset_from_address (domain_data->jit [minfo->index], address);
453 mono_loader_unlock ();
458 * mono_debug_address_from_il_offset:
463 * Returns: the machine address corresponding to IL offset @il_offset.
464 * The returned value is an offset relative to the beginning of the method @method.
467 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
469 MonoDebugMethodInfo *minfo;
470 MonoDebugDomainData *domain_data;
477 minfo = _mono_debug_lookup_method (method);
478 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
479 !minfo->handle->symfile->offset_table) {
480 mono_loader_unlock ();
484 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
486 res = _mono_debug_address_from_il_offset (domain_data->jit [minfo->index], il_offset);
487 mono_loader_unlock ();
491 static MonoDebugDomainData *
492 mono_debug_get_domain_data (MonoDebugHandle *handle, MonoDomain *domain)
494 MonoDebugDomainData *data;
495 int domain_id = mono_domain_get_id (domain);
497 /* We checked this earlier. */
498 g_assert (handle->symfile);
500 for (data = handle->_priv->domain_table; data; data = data->_priv->next)
501 if (data->domain_id == domain_id)
504 data = g_new0 (MonoDebugDomainData, 1);
505 data->domain_id = domain_id;
506 data->jit = g_new0 (MonoDebugMethodJitInfo *, read32(&(handle->symfile->offset_table->_method_count)) + 1);
508 data->_priv = g_new0 (MonoDebugDomainDataPriv, 1);
509 data->_priv->next = handle->_priv->domain_table;
510 data->_priv->wrapper_info = g_hash_table_new (g_direct_hash, g_direct_equal);
511 handle->_priv->domain_table = data;