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 address)
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.address <= address)
340 * Used by the exception code to get a source location from a machine address.
342 * Returns a textual representation of the specified address which is suitable to be displayed to
343 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
345 * If the optional @line_number argument is not NULL, the line number is stored there and just the
346 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
347 * line number 8 in the variable pointed to by @line_number).
350 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
353 MonoDebugMethodInfo *minfo;
354 MonoDebugDomainData *domain_data;
357 minfo = _mono_debug_lookup_method (method);
358 if (!minfo || !minfo->handle || !minfo->handle->symfile ||
359 !minfo->handle->symfile->offset_table) {
360 mono_loader_unlock ();
364 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
365 if (!domain_data->jit [minfo->index]) {
366 mono_loader_unlock ();
370 if (minfo->handle && minfo->handle->symfile) {
371 gint32 offset = il_offset_from_address (domain_data->jit [minfo->index], address);
375 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
376 mono_loader_unlock ();
380 mono_loader_unlock ();
385 * Used by the exception code to get a source location from an IL offset.
387 * Returns a textual representation of the specified address which is suitable to be displayed to
388 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
390 * If the optional @line_number argument is not NULL, the line number is stored there and just the
391 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
392 * line number 8 in the variable pointed to by @line_number).
395 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
398 MonoDebugMethodInfo *minfo;
401 minfo = _mono_debug_lookup_method (method);
402 if (!minfo || !minfo->handle || !minfo->handle->symfile) {
403 mono_loader_unlock ();
407 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
408 mono_loader_unlock ();
413 * Returns the IL offset corresponding to machine address @address which is an offset
414 * relative to the beginning of the method @method.
417 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
419 MonoDebugMethodInfo *minfo;
420 MonoDebugDomainData *domain_data;
427 minfo = _mono_debug_lookup_method (method);
428 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
429 !minfo->handle->symfile->offset_table) {
430 mono_loader_unlock ();
434 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
436 res = il_offset_from_address (domain_data->jit [minfo->index], address);
437 mono_loader_unlock ();
442 * Returns the machine address corresponding to IL offset @il_offset.
443 * The returned value is an offset relative to the beginning of the method @method.
446 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
448 MonoDebugMethodInfo *minfo;
449 MonoDebugDomainData *domain_data;
456 minfo = _mono_debug_lookup_method (method);
457 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
458 !minfo->handle->symfile->offset_table) {
459 mono_loader_unlock ();
463 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
465 res = _mono_debug_address_from_il_offset (domain_data->jit [minfo->index], il_offset);
466 mono_loader_unlock ();
470 static MonoDebugDomainData *
471 mono_debug_get_domain_data (MonoDebugHandle *handle, MonoDomain *domain)
473 MonoDebugDomainData *data;
474 int domain_id = mono_domain_get_id (domain);
476 /* We checked this earlier. */
477 g_assert (handle->symfile);
479 for (data = handle->_priv->domain_table; data; data = data->_priv->next)
480 if (data->domain_id == domain_id)
483 data = g_new0 (MonoDebugDomainData, 1);
484 data->domain_id = domain_id;
485 data->jit = g_new0 (MonoDebugMethodJitInfo *, read32(&(handle->symfile->offset_table->_method_count)) + 1);
487 data->_priv = g_new0 (MonoDebugDomainDataPriv, 1);
488 data->_priv->next = handle->_priv->domain_table;
489 data->_priv->wrapper_info = g_hash_table_new (g_direct_hash, g_direct_equal);
490 handle->_priv->domain_table = data;