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 = _mono_debug_lookup_method (method);
354 MonoDebugDomainData *domain_data;
356 if (!minfo || !minfo->handle || !minfo->handle->symfile ||
357 !minfo->handle->symfile->offset_table)
360 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
361 if (!domain_data->jit [minfo->index])
364 if (minfo->handle && minfo->handle->symfile) {
365 gint32 offset = il_offset_from_address (domain_data->jit [minfo->index], address);
370 return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
377 * Used by the exception code to get a source location from an IL offset.
379 * Returns a textual representation of the specified address which is suitable to be displayed to
380 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
382 * If the optional @line_number argument is not NULL, the line number is stored there and just the
383 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
384 * line number 8 in the variable pointed to by @line_number).
387 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
389 MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
391 if (!minfo || !minfo->handle || !minfo->handle->symfile)
394 return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
398 * Returns the IL offset corresponding to machine address @address which is an offset
399 * relative to the beginning of the method @method.
402 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
404 MonoDebugMethodInfo *minfo;
405 MonoDebugDomainData *domain_data;
410 minfo = _mono_debug_lookup_method (method);
411 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
412 !minfo->handle->symfile->offset_table)
415 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
417 return il_offset_from_address (domain_data->jit [minfo->index], address);
421 * Returns the machine address corresponding to IL offset @il_offset.
422 * The returned value is an offset relative to the beginning of the method @method.
425 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
427 MonoDebugMethodInfo *minfo;
428 MonoDebugDomainData *domain_data;
433 minfo = _mono_debug_lookup_method (method);
434 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
435 !minfo->handle->symfile->offset_table)
438 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
440 return _mono_debug_address_from_il_offset (domain_data->jit [minfo->index], il_offset);
443 static MonoDebugDomainData *
444 mono_debug_get_domain_data (MonoDebugHandle *handle, MonoDomain *domain)
446 MonoDebugDomainData *data;
447 int domain_id = mono_domain_get_id (domain);
449 /* We checked this earlier. */
450 g_assert (handle->symfile);
452 for (data = handle->_priv->domain_table; data; data = data->_priv->next)
453 if (data->domain_id == domain_id)
456 data = g_new0 (MonoDebugDomainData, 1);
457 data->domain_id = domain_id;
458 data->jit = g_new0 (MonoDebugMethodJitInfo *, read32(&(handle->symfile->offset_table->_method_count)) + 1);
460 data->_priv = g_new0 (MonoDebugDomainDataPriv, 1);
461 data->_priv->next = handle->_priv->domain_table;
462 data->_priv->wrapper_info = g_hash_table_new (g_direct_hash, g_direct_equal);
463 handle->_priv->domain_table = data;