5 #include <mono/metadata/metadata.h>
6 #include <mono/metadata/tabledefs.h>
7 #include <mono/metadata/rawbuffer.h>
8 #include <mono/metadata/tokentype.h>
9 #include <mono/metadata/appdomain.h>
10 #include <mono/metadata/exception.h>
11 #include <mono/metadata/debug-helpers.h>
12 #include <mono/metadata/debug-mono-symfile.h>
17 #define RANGE_TABLE_CHUNK_SIZE 256
18 #define CLASS_TABLE_CHUNK_SIZE 256
19 #define TYPE_TABLE_PTR_CHUNK_SIZE 256
20 #define TYPE_TABLE_CHUNK_SIZE 65536
22 struct MonoSymbolFilePriv
29 guint32 string_table_size;
30 guint32 string_offset_size;
32 GHashTable *method_table;
33 GHashTable *method_hash;
34 MonoSymbolFileOffsetTable *offset_table;
40 MonoDebugMethodInfo *minfo;
41 MonoSymbolFileMethodEntry *entry;
42 guint32 method_name_offset;
45 } MonoSymbolFileMethodEntryPriv;
47 static GHashTable *type_table;
48 static GHashTable *class_table;
50 MonoGlobalSymbolFile *mono_debugger_global_symbol_file = NULL;
52 static int write_string_table (MonoSymbolFile *symfile);
53 static int create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings);
54 static void close_symfile (MonoSymbolFile *symfile);
55 static MonoDebugRangeInfo *allocate_range_entry (MonoSymbolFile *symfile);
56 static MonoDebugClassInfo *allocate_class_entry (MonoSymbolFile *symfile);
57 static guint32 allocate_type_entry (MonoGlobalSymbolFile *global_symfile, guint32 size, guint8 **ptr);
58 static guint32 write_type (MonoGlobalSymbolFile *global_symfile, MonoType *type);
61 free_method_info (MonoDebugMethodInfo *minfo)
68 get_class_name (MonoClass *klass)
70 if (klass->nested_in) {
71 gchar *parent_name = get_class_name (klass->nested_in);
72 gchar *name = g_strdup_printf ("%s.%s", parent_name, klass->name);
77 return g_strdup_printf ("%s%s%s", klass->name_space,
78 klass->name_space [0] ? "." : "", klass->name);
82 get_method_name (MonoMethod *method)
84 gchar *tmpsig = mono_signature_get_desc (method->signature, TRUE);
85 gchar *class_name = get_class_name (method->klass);
86 gchar *name = g_strdup_printf ("%s.%s(%s)", class_name, method->name, tmpsig);
93 load_symfile (MonoSymbolFile *symfile)
95 MonoSymbolFilePriv *priv = symfile->_priv;
96 MonoSymbolFileMethodEntry *me;
97 const char *ptr, *start;
102 if (!mono_debugger_global_symbol_file)
103 mono_debugger_global_symbol_file = g_new0 (MonoGlobalSymbolFile, 1);
104 symfile->global = mono_debugger_global_symbol_file;
106 ptr = start = symfile->raw_contents;
108 magic = *((guint64 *) ptr)++;
109 if (magic != MONO_SYMBOL_FILE_MAGIC) {
110 g_warning ("Symbol file %s has is not a mono symbol file", priv->file_name);
114 version = *((guint32 *) ptr)++;
115 if (version != MONO_SYMBOL_FILE_VERSION) {
116 g_warning ("Symbol file %s has incorrect line number table version "
117 "(expected %d, got %ld)", priv->file_name,
118 MONO_SYMBOL_FILE_VERSION, version);
122 priv->offset_table = (MonoSymbolFileOffsetTable *) ptr;
124 mono_debug_symfile_add_type (symfile, mono_defaults.object_class);
131 priv->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
132 (GDestroyNotify) g_free);
133 priv->method_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
134 (GDestroyNotify) free_method_info);
136 ptr = symfile->raw_contents + priv->offset_table->method_table_offset;
137 me = (MonoSymbolFileMethodEntry *) ptr;
139 for (i = 0; i < priv->offset_table->method_count; i++, me++) {
140 MonoMethod *method = mono_get_method (priv->image, me->token, NULL);
141 MonoSymbolFileMethodEntryPriv *mep;
142 MonoDebugMethodInfo *minfo;
147 minfo = g_new0 (MonoDebugMethodInfo, 1);
148 minfo->file_offset = ((const char *) me) - start;
149 minfo->method = method;
150 minfo->symfile = symfile;
151 minfo->num_il_offsets = me->num_line_numbers;
152 minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
153 (symfile->raw_contents + me->line_number_table_offset);
155 mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
156 mep->method = method;
161 mep->method_name_offset = priv->string_table_size;
162 mep->name = get_method_name (method);
163 priv->string_table_size += strlen (mep->name) + 5;
165 g_hash_table_insert (priv->method_table, method, mep);
166 g_hash_table_insert (priv->method_hash, method, minfo);
169 if (!write_string_table (symfile))
176 mono_debug_open_mono_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
178 MonoSymbolFile *symfile;
179 MonoSymbolFilePriv *priv;
184 fd = open (filename, O_RDONLY);
187 g_warning ("Can't open symbol file: %s", filename);
191 file_size = lseek (fd, 0, SEEK_END);
192 lseek (fd, 0, SEEK_SET);
194 if (file_size == (off_t) -1) {
196 g_warning ("Can't get size of symbol file: %s", filename);
200 ptr = mono_raw_buffer_load (fd, FALSE, 0, file_size);
203 g_warning ("Can't read symbol file: %s", filename);
207 symfile = g_new0 (MonoSymbolFile, 1);
208 symfile->magic = MONO_SYMBOL_FILE_MAGIC;
209 symfile->version = MONO_SYMBOL_FILE_VERSION;
210 symfile->dynamic_magic = MONO_SYMBOL_FILE_DYNAMIC_MAGIC;
211 symfile->dynamic_version = MONO_SYMBOL_FILE_DYNAMIC_VERSION;
212 symfile->image_file = g_strdup (image->name);
213 symfile->symbol_file = g_strdup (filename);
214 symfile->raw_contents = ptr;
215 symfile->raw_contents_size = file_size;
217 symfile->_priv = priv = g_new0 (MonoSymbolFilePriv, 1);
221 priv->file_name = g_strdup (filename);
223 if (!load_symfile (symfile)) {
224 mono_debug_close_mono_symbol_file (symfile);
232 close_symfile (MonoSymbolFile *symfile)
234 MonoSymbolFilePriv *priv = symfile->_priv;
236 if (symfile->raw_contents) {
237 mono_raw_buffer_free (symfile->raw_contents);
238 symfile->raw_contents = NULL;
246 if (priv->method_table) {
247 g_hash_table_destroy (priv->method_table);
248 priv->method_table = NULL;
251 if (symfile->is_dynamic) {
252 unlink (priv->file_name);
253 priv->method_hash = NULL;
254 } else if (priv->method_hash) {
255 g_hash_table_destroy (priv->method_hash);
256 priv->method_hash = NULL;
259 if (symfile->image_file) {
260 g_free (symfile->image_file);
261 symfile->image_file = NULL;
264 if (priv->file_name) {
265 g_free (priv->file_name);
266 priv->file_name = NULL;
273 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
278 close_symfile (symfile);
280 g_free (symfile->_priv->source_file);
281 g_free (symfile->_priv);
282 g_free (symfile->image_file);
283 g_free (symfile->symbol_file);
288 read_string (const char *ptr)
290 int len = *((guint32 *) ptr)++;
292 return g_filename_from_utf8 (ptr, len, NULL, NULL, NULL);
296 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
297 guint32 *line_number)
299 MonoSymbolFilePriv *priv = symfile->_priv;
300 MonoSymbolFileLineNumberEntry *lne;
301 MonoSymbolFileMethodEntryPriv *mep;
302 gchar *source_file = NULL;
306 if (!priv->method_table || symfile->is_dynamic)
309 mep = g_hash_table_lookup (priv->method_table, method);
313 if (mep->entry->source_file_offset)
314 source_file = read_string (symfile->raw_contents + mep->entry->source_file_offset);
316 ptr = symfile->raw_contents + mep->entry->line_number_table_offset;
318 lne = (MonoSymbolFileLineNumberEntry *) ptr;
320 for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
321 if (lne->offset < offset)
325 *line_number = lne->row;
330 } else if (source_file) {
331 gchar *retval = g_strdup_printf ("%s:%d", source_file, lne->row);
332 g_free (source_file);
335 return g_strdup_printf ("%d", lne->row);
342 mono_debug_symfile_add_method (MonoSymbolFile *symfile, MonoMethod *method)
344 MonoSymbolFileMethodEntryPriv *mep;
345 MonoSymbolFileMethodAddress *address;
346 MonoDebugVarInfo *var_table;
347 MonoDebugRangeInfo *range;
348 MonoMethodHeader *header;
349 guint32 size, num_variables, variable_size, variable_offset;
350 guint32 type_size, type_offset, *type_index_table;
351 guint32 line_size, line_offset;
352 MonoDebugLineNumberEntry *line_table;
357 if (!symfile->_priv->method_table)
360 header = ((MonoMethodNormal *) method)->header;
362 mep = g_hash_table_lookup (symfile->_priv->method_table, method);
367 mep->minfo = g_hash_table_lookup (symfile->_priv->method_hash, mep->method);
372 if (!mep->minfo->jit)
375 symfile->generation++;
377 size = sizeof (MonoSymbolFileMethodAddress);
379 num_variables = mep->entry->num_parameters + mep->entry->num_locals;
380 if (mep->entry->this_type_index)
383 variable_size = num_variables * sizeof (MonoDebugVarInfo);
384 variable_offset = size;
385 size += variable_size;
387 type_size = num_variables * sizeof (gpointer);
391 if (mep->minfo->jit->line_numbers) {
393 line_size = mep->minfo->jit->line_numbers->len * sizeof (MonoDebugLineNumberEntry);
397 address = g_malloc0 (size);
398 ptr = (guint8 *) address;
400 address->size = size;
401 address->start_address = mep->minfo->jit->code_start;
402 address->end_address = mep->minfo->jit->code_start + mep->minfo->jit->code_size;
403 address->method_start_address = address->start_address + mep->minfo->jit->prologue_end;
404 address->method_end_address = address->start_address + mep->minfo->jit->epilogue_begin;
405 address->wrapper_address = mep->minfo->jit->wrapper_addr;
406 address->variable_table_offset = variable_offset;
407 address->type_table_offset = type_offset;
409 if (mep->minfo->jit->line_numbers) {
410 address->num_line_numbers = mep->minfo->jit->line_numbers->len;
411 address->line_number_offset = line_offset;
413 line_table = (MonoDebugLineNumberEntry *) (ptr + line_offset);
414 memcpy (line_table, mep->minfo->jit->line_numbers->data, line_size);
417 range = allocate_range_entry (symfile);
418 range->file_offset = mep->minfo->file_offset;
419 range->start_address = address->start_address;
420 range->end_address = address->end_address;
421 range->dynamic_data = address;
422 range->dynamic_size = size;
424 var_table = (MonoDebugVarInfo *) (ptr + variable_offset);
425 type_table = (guint32 *) (ptr + type_offset);
427 type_index_table = (guint32 *)
428 (symfile->raw_contents + mep->entry->type_index_table_offset);
430 if (mep->entry->this_type_index) {
431 if (!mep->minfo->jit->this_var) {
432 g_warning (G_STRLOC ": Method %s.%s doesn't have `this'.",
433 mep->method->klass->name, mep->method->name);
436 *var_table++ = *mep->minfo->jit->this_var;
437 *type_table++ = write_type (symfile->global, &method->klass->this_arg);
441 if (mep->minfo->jit->num_params != mep->entry->num_parameters) {
442 g_warning (G_STRLOC ": Method %s.%s has %d parameters, but symbol file claims it has %d.",
443 mep->method->klass->name, mep->method->name, mep->minfo->jit->num_params,
444 mep->entry->num_parameters);
446 var_table += mep->entry->num_parameters;
448 for (i = 0; i < mep->minfo->jit->num_params; i++) {
449 *var_table++ = mep->minfo->jit->params [i];
450 *type_table++ = write_type (symfile->global, method->signature->params [i]);
454 if (mep->minfo->jit->num_locals < mep->entry->num_locals) {
456 g_warning (G_STRLOC ": Method %s.%s has %d locals, but symbol file claims it has %d.",
457 mep->method->klass->name, mep->method->name, mep->minfo->jit->num_locals,
458 mep->entry->num_locals);
460 var_table += mep->entry->num_locals;
462 g_assert ((header != NULL) || (mep->entry->num_locals == 0));
463 for (i = 0; i < mep->entry->num_locals; i++) {
464 /*MonoDebugVarInfo *var = &mep->minfo->jit->locals [i];*/
465 *var_table++ = mep->minfo->jit->locals [i];
466 *type_table++ = write_type (symfile->global, header->locals [i]);
472 mono_debug_symfile_add_type (MonoSymbolFile *symfile, MonoClass *klass)
474 MonoDebugClassInfo *info;
477 class_table = g_hash_table_new (g_direct_hash, g_direct_equal);
479 /* We write typeof (object) into each symbol file's type table. */
480 if ((klass != mono_defaults.object_class) && g_hash_table_lookup (class_table, klass))
483 symfile->generation++;
485 info = allocate_class_entry (symfile);
488 info->token = klass->element_class->type_token;
489 info->rank = klass->rank;
491 info->token = klass->type_token;
492 info->type_info = write_type (symfile->global, &klass->this_arg);
496 create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings)
498 MonoSymbolFilePriv *priv = symfile->_priv;
504 if (!mono_debugger_global_symbol_file)
505 mono_debugger_global_symbol_file = g_new0 (MonoGlobalSymbolFile, 1);
506 symfile->global = mono_debugger_global_symbol_file;
508 priv->fd = g_file_open_tmp (NULL, &priv->file_name, NULL);
509 if (priv->fd == -1) {
511 g_warning ("Can't create symbol file");
515 symfile->symbol_file = g_strdup (priv->file_name);
517 magic = MONO_SYMBOL_FILE_MAGIC;
518 if (write (priv->fd, &magic, sizeof (magic)) < 0)
521 version = MONO_SYMBOL_FILE_VERSION;
522 if (write (priv->fd, &version, sizeof (version)) < 0)
525 offset = lseek (priv->fd, 0, SEEK_CUR);
527 priv->offset_table = g_new0 (MonoSymbolFileOffsetTable, 1);
528 if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
531 mono_debug_symfile_add_type (symfile, mono_defaults.object_class);
534 // Write offset table.
537 symfile->raw_contents_size = lseek (priv->fd, 0, SEEK_CUR);
539 lseek (priv->fd, offset, SEEK_SET);
540 if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
543 lseek (priv->fd, symfile->raw_contents_size, SEEK_SET);
545 ptr = mono_raw_buffer_load (priv->fd, TRUE, 0, symfile->raw_contents_size);
549 symfile->raw_contents = ptr;
555 mono_debug_create_mono_symbol_file (MonoImage *image)
557 MonoSymbolFile *symfile;
559 symfile = g_new0 (MonoSymbolFile, 1);
560 symfile->magic = MONO_SYMBOL_FILE_MAGIC;
561 symfile->version = MONO_SYMBOL_FILE_VERSION;
562 symfile->dynamic_magic = MONO_SYMBOL_FILE_DYNAMIC_MAGIC;
563 symfile->dynamic_version = MONO_SYMBOL_FILE_DYNAMIC_VERSION;
564 symfile->is_dynamic = TRUE;
565 symfile->image_file = g_strdup (image->name);
567 symfile->_priv = g_new0 (MonoSymbolFilePriv, 1);
568 symfile->_priv->image = image;
570 if (!create_symfile (symfile, TRUE)) {
571 mono_debug_close_mono_symbol_file (symfile);
578 MonoDebugMethodInfo *
579 mono_debug_find_method (MonoSymbolFile *symfile, MonoMethod *method)
581 if (!symfile->_priv->method_hash)
584 return g_hash_table_lookup (symfile->_priv->method_hash, method);
588 write_method_name (gpointer key, gpointer value, gpointer user_data)
590 MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
591 MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
592 MonoSymbolFilePriv *priv = symfile->_priv;
593 guint8 *offset_ptr, *string_ptr;
596 offset = mep->method_name_offset + priv->string_offset_size;
598 offset_ptr = symfile->string_table + mep->index * 4;
599 string_ptr = symfile->string_table + offset;
601 *((guint32 *) offset_ptr) = offset;
602 *((guint32 *) string_ptr)++ = strlen (mep->name);
603 strcpy (string_ptr, mep->name);
607 write_string_table (MonoSymbolFile *symfile)
609 MonoSymbolFilePriv *priv = symfile->_priv;
611 priv->string_offset_size = priv->offset_table->method_count * 4;
613 symfile->string_table_size = priv->string_table_size + priv->string_offset_size;
614 symfile->string_table = g_malloc0 (symfile->string_table_size);
616 g_hash_table_foreach (symfile->_priv->method_table, write_method_name, symfile);
620 MonoReflectionMethod *
621 ves_icall_MonoDebugger_GetMethod (MonoReflectionAssembly *assembly, guint32 token)
625 method = mono_get_method (assembly->assembly->image, token, NULL);
627 return mono_method_get_object (mono_domain_get (), method, NULL);
631 ves_icall_MonoDebugger_GetType (MonoReflectionAssembly *assembly, guint32 token)
635 klass = mono_class_get (assembly->assembly->image, token);
637 g_warning (G_STRLOC ": %x", token);
641 return mono_type_get_object (mono_domain_get (), &klass->byval_arg);
645 ves_icall_MonoDebugger_GetLocalTypeFromSignature (MonoReflectionAssembly *assembly, MonoArray *signature)
653 MONO_CHECK_ARG_NULL (assembly);
654 MONO_CHECK_ARG_NULL (signature);
656 domain = mono_domain_get();
657 image = assembly->assembly->image;
659 ptr = mono_array_addr (signature, char, 0);
660 g_assert (*ptr++ == 0x07);
661 len = mono_metadata_decode_value (ptr, &ptr);
664 type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
666 return mono_type_get_object (domain, type);
669 static MonoDebugRangeInfo *
670 allocate_range_entry (MonoSymbolFile *symfile)
672 MonoDebugRangeInfo *retval;
673 guint32 size, chunks;
675 symfile->range_entry_size = sizeof (MonoDebugRangeInfo);
677 if (!symfile->range_table) {
678 size = sizeof (MonoDebugRangeInfo) * RANGE_TABLE_CHUNK_SIZE;
679 symfile->range_table = g_malloc0 (size);
680 symfile->num_range_entries = 1;
681 return symfile->range_table;
684 if (!((symfile->num_range_entries + 1) % RANGE_TABLE_CHUNK_SIZE)) {
685 chunks = (symfile->num_range_entries + 1) / RANGE_TABLE_CHUNK_SIZE;
686 size = sizeof (MonoDebugRangeInfo) * RANGE_TABLE_CHUNK_SIZE * (chunks + 1);
688 symfile->range_table = g_realloc (symfile->range_table, size);
691 retval = symfile->range_table + symfile->num_range_entries;
692 symfile->num_range_entries++;
696 static MonoDebugClassInfo *
697 allocate_class_entry (MonoSymbolFile *symfile)
699 MonoDebugClassInfo *retval;
700 guint32 size, chunks;
702 symfile->class_entry_size = sizeof (MonoDebugClassInfo);
704 if (!symfile->class_table) {
705 size = sizeof (MonoDebugClassInfo) * CLASS_TABLE_CHUNK_SIZE;
706 symfile->class_table = g_malloc0 (size);
707 symfile->num_class_entries = 1;
708 return symfile->class_table;
711 if (!((symfile->num_class_entries + 1) % CLASS_TABLE_CHUNK_SIZE)) {
712 chunks = (symfile->num_class_entries + 1) / CLASS_TABLE_CHUNK_SIZE;
713 size = sizeof (MonoDebugClassInfo) * CLASS_TABLE_CHUNK_SIZE * (chunks + 1);
715 symfile->class_table = g_realloc (symfile->class_table, size);
718 retval = symfile->class_table + symfile->num_class_entries;
719 symfile->num_class_entries++;
724 * Allocate a new entry of size `size' in the type table.
725 * Returns the global offset which is to be used to reference this type and
726 * a pointer (in the `ptr' argument) which is to be used to write the type.
729 allocate_type_entry (MonoGlobalSymbolFile *global, guint32 size, guint8 **ptr)
734 g_assert (size + 4 < TYPE_TABLE_CHUNK_SIZE);
735 g_assert (ptr != NULL);
737 /* Initialize things if necessary. */
738 if (!global->current_type_table) {
739 global->current_type_table = g_malloc0 (TYPE_TABLE_CHUNK_SIZE);
740 global->type_table_size = TYPE_TABLE_CHUNK_SIZE;
741 global->type_table_chunk_size = TYPE_TABLE_CHUNK_SIZE;
742 global->type_table_offset = 1;
746 /* First let's check whether there's still enough room in the current_type_table. */
747 if (global->type_table_offset + size + 4 < global->type_table_size) {
748 retval = global->type_table_offset;
749 global->type_table_offset += size + 4;
750 data = ((guint8 *) global->current_type_table) + retval - global->type_table_start;
751 *((gint32 *) data)++ = size;
756 /* Add the current_type_table to the type_tables vector and ... */
757 if (!global->type_tables) {
758 guint32 tsize = sizeof (gpointer) * TYPE_TABLE_PTR_CHUNK_SIZE;
759 global->type_tables = g_malloc0 (tsize);
762 if (!((global->num_type_tables + 1) % TYPE_TABLE_PTR_CHUNK_SIZE)) {
763 guint32 chunks = (global->num_type_tables + 1) / TYPE_TABLE_PTR_CHUNK_SIZE;
764 guint32 tsize = sizeof (gpointer) * TYPE_TABLE_PTR_CHUNK_SIZE * (chunks + 1);
766 global->type_tables = g_realloc (global->type_tables, tsize);
769 global->type_tables [global->num_type_tables++] = global->current_type_table;
771 /* .... allocate a new current_type_table. */
772 global->current_type_table = g_malloc0 (TYPE_TABLE_CHUNK_SIZE);
773 global->type_table_start = global->type_table_offset = global->type_table_size;
774 global->type_table_size += TYPE_TABLE_CHUNK_SIZE;
780 write_simple_type (MonoGlobalSymbolFile *global, MonoType *type)
782 guint8 buffer [BUFSIZ], *ptr = buffer;
783 guint32 size, offset;
786 type_table = g_hash_table_new (g_direct_hash, g_direct_equal);
788 offset = GPOINTER_TO_UINT (g_hash_table_lookup (type_table, type));
792 switch (type->type) {
793 case MONO_TYPE_BOOLEAN:
796 *((gint32 *) ptr)++ = 1;
802 *((gint32 *) ptr)++ = 2;
808 *((gint32 *) ptr)++ = 4;
814 *((gint32 *) ptr)++ = 8;
819 *((gint32 *) ptr)++ = sizeof (void *);
823 *((gint32 *) ptr)++ = 0;
826 case MONO_TYPE_STRING: {
829 *((gint32 *) ptr)++ = -8;
830 *((guint32 *) ptr)++ = sizeof (MonoString);
832 *ptr++ = (guint8*)&string.length - (guint8*)&string;
833 *ptr++ = sizeof (string.length);
834 *ptr++ = (guint8*)&string.chars - (guint8*)&string;
843 offset = allocate_type_entry (global, size, &ptr);
844 memcpy (ptr, buffer, size);
846 g_hash_table_insert (type_table, type, GUINT_TO_POINTER (offset));
852 * Adds type `type' to the type table and returns its offset.
855 write_type (MonoGlobalSymbolFile *global, MonoType *type)
857 guint8 buffer [BUFSIZ], *ptr = buffer, *old_ptr;
858 GPtrArray *methods = NULL;
859 int num_fields = 0, num_properties = 0, num_methods = 0;
860 int num_params = 0, kind;
861 guint32 size, data_size, offset;
862 MonoClass *klass = NULL;
865 type_table = g_hash_table_new (g_direct_hash, g_direct_equal);
867 class_table = g_hash_table_new (g_direct_hash, g_direct_equal);
869 offset = GPOINTER_TO_UINT (g_hash_table_lookup (type_table, type));
873 offset = write_simple_type (global, type);
878 if (kind == MONO_TYPE_OBJECT) {
879 klass = mono_defaults.object_class;
880 kind = MONO_TYPE_CLASS;
881 } else if ((kind == MONO_TYPE_VALUETYPE) || (kind == MONO_TYPE_CLASS)) {
882 klass = type->data.klass;
883 offset = GPOINTER_TO_UINT (g_hash_table_lookup (class_table, klass));
889 case MONO_TYPE_SZARRAY:
893 case MONO_TYPE_ARRAY:
897 case MONO_TYPE_VALUETYPE:
898 case MONO_TYPE_CLASS: {
899 GHashTable *method_slots = NULL;
902 if (klass->init_pending) {
907 mono_class_init (klass);
909 offset = GPOINTER_TO_UINT (g_hash_table_lookup (class_table, klass));
913 if (klass->enumtype) {
918 for (i = 0; i < klass->field.count; i++)
919 if (!(klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC))
922 for (i = 0; i < klass->property.count; i++)
923 if (!(klass->properties [i].attrs & FIELD_ATTRIBUTE_STATIC))
926 method_slots = g_hash_table_new (NULL, NULL);
927 methods = g_ptr_array_new ();
929 for (i = klass->method.count - 1; i >= 0; i--) {
930 MonoMethod *method = klass->methods [i];
932 if (strcmp (method->name, ".ctor") == 0 || strcmp (method->name, ".cctor") == 0)
934 if (method->flags & (METHOD_ATTRIBUTE_STATIC | METHOD_ATTRIBUTE_SPECIAL_NAME))
936 if (!((method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC))
938 if (g_hash_table_lookup (method_slots, GUINT_TO_POINTER (method->slot)))
940 g_hash_table_insert (method_slots, GUINT_TO_POINTER (method->slot), method);
943 num_params += method->signature->param_count;
945 g_ptr_array_add (methods, method);
948 g_hash_table_destroy (method_slots);
950 size = 34 + num_fields * 8 + num_properties * (4 + 2 * sizeof (gpointer)) +
951 num_methods * (8 + sizeof (gpointer)) + num_params * 4;
953 if (kind == MONO_TYPE_CLASS)
966 offset = allocate_type_entry (global, data_size, &ptr);
969 g_hash_table_insert (type_table, type, GUINT_TO_POINTER (offset));
972 case MONO_TYPE_SZARRAY: {
975 *((gint32 *) ptr)++ = -size;
976 *((guint32 *) ptr)++ = sizeof (MonoArray);
978 *ptr++ = (guint8*)&array.max_length - (guint8*)&array;
979 *ptr++ = sizeof (array.max_length);
980 *ptr++ = (guint8*)&array.vector - (guint8*)&array;
981 *((guint32 *) ptr)++ = write_type (global, type->data.type);
985 case MONO_TYPE_ARRAY: {
987 MonoArrayBounds bounds;
989 *((gint32 *) ptr)++ = -size;
990 *((guint32 *) ptr)++ = sizeof (MonoArray);
992 *ptr++ = (guint8*)&array.max_length - (guint8*)&array;
993 *ptr++ = sizeof (array.max_length);
994 *ptr++ = (guint8*)&array.vector - (guint8*)&array;
995 *ptr++ = type->data.array->rank;
996 *ptr++ = (guint8*)&array.bounds - (guint8*)&array;
997 *ptr++ = sizeof (MonoArrayBounds);
998 *ptr++ = (guint8*)&bounds.lower_bound - (guint8*)&bounds;
999 *ptr++ = sizeof (bounds.lower_bound);
1000 *ptr++ = (guint8*)&bounds.length - (guint8*)&bounds;
1001 *ptr++ = sizeof (bounds.length);
1002 *((guint32 *) ptr)++ = write_type (global, type->data.array->type);
1006 case MONO_TYPE_VALUETYPE:
1007 case MONO_TYPE_CLASS: {
1008 int base_offset = kind == MONO_TYPE_CLASS ? 0 : - sizeof (MonoObject);
1011 if (klass->init_pending) {
1012 *((gint32 *) ptr)++ = -1;
1016 g_hash_table_insert (class_table, klass, GUINT_TO_POINTER (offset));
1018 if (klass->enumtype) {
1019 *((gint32 *) ptr)++ = -size;
1020 *((guint32 *) ptr)++ = sizeof (MonoObject);
1022 *((guint32 *) ptr)++ = write_type (global, klass->enum_basetype);
1026 *((gint32 *) ptr)++ = -size;
1028 *((guint32 *) ptr)++ = klass->instance_size + base_offset;
1029 if (type->type == MONO_TYPE_OBJECT)
1032 *ptr++ = kind == MONO_TYPE_CLASS ? 6 : 5;
1033 *ptr++ = kind == MONO_TYPE_CLASS;
1034 *((guint32 *) ptr)++ = num_fields;
1035 *((guint32 *) ptr)++ = num_fields * (4 + sizeof (gpointer));
1036 *((guint32 *) ptr)++ = num_properties;
1037 *((guint32 *) ptr)++ = num_properties * 3 * sizeof (gpointer);
1038 *((guint32 *) ptr)++ = num_methods;
1039 *((guint32 *) ptr)++ = num_methods * (4 + 2 * sizeof (gpointer)) +
1040 num_params * sizeof (gpointer);
1041 for (i = 0; i < klass->field.count; i++) {
1042 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
1045 *((guint32 *) ptr)++ = klass->fields [i].offset + base_offset;
1046 *((guint32 *) ptr)++ = write_type (global, klass->fields [i].type);
1049 for (i = 0; i < klass->property.count; i++) {
1050 if (klass->properties [i].attrs & FIELD_ATTRIBUTE_STATIC)
1053 if (klass->properties [i].get)
1054 *((guint32 *) ptr)++ = write_type
1055 (global, klass->properties [i].get->signature->ret);
1057 *((guint32 *) ptr)++ = 0;
1058 *((gpointer *) ptr)++ = klass->properties [i].get;
1059 *((gpointer *) ptr)++ = klass->properties [i].set;
1062 for (i = 0; i < methods->len; i++) {
1063 MonoMethod *method = g_ptr_array_index (methods, i);
1065 *((gpointer *) ptr)++ = method;
1066 if ((method->signature->ret) && (method->signature->ret->type != MONO_TYPE_VOID))
1067 *((guint32 *) ptr)++ = write_type (global, method->signature->ret);
1069 *((guint32 *) ptr)++ = 0;
1070 *((guint32 *) ptr)++ = method->signature->param_count;
1071 for (j = 0; j < method->signature->param_count; j++)
1072 *((guint32 *) ptr)++ = write_type (global, method->signature->params [j]);
1075 g_ptr_array_free (methods, FALSE);
1077 if (kind == MONO_TYPE_CLASS) {
1079 *((guint32 *) ptr)++ = write_type (global, &klass->parent->this_arg);
1081 *((guint32 *) ptr)++ = 0;
1088 g_message (G_STRLOC ": %p - %x,%x,%x", type, type->attrs, kind, type->byref);
1090 *((gint32 *) ptr)++ = -1;
1094 if (ptr - old_ptr != data_size) {
1095 g_warning (G_STRLOC ": %d,%d - %d", ptr - old_ptr, data_size, kind);
1097 g_warning (G_STRLOC ": %s.%s", klass->name_space, klass->name);
1098 g_assert_not_reached ();