More work on the type stuff.
[mono.git] / mono / metadata / debug-mono-symfile.c
1 #include <config.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <signal.h>
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>
13
14 #include <fcntl.h>
15 #include <unistd.h>
16
17 #define RANGE_TABLE_CHUNK_SIZE  256
18
19 struct MonoSymbolFilePriv
20 {
21         int fd;
22         int error;
23         char *file_name;
24         char *source_file;
25         guint32 string_table_size;
26         guint32 string_offset_size;
27         MonoImage *image;
28         GHashTable *method_table;
29         GHashTable *method_hash;
30         MonoSymbolFileOffsetTable *offset_table;
31 };
32
33 typedef struct
34 {
35         MonoMethod *method;
36         MonoDebugMethodInfo *minfo;
37         MonoSymbolFileMethodEntry *entry;
38         guint32 method_name_offset;
39         guint32 index;
40         gchar *name;
41 } MonoSymbolFileMethodEntryPriv;
42
43 static GHashTable *type_table;
44
45 static int write_string_table (MonoSymbolFile *symfile);
46 static int create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings);
47 static void close_symfile (MonoSymbolFile *symfile);
48 static MonoDebugRangeInfo *allocate_range_entry (MonoSymbolFile *symfile);
49 static gpointer write_type (MonoSymbolFile *symfile, MonoType *type);
50
51 static void
52 free_method_info (MonoDebugMethodInfo *minfo)
53 {
54         g_free (minfo->jit);
55         g_free (minfo);
56 }
57
58 static int
59 load_symfile (MonoSymbolFile *symfile)
60 {
61         MonoSymbolFilePriv *priv = symfile->_priv;
62         MonoSymbolFileMethodEntry *me;
63         const char *ptr, *start;
64         guint64 magic;
65         long version;
66         int i;
67
68         ptr = start = symfile->raw_contents;
69
70         magic = *((guint64 *) ptr)++;
71         if (magic != MONO_SYMBOL_FILE_MAGIC) {
72                 g_warning ("Symbol file %s has is not a mono symbol file", priv->file_name);
73                 return FALSE;
74         }
75
76         version = *((guint32 *) ptr)++;
77         if (version != MONO_SYMBOL_FILE_VERSION) {
78                 g_warning ("Symbol file %s has incorrect line number table version "
79                            "(expected %d, got %ld)", priv->file_name,
80                            MONO_SYMBOL_FILE_VERSION, version);
81                 return FALSE;
82         }
83
84         priv->offset_table = (MonoSymbolFileOffsetTable *) ptr;
85
86         /*
87          * Read method table.
88          *
89          */
90
91         priv->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
92                                                     (GDestroyNotify) g_free);
93         priv->method_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
94                                                    (GDestroyNotify) free_method_info);
95
96         ptr = symfile->raw_contents + priv->offset_table->method_table_offset;
97         me = (MonoSymbolFileMethodEntry *) ptr;
98
99         for (i = 0; i < priv->offset_table->method_count; i++, me++) {
100                 MonoMethod *method = mono_get_method (priv->image, me->token, NULL);
101                 MonoSymbolFileMethodEntryPriv *mep;
102                 MonoDebugMethodInfo *minfo;
103
104                 if (!method)
105                         continue;
106
107                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
108                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
109                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
110                         g_assert_not_reached ();
111
112                 if (!((MonoMethodNormal *) method)->header) {
113                         g_warning (G_STRLOC ": Internal error: method %s.%s doesn't have a header",
114                                    method->klass->name, method->name);
115                         continue;
116                 }
117
118                 minfo = g_new0 (MonoDebugMethodInfo, 1);
119                 minfo->file_offset = ((const char *) me) - start;
120                 minfo->method = method;
121                 minfo->symfile = symfile;
122                 minfo->num_il_offsets = me->num_line_numbers;
123                 minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
124                         (symfile->raw_contents + me->line_number_table_offset);
125
126                 mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
127                 mep->method = method;
128                 mep->minfo = minfo;
129                 mep->entry = me;
130                 mep->index = i;
131
132                 mep->method_name_offset = priv->string_table_size;
133                 mep->name = g_strdup_printf ("%s%s.%s", method->klass->name_space,
134                                              method->klass->name, method->name);
135                 priv->string_table_size += strlen (mep->name) + 1;
136
137                 g_hash_table_insert (priv->method_table, method, mep);
138                 g_hash_table_insert (priv->method_hash, method, minfo);
139         }
140
141         if (!write_string_table (symfile))
142                 return FALSE;
143
144         return TRUE;
145 }
146
147 MonoSymbolFile *
148 mono_debug_open_mono_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
149 {
150         MonoSymbolFile *symfile;
151         MonoSymbolFilePriv *priv;
152         off_t file_size;
153         void *ptr;
154         int fd;
155
156         fd = open (filename, O_RDONLY);
157         if (fd == -1) {
158                 if (emit_warnings)
159                         g_warning ("Can't open symbol file: %s", filename);
160                 return NULL;
161         }
162
163         file_size = lseek (fd, 0, SEEK_END);
164         lseek (fd, 0, SEEK_SET);
165
166         if (file_size == (off_t) -1) {
167                 if (emit_warnings)
168                         g_warning ("Can't get size of symbol file: %s", filename);
169                 return NULL;
170         }
171
172         ptr = mono_raw_buffer_load (fd, FALSE, 0, file_size);
173         if (!ptr) {
174                 if (emit_warnings)
175                         g_warning ("Can't read symbol file: %s", filename);
176                 return NULL;
177         }
178
179         symfile = g_new0 (MonoSymbolFile, 1);
180         symfile->magic = MONO_SYMBOL_FILE_MAGIC;
181         symfile->version = MONO_SYMBOL_FILE_VERSION;
182         symfile->dynamic_magic = MONO_SYMBOL_FILE_DYNAMIC_MAGIC;
183         symfile->dynamic_version = MONO_SYMBOL_FILE_DYNAMIC_VERSION;
184         symfile->image_file = g_strdup (image->name);
185         symfile->symbol_file = g_strdup (filename);
186         symfile->raw_contents = ptr;
187         symfile->raw_contents_size = file_size;
188
189         symfile->_priv = priv = g_new0 (MonoSymbolFilePriv, 1);
190
191         priv->fd = fd;
192         priv->image = image;
193         priv->file_name = g_strdup (filename);
194
195         if (!load_symfile (symfile)) {
196                 mono_debug_close_mono_symbol_file (symfile);
197                 return NULL;
198         }
199
200         return symfile;
201 }
202
203 static void
204 close_symfile (MonoSymbolFile *symfile)
205 {
206         MonoSymbolFilePriv *priv = symfile->_priv;
207
208         if (symfile->raw_contents) {
209                 mono_raw_buffer_free (symfile->raw_contents);
210                 symfile->raw_contents = NULL;
211         }
212
213         if (priv->fd) {
214                 close (priv->fd);
215                 priv->fd = 0;
216         }
217
218         if (priv->method_table) {
219                 g_hash_table_destroy (priv->method_table);
220                 priv->method_table = NULL;
221         }
222
223         if (priv->method_hash) {
224                 g_hash_table_destroy (priv->method_hash);
225                 priv->method_hash = NULL;
226         }
227
228         if (symfile->is_dynamic)
229                 unlink (priv->file_name);
230
231         if (symfile->image_file) {
232                 g_free (symfile->image_file);
233                 symfile->image_file = NULL;
234         }
235
236         if (priv->file_name) {
237                 g_free (priv->file_name);
238                 priv->file_name = NULL;
239         }
240
241         priv->error = FALSE;
242 }
243
244 void
245 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
246 {
247         if (!symfile)
248                 return;
249
250         close_symfile (symfile);
251
252         g_free (symfile->_priv->source_file);
253         g_free (symfile->_priv);
254         g_free (symfile->image_file);
255         g_free (symfile->symbol_file);
256         g_free (symfile);
257 }
258
259 static int
260 write_string (int fd, const char *string)
261 {
262         guint32 length = strlen (string);
263
264         if (write (fd, &length, sizeof (length)) < 0)
265                 return FALSE;
266
267         if (write (fd, string, strlen (string)) < 0)
268                 return FALSE;
269
270         return TRUE;
271 }
272
273 static gchar *
274 read_string (const char *ptr)
275 {
276         int len = *((guint32 *) ptr)++;
277
278         return g_filename_from_utf8 (ptr, len, NULL, NULL, NULL);
279 }
280
281 gchar *
282 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
283                                  guint32 *line_number)
284 {
285         MonoSymbolFilePriv *priv = symfile->_priv;
286         MonoSymbolFileLineNumberEntry *lne;
287         MonoSymbolFileMethodEntryPriv *mep;
288         gchar *source_file = NULL;
289         const char *ptr;
290         int i;
291
292         if (!priv->method_table || symfile->is_dynamic)
293                 return NULL;
294
295         mep = g_hash_table_lookup (priv->method_table, method);
296         if (!mep)
297                 return NULL;
298
299         if (mep->entry->source_file_offset)
300                 source_file = read_string (symfile->raw_contents + mep->entry->source_file_offset);
301
302         ptr = symfile->raw_contents + mep->entry->line_number_table_offset;
303
304         lne = (MonoSymbolFileLineNumberEntry *) ptr;
305
306         for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
307                 if (lne->offset < offset)
308                         continue;
309
310                 if (line_number) {
311                         *line_number = lne->row;
312                         if (source_file)
313                                 return source_file;
314                         else
315                                 return NULL;
316                 } else if (source_file) {
317                         gchar *retval = g_strdup_printf ("%s:%d", source_file, lne->row);
318                         g_free (source_file);
319                         return retval;
320                 } else
321                         return g_strdup_printf ("%d", lne->row);
322         }
323
324         return NULL;
325 }
326
327 void
328 mono_debug_symfile_add_method (MonoSymbolFile *symfile, MonoMethod *method)
329 {
330         MonoSymbolFileMethodEntryPriv *mep;
331         MonoSymbolFileMethodAddress *address;
332         MonoDebugVarInfo *var_table;
333         MonoSymbolFileLineNumberEntry *lne;
334         MonoDebugRangeInfo *range;
335         guint32 size, line_size, line_offset, num_variables, variable_size, variable_offset;
336         guint32 type_size, type_offset, *line_addresses, *type_index_table;
337         gpointer *type_table;
338         guint8 *ptr;
339         int i;
340
341         mep = g_hash_table_lookup (symfile->_priv->method_table, method);
342         if (!mep)
343                 return;
344
345         if (!mep->minfo) {
346                 mep->minfo = g_hash_table_lookup (symfile->_priv->method_hash, mep->method);
347                 if (!mep->minfo)
348                         return;
349         }
350
351         if (!mep->minfo->jit)
352                 return;
353
354         symfile->generation++;
355
356         size = sizeof (MonoSymbolFileMethodAddress);
357
358         line_size = mep->entry->num_line_numbers * sizeof (MonoSymbolFileLineNumberEntry);
359         line_offset = size;
360         size += line_size;
361
362         num_variables = mep->entry->num_parameters + mep->entry->num_locals;
363         if (mep->entry->this_type_index)
364                 num_variables++;
365
366         variable_size = num_variables * sizeof (MonoDebugVarInfo);
367         variable_offset = size;
368         size += variable_size;
369
370         type_size = num_variables * sizeof (gpointer);
371         type_offset = size;
372         size += type_size;
373
374         address = g_malloc0 (size);
375         ptr = (guint8 *) address;
376
377         address->size = size;
378         address->start_address = GPOINTER_TO_UINT (mep->minfo->jit->code_start);
379         address->end_address = GPOINTER_TO_UINT (mep->minfo->jit->code_start + mep->minfo->jit->code_size);
380         address->line_table_offset = line_offset;
381         address->variable_table_offset = variable_offset;
382         address->type_table_offset = type_offset;
383
384         range = allocate_range_entry (symfile);
385         range->file_offset = mep->minfo->file_offset;
386         range->start_address = address->start_address;
387         range->end_address = address->end_address;
388         range->dynamic_data = address;
389         range->dynamic_size = size;
390
391         var_table = (MonoDebugVarInfo *) (ptr + variable_offset);
392         type_table = (gpointer *) (ptr + type_offset);
393
394         type_index_table = (guint32 *)
395                 (symfile->raw_contents + mep->entry->type_index_table_offset);
396
397         if (mep->entry->this_type_index) {
398                 if (!mep->minfo->jit->this_var) {
399                         g_warning (G_STRLOC ": Method %s.%s doesn't have `this'.",
400                                    mep->method->klass->name, mep->method->name);
401                         var_table++;
402                 } else {
403                         *var_table++ = *mep->minfo->jit->this_var;
404                         *type_table++ = write_type (symfile, &method->klass->this_arg);
405                 }
406         }
407
408         if (mep->minfo->jit->num_params != mep->entry->num_parameters) {
409                 g_warning (G_STRLOC ": Method %s.%s has %d parameters, but symbol file claims it has %d.",
410                            mep->method->klass->name, mep->method->name, mep->minfo->jit->num_params,
411                            mep->entry->num_parameters);
412                 var_table += mep->entry->num_parameters;
413         } else {
414                 for (i = 0; i < mep->minfo->jit->num_params; i++) {
415                         *var_table++ = mep->minfo->jit->params [i];
416                         *type_table++ = write_type (symfile, method->signature->params [i]);
417                 }
418         }
419
420         if (mep->minfo->jit->num_locals != mep->entry->num_locals) {
421 #if 0
422                 g_warning (G_STRLOC ": Method %s.%s has %d locals, but symbol file claims it has %d.",
423                            mep->method->klass->name, mep->method->name, mep->minfo->jit->num_locals,
424                            mep->entry->num_locals);
425 #endif
426                 var_table += mep->entry->num_locals;
427         } else
428                 for (i = 0; i < mep->minfo->jit->num_locals; i++)
429                         *var_table++ = mep->minfo->jit->locals [i];
430
431         lne = (MonoSymbolFileLineNumberEntry *)
432                 (symfile->raw_contents + mep->entry->line_number_table_offset);
433
434         line_addresses = (guint32 *) (ptr + line_offset);
435
436         for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
437                 int j;
438
439                 if (i == 0) {
440                         line_addresses [i] = 0;
441                         continue;
442                 } else if (lne->offset == 0) {
443                         line_addresses [i] = mep->minfo->jit->prologue_end;
444                         continue;
445                 }
446
447                 line_addresses [i] = mep->minfo->jit->code_size;
448
449                 for (j = 0; j < mep->minfo->num_il_offsets; j++) {
450                         MonoSymbolFileLineNumberEntry *il = &mep->minfo->il_offsets [j];
451
452                         if (il->offset >= lne->offset) {
453                                 line_addresses [i] = mep->minfo->jit->il_addresses [j];
454                                 break;
455                         }
456                 }
457         }
458 }
459
460 static void
461 free_method_entry (MonoSymbolFileMethodEntryPriv *mep)
462 {
463         g_free (mep->name);
464         g_free (mep->entry);
465         g_free (mep);
466 }
467
468 static void
469 create_method (MonoSymbolFile *symfile, guint32 token, MonoMethod *method)
470 {
471         MonoSymbolFileMethodEntryPriv *mep;
472         MonoDebugMethodInfo *minfo;
473
474         g_assert (method->klass->image == symfile->_priv->image);
475
476         mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
477         mep->entry = g_new0 (MonoSymbolFileMethodEntry, 1);
478         mep->entry->token = token;
479         mep->entry->source_file_offset = symfile->_priv->offset_table->source_table_offset;
480
481         mep->method_name_offset = symfile->_priv->string_table_size;
482         mep->name = g_strdup_printf ("%s%s.%s", method->klass->name_space,
483                                      method->klass->name, method->name);
484         symfile->_priv->string_table_size += strlen (mep->name) + 1;
485
486         minfo = g_new0 (MonoDebugMethodInfo, 1);
487         minfo->method = method;
488         minfo->symfile = symfile;
489
490         mep->minfo = minfo;
491         mep->method = method;
492
493         symfile->_priv->offset_table->method_count++;
494
495         g_hash_table_insert (symfile->_priv->method_table, method, mep);
496         g_hash_table_insert (symfile->_priv->method_hash, method, minfo);
497 }
498
499 static void
500 write_method (gpointer key, gpointer value, gpointer user_data)
501 {
502         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
503         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
504
505         if (symfile->_priv->error)
506                 return;
507
508         mep->minfo->file_offset = lseek (symfile->_priv->fd, 0, SEEK_CUR);
509
510         if (write (symfile->_priv->fd, mep->entry, sizeof (MonoSymbolFileMethodEntry)) < 0) {
511                 symfile->_priv->error = TRUE;
512                 return;
513         }
514 }
515
516 static void
517 write_line_numbers (gpointer key, gpointer value, gpointer user_data)
518 {
519         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
520         MonoSymbolFilePriv *priv = symfile->_priv;
521         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
522         MonoSymbolFileLineNumberEntry lne;
523         const unsigned char *ip, *start, *end;
524         MonoMethodHeader *header;
525
526         if (priv->error)
527                 return;
528
529         if ((mep->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
530             (mep->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
531             (mep->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
532                 g_assert_not_reached ();
533
534         header = ((MonoMethodNormal *) mep->method)->header;
535         g_assert (header);
536
537         mep->entry->line_number_table_offset = lseek (priv->fd, 0, SEEK_CUR);
538         ++mep->entry->num_line_numbers;
539
540         lne.offset = 0;
541         lne.row = -1;
542
543         if (write (priv->fd, &lne, sizeof (MonoSymbolFileLineNumberEntry)) < 0) {
544                 priv->error = TRUE;
545                 return;
546         }
547
548         ip = start = header->code;
549         end = ip + header->code_size;
550
551         while (ip < end) {
552                 gchar *line;
553
554                 ++mep->entry->num_line_numbers;
555                 lne.offset = ip - start;
556                 lne.row = -1;
557
558                 if (write (priv->fd, &lne, sizeof (MonoSymbolFileLineNumberEntry)) < 0) {
559                         priv->error = TRUE;
560                         return;
561                 }
562
563                 line = mono_disasm_code_one (NULL, mep->method, ip, &ip);
564                 g_free (line);
565         }
566 }
567
568 static void
569 create_methods (MonoSymbolFile *symfile)
570 {
571         MonoImage *image = symfile->_priv->image;
572         MonoTableInfo *table = &image->tables [MONO_TABLE_METHOD];
573         int idx;
574
575         for (idx = 1; idx <= table->rows; idx++) {
576                 guint32 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
577                 MonoMethod *method = mono_get_method (image, token, NULL);
578
579                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
580                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
581                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
582                         continue;
583
584                 if (method->wrapper_type != MONO_WRAPPER_NONE)
585                         continue;
586
587                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
588                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
589                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
590                         g_assert_not_reached ();
591
592                 if (!((MonoMethodNormal *) method)->header) {
593                         g_warning (G_STRLOC ": Internal error: method %s.%s doesn't have a header",
594                                    method->klass->name, method->name);
595                         continue;
596                 }
597
598                 create_method (symfile, token, method);
599         }
600 }
601
602 static void
603 load_line_numbers (gpointer key, gpointer value, gpointer user_data)
604 {
605         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
606         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
607
608         mep->minfo->num_il_offsets = mep->entry->num_line_numbers;
609         mep->minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
610                 (symfile->raw_contents + mep->entry->line_number_table_offset);
611 }
612
613 static int
614 create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings)
615 {
616         MonoSymbolFilePriv *priv = symfile->_priv;
617         char *ptr;
618         guint64 magic;
619         long version;
620         off_t offset;
621
622         priv->fd = g_file_open_tmp (NULL, &priv->file_name, NULL);
623         if (priv->fd == -1) {
624                 if (emit_warnings)
625                         g_warning ("Can't create symbol file");
626                 return FALSE;
627         }
628
629         symfile->symbol_file = g_strdup (priv->file_name);
630
631         magic = MONO_SYMBOL_FILE_MAGIC;
632         if (write (priv->fd, &magic, sizeof (magic)) < 0)
633                 return FALSE;
634
635         version = MONO_SYMBOL_FILE_VERSION;
636         if (write (priv->fd, &version, sizeof (version)) < 0)
637                 return FALSE;
638
639         offset = lseek (priv->fd, 0, SEEK_CUR);
640
641         priv->offset_table = g_new0 (MonoSymbolFileOffsetTable, 1);
642         if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
643                 return FALSE;
644
645         //
646         // Write source file table.
647         //
648         if (priv->source_file) {
649                 priv->offset_table->source_table_offset = lseek (priv->fd, 0, SEEK_CUR);
650                 if (!write_string (priv->fd, priv->source_file))
651                         return FALSE;
652                 priv->offset_table->source_table_size = lseek (priv->fd, 0, SEEK_CUR) -
653                         priv->offset_table->source_table_offset;
654         }
655
656         //
657         // Create method table.
658         //
659
660         priv->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
661                                                     (GDestroyNotify) free_method_entry);
662         priv->method_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
663                                                    (GDestroyNotify) free_method_info);
664
665         create_methods (symfile);
666
667         //
668         // Write line numbers.
669         //
670
671         priv->offset_table->line_number_table_offset = lseek (priv->fd, 0, SEEK_CUR);
672
673         g_hash_table_foreach (priv->method_table, write_line_numbers, symfile);
674         if (priv->error)
675                 return FALSE;
676
677         priv->offset_table->line_number_table_size = lseek (priv->fd, 0, SEEK_CUR) -
678                 priv->offset_table->line_number_table_offset;
679
680         //
681         // Write method table.
682         //
683
684         priv->offset_table->method_table_offset = lseek (priv->fd, 0, SEEK_CUR);
685
686         g_hash_table_foreach (priv->method_table, write_method, symfile);
687         if (priv->error)
688                 return FALSE;
689
690         priv->offset_table->method_table_size = lseek (priv->fd, 0, SEEK_CUR) -
691                 priv->offset_table->method_table_offset;
692
693         //
694         // Write offset table.
695         //
696
697         symfile->raw_contents_size = lseek (priv->fd, 0, SEEK_CUR);
698
699         lseek (priv->fd, offset, SEEK_SET);
700         if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
701                 return FALSE;
702
703         lseek (priv->fd, symfile->raw_contents_size, SEEK_SET);
704
705         ptr = mono_raw_buffer_load (priv->fd, TRUE, 0, symfile->raw_contents_size);
706         if (!ptr)
707                 return FALSE;
708
709         symfile->raw_contents = ptr;
710
711         //
712         // Load line number table.
713         //
714         g_hash_table_foreach (priv->method_table, load_line_numbers, symfile);
715         if (priv->error)
716                 return FALSE;
717
718         if (!write_string_table (symfile))
719                 return FALSE;
720
721         return TRUE;
722 }
723
724 MonoSymbolFile *
725 mono_debug_create_mono_symbol_file (MonoImage *image)
726 {
727         MonoSymbolFile *symfile;
728
729         symfile = g_new0 (MonoSymbolFile, 1);
730         symfile->magic = MONO_SYMBOL_FILE_MAGIC;
731         symfile->version = MONO_SYMBOL_FILE_VERSION;
732         symfile->dynamic_magic = MONO_SYMBOL_FILE_DYNAMIC_MAGIC;
733         symfile->dynamic_version = MONO_SYMBOL_FILE_DYNAMIC_VERSION;
734         symfile->is_dynamic = TRUE;
735         symfile->image_file = g_strdup (image->name);
736
737         symfile->_priv = g_new0 (MonoSymbolFilePriv, 1);
738         symfile->_priv->image = image;
739
740         if (!create_symfile (symfile, TRUE)) {
741                 mono_debug_close_mono_symbol_file (symfile);
742                 return NULL;
743         }
744
745         return symfile;
746 }
747
748 MonoDebugMethodInfo *
749 mono_debug_find_method (MonoSymbolFile *symfile, MonoMethod *method)
750 {
751         return g_hash_table_lookup (symfile->_priv->method_hash, method);
752 }
753
754 static void
755 write_method_name (gpointer key, gpointer value, gpointer user_data)
756 {
757         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
758         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
759         MonoSymbolFilePriv *priv = symfile->_priv;
760         guint8 *offset_ptr, *string_ptr;
761         guint32 offset;
762
763         offset = mep->method_name_offset + priv->string_offset_size;
764
765         offset_ptr = symfile->string_table + mep->index * 4;
766         string_ptr = symfile->string_table + offset;
767
768         *((guint32 *) offset_ptr) = offset;
769         strcpy (string_ptr, mep->name);
770 }
771
772 static int
773 write_string_table (MonoSymbolFile *symfile)
774 {
775         MonoSymbolFilePriv *priv = symfile->_priv;
776
777         priv->string_offset_size = priv->offset_table->method_count * 4;
778
779         symfile->string_table_size = priv->string_table_size + priv->string_offset_size;
780         symfile->string_table = g_malloc0 (symfile->string_table_size);
781
782         g_hash_table_foreach (symfile->_priv->method_table, write_method_name, symfile);
783         return TRUE;
784 }
785
786 MonoReflectionMethod *
787 ves_icall_MonoDebugger_GetMethod (MonoReflectionAssembly *assembly, guint32 token)
788 {
789         MonoMethod *method;
790
791         method = mono_get_method (assembly->assembly->image, token, NULL);
792
793         return mono_method_get_object (mono_domain_get (), method, NULL);
794 }
795
796 MonoReflectionType *
797 ves_icall_MonoDebugger_GetLocalTypeFromSignature (MonoReflectionAssembly *assembly, MonoArray *signature)
798 {
799         MonoDomain *domain; 
800         MonoImage *image;
801         MonoType *type;
802         const char *ptr;
803         int len = 0;
804
805         MONO_CHECK_ARG_NULL (assembly);
806         MONO_CHECK_ARG_NULL (signature);
807
808         domain = mono_domain_get();
809         image = assembly->assembly->image;
810
811         ptr = mono_array_addr (signature, char, 0);
812         g_assert (*ptr++ == 0x07);
813         len = mono_metadata_decode_value (ptr, &ptr);
814         g_assert (len == 1);
815
816         type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
817
818         return mono_type_get_object (domain, type);
819 }
820
821 static MonoDebugRangeInfo *
822 allocate_range_entry (MonoSymbolFile *symfile)
823 {
824         MonoDebugRangeInfo *retval;
825         guint32 size, chunks;
826
827         symfile->range_entry_size = sizeof (MonoDebugRangeInfo);
828
829         if (!symfile->range_table) {
830                 size = sizeof (MonoDebugRangeInfo) * RANGE_TABLE_CHUNK_SIZE;
831                 symfile->range_table = g_malloc0 (size);
832                 symfile->num_range_entries = 1;
833                 return symfile->range_table;
834         }
835
836         if (!((symfile->num_range_entries + 1) % RANGE_TABLE_CHUNK_SIZE)) {
837                 chunks = (symfile->num_range_entries + 1) / RANGE_TABLE_CHUNK_SIZE;
838                 size = sizeof (MonoDebugRangeInfo) * RANGE_TABLE_CHUNK_SIZE * (chunks + 1);
839
840                 symfile->range_table = g_realloc (symfile->range_table, size);
841         }
842
843         retval = symfile->range_table + symfile->num_range_entries;
844         symfile->num_range_entries++;
845         return retval;
846 }
847
848 static gpointer
849 write_type (MonoSymbolFile *symfile, MonoType *type)
850 {
851         guint8 buffer [BUFSIZ], *ptr = buffer, *retval;
852         guint32 size;
853
854         if (!type_table)
855                 type_table = g_hash_table_new (g_direct_hash, g_direct_equal);
856
857         retval = g_hash_table_lookup (type_table, type);
858         if (retval)
859                 return retval;
860
861         switch (type->type) {
862         case MONO_TYPE_BOOLEAN:
863         case MONO_TYPE_I1:
864         case MONO_TYPE_U1:
865                 *((int *) ptr)++ = 1;
866                 break;
867
868         case MONO_TYPE_CHAR:
869         case MONO_TYPE_I2:
870         case MONO_TYPE_U2:
871                 *((int *) ptr)++ = 2;
872                 break;
873
874         case MONO_TYPE_I4:
875         case MONO_TYPE_U4:
876         case MONO_TYPE_R4:
877                 *((int *) ptr)++ = 4;
878                 break;
879
880         case MONO_TYPE_I8:
881         case MONO_TYPE_U8:
882         case MONO_TYPE_R8:
883                 *((int *) ptr)++ = 8;
884                 break;
885
886         case MONO_TYPE_STRING: {
887                 MonoString string;
888
889                 *((int *) ptr)++ = -8;
890                 *((guint32 *) ptr)++ = sizeof (MonoString);
891                 *ptr++ = 1;
892                 *ptr++ = (guint8*)&string.length - (guint8*)&string;
893                 *ptr++ = sizeof (string.length);
894                 *ptr++ = (guint8*)&string.chars - (guint8*)&string;
895                 break;
896         }
897
898         case MONO_TYPE_SZARRAY: {
899                 MonoArray array;
900
901                 *((int *) ptr)++ = -8 - sizeof (gpointer);
902                 *((guint32 *) ptr)++ = sizeof (MonoArray);
903                 *ptr++ = 2;
904                 *ptr++ = (guint8*)&array.max_length - (guint8*)&array;
905                 *ptr++ = sizeof (array.max_length);
906                 *ptr++ = (guint8*)&array.vector - (guint8*)&array;
907                 *((gpointer *) ptr)++ = write_type (symfile, type->data.type);
908                 break;
909         }
910
911         case MONO_TYPE_ARRAY: {
912                 MonoArray array;
913                 MonoArrayBounds bounds;
914
915                 *((int *) ptr)++ = -15 - sizeof (gpointer);
916                 *((guint32 *) ptr)++ = sizeof (MonoArray);
917                 *ptr++ = 3;
918                 *ptr++ = (guint8*)&array.max_length - (guint8*)&array;
919                 *ptr++ = sizeof (array.max_length);
920                 *ptr++ = (guint8*)&array.vector - (guint8*)&array;
921                 *ptr++ = type->data.array->rank;
922                 *ptr++ = (guint8*)&array.bounds - (guint8*)&array;
923                 *ptr++ = sizeof (MonoArrayBounds);
924                 *ptr++ = (guint8*)&bounds.lower_bound - (guint8*)&bounds;
925                 *ptr++ = sizeof (bounds.lower_bound);
926                 *ptr++ = (guint8*)&bounds.length - (guint8*)&bounds;
927                 *ptr++ = sizeof (bounds.length);
928                 *((gpointer *) ptr)++ = write_type (symfile, type->data.array->type);
929                 break;
930         }
931
932         case MONO_TYPE_VALUETYPE:
933         case MONO_TYPE_CLASS: {
934                 MonoClass *klass = type->data.klass;
935
936                 mono_class_init (klass);
937                 if (klass->enumtype) {
938                         *((int *) ptr)++ = -5 - sizeof (gpointer);
939                         *((guint32 *) ptr)++ = sizeof (MonoObject);
940                         *ptr++ = 4;
941                         *((gpointer *) ptr)++ = write_type (symfile, klass->enum_basetype);
942                         break;
943                 }
944
945                 *((int *) ptr)++ = -4;
946                 *((guint32 *) ptr)++ = klass->instance_size;
947                 *ptr++ = 5;
948                 break;
949         }
950
951         default:
952                 g_message (G_STRLOC ": %p - %x,%x,%x", type, type->attrs, type->type, type->byref);
953
954                 *((int *) ptr)++ = -1;
955                 break;
956         }
957
958         size = ptr - buffer;
959
960         retval = g_malloc0 (size + 4);
961         memcpy (retval + 4, buffer, size);
962         *((int *) retval) = size;
963
964         g_hash_table_insert (type_table, type, retval);
965
966         return retval;
967 }