2010-05-15 Geoff Norton <gnorton@novell.com>
[mono.git] / mono / metadata / mono-debug.c
blob785e68e5569715ad93cfa42d3aa802b51fe31fb0
1 /*
2 * mono-debug.c:
4 * Author:
5 * Mono Project (http://www.mono-project.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 */
11 #include <config.h>
12 #include <mono/metadata/assembly.h>
13 #include <mono/metadata/tabledefs.h>
14 #include <mono/metadata/tokentype.h>
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/class-internals.h>
17 #include <mono/metadata/mono-debug.h>
18 #include <mono/metadata/mono-debug-debugger.h>
19 #include <mono/metadata/mono-endian.h>
20 #include <string.h>
22 #define DATA_TABLE_CHUNK_SIZE 16384
24 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
26 #if NO_UNALIGNED_ACCESS
27 #define RETURN_UNALIGNED(type, addr) \
28 { \
29 type val; \
30 memcpy(&val, p + offset, sizeof(val)); \
31 return val; \
33 #define WRITE_UNALIGNED(type, addr, val) \
34 memcpy(addr, &val, sizeof(type))
35 #define READ_UNALIGNED(type, addr, val) \
36 memcpy(&val, addr, sizeof(type))
37 #else
38 #define RETURN_UNALIGNED(type, addr) \
39 return *(type*)(p + offset);
40 #define WRITE_UNALIGNED(type, addr, val) \
41 (*(type *)(addr) = (val))
42 #define READ_UNALIGNED(type, addr, val) \
43 val = (*(type *)(addr))
44 #endif
46 typedef enum {
47 MONO_DEBUG_DATA_ITEM_UNKNOWN = 0,
48 MONO_DEBUG_DATA_ITEM_CLASS,
49 MONO_DEBUG_DATA_ITEM_METHOD,
50 MONO_DEBUG_DATA_ITEM_DELEGATE_TRAMPOLINE
51 } MonoDebugDataItemType;
53 typedef struct _MonoDebugDataChunk MonoDebugDataChunk;
55 struct _MonoDebugDataChunk {
56 guint32 total_size;
57 guint32 allocated_size;
58 guint32 current_offset;
59 guint32 dummy;
60 MonoDebugDataChunk *next;
61 guint8 data [MONO_ZERO_LEN_ARRAY];
64 struct _MonoDebugDataTable {
65 gint32 domain;
66 gint32 _dummy; /* alignment for next field. */
67 MonoDebugDataChunk *first_chunk;
68 MonoDebugDataChunk *current_chunk;
69 GHashTable *method_hash;
70 GHashTable *method_address_hash;
73 typedef struct {
74 const gchar *method_name;
75 const gchar *obsolete_cil_code;
76 guint32 wrapper_type;
77 } MonoDebugWrapperData;
79 typedef struct {
80 guint32 size;
81 guint32 symfile_id;
82 guint32 domain_id;
83 guint32 method_id;
84 MonoDebugWrapperData *wrapper_data;
85 MonoMethod *method;
86 GSList *address_list;
87 } MonoDebugMethodHeader;
89 struct _MonoDebugMethodAddress {
90 MonoDebugMethodHeader header;
91 const guint8 *code_start;
92 const guint8 *wrapper_addr;
93 guint32 code_size;
94 guint8 data [MONO_ZERO_LEN_ARRAY];
97 struct _MonoDebugClassEntry {
98 guint32 size;
99 guint8 data [MONO_ZERO_LEN_ARRAY];
102 typedef struct {
103 gpointer code;
104 guint32 size;
105 } MonoDebugDelegateTrampolineEntry;
107 MonoSymbolTable *mono_symbol_table = NULL;
108 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
109 gint32 mono_debug_debugger_version = 5;
110 gint32 _mono_debug_using_mono_debugger = 0;
112 static gboolean mono_debug_initialized = FALSE;
113 GHashTable *mono_debug_handles = NULL;
115 static GHashTable *data_table_hash = NULL;
116 static int next_symbol_file_id = 0;
118 static MonoDebugHandle *mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size);
120 static MonoDebugHandle *_mono_debug_get_image (MonoImage *image);
121 static void mono_debug_add_assembly (MonoAssembly *assembly,
122 gpointer user_data);
123 static void mono_debug_add_type (MonoClass *klass);
125 void _mono_debug_init_corlib (MonoDomain *domain);
127 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
128 extern void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass);
130 static MonoDebugDataTable *
131 create_data_table (MonoDomain *domain)
133 MonoDebugDataTable *table;
134 MonoDebugDataChunk *chunk;
136 table = g_new0 (MonoDebugDataTable, 1);
137 table->domain = domain ? mono_domain_get_id (domain) : -1;
139 table->method_address_hash = g_hash_table_new (NULL, NULL);
140 table->method_hash = g_hash_table_new (NULL, NULL);
142 chunk = g_malloc0 (sizeof (MonoDebugDataChunk) + DATA_TABLE_CHUNK_SIZE);
143 chunk->total_size = DATA_TABLE_CHUNK_SIZE;
145 table->first_chunk = table->current_chunk = chunk;
147 if (domain) {
148 mono_debug_list_add (&mono_symbol_table->data_tables, table);
149 g_hash_table_insert (data_table_hash, domain, table);
152 return table;
155 static void
156 free_header_data (gpointer key, gpointer value, gpointer user_data)
158 MonoDebugMethodHeader *header = (MonoDebugMethodHeader*)value;
160 if (header->wrapper_data) {
161 g_free ((gpointer)header->wrapper_data->method_name);
162 g_slist_free (header->address_list);
163 g_free (header->wrapper_data);
167 static void
168 free_data_table (MonoDebugDataTable *table)
170 MonoDebugDataChunk *chunk, *next_chunk;
172 g_hash_table_foreach (table->method_hash, free_header_data, NULL);
173 g_hash_table_destroy (table->method_hash);
174 g_hash_table_destroy (table->method_address_hash);
176 table->method_hash = NULL;
177 table->method_address_hash = NULL;
179 chunk = table->first_chunk;
180 while (chunk) {
181 next_chunk = chunk->next;
182 g_free (chunk);
183 chunk = next_chunk;
186 table->first_chunk = table->current_chunk = NULL;
187 mono_debug_list_remove (&mono_symbol_table->data_tables, table);
188 g_free (table);
191 static MonoDebugDataTable *
192 lookup_data_table (MonoDomain *domain)
194 MonoDebugDataTable *table;
196 table = g_hash_table_lookup (data_table_hash, domain);
197 g_assert (table);
198 return table;
201 static void
202 free_debug_handle (MonoDebugHandle *handle)
204 if (handle->symfile)
205 mono_debug_close_mono_symbol_file (handle->symfile);
206 /* decrease the refcount added with mono_image_addref () */
207 free_data_table (handle->type_table);
208 mono_image_close (handle->image);
209 g_free (handle->image_file);
210 g_free (handle);
214 * Initialize debugging support.
216 * This method must be called after loading corlib,
217 * but before opening the application's main assembly because we need to set some
218 * callbacks here.
220 void
221 mono_debug_init (MonoDebugFormat format)
223 g_assert (!mono_debug_initialized);
225 if (_mono_debug_using_mono_debugger)
226 format = MONO_DEBUG_FORMAT_DEBUGGER;
228 mono_debug_initialized = TRUE;
229 mono_debug_format = format;
231 mono_debugger_initialize (_mono_debug_using_mono_debugger);
233 mono_debugger_lock ();
235 mono_symbol_table = g_new0 (MonoSymbolTable, 1);
236 mono_symbol_table->magic = MONO_DEBUGGER_MAGIC;
237 mono_symbol_table->version = MONO_DEBUGGER_MAJOR_VERSION;
238 mono_symbol_table->total_size = sizeof (MonoSymbolTable);
240 mono_debug_handles = g_hash_table_new_full
241 (NULL, NULL, NULL, (GDestroyNotify) free_debug_handle);
243 data_table_hash = g_hash_table_new_full (
244 NULL, NULL, NULL, (GDestroyNotify) free_data_table);
246 mono_debugger_class_init_func = mono_debug_add_type;
247 mono_debugger_class_loaded_methods_func = mono_debugger_class_initialized;
248 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
250 mono_symbol_table->global_data_table = create_data_table (NULL);
252 mono_debugger_unlock ();
256 * INTERNAL USE ONLY !
258 void
259 _mono_debug_init_corlib (MonoDomain *domain)
261 if (!mono_debug_initialized)
262 return;
264 mono_symbol_table->corlib = mono_debug_open_image (mono_defaults.corlib, NULL, 0);
265 mono_debugger_event (MONO_DEBUGGER_EVENT_INITIALIZE_CORLIB,
266 (guint64) (gsize) mono_symbol_table->corlib, 0);
269 void
270 mono_debug_open_image_from_memory (MonoImage *image, const guint8 *raw_contents, int size)
272 mono_debug_open_image (image, raw_contents, size);
276 gboolean
277 mono_debug_using_mono_debugger (void)
279 return _mono_debug_using_mono_debugger;
282 void
283 mono_debug_cleanup (void)
285 if (mono_debug_handles)
286 g_hash_table_destroy (mono_debug_handles);
287 mono_debug_handles = NULL;
289 if (data_table_hash) {
290 g_hash_table_destroy (data_table_hash);
291 data_table_hash = NULL;
294 if (mono_symbol_table->global_data_table)
295 free_data_table (mono_symbol_table->global_data_table);
297 g_free (mono_symbol_table);
298 mono_symbol_table = NULL;
301 void
302 mono_debug_domain_create (MonoDomain *domain)
304 MonoDebugDataTable *table;
306 if (!mono_debug_initialized)
307 return;
309 mono_debugger_lock ();
311 table = create_data_table (domain);
313 mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_CREATE, (guint64) (gsize) table,
314 mono_domain_get_id (domain));
316 mono_debugger_unlock ();
319 void
320 mono_debug_domain_unload (MonoDomain *domain)
322 MonoDebugDataTable *table;
324 if (!mono_debug_initialized)
325 return;
327 mono_debugger_lock ();
329 table = g_hash_table_lookup (data_table_hash, domain);
330 if (!table) {
331 g_warning (G_STRLOC ": unloading unknown domain %p / %d",
332 domain, mono_domain_get_id (domain));
333 mono_debugger_unlock ();
334 return;
337 mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_UNLOAD, (guint64) (gsize) table,
338 mono_domain_get_id (domain));
340 g_hash_table_remove (data_table_hash, domain);
342 mono_debugger_unlock ();
346 * LOCKING: Assumes the debug lock is held.
348 static MonoDebugHandle *
349 _mono_debug_get_image (MonoImage *image)
351 return g_hash_table_lookup (mono_debug_handles, image);
354 void
355 mono_debug_close_image (MonoImage *image)
357 MonoDebugHandle *handle;
359 if (!mono_debug_initialized)
360 return;
362 mono_debugger_lock ();
364 handle = _mono_debug_get_image (image);
365 if (!handle) {
366 mono_debugger_unlock ();
367 return;
370 mono_debugger_event (MONO_DEBUGGER_EVENT_UNLOAD_MODULE, (guint64) (gsize) handle,
371 handle->index);
373 mono_debug_list_remove (&mono_symbol_table->symbol_files, handle);
374 g_hash_table_remove (mono_debug_handles, image);
376 mono_debugger_unlock ();
379 static MonoDebugHandle *
380 mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
382 MonoDebugHandle *handle;
384 if (mono_image_is_dynamic (image))
385 return NULL;
387 mono_debugger_lock ();
389 handle = _mono_debug_get_image (image);
390 if (handle != NULL) {
391 mono_debugger_unlock ();
392 return handle;
395 handle = g_new0 (MonoDebugHandle, 1);
396 handle->index = ++next_symbol_file_id;
398 handle->image = image;
399 mono_image_addref (image);
400 handle->image_file = g_strdup (mono_image_get_filename (image));
402 handle->type_table = create_data_table (NULL);
404 handle->symfile = mono_debug_open_mono_symbols (
405 handle, raw_contents, size, _mono_debug_using_mono_debugger);
407 mono_debug_list_add (&mono_symbol_table->symbol_files, handle);
409 g_hash_table_insert (mono_debug_handles, image, handle);
411 if (mono_symbol_table->corlib)
412 mono_debugger_event (MONO_DEBUGGER_EVENT_LOAD_MODULE,
413 (guint64) (gsize) handle, 0);
415 mono_debugger_unlock ();
417 return handle;
420 static void
421 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
423 mono_debugger_lock ();
424 mono_debug_open_image (mono_assembly_get_image (assembly), NULL, 0);
425 mono_debugger_unlock ();
428 static guint8 *
429 allocate_data_item (MonoDebugDataTable *table, MonoDebugDataItemType type, guint32 size)
431 guint32 chunk_size;
432 guint8 *data;
434 size = ALIGN_TO (size, sizeof (gpointer));
436 if (size + 16 < DATA_TABLE_CHUNK_SIZE)
437 chunk_size = DATA_TABLE_CHUNK_SIZE;
438 else
439 chunk_size = size + 16;
441 g_assert (table->current_chunk->current_offset == table->current_chunk->allocated_size);
443 if (table->current_chunk->allocated_size + size + 8 >= table->current_chunk->total_size) {
444 MonoDebugDataChunk *new_chunk;
446 new_chunk = g_malloc0 (sizeof (MonoDebugDataChunk) + chunk_size);
447 new_chunk->total_size = chunk_size;
449 table->current_chunk->next = new_chunk;
450 table->current_chunk = new_chunk;
453 data = &table->current_chunk->data [table->current_chunk->allocated_size];
454 table->current_chunk->allocated_size += size + 8;
456 * ((guint32 *) data) = size;
457 data += 4;
458 * ((guint32 *) data) = type;
459 data += 4;
460 return data;
463 static void
464 write_data_item (MonoDebugDataTable *table, const guint8 *data)
466 MonoDebugDataChunk *current_chunk = table->current_chunk;
467 guint32 size = * ((guint32 *) (data - 8));
469 g_assert (current_chunk->current_offset + size + 8 == current_chunk->allocated_size);
470 current_chunk->current_offset = current_chunk->allocated_size;
473 struct LookupMethodData
475 MonoDebugMethodInfo *minfo;
476 MonoMethod *method;
479 static void
480 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
482 MonoDebugHandle *handle = (MonoDebugHandle *) value;
483 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
485 if (data->minfo)
486 return;
488 if (handle->symfile)
489 data->minfo = mono_debug_symfile_lookup_method (handle, data->method);
492 static MonoDebugMethodInfo *
493 _mono_debug_lookup_method (MonoMethod *method)
495 struct LookupMethodData data;
497 data.minfo = NULL;
498 data.method = method;
500 if (!mono_debug_handles)
501 return NULL;
503 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
504 return data.minfo;
508 * mono_debug_lookup_method:
510 * Lookup symbol file information for the method @method. The returned
511 * `MonoDebugMethodInfo' is a private structure, but it can be passed to
512 * mono_debug_symfile_lookup_location().
514 MonoDebugMethodInfo *
515 mono_debug_lookup_method (MonoMethod *method)
517 MonoDebugMethodInfo *minfo;
519 mono_debugger_lock ();
520 minfo = _mono_debug_lookup_method (method);
521 mono_debugger_unlock ();
522 return minfo;
525 static inline void
526 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
528 do {
529 guint8 byte = value & 0x7f;
530 value >>= 7;
531 if (value)
532 byte |= 0x80;
533 *ptr++ = byte;
534 } while (value);
536 *rptr = ptr;
539 static inline void
540 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
542 gboolean more = 1;
544 while (more) {
545 guint8 byte = value & 0x7f;
546 value >>= 7;
548 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
549 more = 0;
550 else
551 byte |= 0x80;
552 *ptr++ = byte;
555 *rptr = ptr;
558 static void
559 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
561 write_leb128 (var->index, ptr, &ptr);
562 write_sleb128 (var->offset, ptr, &ptr);
563 write_leb128 (var->size, ptr, &ptr);
564 write_leb128 (var->begin_scope, ptr, &ptr);
565 write_leb128 (var->end_scope, ptr, &ptr);
566 WRITE_UNALIGNED (gpointer, ptr, var->type);
567 ptr += sizeof (gpointer);
568 *rptr = ptr;
571 MonoDebugMethodAddress *
572 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
574 MonoMethod *declaring;
575 MonoDebugDataTable *table;
576 MonoDebugMethodHeader *header;
577 MonoDebugMethodAddress *address;
578 MonoDebugMethodInfo *minfo;
579 MonoDebugHandle *handle;
580 guint8 buffer [BUFSIZ];
581 guint8 *ptr, *oldptr;
582 guint32 i, size, total_size, max_size;
583 gboolean is_wrapper = FALSE;
585 mono_debugger_lock ();
587 table = lookup_data_table (domain);
589 handle = _mono_debug_get_image (method->klass->image);
590 minfo = _mono_debug_lookup_method (method);
592 if (!minfo || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
593 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
594 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
595 (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
596 (method->wrapper_type != MONO_WRAPPER_NONE)) {
597 is_wrapper = TRUE;
600 max_size = (5 * 5) + 1 + (10 * jit->num_line_numbers) +
601 (25 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
603 if (max_size > BUFSIZ)
604 ptr = oldptr = g_malloc (max_size);
605 else
606 ptr = oldptr = buffer;
608 write_leb128 (jit->prologue_end, ptr, &ptr);
609 write_leb128 (jit->epilogue_begin, ptr, &ptr);
611 write_leb128 (jit->num_line_numbers, ptr, &ptr);
612 for (i = 0; i < jit->num_line_numbers; i++) {
613 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
615 write_sleb128 (lne->il_offset, ptr, &ptr);
616 write_sleb128 (lne->native_offset, ptr, &ptr);
619 *ptr++ = jit->this_var ? 1 : 0;
620 if (jit->this_var)
621 write_variable (jit->this_var, ptr, &ptr);
623 write_leb128 (jit->num_params, ptr, &ptr);
624 for (i = 0; i < jit->num_params; i++)
625 write_variable (&jit->params [i], ptr, &ptr);
627 write_leb128 (jit->num_locals, ptr, &ptr);
628 for (i = 0; i < jit->num_locals; i++)
629 write_variable (&jit->locals [i], ptr, &ptr);
631 size = ptr - oldptr;
632 g_assert (size < max_size);
633 total_size = size + sizeof (MonoDebugMethodAddress);
635 address = (MonoDebugMethodAddress *) allocate_data_item (
636 table, MONO_DEBUG_DATA_ITEM_METHOD, total_size);
638 address->header.size = total_size;
639 address->header.symfile_id = handle ? handle->index : 0;
640 address->header.domain_id = mono_domain_get_id (domain);
641 address->header.method_id = is_wrapper ? 0 : minfo->index;
642 address->header.method = method;
644 address->code_start = jit->code_start;
645 address->code_size = jit->code_size;
647 memcpy (&address->data, oldptr, size);
648 if (max_size > BUFSIZ)
649 g_free (oldptr);
651 declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
652 header = g_hash_table_lookup (table->method_hash, declaring);
654 if (!header) {
655 header = &address->header;
656 g_hash_table_insert (table->method_hash, declaring, header);
658 if (is_wrapper) {
659 MonoDebugWrapperData *wrapper;
661 header->wrapper_data = wrapper = g_new0 (MonoDebugWrapperData, 1);
663 wrapper->wrapper_type = method->wrapper_type;
664 wrapper->method_name = mono_method_full_name (declaring, TRUE);
665 wrapper->obsolete_cil_code = "";
667 } else {
668 address->header.wrapper_data = header->wrapper_data;
669 header->address_list = g_slist_prepend (header->address_list, address);
672 g_hash_table_insert (table->method_address_hash, method, address);
674 write_data_item (table, (guint8 *) address);
676 mono_debugger_unlock ();
677 return address;
680 void
681 mono_debug_add_delegate_trampoline (gpointer code, int size)
683 MonoDebugDelegateTrampolineEntry *entry;
685 if (!mono_debug_initialized)
686 return;
688 mono_debugger_lock ();
690 entry = (MonoDebugDelegateTrampolineEntry *) allocate_data_item (
691 mono_symbol_table->global_data_table, MONO_DEBUG_DATA_ITEM_DELEGATE_TRAMPOLINE,
692 sizeof (MonoDebugDelegateTrampolineEntry));
693 entry->code = code;
694 entry->size = size;
696 write_data_item (mono_symbol_table->global_data_table, (guint8 *) entry);
698 mono_debugger_unlock ();
701 static inline guint32
702 read_leb128 (guint8 *ptr, guint8 **rptr)
704 guint32 result = 0, shift = 0;
706 while (TRUE) {
707 guint8 byte = *ptr++;
709 result |= (byte & 0x7f) << shift;
710 if ((byte & 0x80) == 0)
711 break;
712 shift += 7;
715 *rptr = ptr;
716 return result;
719 static inline gint32
720 read_sleb128 (guint8 *ptr, guint8 **rptr)
722 gint32 result = 0;
723 guint32 shift = 0;
725 while (TRUE) {
726 guint8 byte = *ptr++;
728 result |= (byte & 0x7f) << shift;
729 shift += 7;
731 if (byte & 0x80)
732 continue;
734 if ((shift < 32) && (byte & 0x40))
735 result |= - (1 << shift);
736 break;
739 *rptr = ptr;
740 return result;
743 static void
744 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
746 var->index = read_leb128 (ptr, &ptr);
747 var->offset = read_sleb128 (ptr, &ptr);
748 var->size = read_leb128 (ptr, &ptr);
749 var->begin_scope = read_leb128 (ptr, &ptr);
750 var->end_scope = read_leb128 (ptr, &ptr);
751 READ_UNALIGNED (gpointer, ptr, var->type);
752 ptr += sizeof (gpointer);
753 *rptr = ptr;
756 void
757 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
759 if (!jit)
760 return;
761 g_free (jit->line_numbers);
762 g_free (jit->this_var);
763 g_free (jit->params);
764 g_free (jit->locals);
765 g_free (jit);
768 static MonoDebugMethodJitInfo *
769 mono_debug_read_method (MonoDebugMethodAddress *address)
771 MonoDebugMethodJitInfo *jit;
772 guint32 i;
773 guint8 *ptr;
775 jit = g_new0 (MonoDebugMethodJitInfo, 1);
776 jit->code_start = address->code_start;
777 jit->code_size = address->code_size;
778 jit->wrapper_addr = address->wrapper_addr;
780 ptr = (guint8 *) &address->data;
782 jit->prologue_end = read_leb128 (ptr, &ptr);
783 jit->epilogue_begin = read_leb128 (ptr, &ptr);
785 jit->num_line_numbers = read_leb128 (ptr, &ptr);
786 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
787 for (i = 0; i < jit->num_line_numbers; i++) {
788 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
790 lne->il_offset = read_sleb128 (ptr, &ptr);
791 lne->native_offset = read_sleb128 (ptr, &ptr);
794 if (*ptr++) {
795 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
796 read_variable (jit->this_var, ptr, &ptr);
799 jit->num_params = read_leb128 (ptr, &ptr);
800 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
801 for (i = 0; i < jit->num_params; i++)
802 read_variable (&jit->params [i], ptr, &ptr);
804 jit->num_locals = read_leb128 (ptr, &ptr);
805 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
806 for (i = 0; i < jit->num_locals; i++)
807 read_variable (&jit->locals [i], ptr, &ptr);
809 return jit;
812 static void
813 mono_debug_add_type (MonoClass *klass)
815 MonoDebugHandle *handle;
816 MonoDebugClassEntry *entry;
817 guint8 buffer [BUFSIZ];
818 guint8 *ptr, *oldptr;
819 guint32 size, total_size, max_size;
820 int base_offset = 0;
822 if (klass->generic_class || klass->rank ||
823 (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
824 return;
826 mono_debugger_lock ();
828 handle = _mono_debug_get_image (klass->image);
829 if (!handle) {
830 mono_debugger_unlock ();
831 return;
834 max_size = 12 + sizeof (gpointer);
835 if (max_size > BUFSIZ)
836 ptr = oldptr = g_malloc (max_size);
837 else
838 ptr = oldptr = buffer;
840 if (klass->valuetype)
841 base_offset = - (int)(sizeof (MonoObject));
843 write_leb128 (klass->type_token, ptr, &ptr);
844 write_leb128 (klass->instance_size + base_offset, ptr, &ptr);
845 WRITE_UNALIGNED (gpointer, ptr, klass);
846 ptr += sizeof (gpointer);
848 size = ptr - oldptr;
849 g_assert (size < max_size);
850 total_size = size + sizeof (MonoDebugClassEntry);
852 g_assert (total_size + 9 < DATA_TABLE_CHUNK_SIZE);
854 entry = (MonoDebugClassEntry *) allocate_data_item (
855 handle->type_table, MONO_DEBUG_DATA_ITEM_CLASS, total_size);
857 entry->size = total_size;
859 memcpy (&entry->data, oldptr, size);
861 write_data_item (handle->type_table, (guint8 *) entry);
863 if (max_size > BUFSIZ)
864 g_free (oldptr);
866 mono_debugger_unlock ();
869 static MonoDebugMethodJitInfo *
870 find_method (MonoMethod *method, MonoDomain *domain)
872 MonoDebugDataTable *table;
873 MonoDebugMethodAddress *address;
875 table = lookup_data_table (domain);
876 address = g_hash_table_lookup (table->method_address_hash, method);
878 if (!address)
879 return NULL;
881 return mono_debug_read_method (address);
884 MonoDebugMethodJitInfo *
885 mono_debug_find_method (MonoMethod *method, MonoDomain *domain)
887 MonoDebugMethodJitInfo *res;
889 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
890 return NULL;
892 mono_debugger_lock ();
893 res = find_method (method, domain);
894 mono_debugger_unlock ();
895 return res;
898 struct LookupMethodAddressData
900 MonoMethod *method;
901 MonoDebugMethodHeader *result;
904 static void
905 lookup_method_address_func (gpointer key, gpointer value, gpointer user_data)
907 MonoDebugDataTable *table = (MonoDebugDataTable *) value;
908 struct LookupMethodAddressData *data = (struct LookupMethodAddressData *) user_data;
909 MonoDebugMethodHeader *header;
911 header = g_hash_table_lookup (table->method_hash, data->method);
912 if (header)
913 data->result = header;
916 MonoDebugMethodAddressList *
917 mono_debug_lookup_method_addresses (MonoMethod *method)
919 MonoDebugMethodAddressList *info;
920 MonoDebugMethodHeader *header = NULL;
921 struct LookupMethodAddressData data;
922 MonoMethod *declaring;
923 int count, size;
924 GSList *list;
925 guint8 *ptr;
927 g_assert ((mono_debug_debugger_version == 4) || (mono_debug_debugger_version == 5));
929 mono_debugger_lock ();
931 declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
933 data.method = declaring;
934 data.result = NULL;
936 g_hash_table_foreach (data_table_hash, lookup_method_address_func, &data);
937 header = data.result;
939 if (!header) {
940 mono_debugger_unlock ();
941 return NULL;
944 count = g_slist_length (header->address_list) + 1;
945 size = sizeof (MonoDebugMethodAddressList) + count * sizeof (gpointer);
947 info = g_malloc0 (size);
948 info->size = size;
949 info->count = count;
951 ptr = info->data;
953 WRITE_UNALIGNED (gpointer, ptr, header);
954 ptr += sizeof (gpointer);
956 for (list = header->address_list; list; list = list->next) {
957 WRITE_UNALIGNED (gpointer, ptr, list->data);
958 ptr += sizeof (gpointer);
961 mono_debugger_unlock ();
962 return info;
965 static gint32
966 il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
968 MonoDebugMethodJitInfo *jit;
969 int i;
971 jit = find_method (method, domain);
972 if (!jit || !jit->line_numbers)
973 goto cleanup_and_fail;
975 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
976 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
978 if (lne.native_offset <= native_offset) {
979 mono_debug_free_method_jit_info (jit);
980 return lne.il_offset;
984 cleanup_and_fail:
985 mono_debug_free_method_jit_info (jit);
986 return -1;
990 * mono_debug_il_offset_from_address:
992 * Compute the IL offset corresponding to NATIVE_OFFSET inside the native
993 * code of METHOD in DOMAIN.
995 gint32
996 mono_debug_il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
998 gint32 res;
1000 mono_debugger_lock ();
1002 res = il_offset_from_address (method, domain, native_offset);
1004 mono_debugger_unlock ();
1006 return res;
1010 * mono_debug_lookup_source_location:
1011 * @address: Native offset within the @method's machine code.
1013 * Lookup the source code corresponding to the machine instruction located at
1014 * native offset @address within @method.
1016 * The returned `MonoDebugSourceLocation' contains both file / line number
1017 * information and the corresponding IL offset. It must be freed by
1018 * mono_debug_free_source_location().
1020 MonoDebugSourceLocation *
1021 mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDomain *domain)
1023 MonoDebugMethodInfo *minfo;
1024 MonoDebugSourceLocation *location;
1025 gint32 offset;
1027 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
1028 return NULL;
1030 mono_debugger_lock ();
1031 minfo = _mono_debug_lookup_method (method);
1032 if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
1033 mono_debugger_unlock ();
1034 return NULL;
1037 offset = il_offset_from_address (method, domain, address);
1038 if (offset < 0) {
1039 mono_debugger_unlock ();
1040 return NULL;
1043 location = mono_debug_symfile_lookup_location (minfo, offset);
1044 mono_debugger_unlock ();
1045 return location;
1049 * mono_debug_lookup_locals:
1051 * Return information about the local variables of MINFO.
1052 * NAMES and INDEXES are set to g_malloc-ed arrays containing the local names and
1053 * their IL indexes.
1054 * Returns: the number of elements placed into the arrays, or -1 if there is no
1055 * local variable info.
1058 mono_debug_lookup_locals (MonoMethod *method, char ***names, int **indexes)
1060 MonoDebugMethodInfo *minfo;
1061 int res;
1063 *names = NULL;
1064 *indexes = NULL;
1066 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
1067 return -1;
1069 mono_debugger_lock ();
1070 minfo = _mono_debug_lookup_method (method);
1071 if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
1072 mono_debugger_unlock ();
1073 return -1;
1076 res = mono_debug_symfile_lookup_locals (minfo, names, indexes);
1077 mono_debugger_unlock ();
1079 return res;
1083 * mono_debug_free_source_location:
1084 * @location: A `MonoDebugSourceLocation'.
1086 * Frees the @location.
1088 void
1089 mono_debug_free_source_location (MonoDebugSourceLocation *location)
1091 if (location) {
1092 g_free (location->source_file);
1093 g_free (location);
1098 * mono_debug_print_stack_frame:
1099 * @native_offset: Native offset within the @method's machine code.
1101 * Conventient wrapper around mono_debug_lookup_source_location() which can be
1102 * used if you only want to use the location to print a stack frame.
1104 gchar *
1105 mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain)
1107 MonoDebugSourceLocation *location;
1108 gchar *fname, *ptr, *res;
1109 int offset;
1111 fname = mono_method_full_name (method, TRUE);
1112 for (ptr = fname; *ptr; ptr++) {
1113 if (*ptr == ':') *ptr = '.';
1116 location = mono_debug_lookup_source_location (method, native_offset, domain);
1118 if (!location) {
1119 if (mono_debug_initialized) {
1120 mono_debugger_lock ();
1121 offset = il_offset_from_address (method, domain, native_offset);
1122 mono_debugger_unlock ();
1123 } else {
1124 offset = -1;
1127 if (offset < 0)
1128 res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
1129 else
1130 res = g_strdup_printf ("at %s <IL 0x%05x, 0x%05x>", fname, offset, native_offset);
1131 g_free (fname);
1132 return res;
1135 res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset,
1136 location->source_file, location->row);
1138 g_free (fname);
1139 mono_debug_free_source_location (location);
1140 return res;
1143 void
1144 mono_debug_list_add (MonoDebugList **list, gconstpointer data)
1146 MonoDebugList *element, **ptr;
1148 element = g_new0 (MonoDebugList, 1);
1149 element->data = data;
1151 for (ptr = list; *ptr; ptr = &(*ptr)->next)
1154 *ptr = element;
1157 void
1158 mono_debug_list_remove (MonoDebugList **list, gconstpointer data)
1160 MonoDebugList **ptr;
1161 MonoDebugList *next;
1163 for (ptr = list; *ptr; ptr = &(*ptr)->next) {
1164 if ((*ptr)->data != data)
1165 continue;
1167 next = (*ptr)->next;
1168 g_free ((*ptr));
1169 *ptr = next;
1170 break;
1174 static gboolean is_attached = FALSE;
1176 void
1177 mono_set_is_debugger_attached (gboolean attached)
1179 is_attached = attached;
1182 gboolean
1183 mono_is_debugger_attached (void)
1185 return is_attached;