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