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/mono-debug.h>
7 #include <mono/metadata/mono-debug-debugger.h>
8 #include <mono/metadata/mono-endian.h>
10 struct _MonoDebugHandlePriv
12 MonoDebuggerSymbolFile *debugger_info;
13 MonoDebugDomainData *domain_table;
16 struct _MonoDebugDomainDataPriv
18 GHashTable *wrapper_info;
19 MonoDebugDomainData *next;
22 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
24 static gboolean in_the_mono_debugger = FALSE;
25 static gboolean mono_debug_initialized = FALSE;
26 GHashTable *mono_debug_handles = NULL;
28 static MonoDebugHandle *mono_debug_open_image (MonoImage *image);
29 static void mono_debug_close_image (MonoDebugHandle *debug);
31 static MonoDebugHandle *_mono_debug_get_image (MonoImage *image);
32 static void mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data);
33 static void mono_debug_add_type (MonoClass *klass);
35 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
38 * Initialize debugging support.
40 * This method must be called after loading corlib,
41 * but before opening the application's main assembly because we need to set some
45 mono_debug_init (MonoDomain *domain, MonoDebugFormat format)
49 g_assert (!mono_debug_initialized);
51 mono_debug_initialized = TRUE;
52 mono_debug_format = format;
53 in_the_mono_debugger = format == MONO_DEBUG_FORMAT_DEBUGGER;
55 if (in_the_mono_debugger)
56 mono_debugger_initialize (domain);
58 mono_debugger_lock ();
60 mono_debug_handles = g_hash_table_new_full
61 (NULL, NULL, NULL, (GDestroyNotify) mono_debug_close_image);
63 mono_debugger_class_init_func = mono_debug_add_type;
64 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
66 mono_debug_open_image (mono_defaults.corlib);
67 for (ass = mono_defaults.corlib->references; ass && *ass; ass++)
68 mono_debug_open_image ((*ass)->image);
72 * Initialize debugging support - part 2.
74 * This method must be called after loading the application's main assembly.
77 mono_debug_init_2 (MonoAssembly *assembly)
79 MonoDebugHandle *handle;
81 mono_debug_open_image (assembly->image);
83 handle = _mono_debug_get_image (mono_defaults.corlib);
88 mono_debug_cleanup (void)
90 mono_debugger_cleanup ();
92 if (mono_debug_handles)
93 g_hash_table_destroy (mono_debug_handles);
94 mono_debug_handles = NULL;
97 static MonoDebugHandle *
98 _mono_debug_get_image (MonoImage *image)
100 return g_hash_table_lookup (mono_debug_handles, image);
103 static MonoDebugHandle *
104 mono_debug_open_image (MonoImage *image)
106 MonoDebugHandle *handle;
108 handle = _mono_debug_get_image (image);
112 handle = g_new0 (MonoDebugHandle, 1);
113 handle->image = image;
114 handle->image->ref_count++;
115 handle->image_file = g_strdup (image->name);
116 handle->_priv = g_new0 (MonoDebugHandlePriv, 1);
118 g_hash_table_insert (mono_debug_handles, image, handle);
120 if (image->assembly->dynamic)
123 handle->symfile = mono_debug_open_mono_symbol_file (handle, in_the_mono_debugger);
124 if (in_the_mono_debugger) {
125 handle->_priv->debugger_info = mono_debugger_add_symbol_file (handle);
126 if (image == mono_defaults.corlib)
127 mono_debugger_add_builtin_types (handle->_priv->debugger_info);
134 mono_debug_close_image (MonoDebugHandle *handle)
137 mono_debug_close_mono_symbol_file (handle->symfile);
138 handle->image->ref_count--;
139 g_free (handle->_priv);
144 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
146 mono_debugger_lock ();
147 mono_debug_open_image (assembly->image);
148 mono_debugger_unlock ();
152 * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
153 * a new class is initialized.
156 mono_debug_add_type (MonoClass *klass)
158 MonoDebugHandle *handle;
160 handle = _mono_debug_get_image (klass->image);
164 if (handle->_priv->debugger_info)
165 mono_debugger_add_type (handle->_priv->debugger_info, klass);
168 struct LookupMethodData
170 MonoDebugMethodInfo *minfo;
175 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
177 MonoDebugHandle *handle = (MonoDebugHandle *) value;
178 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
184 data->minfo = mono_debug_find_method (handle, data->method);
187 static MonoDebugMethodInfo *
188 _mono_debug_lookup_method (MonoMethod *method)
190 struct LookupMethodData data;
193 data.method = method;
195 if (!mono_debug_handles)
198 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
203 * This is called by the JIT to tell the debugging code about a newly compiled
207 mono_debug_add_wrapper (MonoMethod *method, MonoMethod *wrapper_method, MonoDomain *domain)
209 MonoClass *klass = method->klass;
210 MonoDebugHandle *handle;
211 MonoDebugMethodInfo *minfo;
212 MonoDebugMethodJitInfo *jit;
213 MonoDebugDomainData *domain_data;
215 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
218 mono_class_init (klass);
220 handle = _mono_debug_get_image (klass->image);
223 minfo = _mono_debug_lookup_method (method);
227 domain_data = mono_debug_get_domain_data (handle, domain);
228 if (domain_data->jit [minfo->index]) {
230 // This is bug #48591.
234 jit = g_hash_table_lookup (domain_data->_priv->wrapper_info, wrapper_method);
237 mono_debugger_lock ();
239 domain_data->jit [minfo->index] = jit;
240 jit->wrapper_addr = method->addr;
242 if (handle->_priv->debugger_info && (domain == mono_root_domain))
243 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
245 mono_debugger_unlock ();
249 * This is called by the JIT to tell the debugging code about a newly
253 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
255 MonoClass *klass = method->klass;
256 MonoDebugDomainData *domain_data;
257 MonoDebugHandle *handle;
258 MonoDebugMethodInfo *minfo;
260 mono_class_init (klass);
262 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
263 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
264 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
265 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
268 handle = _mono_debug_get_image (klass->image);
272 minfo = _mono_debug_lookup_method (method);
276 mono_debugger_lock ();
278 domain_data = mono_debug_get_domain_data (handle, domain);
279 if (domain_data->jit [minfo->index]) {
281 // This is bug #48591.
282 mono_debugger_unlock ();
286 if (method->wrapper_type != MONO_WRAPPER_NONE) {
287 g_hash_table_insert (domain_data->_priv->wrapper_info, method, jit);
288 mono_debugger_unlock ();
292 domain_data->jit [minfo->index] = jit;
294 if (handle->_priv->debugger_info && (domain == mono_root_domain))
295 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
297 mono_debugger_unlock ();
301 il_offset_from_address (MonoDebugMethodJitInfo *jit, guint32 address)
305 if (!jit || !jit->line_numbers)
308 for (i = jit->line_numbers->len - 1; i >= 0; i--) {
309 MonoDebugLineNumberEntry lne = g_array_index (
310 jit->line_numbers, MonoDebugLineNumberEntry, i);
312 if (lne.address <= address)
320 * Used by the exception code to get a source location from a machine address.
322 * Returns a textual representation of the specified address which is suitable to be displayed to
323 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
325 * If the optional @line_number argument is not NULL, the line number is stored there and just the
326 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
327 * line number 8 in the variable pointed to by @line_number).
330 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
333 MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
334 MonoDebugDomainData *domain_data;
339 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
340 if (!domain_data->jit [minfo->index])
344 gint32 offset = il_offset_from_address (domain_data->jit [minfo->index], address);
349 return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
356 * Used by the exception code to get a source location from an IL offset.
358 * Returns a textual representation of the specified address which is suitable to be displayed to
359 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
361 * If the optional @line_number argument is not NULL, the line number is stored there and just the
362 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
363 * line number 8 in the variable pointed to by @line_number).
366 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
368 MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
370 if (!minfo || !minfo->handle)
373 return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
377 * Returns the IL offset corresponding to machine address @address which is an offset
378 * relative to the beginning of the method @method.
381 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
383 MonoDebugMethodInfo *minfo;
384 MonoDebugDomainData *domain_data;
389 minfo = _mono_debug_lookup_method (method);
390 if (!minfo || !minfo->il_offsets)
393 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
395 return il_offset_from_address (domain_data->jit [minfo->index], address);
399 * Returns the machine address corresponding to IL offset @il_offset.
400 * The returned value is an offset relative to the beginning of the method @method.
403 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
405 MonoDebugMethodInfo *minfo;
406 MonoDebugDomainData *domain_data;
411 minfo = _mono_debug_lookup_method (method);
412 if (!minfo || !minfo->il_offsets)
415 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
417 return _mono_debug_address_from_il_offset (domain_data->jit [minfo->index], il_offset);
420 MonoDebugDomainData *
421 mono_debug_get_domain_data (MonoDebugHandle *handle, MonoDomain *domain)
423 MonoDebugDomainData *data;
425 for (data = handle->_priv->domain_table; data; data = data->_priv->next)
426 if (data->domain_id == domain->domain_id)
429 data = g_new0 (MonoDebugDomainData, 1);
430 data->domain_id = domain->domain_id;
431 data->jit = g_new0 (MonoDebugMethodJitInfo *, read32(&(handle->symfile->offset_table->_method_count)) + 1);
433 data->_priv = g_new0 (MonoDebugDomainDataPriv, 1);
434 data->_priv->next = handle->_priv->domain_table;
435 data->_priv->wrapper_info = g_hash_table_new (g_direct_hash, g_direct_equal);
436 handle->_priv->domain_table = data;