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);
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->symfile, 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 g_assert (!domain_data->jit [minfo->index]);
230 jit = g_hash_table_lookup (domain_data->_priv->wrapper_info, wrapper_method);
233 mono_debugger_lock ();
235 domain_data->jit [minfo->index] = jit;
236 jit->wrapper_addr = method->addr;
238 if (handle->_priv->debugger_info && (domain == mono_root_domain))
239 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
241 mono_debugger_unlock ();
245 * This is called by the JIT to tell the debugging code about a newly
249 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
251 MonoClass *klass = method->klass;
252 MonoDebugDomainData *domain_data;
253 MonoDebugHandle *handle;
254 MonoDebugMethodInfo *minfo;
256 mono_class_init (klass);
258 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
259 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
260 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
261 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
264 handle = _mono_debug_get_image (klass->image);
267 minfo = _mono_debug_lookup_method (method);
271 mono_debugger_lock ();
273 domain_data = mono_debug_get_domain_data (handle, domain);
274 g_assert (!domain_data->jit [minfo->index]);
276 if (method->wrapper_type != MONO_WRAPPER_NONE) {
277 g_hash_table_insert (domain_data->_priv->wrapper_info, method, jit);
278 mono_debugger_unlock ();
282 domain_data->jit [minfo->index] = jit;
284 if (handle->_priv->debugger_info && (domain == mono_root_domain))
285 mono_debugger_add_method (handle->_priv->debugger_info, minfo, jit);
287 mono_debugger_unlock ();
291 il_offset_from_address (MonoDebugMethodJitInfo *jit, guint32 address)
295 if (!jit || !jit->line_numbers)
298 for (i = jit->line_numbers->len - 1; i >= 0; i--) {
299 MonoDebugLineNumberEntry lne = g_array_index (
300 jit->line_numbers, MonoDebugLineNumberEntry, i);
302 if (lne.address <= address)
310 * Used by the exception code to get a source location from a machine address.
312 * Returns a textual representation of the specified address which is suitable to be displayed to
313 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
315 * If the optional @line_number argument is not NULL, the line number is stored there and just the
316 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
317 * line number 8 in the variable pointed to by @line_number).
320 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
323 MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
324 MonoDebugDomainData *domain_data;
329 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
330 if (!domain_data->jit [minfo->index])
334 gint32 offset = il_offset_from_address (domain_data->jit [minfo->index], address);
339 return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
346 * Used by the exception code to get a source location from an IL offset.
348 * Returns a textual representation of the specified address which is suitable to be displayed to
349 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
351 * If the optional @line_number argument is not NULL, the line number is stored there and just the
352 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
353 * line number 8 in the variable pointed to by @line_number).
356 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
358 MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
360 if (!minfo || !minfo->handle)
363 return mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
367 * Returns the IL offset corresponding to machine address @address which is an offset
368 * relative to the beginning of the method @method.
371 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
373 MonoDebugMethodInfo *minfo;
374 MonoDebugDomainData *domain_data;
379 minfo = _mono_debug_lookup_method (method);
380 if (!minfo || !minfo->il_offsets)
383 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
385 return il_offset_from_address (domain_data->jit [minfo->index], address);
389 * Returns the machine address corresponding to IL offset @il_offset.
390 * The returned value is an offset relative to the beginning of the method @method.
393 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
395 MonoDebugMethodInfo *minfo;
396 MonoDebugDomainData *domain_data;
401 minfo = _mono_debug_lookup_method (method);
402 if (!minfo || !minfo->il_offsets)
405 domain_data = mono_debug_get_domain_data (minfo->handle, domain);
407 return _mono_debug_address_from_il_offset (domain_data->jit [minfo->index], il_offset);
410 MonoDebugDomainData *
411 mono_debug_get_domain_data (MonoDebugHandle *handle, MonoDomain *domain)
413 MonoDebugDomainData *data;
415 for (data = handle->_priv->domain_table; data; data = data->_priv->next)
416 if (data->domain_id == domain->domain_id)
419 data = g_new0 (MonoDebugDomainData, 1);
420 data->domain_id = domain->domain_id;
421 data->jit = g_new0 (MonoDebugMethodJitInfo *, handle->symfile->offset_table->method_count + 1);
423 data->_priv = g_new0 (MonoDebugDomainDataPriv, 1);
424 data->_priv->next = handle->_priv->domain_table;
425 data->_priv->wrapper_info = g_hash_table_new (g_direct_hash, g_direct_equal);
426 handle->_priv->domain_table = data;