[sgen] One internal allocator per worker thread, to get rid of locking.
[mono-project/dkf.git] / mono / metadata / mono-debug.c
blob92c70c33963275a2827e4268f9ff9c8bd51e3304
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 static 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) {
295 if (mono_symbol_table->global_data_table)
296 free_data_table (mono_symbol_table->global_data_table);
298 g_free (mono_symbol_table);
299 mono_symbol_table = NULL;
303 void
304 mono_debug_domain_create (MonoDomain *domain)
306 MonoDebugDataTable *table;
308 if (!mono_debug_initialized)
309 return;
311 mono_debugger_lock ();
313 table = create_data_table (domain);
315 mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_CREATE, (guint64) (gsize) table,
316 mono_domain_get_id (domain));
318 mono_debugger_unlock ();
321 void
322 mono_debug_domain_unload (MonoDomain *domain)
324 MonoDebugDataTable *table;
326 if (!mono_debug_initialized)
327 return;
329 mono_debugger_lock ();
331 table = g_hash_table_lookup (data_table_hash, domain);
332 if (!table) {
333 g_warning (G_STRLOC ": unloading unknown domain %p / %d",
334 domain, mono_domain_get_id (domain));
335 mono_debugger_unlock ();
336 return;
339 mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_UNLOAD, (guint64) (gsize) table,
340 mono_domain_get_id (domain));
342 g_hash_table_remove (data_table_hash, domain);
344 mono_debugger_unlock ();
348 * LOCKING: Assumes the debug lock is held.
350 static MonoDebugHandle *
351 _mono_debug_get_image (MonoImage *image)
353 return g_hash_table_lookup (mono_debug_handles, image);
356 void
357 mono_debug_close_image (MonoImage *image)
359 MonoDebugHandle *handle;
361 if (!mono_debug_initialized)
362 return;
364 mono_debugger_lock ();
366 handle = _mono_debug_get_image (image);
367 if (!handle) {
368 mono_debugger_unlock ();
369 return;
372 mono_debugger_event (MONO_DEBUGGER_EVENT_UNLOAD_MODULE, (guint64) (gsize) handle,
373 handle->index);
375 mono_debug_list_remove (&mono_symbol_table->symbol_files, handle);
376 g_hash_table_remove (mono_debug_handles, image);
378 mono_debugger_unlock ();
381 static MonoDebugHandle *
382 mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
384 MonoDebugHandle *handle;
386 if (mono_image_is_dynamic (image))
387 return NULL;
389 mono_debugger_lock ();
391 handle = _mono_debug_get_image (image);
392 if (handle != NULL) {
393 mono_debugger_unlock ();
394 return handle;
397 handle = g_new0 (MonoDebugHandle, 1);
398 handle->index = ++next_symbol_file_id;
400 handle->image = image;
401 mono_image_addref (image);
402 handle->image_file = g_strdup (mono_image_get_filename (image));
404 handle->type_table = create_data_table (NULL);
406 handle->symfile = mono_debug_open_mono_symbols (
407 handle, raw_contents, size, _mono_debug_using_mono_debugger);
409 mono_debug_list_add (&mono_symbol_table->symbol_files, handle);
411 g_hash_table_insert (mono_debug_handles, image, handle);
413 if (mono_symbol_table->corlib)
414 mono_debugger_event (MONO_DEBUGGER_EVENT_LOAD_MODULE,
415 (guint64) (gsize) handle, 0);
417 mono_debugger_unlock ();
419 return handle;
422 static void
423 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
425 mono_debugger_lock ();
426 mono_debug_open_image (mono_assembly_get_image (assembly), NULL, 0);
427 mono_debugger_unlock ();
430 static guint8 *
431 allocate_data_item (MonoDebugDataTable *table, MonoDebugDataItemType type, guint32 size)
433 guint32 chunk_size;
434 guint8 *data;
436 size = ALIGN_TO (size, sizeof (gpointer));
438 if (size + 16 < DATA_TABLE_CHUNK_SIZE)
439 chunk_size = DATA_TABLE_CHUNK_SIZE;
440 else
441 chunk_size = size + 16;
443 g_assert (table->current_chunk->current_offset == table->current_chunk->allocated_size);
445 if (table->current_chunk->allocated_size + size + 8 >= table->current_chunk->total_size) {
446 MonoDebugDataChunk *new_chunk;
448 new_chunk = g_malloc0 (sizeof (MonoDebugDataChunk) + chunk_size);
449 new_chunk->total_size = chunk_size;
451 table->current_chunk->next = new_chunk;
452 table->current_chunk = new_chunk;
455 data = &table->current_chunk->data [table->current_chunk->allocated_size];
456 table->current_chunk->allocated_size += size + 8;
458 * ((guint32 *) data) = size;
459 data += 4;
460 * ((guint32 *) data) = type;
461 data += 4;
462 return data;
465 static void
466 write_data_item (MonoDebugDataTable *table, const guint8 *data)
468 MonoDebugDataChunk *current_chunk = table->current_chunk;
469 guint32 size = * ((guint32 *) (data - 8));
471 g_assert (current_chunk->current_offset + size + 8 == current_chunk->allocated_size);
472 current_chunk->current_offset = current_chunk->allocated_size;
475 struct LookupMethodData
477 MonoDebugMethodInfo *minfo;
478 MonoMethod *method;
481 static void
482 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
484 MonoDebugHandle *handle = (MonoDebugHandle *) value;
485 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
487 if (data->minfo)
488 return;
490 if (handle->symfile)
491 data->minfo = mono_debug_symfile_lookup_method (handle, data->method);
494 static MonoDebugMethodInfo *
495 _mono_debug_lookup_method (MonoMethod *method)
497 struct LookupMethodData data;
499 data.minfo = NULL;
500 data.method = method;
502 if (!mono_debug_handles)
503 return NULL;
505 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
506 return data.minfo;
510 * mono_debug_lookup_method:
512 * Lookup symbol file information for the method @method. The returned
513 * `MonoDebugMethodInfo' is a private structure, but it can be passed to
514 * mono_debug_symfile_lookup_location().
516 MonoDebugMethodInfo *
517 mono_debug_lookup_method (MonoMethod *method)
519 MonoDebugMethodInfo *minfo;
521 mono_debugger_lock ();
522 minfo = _mono_debug_lookup_method (method);
523 mono_debugger_unlock ();
524 return minfo;
527 static inline void
528 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
530 do {
531 guint8 byte = value & 0x7f;
532 value >>= 7;
533 if (value)
534 byte |= 0x80;
535 *ptr++ = byte;
536 } while (value);
538 *rptr = ptr;
541 static inline void
542 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
544 gboolean more = 1;
546 while (more) {
547 guint8 byte = value & 0x7f;
548 value >>= 7;
550 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
551 more = 0;
552 else
553 byte |= 0x80;
554 *ptr++ = byte;
557 *rptr = ptr;
560 static void
561 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
563 write_leb128 (var->index, ptr, &ptr);
564 write_sleb128 (var->offset, ptr, &ptr);
565 write_leb128 (var->size, ptr, &ptr);
566 write_leb128 (var->begin_scope, ptr, &ptr);
567 write_leb128 (var->end_scope, ptr, &ptr);
568 WRITE_UNALIGNED (gpointer, ptr, var->type);
569 ptr += sizeof (gpointer);
570 *rptr = ptr;
573 MonoDebugMethodAddress *
574 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
576 MonoMethod *declaring;
577 MonoDebugDataTable *table;
578 MonoDebugMethodHeader *header;
579 MonoDebugMethodAddress *address;
580 MonoDebugMethodInfo *minfo;
581 MonoDebugHandle *handle;
582 guint8 buffer [BUFSIZ];
583 guint8 *ptr, *oldptr;
584 guint32 i, size, total_size, max_size;
585 gboolean is_wrapper = FALSE;
587 mono_debugger_lock ();
589 table = lookup_data_table (domain);
591 handle = _mono_debug_get_image (method->klass->image);
592 minfo = _mono_debug_lookup_method (method);
594 if (!minfo || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
595 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
596 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
597 (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
598 (method->wrapper_type != MONO_WRAPPER_NONE)) {
599 is_wrapper = TRUE;
602 max_size = (5 * 5) + 1 + (10 * jit->num_line_numbers) +
603 (25 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
605 if (max_size > BUFSIZ)
606 ptr = oldptr = g_malloc (max_size);
607 else
608 ptr = oldptr = buffer;
610 write_leb128 (jit->prologue_end, ptr, &ptr);
611 write_leb128 (jit->epilogue_begin, ptr, &ptr);
613 write_leb128 (jit->num_line_numbers, ptr, &ptr);
614 for (i = 0; i < jit->num_line_numbers; i++) {
615 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
617 write_sleb128 (lne->il_offset, ptr, &ptr);
618 write_sleb128 (lne->native_offset, ptr, &ptr);
621 *ptr++ = jit->this_var ? 1 : 0;
622 if (jit->this_var)
623 write_variable (jit->this_var, ptr, &ptr);
625 write_leb128 (jit->num_params, ptr, &ptr);
626 for (i = 0; i < jit->num_params; i++)
627 write_variable (&jit->params [i], ptr, &ptr);
629 write_leb128 (jit->num_locals, ptr, &ptr);
630 for (i = 0; i < jit->num_locals; i++)
631 write_variable (&jit->locals [i], ptr, &ptr);
633 size = ptr - oldptr;
634 g_assert (size < max_size);
635 total_size = size + sizeof (MonoDebugMethodAddress);
637 address = (MonoDebugMethodAddress *) allocate_data_item (
638 table, MONO_DEBUG_DATA_ITEM_METHOD, total_size);
640 address->header.size = total_size;
641 address->header.symfile_id = handle ? handle->index : 0;
642 address->header.domain_id = mono_domain_get_id (domain);
643 address->header.method_id = is_wrapper ? 0 : minfo->index;
644 address->header.method = method;
646 address->code_start = jit->code_start;
647 address->code_size = jit->code_size;
649 memcpy (&address->data, oldptr, size);
650 if (max_size > BUFSIZ)
651 g_free (oldptr);
653 declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
654 header = g_hash_table_lookup (table->method_hash, declaring);
656 if (!header) {
657 header = &address->header;
658 g_hash_table_insert (table->method_hash, declaring, header);
660 if (is_wrapper) {
661 MonoDebugWrapperData *wrapper;
663 header->wrapper_data = wrapper = g_new0 (MonoDebugWrapperData, 1);
665 wrapper->wrapper_type = method->wrapper_type;
666 wrapper->method_name = mono_method_full_name (declaring, TRUE);
667 wrapper->obsolete_cil_code = "";
669 } else {
670 address->header.wrapper_data = header->wrapper_data;
671 header->address_list = g_slist_prepend (header->address_list, address);
674 g_hash_table_insert (table->method_address_hash, method, address);
676 write_data_item (table, (guint8 *) address);
678 mono_debugger_unlock ();
679 return address;
682 void
683 mono_debug_add_delegate_trampoline (gpointer code, int size)
685 MonoDebugDelegateTrampolineEntry *entry;
687 if (!mono_debug_initialized)
688 return;
690 mono_debugger_lock ();
692 entry = (MonoDebugDelegateTrampolineEntry *) allocate_data_item (
693 mono_symbol_table->global_data_table, MONO_DEBUG_DATA_ITEM_DELEGATE_TRAMPOLINE,
694 sizeof (MonoDebugDelegateTrampolineEntry));
695 entry->code = code;
696 entry->size = size;
698 write_data_item (mono_symbol_table->global_data_table, (guint8 *) entry);
700 mono_debugger_unlock ();
703 static inline guint32
704 read_leb128 (guint8 *ptr, guint8 **rptr)
706 guint32 result = 0, shift = 0;
708 while (TRUE) {
709 guint8 byte = *ptr++;
711 result |= (byte & 0x7f) << shift;
712 if ((byte & 0x80) == 0)
713 break;
714 shift += 7;
717 *rptr = ptr;
718 return result;
721 static inline gint32
722 read_sleb128 (guint8 *ptr, guint8 **rptr)
724 gint32 result = 0;
725 guint32 shift = 0;
727 while (TRUE) {
728 guint8 byte = *ptr++;
730 result |= (byte & 0x7f) << shift;
731 shift += 7;
733 if (byte & 0x80)
734 continue;
736 if ((shift < 32) && (byte & 0x40))
737 result |= - (1 << shift);
738 break;
741 *rptr = ptr;
742 return result;
745 static void
746 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
748 var->index = read_leb128 (ptr, &ptr);
749 var->offset = read_sleb128 (ptr, &ptr);
750 var->size = read_leb128 (ptr, &ptr);
751 var->begin_scope = read_leb128 (ptr, &ptr);
752 var->end_scope = read_leb128 (ptr, &ptr);
753 READ_UNALIGNED (gpointer, ptr, var->type);
754 ptr += sizeof (gpointer);
755 *rptr = ptr;
758 void
759 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
761 if (!jit)
762 return;
763 g_free (jit->line_numbers);
764 g_free (jit->this_var);
765 g_free (jit->params);
766 g_free (jit->locals);
767 g_free (jit);
770 static MonoDebugMethodJitInfo *
771 mono_debug_read_method (MonoDebugMethodAddress *address)
773 MonoDebugMethodJitInfo *jit;
774 guint32 i;
775 guint8 *ptr;
777 jit = g_new0 (MonoDebugMethodJitInfo, 1);
778 jit->code_start = address->code_start;
779 jit->code_size = address->code_size;
780 jit->wrapper_addr = address->wrapper_addr;
782 ptr = (guint8 *) &address->data;
784 jit->prologue_end = read_leb128 (ptr, &ptr);
785 jit->epilogue_begin = read_leb128 (ptr, &ptr);
787 jit->num_line_numbers = read_leb128 (ptr, &ptr);
788 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
789 for (i = 0; i < jit->num_line_numbers; i++) {
790 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
792 lne->il_offset = read_sleb128 (ptr, &ptr);
793 lne->native_offset = read_sleb128 (ptr, &ptr);
796 if (*ptr++) {
797 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
798 read_variable (jit->this_var, ptr, &ptr);
801 jit->num_params = read_leb128 (ptr, &ptr);
802 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
803 for (i = 0; i < jit->num_params; i++)
804 read_variable (&jit->params [i], ptr, &ptr);
806 jit->num_locals = read_leb128 (ptr, &ptr);
807 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
808 for (i = 0; i < jit->num_locals; i++)
809 read_variable (&jit->locals [i], ptr, &ptr);
811 return jit;
814 static void
815 mono_debug_add_type (MonoClass *klass)
817 MonoDebugHandle *handle;
818 MonoDebugClassEntry *entry;
819 guint8 buffer [BUFSIZ];
820 guint8 *ptr, *oldptr;
821 guint32 size, total_size, max_size;
822 int base_offset = 0;
824 if (klass->generic_class || klass->rank ||
825 (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
826 return;
828 mono_debugger_lock ();
830 handle = _mono_debug_get_image (klass->image);
831 if (!handle) {
832 mono_debugger_unlock ();
833 return;
836 max_size = 12 + sizeof (gpointer);
837 if (max_size > BUFSIZ)
838 ptr = oldptr = g_malloc (max_size);
839 else
840 ptr = oldptr = buffer;
842 if (klass->valuetype)
843 base_offset = - (int)(sizeof (MonoObject));
845 write_leb128 (klass->type_token, ptr, &ptr);
846 write_leb128 (klass->instance_size + base_offset, ptr, &ptr);
847 WRITE_UNALIGNED (gpointer, ptr, klass);
848 ptr += sizeof (gpointer);
850 size = ptr - oldptr;
851 g_assert (size < max_size);
852 total_size = size + sizeof (MonoDebugClassEntry);
854 g_assert (total_size + 9 < DATA_TABLE_CHUNK_SIZE);
856 entry = (MonoDebugClassEntry *) allocate_data_item (
857 handle->type_table, MONO_DEBUG_DATA_ITEM_CLASS, total_size);
859 entry->size = total_size;
861 memcpy (&entry->data, oldptr, size);
863 write_data_item (handle->type_table, (guint8 *) entry);
865 if (max_size > BUFSIZ)
866 g_free (oldptr);
868 mono_debugger_unlock ();
871 static MonoDebugMethodJitInfo *
872 find_method (MonoMethod *method, MonoDomain *domain)
874 MonoDebugDataTable *table;
875 MonoDebugMethodAddress *address;
877 table = lookup_data_table (domain);
878 address = g_hash_table_lookup (table->method_address_hash, method);
880 if (!address)
881 return NULL;
883 return mono_debug_read_method (address);
886 MonoDebugMethodJitInfo *
887 mono_debug_find_method (MonoMethod *method, MonoDomain *domain)
889 MonoDebugMethodJitInfo *res;
891 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
892 return NULL;
894 mono_debugger_lock ();
895 res = find_method (method, domain);
896 mono_debugger_unlock ();
897 return res;
900 struct LookupMethodAddressData
902 MonoMethod *method;
903 MonoDebugMethodHeader *result;
906 static void
907 lookup_method_address_func (gpointer key, gpointer value, gpointer user_data)
909 MonoDebugDataTable *table = (MonoDebugDataTable *) value;
910 struct LookupMethodAddressData *data = (struct LookupMethodAddressData *) user_data;
911 MonoDebugMethodHeader *header;
913 header = g_hash_table_lookup (table->method_hash, data->method);
914 if (header)
915 data->result = header;
918 MonoDebugMethodAddressList *
919 mono_debug_lookup_method_addresses (MonoMethod *method)
921 MonoDebugMethodAddressList *info;
922 MonoDebugMethodHeader *header = NULL;
923 struct LookupMethodAddressData data;
924 MonoMethod *declaring;
925 int count, size;
926 GSList *list;
927 guint8 *ptr;
929 g_assert ((mono_debug_debugger_version == 4) || (mono_debug_debugger_version == 5));
931 mono_debugger_lock ();
933 declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
935 data.method = declaring;
936 data.result = NULL;
938 g_hash_table_foreach (data_table_hash, lookup_method_address_func, &data);
939 header = data.result;
941 if (!header) {
942 mono_debugger_unlock ();
943 return NULL;
946 count = g_slist_length (header->address_list) + 1;
947 size = sizeof (MonoDebugMethodAddressList) + count * sizeof (gpointer);
949 info = g_malloc0 (size);
950 info->size = size;
951 info->count = count;
953 ptr = info->data;
955 WRITE_UNALIGNED (gpointer, ptr, header);
956 ptr += sizeof (gpointer);
958 for (list = header->address_list; list; list = list->next) {
959 WRITE_UNALIGNED (gpointer, ptr, list->data);
960 ptr += sizeof (gpointer);
963 mono_debugger_unlock ();
964 return info;
967 static gint32
968 il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
970 MonoDebugMethodJitInfo *jit;
971 int i;
973 jit = find_method (method, domain);
974 if (!jit || !jit->line_numbers)
975 goto cleanup_and_fail;
977 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
978 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
980 if (lne.native_offset <= native_offset) {
981 mono_debug_free_method_jit_info (jit);
982 return lne.il_offset;
986 cleanup_and_fail:
987 mono_debug_free_method_jit_info (jit);
988 return -1;
992 * mono_debug_il_offset_from_address:
994 * Compute the IL offset corresponding to NATIVE_OFFSET inside the native
995 * code of METHOD in DOMAIN.
997 gint32
998 mono_debug_il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
1000 gint32 res;
1002 mono_debugger_lock ();
1004 res = il_offset_from_address (method, domain, native_offset);
1006 mono_debugger_unlock ();
1008 return res;
1012 * mono_debug_lookup_source_location:
1013 * @address: Native offset within the @method's machine code.
1015 * Lookup the source code corresponding to the machine instruction located at
1016 * native offset @address within @method.
1018 * The returned `MonoDebugSourceLocation' contains both file / line number
1019 * information and the corresponding IL offset. It must be freed by
1020 * mono_debug_free_source_location().
1022 MonoDebugSourceLocation *
1023 mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDomain *domain)
1025 MonoDebugMethodInfo *minfo;
1026 MonoDebugSourceLocation *location;
1027 gint32 offset;
1029 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
1030 return NULL;
1032 mono_debugger_lock ();
1033 minfo = _mono_debug_lookup_method (method);
1034 if (!minfo || !minfo->handle || !minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile)) {
1035 mono_debugger_unlock ();
1036 return NULL;
1039 offset = il_offset_from_address (method, domain, address);
1040 if (offset < 0) {
1041 mono_debugger_unlock ();
1042 return NULL;
1045 location = mono_debug_symfile_lookup_location (minfo, offset);
1046 mono_debugger_unlock ();
1047 return location;
1051 * mono_debug_lookup_locals:
1053 * Return information about the local variables of MINFO.
1054 * The result should be freed using mono_debug_symfile_free_locals ().
1056 MonoDebugLocalsInfo*
1057 mono_debug_lookup_locals (MonoMethod *method)
1059 MonoDebugMethodInfo *minfo;
1060 MonoDebugLocalsInfo *res;
1062 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
1063 return NULL;
1065 mono_debugger_lock ();
1066 minfo = _mono_debug_lookup_method (method);
1067 if (!minfo || !minfo->handle || !minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile)) {
1068 mono_debugger_unlock ();
1069 return NULL;
1072 res = mono_debug_symfile_lookup_locals (minfo);
1073 mono_debugger_unlock ();
1075 return res;
1079 * mono_debug_free_source_location:
1080 * @location: A `MonoDebugSourceLocation'.
1082 * Frees the @location.
1084 void
1085 mono_debug_free_source_location (MonoDebugSourceLocation *location)
1087 if (location) {
1088 g_free (location->source_file);
1089 g_free (location);
1094 * mono_debug_print_stack_frame:
1095 * @native_offset: Native offset within the @method's machine code.
1097 * Conventient wrapper around mono_debug_lookup_source_location() which can be
1098 * used if you only want to use the location to print a stack frame.
1100 gchar *
1101 mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain)
1103 MonoDebugSourceLocation *location;
1104 gchar *fname, *ptr, *res;
1105 int offset;
1107 fname = mono_method_full_name (method, TRUE);
1108 for (ptr = fname; *ptr; ptr++) {
1109 if (*ptr == ':') *ptr = '.';
1112 location = mono_debug_lookup_source_location (method, native_offset, domain);
1114 if (!location) {
1115 if (mono_debug_initialized) {
1116 mono_debugger_lock ();
1117 offset = il_offset_from_address (method, domain, native_offset);
1118 mono_debugger_unlock ();
1119 } else {
1120 offset = -1;
1123 if (offset < 0)
1124 res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
1125 else
1126 res = g_strdup_printf ("at %s <IL 0x%05x, 0x%05x>", fname, offset, native_offset);
1127 g_free (fname);
1128 return res;
1131 res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset,
1132 location->source_file, location->row);
1134 g_free (fname);
1135 mono_debug_free_source_location (location);
1136 return res;
1139 void
1140 mono_debug_list_add (MonoDebugList **list, gconstpointer data)
1142 MonoDebugList *element, **ptr;
1144 element = g_new0 (MonoDebugList, 1);
1145 element->data = data;
1147 for (ptr = list; *ptr; ptr = &(*ptr)->next)
1150 *ptr = element;
1153 void
1154 mono_debug_list_remove (MonoDebugList **list, gconstpointer data)
1156 MonoDebugList **ptr;
1157 MonoDebugList *next;
1159 for (ptr = list; *ptr; ptr = &(*ptr)->next) {
1160 if ((*ptr)->data != data)
1161 continue;
1163 next = (*ptr)->next;
1164 g_free ((*ptr));
1165 *ptr = next;
1166 break;
1170 static gboolean is_attached = FALSE;
1172 void
1173 mono_set_is_debugger_attached (gboolean attached)
1175 is_attached = attached;
1178 gboolean
1179 mono_is_debugger_attached (void)
1181 return is_attached;