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>
9 struct _MonoDebugHandlePriv
11 MonoDebuggerSymbolFile *debugger_info;
12 MonoDebugDomainData *domain_table;
15 struct _MonoDebugDomainDataPriv
17 GHashTable *wrapper_info;
18 MonoDebugDomainData *next;
21 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
23 static gboolean in_the_mono_debugger = FALSE;
24 static gboolean mono_debug_initialized = FALSE;
25 GHashTable *mono_debug_handles = NULL;
27 static MonoDebugHandle *mono_debug_open_image (MonoImage *image);
28 static void mono_debug_close_image (MonoDebugHandle *debug);
30 static MonoDebugHandle *_mono_debug_get_image (MonoImage *image);
31 static void mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data);
32 static void mono_debug_add_type (MonoClass *klass);
34 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
37 * Initialize debugging support.
39 * This method must be called after loading corlib,
40 * but before opening the application's main assembly because we need to set some
44 mono_debug_init (MonoDomain *domain, MonoDebugFormat format)
48 g_assert (!mono_debug_initialized);
50 mono_debug_initialized = TRUE;
51 mono_debug_format = format;
52 in_the_mono_debugger = format == MONO_DEBUG_FORMAT_DEBUGGER;
54 if (in_the_mono_debugger)
55 mono_debugger_initialize (domain);
57 mono_debugger_lock ();
59 mono_debug_handles = g_hash_table_new_full
60 (NULL, NULL, NULL, (GDestroyNotify) mono_debug_close_image);
62 mono_debugger_class_init_func = mono_debug_add_type;
63 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
65 mono_debug_open_image (mono_defaults.corlib);
66 for (ass = mono_defaults.corlib->references; ass && *ass; ass++)
67 mono_debug_open_image ((*ass)->image);
71 * Initialize debugging support - part 2.
73 * This method must be called after loading the application's main assembly.
76 mono_debug_init_2 (MonoAssembly *assembly)
78 MonoDebugHandle *handle;
80 mono_debug_open_image (assembly->image);
82 handle = _mono_debug_get_image (mono_defaults.corlib);
85 mono_debugger_unlock ();
89 mono_debug_cleanup (void)
91 mono_debugger_cleanup ();
93 if (mono_debug_handles)
94 g_hash_table_destroy (mono_debug_handles);
95 mono_debug_handles = NULL;
98 static MonoDebugHandle *
99 _mono_debug_get_image (MonoImage *image)
101 return g_hash_table_lookup (mono_debug_handles, image);
104 static MonoDebugHandle *
105 mono_debug_open_image (MonoImage *image)
107 MonoDebugHandle *handle;
109 handle = _mono_debug_get_image (image);
113 handle = g_new0 (MonoDebugHandle, 1);
114 handle->image = image;
115 handle->image->ref_count++;
116 handle->image_file = g_strdup (image->name);
117 handle->_priv = g_new0 (MonoDebugHandlePriv, 1);
119 g_hash_table_insert (mono_debug_handles, image, handle);
121 if (image->assembly->dynamic)
124 handle->symfile = mono_debug_open_mono_symbol_file (handle, in_the_mono_debugger);
125 if (in_the_mono_debugger) {
126 handle->_priv->debugger_info = mono_debugger_add_symbol_file (handle);
127 if (image == mono_defaults.corlib)
128 mono_debugger_add_builtin_types (handle->_priv->debugger_info);
135 mono_debug_close_image (MonoDebugHandle *handle)
138 mono_debug_close_mono_symbol_file (handle->symfile);
139 handle->image->ref_count--;
140 g_free (handle->_priv);
145 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
147 mono_debugger_lock ();
148 mono_debug_open_image (assembly->image);
149 mono_debugger_unlock ();
153 * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
154 * a new class is initialized.
157 mono_debug_add_type (MonoClass *klass)
159 MonoDebugHandle *handle;
161 handle = _mono_debug_get_image (klass->image);
165 if (handle->_priv->debugger_info)
166 mono_debugger_add_type (handle->_priv->debugger_info, klass);
169 struct LookupMethodData
171 MonoDebugMethodInfo *minfo;
176 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
178 MonoDebugHandle *handle = (MonoDebugHandle *) value;
179 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
185 data->minfo = mono_debug_find_method (handle->symfile, data->method);
188 static MonoDebugMethodInfo *
189 _mono_debug_lookup_method (MonoMethod *method)
191 struct LookupMethodData data;
194 data.method = method;
196 if (!mono_debug_handles)
199 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
204 * This is called by the JIT to tell the debugging code about a newly compiled
208 mono_debug_add_wrapper (MonoMethod *method, MonoMethod *wrapper_method, MonoDomain *domain)
210 MonoClass *klass = method->klass;
211 MonoDebugHandle *handle;
212 MonoDebugMethodInfo *minfo;
213 MonoDebugMethodJitInfo *jit;
214 MonoDebugDomainData *domain_data;
216 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
219 mono_class_init (klass);
221 handle = _mono_debug_get_image (klass->image);
224 minfo = _mono_debug_lookup_method (method);
228 domain_data = mono_debug_get_domain_data (handle, domain);
229 if (domain_data->jit [minfo->index]) {
231 // This is bug #48591.
235 jit = g_hash_table_lookup (domain_data->_priv->wrapper_info, wrapper_method);
238 mono_debugger_lock ();
240 domain_data->jit [minfo->index] = jit;
241 jit->wrapper_addr = method->addr;
243 if (handle->_priv->debugger_info && (domain == mono_root_domain))
244 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
246 mono_debugger_unlock ();
250 * This is called by the JIT to tell the debugging code about a newly
254 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
256 MonoClass *klass = method->klass;
257 MonoDebugDomainData *domain_data;
258 MonoDebugHandle *handle;
259 MonoDebugMethodInfo *minfo;
261 mono_class_init (klass);
263 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
264 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
265 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
266 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
269 handle = _mono_debug_get_image (klass->image);
273 minfo = _mono_debug_lookup_method (method);
277 mono_debugger_lock ();
279 domain_data = mono_debug_get_domain_data (handle, domain);
280 if (domain_data->jit [minfo->index]) {
282 // This is bug #48591.
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 *, 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;