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);
70 mono_debugger_unlock ();
74 mono_debug_init_1 (MonoDomain *domain)
76 MonoDebugHandle *handle = mono_debug_open_image (mono_get_corlib ());
78 if (in_the_mono_debugger)
79 mono_debugger_add_builtin_types (handle->_priv->debugger_info);
83 * Initialize debugging support - part 2.
85 * This method must be called after loading the application's main assembly.
88 mono_debug_init_2 (MonoAssembly *assembly)
90 mono_debug_open_image (mono_assembly_get_image (assembly));
94 mono_debug_cleanup (void)
96 mono_debugger_cleanup ();
98 if (mono_debug_handles)
99 g_hash_table_destroy (mono_debug_handles);
100 mono_debug_handles = NULL;
103 static MonoDebugHandle *
104 _mono_debug_get_image (MonoImage *image)
106 return g_hash_table_lookup (mono_debug_handles, image);
109 static MonoDebugHandle *
110 mono_debug_open_image (MonoImage *image)
112 MonoDebugHandle *handle;
114 handle = _mono_debug_get_image (image);
118 handle = g_new0 (MonoDebugHandle, 1);
119 handle->image = image;
120 mono_image_addref (image);
121 handle->image_file = g_strdup (mono_image_get_filename (image));
122 handle->_priv = g_new0 (MonoDebugHandlePriv, 1);
124 g_hash_table_insert (mono_debug_handles, image, handle);
126 if (mono_image_is_dynamic (image))
129 handle->symfile = mono_debug_open_mono_symbol_file (handle, in_the_mono_debugger);
130 if (in_the_mono_debugger)
131 handle->_priv->debugger_info = mono_debugger_add_symbol_file (handle);
137 mono_debug_close_image (MonoDebugHandle *handle)
140 mono_debug_close_mono_symbol_file (handle->symfile);
141 /* decrease the refcount added with mono_image_addref () */
142 mono_image_close (handle->image);
143 /* FIXME: should also free handle->image_file? */
144 g_free (handle->_priv);
149 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
151 mono_debugger_lock ();
152 mono_debug_open_image (mono_assembly_get_image (assembly));
153 mono_debugger_unlock ();
157 * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
158 * a new class is initialized.
160 MonoDebuggerSymbolFile *
161 _mono_debugger_get_symfile (MonoImage *image)
163 MonoDebugHandle *handle = _mono_debug_get_image (image);
167 return handle->_priv->debugger_info;
171 mono_debug_start_add_type (MonoClass *klass)
173 MonoDebugHandle *handle;
175 handle = _mono_debug_get_image (klass->image);
179 if (handle->_priv->debugger_info)
180 mono_debugger_start_add_type (handle->_priv->debugger_info, klass);
184 mono_debug_add_type (MonoClass *klass)
186 MonoDebugHandle *handle;
188 handle = _mono_debug_get_image (klass->image);
192 if (handle->_priv->debugger_info)
193 mono_debugger_add_type (handle->_priv->debugger_info, klass);
197 struct LookupMethodData
199 MonoDebugMethodInfo *minfo;
204 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
206 MonoDebugHandle *handle = (MonoDebugHandle *) value;
207 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
213 data->minfo = mono_debug_find_method (handle, data->method);
216 static MonoDebugMethodInfo *
217 _mono_debug_lookup_method (MonoMethod *method)
219 struct LookupMethodData data;
222 data.method = method;
224 if (!mono_debug_handles)
227 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
232 * This is called by the JIT to tell the debugging code about a newly compiled
236 mono_debug_add_wrapper (MonoMethod *method, gpointer wrapper, MonoDomain *domain)
238 MonoClass *klass = method->klass;
239 MonoDebugDomainData *domain_data;
240 MonoDebugHandle *handle;
241 MonoDebugMethodJitInfo *jit;
243 mono_debugger_lock ();
245 mono_class_init (klass);
247 handle = _mono_debug_get_image (klass->image);
248 if (!handle || !handle->symfile || !handle->symfile->offset_table) {
249 mono_debugger_unlock ();
253 domain_data = mono_debug_get_domain_data (handle, domain);
254 jit = g_hash_table_lookup (domain_data->_priv->wrapper_info, method);
257 mono_debugger_add_wrapper (method, jit, wrapper);
259 mono_debugger_unlock ();
263 * This is called by the JIT to tell the debugging code about a newly
267 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
269 MonoClass *klass = method->klass;
270 MonoDebugDomainData *domain_data;
271 MonoDebugHandle *handle;
272 MonoDebugMethodInfo *minfo;
274 mono_debugger_lock ();
276 mono_class_init (klass);
278 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
279 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
280 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
281 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
282 mono_debugger_unlock ();
286 handle = _mono_debug_get_image (klass->image);
287 if (!handle || !handle->symfile || !handle->symfile->offset_table) {
288 mono_debugger_unlock ();
292 domain_data = mono_debug_get_domain_data (handle, domain);
293 if (method->wrapper_type != MONO_WRAPPER_NONE) {
294 g_hash_table_insert (domain_data->_priv->wrapper_info, method, jit);
295 mono_debugger_unlock ();
299 minfo = _mono_debug_lookup_method (method);
301 mono_debugger_unlock ();
305 if (domain_data->jit [minfo->index]) {
307 // This is bug #48591.
309 mono_debugger_unlock ();
313 domain_data->jit [minfo->index] = jit;
315 if (handle->_priv->debugger_info && (domain == mono_get_root_domain ()))
316 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
318 mono_debugger_unlock ();
322 il_offset_from_address (MonoDebugMethodJitInfo *jit, guint32 address)
326 if (!jit || !jit->line_numbers)
329 for (i = jit->line_numbers->len - 1; i >= 0; i--) {
330 MonoDebugLineNumberEntry lne = g_array_index (
331 jit->line_numbers, MonoDebugLineNumberEntry, i);
333 if (lne.address <= address)
341 * Used by the exception code to get a source location from a machine address.
343 * Returns a textual representation of the specified address which is suitable to be displayed to
344 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
346 * If the optional @line_number argument is not NULL, the line number is stored there and just the
347 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
348 * line number 8 in the variable pointed to by @line_number).
351 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
355 MonoDebugMethodInfo *minfo;
356 MonoDebugDomainData *domain_data;
358 mono_debugger_lock ();
359 minfo = _mono_debug_lookup_method (method);
360 if (!minfo || !minfo->handle || !minfo->handle->symfile ||
361 !minfo->handle->symfile->offset_table) {
362 mono_debugger_unlock ();
366 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
367 if (!domain_data->jit [minfo->index]) {
368 mono_debugger_unlock ();
372 if (minfo->handle && minfo->handle->symfile) {
373 gint32 offset = il_offset_from_address (domain_data->jit [minfo->index], address);
377 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
378 mono_debugger_unlock ();
382 mono_debugger_unlock ();
387 * Used by the exception code to get a source location from an IL offset.
389 * Returns a textual representation of the specified address which is suitable to be displayed to
390 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
392 * If the optional @line_number argument is not NULL, the line number is stored there and just the
393 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
394 * line number 8 in the variable pointed to by @line_number).
397 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
400 MonoDebugMethodInfo *minfo;
402 mono_debugger_lock ();
403 minfo = _mono_debug_lookup_method (method);
404 if (!minfo || !minfo->handle || !minfo->handle->symfile) {
405 mono_debugger_unlock ();
409 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
410 mono_debugger_unlock ();
415 * Returns the IL offset corresponding to machine address @address which is an offset
416 * relative to the beginning of the method @method.
419 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
421 MonoDebugMethodInfo *minfo;
422 MonoDebugDomainData *domain_data;
428 mono_debugger_lock ();
429 minfo = _mono_debug_lookup_method (method);
430 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
431 !minfo->handle->symfile->offset_table) {
432 mono_debugger_unlock ();
436 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
438 res = il_offset_from_address (domain_data->jit [minfo->index], address);
439 mono_debugger_unlock ();
444 * Returns the machine address corresponding to IL offset @il_offset.
445 * The returned value is an offset relative to the beginning of the method @method.
448 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
450 MonoDebugMethodInfo *minfo;
451 MonoDebugDomainData *domain_data;
457 mono_debugger_lock ();
458 minfo = _mono_debug_lookup_method (method);
459 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
460 !minfo->handle->symfile->offset_table) {
461 mono_debugger_unlock ();
465 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
467 res = _mono_debug_address_from_il_offset (domain_data->jit [minfo->index], il_offset);
468 mono_debugger_unlock ();
472 static MonoDebugDomainData *
473 mono_debug_get_domain_data (MonoDebugHandle *handle, MonoDomain *domain)
475 MonoDebugDomainData *data;
476 int domain_id = mono_domain_get_id (domain);
478 /* We checked this earlier. */
479 g_assert (handle->symfile);
481 for (data = handle->_priv->domain_table; data; data = data->_priv->next)
482 if (data->domain_id == domain_id)
485 data = g_new0 (MonoDebugDomainData, 1);
486 data->domain_id = domain_id;
487 data->jit = g_new0 (MonoDebugMethodJitInfo *, read32(&(handle->symfile->offset_table->_method_count)) + 1);
489 data->_priv = g_new0 (MonoDebugDomainDataPriv, 1);
490 data->_priv->next = handle->_priv->domain_table;
491 data->_priv->wrapper_info = g_hash_table_new (g_direct_hash, g_direct_equal);
492 handle->_priv->domain_table = data;