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 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
148 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
149 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
150 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
151 g_assert_not_reached ();
153 if (!((MonoMethodNormal *) method)->header) {
154 g_warning (G_STRLOC ": Internal error: method %s.%s doesn't have a header",
155 method->klass->name, method->name);
159 minfo = g_new0 (MonoDebugMethodInfo, 1);
160 minfo->file_offset = ((const char *) me) - start;
161 minfo->method = method;
162 minfo->symfile = symfile;
163 minfo->num_il_offsets = me->num_line_numbers;
164 minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
165 (symfile->raw_contents + me->line_number_table_offset);
167 mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
168 mep->method = method;
173 mep->method_name_offset = priv->string_table_size;
174 mep->name = get_method_name (method);
175 priv->string_table_size += strlen (mep->name) + 5;
177 g_hash_table_insert (priv->method_table, method, mep);
178 g_hash_table_insert (priv->method_hash, method, minfo);
181 if (!write_string_table (symfile))
188 mono_debug_open_mono_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
190 MonoSymbolFile *symfile;
191 MonoSymbolFilePriv *priv;
196 fd = open (filename, O_RDONLY);
199 g_warning ("Can't open symbol file: %s", filename);
203 file_size = lseek (fd, 0, SEEK_END);
204 lseek (fd, 0, SEEK_SET);
206 if (file_size == (off_t) -1) {
208 g_warning ("Can't get size of symbol file: %s", filename);
212 ptr = mono_raw_buffer_load (fd, FALSE, 0, file_size);
215 g_warning ("Can't read symbol file: %s", filename);
219 symfile = g_new0 (MonoSymbolFile, 1);
220 symfile->magic = MONO_SYMBOL_FILE_MAGIC;
221 symfile->version = MONO_SYMBOL_FILE_VERSION;
222 symfile->dynamic_magic = MONO_SYMBOL_FILE_DYNAMIC_MAGIC;
223 symfile->dynamic_version = MONO_SYMBOL_FILE_DYNAMIC_VERSION;
224 symfile->image_file = g_strdup (image->name);
225 symfile->symbol_file = g_strdup (filename);
226 symfile->raw_contents = ptr;
227 symfile->raw_contents_size = file_size;
229 symfile->_priv = priv = g_new0 (MonoSymbolFilePriv, 1);
233 priv->file_name = g_strdup (filename);
235 if (!load_symfile (symfile)) {
236 mono_debug_close_mono_symbol_file (symfile);
244 close_symfile (MonoSymbolFile *symfile)
246 MonoSymbolFilePriv *priv = symfile->_priv;
248 if (symfile->raw_contents) {
249 mono_raw_buffer_free (symfile->raw_contents);
250 symfile->raw_contents = NULL;
258 if (priv->method_table) {
259 g_hash_table_destroy (priv->method_table);
260 priv->method_table = NULL;
263 if (symfile->is_dynamic) {
264 unlink (priv->file_name);
265 priv->method_hash = NULL;
266 } else if (priv->method_hash) {
267 g_hash_table_destroy (priv->method_hash);
268 priv->method_hash = NULL;
271 if (symfile->image_file) {
272 g_free (symfile->image_file);
273 symfile->image_file = NULL;
276 if (priv->file_name) {
277 g_free (priv->file_name);
278 priv->file_name = NULL;
285 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
290 close_symfile (symfile);
292 g_free (symfile->_priv->source_file);
293 g_free (symfile->_priv);
294 g_free (symfile->image_file);
295 g_free (symfile->symbol_file);
300 read_string (const char *ptr)
302 int len = *((guint32 *) ptr)++;
304 return g_filename_from_utf8 (ptr, len, NULL, NULL, NULL);
308 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
309 guint32 *line_number)
311 MonoSymbolFilePriv *priv = symfile->_priv;
312 MonoSymbolFileLineNumberEntry *lne;
313 MonoSymbolFileMethodEntryPriv *mep;
314 gchar *source_file = NULL;
318 if (!priv->method_table || symfile->is_dynamic)
321 mep = g_hash_table_lookup (priv->method_table, method);
325 if (mep->entry->source_file_offset)
326 source_file = read_string (symfile->raw_contents + mep->entry->source_file_offset);
328 ptr = symfile->raw_contents + mep->entry->line_number_table_offset;
330 lne = (MonoSymbolFileLineNumberEntry *) ptr;
332 for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
333 if (lne->offset < offset)
337 *line_number = lne->row;
342 } else if (source_file) {
343 gchar *retval = g_strdup_printf ("%s:%d", source_file, lne->row);
344 g_free (source_file);
347 return g_strdup_printf ("%d", lne->row);
354 mono_debug_symfile_add_method (MonoSymbolFile *symfile, MonoMethod *method)
356 MonoSymbolFileMethodEntryPriv *mep;
357 MonoSymbolFileMethodAddress *address;
358 MonoDebugVarInfo *var_table;
359 MonoDebugRangeInfo *range;
360 MonoMethodHeader *header;
361 guint32 size, num_variables, variable_size, variable_offset;
362 guint32 type_size, type_offset, *type_index_table;
363 guint32 line_size, line_offset;
364 MonoDebugLineNumberEntry *line_table;
369 if (!symfile->_priv->method_table)
372 header = ((MonoMethodNormal *) method)->header;
374 g_warning (G_STRLOC ": Internal error: method %s.%s doesn't have a header",
375 method->klass->name, method->name);
379 mep = g_hash_table_lookup (symfile->_priv->method_table, method);
384 mep->minfo = g_hash_table_lookup (symfile->_priv->method_hash, mep->method);
389 if (!mep->minfo->jit)
392 symfile->generation++;
394 size = sizeof (MonoSymbolFileMethodAddress);
396 num_variables = mep->entry->num_parameters + mep->entry->num_locals;
397 if (mep->entry->this_type_index)
400 variable_size = num_variables * sizeof (MonoDebugVarInfo);
401 variable_offset = size;
402 size += variable_size;
404 type_size = num_variables * sizeof (gpointer);
408 if (mep->minfo->jit->line_numbers) {
410 line_size = mep->minfo->jit->line_numbers->len * sizeof (MonoDebugLineNumberEntry);
414 address = g_malloc0 (size);
415 ptr = (guint8 *) address;
417 address->size = size;
418 address->start_address = mep->minfo->jit->code_start;
419 address->end_address = mep->minfo->jit->code_start + mep->minfo->jit->code_size;
420 address->method_start_address = address->start_address + mep->minfo->jit->prologue_end;
421 address->method_end_address = address->start_address + mep->minfo->jit->epilogue_begin;
422 address->variable_table_offset = variable_offset;
423 address->type_table_offset = type_offset;
425 if (mep->minfo->jit->line_numbers) {
426 address->num_line_numbers = mep->minfo->jit->line_numbers->len;
427 address->line_number_offset = line_offset;
429 line_table = (MonoDebugLineNumberEntry *) (ptr + line_offset);
430 memcpy (line_table, mep->minfo->jit->line_numbers->data, line_size);
433 range = allocate_range_entry (symfile);
434 range->file_offset = mep->minfo->file_offset;
435 range->start_address = address->start_address;
436 range->end_address = address->end_address;
437 range->dynamic_data = address;
438 range->dynamic_size = size;
440 var_table = (MonoDebugVarInfo *) (ptr + variable_offset);
441 type_table = (guint32 *) (ptr + type_offset);
443 type_index_table = (guint32 *)
444 (symfile->raw_contents + mep->entry->type_index_table_offset);
446 if (mep->entry->this_type_index) {
447 if (!mep->minfo->jit->this_var) {
448 g_warning (G_STRLOC ": Method %s.%s doesn't have `this'.",
449 mep->method->klass->name, mep->method->name);
452 *var_table++ = *mep->minfo->jit->this_var;
453 *type_table++ = write_type (symfile->global, &method->klass->this_arg);
457 if (mep->minfo->jit->num_params != mep->entry->num_parameters) {
458 g_warning (G_STRLOC ": Method %s.%s has %d parameters, but symbol file claims it has %d.",
459 mep->method->klass->name, mep->method->name, mep->minfo->jit->num_params,
460 mep->entry->num_parameters);
462 var_table += mep->entry->num_parameters;
464 for (i = 0; i < mep->minfo->jit->num_params; i++) {
465 *var_table++ = mep->minfo->jit->params [i];
466 *type_table++ = write_type (symfile->global, method->signature->params [i]);
470 if (mep->minfo->jit->num_locals < mep->entry->num_locals) {
472 g_warning (G_STRLOC ": Method %s.%s has %d locals, but symbol file claims it has %d.",
473 mep->method->klass->name, mep->method->name, mep->minfo->jit->num_locals,
474 mep->entry->num_locals);
476 var_table += mep->entry->num_locals;
478 for (i = 0; i < mep->entry->num_locals; i++) {
479 MonoDebugVarInfo *var = &mep->minfo->jit->locals [i];
480 *var_table++ = mep->minfo->jit->locals [i];
481 *type_table++ = write_type (symfile->global, header->locals [i]);
487 mono_debug_symfile_add_type (MonoSymbolFile *symfile, MonoClass *klass)
489 MonoDebugClassInfo *info;
492 class_table = g_hash_table_new (g_direct_hash, g_direct_equal);
494 /* We write typeof (object) into each symbol file's type table. */
495 if ((klass != mono_defaults.object_class) && g_hash_table_lookup (class_table, klass))
498 symfile->generation++;
500 info = allocate_class_entry (symfile);
503 info->token = klass->element_class->type_token;
504 info->rank = klass->rank;
506 info->token = klass->type_token;
507 info->type_info = write_type (symfile->global, &klass->this_arg);
511 create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings)
513 MonoSymbolFilePriv *priv = symfile->_priv;
519 if (!mono_debugger_global_symbol_file)
520 mono_debugger_global_symbol_file = g_new0 (MonoGlobalSymbolFile, 1);
521 symfile->global = mono_debugger_global_symbol_file;
523 priv->fd = g_file_open_tmp (NULL, &priv->file_name, NULL);
524 if (priv->fd == -1) {
526 g_warning ("Can't create symbol file");
530 symfile->symbol_file = g_strdup (priv->file_name);
532 magic = MONO_SYMBOL_FILE_MAGIC;
533 if (write (priv->fd, &magic, sizeof (magic)) < 0)
536 version = MONO_SYMBOL_FILE_VERSION;
537 if (write (priv->fd, &version, sizeof (version)) < 0)
540 offset = lseek (priv->fd, 0, SEEK_CUR);
542 priv->offset_table = g_new0 (MonoSymbolFileOffsetTable, 1);
543 if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
546 mono_debug_symfile_add_type (symfile, mono_defaults.object_class);
549 // Write offset table.
552 symfile->raw_contents_size = lseek (priv->fd, 0, SEEK_CUR);
554 lseek (priv->fd, offset, SEEK_SET);
555 if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
558 lseek (priv->fd, symfile->raw_contents_size, SEEK_SET);
560 ptr = mono_raw_buffer_load (priv->fd, TRUE, 0, symfile->raw_contents_size);
564 symfile->raw_contents = ptr;
570 mono_debug_create_mono_symbol_file (MonoImage *image)
572 MonoSymbolFile *symfile;
574 symfile = g_new0 (MonoSymbolFile, 1);
575 symfile->magic = MONO_SYMBOL_FILE_MAGIC;
576 symfile->version = MONO_SYMBOL_FILE_VERSION;
577 symfile->dynamic_magic = MONO_SYMBOL_FILE_DYNAMIC_MAGIC;
578 symfile->dynamic_version = MONO_SYMBOL_FILE_DYNAMIC_VERSION;
579 symfile->is_dynamic = TRUE;
580 symfile->image_file = g_strdup (image->name);
582 symfile->_priv = g_new0 (MonoSymbolFilePriv, 1);
583 symfile->_priv->image = image;
585 if (!create_symfile (symfile, TRUE)) {
586 mono_debug_close_mono_symbol_file (symfile);
593 MonoDebugMethodInfo *
594 mono_debug_find_method (MonoSymbolFile *symfile, MonoMethod *method)
596 if (!symfile->_priv->method_hash)
599 return g_hash_table_lookup (symfile->_priv->method_hash, method);
603 write_method_name (gpointer key, gpointer value, gpointer user_data)
605 MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
606 MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
607 MonoSymbolFilePriv *priv = symfile->_priv;
608 guint8 *offset_ptr, *string_ptr;
611 offset = mep->method_name_offset + priv->string_offset_size;
613 offset_ptr = symfile->string_table + mep->index * 4;
614 string_ptr = symfile->string_table + offset;
616 *((guint32 *) offset_ptr) = offset;
617 *((guint32 *) string_ptr)++ = strlen (mep->name);
618 strcpy (string_ptr, mep->name);
622 write_string_table (MonoSymbolFile *symfile)
624 MonoSymbolFilePriv *priv = symfile->_priv;
626 priv->string_offset_size = priv->offset_table->method_count * 4;
628 symfile->string_table_size = priv->string_table_size + priv->string_offset_size;
629 symfile->string_table = g_malloc0 (symfile->string_table_size);
631 g_hash_table_foreach (symfile->_priv->method_table, write_method_name, symfile);
635 MonoReflectionMethod *
636 ves_icall_MonoDebugger_GetMethod (MonoReflectionAssembly *assembly, guint32 token)
640 method = mono_get_method (assembly->assembly->image, token, NULL);
642 return mono_method_get_object (mono_domain_get (), method, NULL);
646 ves_icall_MonoDebugger_GetType (MonoReflectionAssembly *assembly, guint32 token)
650 klass = mono_class_get (assembly->assembly->image, token);
652 g_warning (G_STRLOC ": %x", token);
656 return mono_type_get_object (mono_domain_get (), &klass->byval_arg);
660 ves_icall_MonoDebugger_GetLocalTypeFromSignature (MonoReflectionAssembly *assembly, MonoArray *signature)
668 MONO_CHECK_ARG_NULL (assembly);
669 MONO_CHECK_ARG_NULL (signature);
671 domain = mono_domain_get();
672 image = assembly->assembly->image;
674 ptr = mono_array_addr (signature, char, 0);
675 g_assert (*ptr++ == 0x07);
676 len = mono_metadata_decode_value (ptr, &ptr);
679 type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
681 return mono_type_get_object (domain, type);
684 static MonoDebugRangeInfo *
685 allocate_range_entry (MonoSymbolFile *symfile)
687 MonoDebugRangeInfo *retval;
688 guint32 size, chunks;
690 symfile->range_entry_size = sizeof (MonoDebugRangeInfo);
692 if (!symfile->range_table) {
693 size = sizeof (MonoDebugRangeInfo) * RANGE_TABLE_CHUNK_SIZE;
694 symfile->range_table = g_malloc0 (size);
695 symfile->num_range_entries = 1;
696 return symfile->range_table;
699 if (!((symfile->num_range_entries + 1) % RANGE_TABLE_CHUNK_SIZE)) {
700 chunks = (symfile->num_range_entries + 1) / RANGE_TABLE_CHUNK_SIZE;
701 size = sizeof (MonoDebugRangeInfo) * RANGE_TABLE_CHUNK_SIZE * (chunks + 1);
703 symfile->range_table = g_realloc (symfile->range_table, size);
706 retval = symfile->range_table + symfile->num_range_entries;
707 symfile->num_range_entries++;
711 static MonoDebugClassInfo *
712 allocate_class_entry (MonoSymbolFile *symfile)
714 MonoDebugClassInfo *retval;
715 guint32 size, chunks;
717 symfile->class_entry_size = sizeof (MonoDebugClassInfo);
719 if (!symfile->class_table) {
720 size = sizeof (MonoDebugClassInfo) * CLASS_TABLE_CHUNK_SIZE;
721 symfile->class_table = g_malloc0 (size);
722 symfile->num_class_entries = 1;
723 return symfile->class_table;
726 if (!((symfile->num_class_entries + 1) % CLASS_TABLE_CHUNK_SIZE)) {
727 chunks = (symfile->num_class_entries + 1) / CLASS_TABLE_CHUNK_SIZE;
728 size = sizeof (MonoDebugClassInfo) * CLASS_TABLE_CHUNK_SIZE * (chunks + 1);
730 symfile->class_table = g_realloc (symfile->class_table, size);
733 retval = symfile->class_table + symfile->num_class_entries;
734 symfile->num_class_entries++;
739 * Allocate a new entry of size `size' in the type table.
740 * Returns the global offset which is to be used to reference this type and
741 * a pointer (in the `ptr' argument) which is to be used to write the type.
744 allocate_type_entry (MonoGlobalSymbolFile *global, guint32 size, guint8 **ptr)
749 g_assert (size + 4 < TYPE_TABLE_CHUNK_SIZE);
750 g_assert (ptr != NULL);
752 /* Initialize things if necessary. */
753 if (!global->current_type_table) {
754 global->current_type_table = g_malloc0 (TYPE_TABLE_CHUNK_SIZE);
755 global->type_table_size = TYPE_TABLE_CHUNK_SIZE;
756 global->type_table_chunk_size = TYPE_TABLE_CHUNK_SIZE;
757 global->type_table_offset = 1;
761 /* First let's check whether there's still enough room in the current_type_table. */
762 if (global->type_table_offset + size + 4 < global->type_table_size) {
763 retval = global->type_table_offset;
764 global->type_table_offset += size + 4;
765 data = ((guint8 *) global->current_type_table) + retval - global->type_table_start;
766 *((gint32 *) data)++ = size;
771 /* Add the current_type_table to the type_tables vector and ... */
772 if (!global->type_tables) {
773 guint32 tsize = sizeof (gpointer) * TYPE_TABLE_PTR_CHUNK_SIZE;
774 global->type_tables = g_malloc0 (tsize);
777 if (!((global->num_type_tables + 1) % TYPE_TABLE_PTR_CHUNK_SIZE)) {
778 guint32 chunks = (global->num_type_tables + 1) / TYPE_TABLE_PTR_CHUNK_SIZE;
779 guint32 tsize = sizeof (gpointer) * TYPE_TABLE_PTR_CHUNK_SIZE * (chunks + 1);
781 global->type_tables = g_realloc (global->type_tables, tsize);
784 global->type_tables [global->num_type_tables++] = global->current_type_table;
786 /* .... allocate a new current_type_table. */
787 global->current_type_table = g_malloc0 (TYPE_TABLE_CHUNK_SIZE);
788 global->type_table_start = global->type_table_offset = global->type_table_size;
789 global->type_table_size += TYPE_TABLE_CHUNK_SIZE;
795 write_simple_type (MonoGlobalSymbolFile *global, MonoType *type)
797 guint8 buffer [BUFSIZ], *ptr = buffer;
798 guint32 size, offset;
801 type_table = g_hash_table_new (g_direct_hash, g_direct_equal);
803 offset = GPOINTER_TO_UINT (g_hash_table_lookup (type_table, type));
807 switch (type->type) {
808 case MONO_TYPE_BOOLEAN:
811 *((gint32 *) ptr)++ = 1;
817 *((gint32 *) ptr)++ = 2;
823 *((gint32 *) ptr)++ = 4;
829 *((gint32 *) ptr)++ = 8;
834 *((gint32 *) ptr)++ = sizeof (void *);
838 *((gint32 *) ptr)++ = 0;
841 case MONO_TYPE_STRING: {
844 *((gint32 *) ptr)++ = -8;
845 *((guint32 *) ptr)++ = sizeof (MonoString);
847 *ptr++ = (guint8*)&string.length - (guint8*)&string;
848 *ptr++ = sizeof (string.length);
849 *ptr++ = (guint8*)&string.chars - (guint8*)&string;
858 offset = allocate_type_entry (global, size, &ptr);
859 memcpy (ptr, buffer, size);
861 g_hash_table_insert (type_table, type, GUINT_TO_POINTER (offset));
867 * Adds type `type' to the type table and returns its offset.
870 write_type (MonoGlobalSymbolFile *global, MonoType *type)
872 guint8 buffer [BUFSIZ], *ptr = buffer, *old_ptr;
873 GPtrArray *methods = NULL;
874 int num_fields = 0, num_properties = 0, num_methods = 0;
875 int num_params = 0, kind;
876 guint32 size, data_size, offset;
877 MonoClass *klass = NULL;
880 type_table = g_hash_table_new (g_direct_hash, g_direct_equal);
882 class_table = g_hash_table_new (g_direct_hash, g_direct_equal);
884 offset = GPOINTER_TO_UINT (g_hash_table_lookup (type_table, type));
888 offset = write_simple_type (global, type);
893 if (kind == MONO_TYPE_OBJECT) {
894 klass = mono_defaults.object_class;
895 kind = MONO_TYPE_CLASS;
896 } else if ((kind == MONO_TYPE_VALUETYPE) || (kind == MONO_TYPE_CLASS)) {
897 klass = type->data.klass;
898 offset = GPOINTER_TO_UINT (g_hash_table_lookup (class_table, klass));
904 case MONO_TYPE_SZARRAY:
908 case MONO_TYPE_ARRAY:
912 case MONO_TYPE_VALUETYPE:
913 case MONO_TYPE_CLASS: {
914 GHashTable *method_slots = NULL;
917 if (klass->init_pending) {
922 mono_class_init (klass);
924 offset = GPOINTER_TO_UINT (g_hash_table_lookup (class_table, klass));
928 if (klass->enumtype) {
933 for (i = 0; i < klass->field.count; i++)
934 if (!(klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC))
937 for (i = 0; i < klass->property.count; i++)
938 if (!(klass->properties [i].attrs & FIELD_ATTRIBUTE_STATIC))
941 method_slots = g_hash_table_new (NULL, NULL);
942 methods = g_ptr_array_new ();
944 for (i = klass->method.count - 1; i >= 0; i--) {
945 MonoMethod *method = klass->methods [i];
947 if (strcmp (method->name, ".ctor") == 0 || strcmp (method->name, ".cctor") == 0)
949 if (method->flags & (METHOD_ATTRIBUTE_STATIC | METHOD_ATTRIBUTE_SPECIAL_NAME))
951 if (!((method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC))
953 if (g_hash_table_lookup (method_slots, GUINT_TO_POINTER (method->slot)))
955 g_hash_table_insert (method_slots, GUINT_TO_POINTER (method->slot), method);
958 num_params += method->signature->param_count;
960 g_ptr_array_add (methods, method);
963 g_hash_table_destroy (method_slots);
965 size = 34 + num_fields * 8 + num_properties * (4 + 2 * sizeof (gpointer)) +
966 num_methods * (8 + sizeof (gpointer)) + num_params * 4;
968 if (kind == MONO_TYPE_CLASS)
981 offset = allocate_type_entry (global, data_size, &ptr);
984 g_hash_table_insert (type_table, type, GUINT_TO_POINTER (offset));
987 case MONO_TYPE_SZARRAY: {
990 *((gint32 *) ptr)++ = -size;
991 *((guint32 *) ptr)++ = sizeof (MonoArray);
993 *ptr++ = (guint8*)&array.max_length - (guint8*)&array;
994 *ptr++ = sizeof (array.max_length);
995 *ptr++ = (guint8*)&array.vector - (guint8*)&array;
996 *((guint32 *) ptr)++ = write_type (global, type->data.type);
1000 case MONO_TYPE_ARRAY: {
1002 MonoArrayBounds bounds;
1004 *((gint32 *) ptr)++ = -size;
1005 *((guint32 *) ptr)++ = sizeof (MonoArray);
1007 *ptr++ = (guint8*)&array.max_length - (guint8*)&array;
1008 *ptr++ = sizeof (array.max_length);
1009 *ptr++ = (guint8*)&array.vector - (guint8*)&array;
1010 *ptr++ = type->data.array->rank;
1011 *ptr++ = (guint8*)&array.bounds - (guint8*)&array;
1012 *ptr++ = sizeof (MonoArrayBounds);
1013 *ptr++ = (guint8*)&bounds.lower_bound - (guint8*)&bounds;
1014 *ptr++ = sizeof (bounds.lower_bound);
1015 *ptr++ = (guint8*)&bounds.length - (guint8*)&bounds;
1016 *ptr++ = sizeof (bounds.length);
1017 *((guint32 *) ptr)++ = write_type (global, type->data.array->type);
1021 case MONO_TYPE_VALUETYPE:
1022 case MONO_TYPE_CLASS: {
1023 int base_offset = kind == MONO_TYPE_CLASS ? 0 : - sizeof (MonoObject);
1026 if (klass->init_pending) {
1027 *((gint32 *) ptr)++ = -1;
1031 g_hash_table_insert (class_table, klass, GUINT_TO_POINTER (offset));
1033 if (klass->enumtype) {
1034 *((gint32 *) ptr)++ = -size;
1035 *((guint32 *) ptr)++ = sizeof (MonoObject);
1037 *((guint32 *) ptr)++ = write_type (global, klass->enum_basetype);
1041 *((gint32 *) ptr)++ = -size;
1043 *((guint32 *) ptr)++ = klass->instance_size + base_offset;
1044 if (type->type == MONO_TYPE_OBJECT)
1047 *ptr++ = kind == MONO_TYPE_CLASS ? 6 : 5;
1048 *ptr++ = kind == MONO_TYPE_CLASS;
1049 *((guint32 *) ptr)++ = num_fields;
1050 *((guint32 *) ptr)++ = num_fields * (4 + sizeof (gpointer));
1051 *((guint32 *) ptr)++ = num_properties;
1052 *((guint32 *) ptr)++ = num_properties * 3 * sizeof (gpointer);
1053 *((guint32 *) ptr)++ = num_methods;
1054 *((guint32 *) ptr)++ = num_methods * (4 + 2 * sizeof (gpointer)) +
1055 num_params * sizeof (gpointer);
1056 for (i = 0; i < klass->field.count; i++) {
1057 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
1060 *((guint32 *) ptr)++ = klass->fields [i].offset + base_offset;
1061 *((guint32 *) ptr)++ = write_type (global, klass->fields [i].type);
1064 for (i = 0; i < klass->property.count; i++) {
1065 if (klass->properties [i].attrs & FIELD_ATTRIBUTE_STATIC)
1068 if (klass->properties [i].get)
1069 *((guint32 *) ptr)++ = write_type
1070 (global, klass->properties [i].get->signature->ret);
1072 *((guint32 *) ptr)++ = 0;
1073 *((gpointer *) ptr)++ = klass->properties [i].get;
1074 *((gpointer *) ptr)++ = klass->properties [i].set;
1077 for (i = 0; i < methods->len; i++) {
1078 MonoMethod *method = g_ptr_array_index (methods, i);
1080 *((gpointer *) ptr)++ = method;
1081 if ((method->signature->ret) && (method->signature->ret->type != MONO_TYPE_VOID))
1082 *((guint32 *) ptr)++ = write_type (global, method->signature->ret);
1084 *((guint32 *) ptr)++ = 0;
1085 *((guint32 *) ptr)++ = method->signature->param_count;
1086 for (j = 0; j < method->signature->param_count; j++)
1087 *((guint32 *) ptr)++ = write_type (global, method->signature->params [j]);
1090 g_ptr_array_free (methods, FALSE);
1092 if (kind == MONO_TYPE_CLASS) {
1094 *((guint32 *) ptr)++ = write_type (global, &klass->parent->this_arg);
1096 *((guint32 *) ptr)++ = 0;
1103 g_message (G_STRLOC ": %p - %x,%x,%x", type, type->attrs, kind, type->byref);
1105 *((gint32 *) ptr)++ = -1;
1109 if (ptr - old_ptr != data_size) {
1110 g_warning (G_STRLOC ": %d,%d - %d", ptr - old_ptr, data_size, kind);
1112 g_warning (G_STRLOC ": %s.%s", klass->name_space, klass->name);
1113 g_assert_not_reached ();