2002-09-21 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 struct MonoSymbolFilePriv
18 {
19         int fd;
20         int error;
21         char *file_name;
22         char *source_file;
23         guint32 string_table_size;
24         guint32 string_offset_size;
25         MonoImage *image;
26         GHashTable *method_table;
27         GHashTable *method_hash;
28         MonoSymbolFileOffsetTable *offset_table;
29         GPtrArray *range_table;
30 };
31
32 typedef struct
33 {
34         MonoMethod *method;
35         MonoDebugMethodInfo *minfo;
36         MonoSymbolFileMethodEntry *entry;
37         guint32 method_name_offset;
38         guint32 index;
39         gchar *name;
40 } MonoSymbolFileMethodEntryPriv;
41
42 static int write_string_table (MonoSymbolFile *symfile);
43 static int create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings);
44 static void close_symfile (MonoSymbolFile *symfile);
45
46 static void
47 free_method_info (MonoDebugMethodInfo *minfo)
48 {
49         g_free (minfo->jit);
50         g_free (minfo);
51 }
52
53 static int
54 load_symfile (MonoSymbolFile *symfile)
55 {
56         MonoSymbolFilePriv *priv = symfile->_priv;
57         MonoSymbolFileMethodEntry *me;
58         const char *ptr, *start;
59         guint64 magic;
60         long version;
61         int i;
62
63         ptr = start = symfile->raw_contents;
64
65         magic = *((guint64 *) ptr)++;
66         if (magic != MONO_SYMBOL_FILE_MAGIC) {
67                 g_warning ("Symbol file %s has is not a mono symbol file", priv->file_name);
68                 return FALSE;
69         }
70
71         version = *((guint32 *) ptr)++;
72         if (version != MONO_SYMBOL_FILE_VERSION) {
73                 g_warning ("Symbol file %s has incorrect line number table version "
74                            "(expected %d, got %ld)", priv->file_name,
75                            MONO_SYMBOL_FILE_VERSION, version);
76                 return FALSE;
77         }
78
79         priv->offset_table = (MonoSymbolFileOffsetTable *) ptr;
80         symfile->address_table_size = priv->offset_table->address_table_size;
81
82         symfile->type_table_size = symfile->_priv->offset_table->type_count * sizeof (guint8 *);
83         symfile->type_table = g_malloc0 (symfile->type_table_size);
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         if (!write_string_table (symfile))
141                 return FALSE;
142
143         return TRUE;
144 }
145
146 MonoSymbolFile *
147 mono_debug_open_mono_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
148 {
149         MonoSymbolFile *symfile;
150         MonoSymbolFilePriv *priv;
151         off_t file_size;
152         void *ptr;
153         int fd;
154
155         fd = open (filename, O_RDONLY);
156         if (fd == -1) {
157                 if (emit_warnings)
158                         g_warning ("Can't open symbol file: %s", filename);
159                 return NULL;
160         }
161
162         file_size = lseek (fd, 0, SEEK_END);
163         lseek (fd, 0, SEEK_SET);
164
165         if (file_size == (off_t) -1) {
166                 if (emit_warnings)
167                         g_warning ("Can't get size of symbol file: %s", filename);
168                 return NULL;
169         }
170
171         ptr = mono_raw_buffer_load (fd, FALSE, 0, file_size);
172         if (!ptr) {
173                 if (emit_warnings)
174                         g_warning ("Can't read symbol file: %s", filename);
175                 return NULL;
176         }
177
178         symfile = g_new0 (MonoSymbolFile, 1);
179         symfile->magic = MONO_SYMBOL_FILE_MAGIC;
180         symfile->version = MONO_SYMBOL_FILE_VERSION;
181         symfile->image_file = g_strdup (image->name);
182         symfile->raw_contents = ptr;
183         symfile->raw_contents_size = file_size;
184
185         symfile->_priv = priv = g_new0 (MonoSymbolFilePriv, 1);
186
187         priv->fd = fd;
188         priv->image = image;
189         priv->file_name = g_strdup (filename);
190
191         if (!load_symfile (symfile)) {
192                 mono_debug_close_mono_symbol_file (symfile);
193                 return NULL;
194         }
195
196         return symfile;
197 }
198
199 static void
200 close_symfile (MonoSymbolFile *symfile)
201 {
202         MonoSymbolFilePriv *priv = symfile->_priv;
203
204         if (symfile->raw_contents) {
205                 mono_raw_buffer_free (symfile->raw_contents);
206                 symfile->raw_contents = NULL;
207         }
208
209         if (priv->fd) {
210                 close (priv->fd);
211                 priv->fd = 0;
212         }
213
214         if (priv->method_table) {
215                 g_hash_table_destroy (priv->method_table);
216                 priv->method_table = NULL;
217         }
218
219         if (priv->method_hash) {
220                 g_hash_table_destroy (priv->method_hash);
221                 priv->method_hash = NULL;
222         }
223
224         if (symfile->is_dynamic)
225                 unlink (priv->file_name);
226
227         if (symfile->image_file) {
228                 g_free (symfile->image_file);
229                 symfile->image_file = NULL;
230         }
231
232         if (priv->file_name) {
233                 g_free (priv->file_name);
234                 priv->file_name = NULL;
235         }
236
237         priv->error = FALSE;
238 }
239
240 void
241 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
242 {
243         if (!symfile)
244                 return;
245
246         close_symfile (symfile);
247
248         g_free (symfile->_priv->source_file);
249         g_free (symfile->_priv);
250         g_free (symfile);
251 }
252
253 static int
254 write_string (int fd, const char *string)
255 {
256         guint32 length = strlen (string);
257
258         if (write (fd, &length, sizeof (length)) < 0)
259                 return FALSE;
260
261         if (write (fd, string, strlen (string)) < 0)
262                 return FALSE;
263
264         return TRUE;
265 }
266
267 static gchar *
268 read_string (const char *ptr)
269 {
270         int len = *((guint32 *) ptr)++;
271
272         return g_filename_from_utf8 (ptr, len, NULL, NULL, NULL);
273 }
274
275 gchar *
276 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
277                                  guint32 *line_number)
278 {
279         MonoSymbolFilePriv *priv = symfile->_priv;
280         MonoSymbolFileLineNumberEntry *lne;
281         MonoSymbolFileMethodEntryPriv *mep;
282         gchar *source_file = NULL;
283         const char *ptr;
284         int i;
285
286         if (!priv->method_table || symfile->is_dynamic)
287                 return NULL;
288
289         mep = g_hash_table_lookup (priv->method_table, method);
290         if (!mep)
291                 return NULL;
292
293         if (mep->entry->source_file_offset)
294                 source_file = read_string (symfile->raw_contents + mep->entry->source_file_offset);
295
296         ptr = symfile->raw_contents + mep->entry->line_number_table_offset;
297
298         lne = (MonoSymbolFileLineNumberEntry *) ptr;
299
300         for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
301                 if (lne->offset < offset)
302                         continue;
303
304                 if (line_number) {
305                         *line_number = lne->row;
306                         if (source_file)
307                                 return source_file;
308                         else
309                                 return NULL;
310                 } else if (source_file) {
311                         gchar *retval = g_strdup_printf ("%s:%d", source_file, lne->row);
312                         g_free (source_file);
313                         return retval;
314                 } else
315                         return g_strdup_printf ("%d", lne->row);
316         }
317
318         return NULL;
319 }
320
321 static void
322 update_method_func (gpointer key, gpointer value, gpointer user_data)
323 {
324         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
325         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
326         MonoSymbolFileMethodAddress *address;
327         MonoDebugVarInfo *var_table;
328         MonoSymbolFileLineNumberEntry *lne;
329         MonoDebugRangeInfo *range;
330         int i;
331
332         if (!mep->minfo) {
333                 mep->minfo = g_hash_table_lookup (symfile->_priv->method_hash, mep->method);
334                 if (!mep->minfo)
335                         return;
336         }
337
338         if (!mep->minfo->jit)
339                 return;
340
341         address = (MonoSymbolFileMethodAddress *)
342                 (symfile->address_table + mep->entry->address_table_offset);
343
344         address->is_valid = TRUE;
345         address->start_address = GPOINTER_TO_UINT (mep->minfo->jit->code_start);
346         address->end_address = GPOINTER_TO_UINT (mep->minfo->jit->code_start + mep->minfo->jit->code_size);
347
348         range = g_new0 (MonoDebugRangeInfo, 1);
349         range->start_address = address->start_address;
350         range->end_address = address->end_address;
351         range->file_offset = mep->minfo->file_offset;
352
353         var_table = (MonoDebugVarInfo *)
354                 (symfile->address_table + mep->entry->variable_table_offset);
355
356         if (mep->entry->this_type_index) {
357                 if (!mep->minfo->jit->this_var) {
358                         g_warning (G_STRLOC ": Method %s.%s doesn't have `this'.",
359                                    mep->method->klass->name, mep->method->name);
360                         var_table++;
361                 } else
362                         *var_table++ = *mep->minfo->jit->this_var;
363         }
364
365         if (mep->minfo->jit->num_params != mep->entry->num_parameters) {
366                 g_warning (G_STRLOC ": Method %s.%s has %d parameters, but symbol file claims it has %d.",
367                            mep->method->klass->name, mep->method->name, mep->minfo->jit->num_params,
368                            mep->entry->num_parameters);
369                 var_table += mep->entry->num_parameters;
370         } else
371                 for (i = 0; i < mep->minfo->jit->num_params; i++)
372                         *var_table++ = mep->minfo->jit->params [i];
373
374         if (mep->minfo->jit->num_locals != mep->entry->num_locals) {
375                 g_warning (G_STRLOC ": Method %s.%s has %d locals, but symbol file claims it has %d.",
376                            mep->method->klass->name, mep->method->name, mep->minfo->jit->num_locals,
377                            mep->entry->num_locals);
378                 var_table += mep->entry->num_locals;
379         } else
380                 for (i = 0; i < mep->minfo->jit->num_locals; i++)
381                         *var_table++ = mep->minfo->jit->locals [i];
382
383         g_ptr_array_add (symfile->_priv->range_table, range);
384
385         lne = (MonoSymbolFileLineNumberEntry *)
386                 (symfile->raw_contents + mep->entry->line_number_table_offset);
387
388         for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
389                 int j;
390
391                 if (i == 0) {
392                         address->line_addresses [i] = 0;
393                         continue;
394                 } else if (lne->offset == 0) {
395                         address->line_addresses [i] = mep->minfo->jit->prologue_end;
396                         continue;
397                 }
398
399                 address->line_addresses [i] = mep->minfo->jit->code_size;
400
401                 for (j = 0; j < mep->minfo->num_il_offsets; j++) {
402                         MonoSymbolFileLineNumberEntry *il = &mep->minfo->il_offsets [j];
403
404                         if (il->offset >= lne->offset) {
405                                 address->line_addresses [i] = mep->minfo->jit->il_addresses [j];
406                                 break;
407                         }
408                 }
409         }
410 }
411
412 static gint
413 range_table_compare_func (gconstpointer a, gconstpointer b)
414 {
415         const MonoDebugRangeInfo *r1 = (const MonoDebugRangeInfo *) a;
416         const MonoDebugRangeInfo *r2 = (const MonoDebugRangeInfo *) b;
417
418         if (r1->start_address < r2->start_address)
419                 return -1;
420         else if (r1->start_address > r2->start_address)
421                 return 1;
422         else
423                 return 0;
424 }       
425
426 void
427 mono_debug_update_mono_symbol_file (MonoSymbolFile *symfile)
428 {
429         int i;
430
431         if (!symfile->_priv->method_table)
432                 return;
433
434         symfile->_priv->range_table = g_ptr_array_new ();
435
436         if (!symfile->address_table)
437                 symfile->address_table = g_malloc0 (symfile->address_table_size);
438
439         g_hash_table_foreach (symfile->_priv->method_table, update_method_func, symfile);
440
441         symfile->range_table_size = symfile->_priv->range_table->len * sizeof (MonoDebugRangeInfo);
442         symfile->range_table = g_malloc0 (symfile->range_table_size);
443
444         g_ptr_array_sort (symfile->_priv->range_table, range_table_compare_func);
445
446         for (i = 0; i < symfile->_priv->range_table->len; i++) {
447                 MonoDebugRangeInfo *range = g_ptr_array_index (symfile->_priv->range_table, i);
448
449                 symfile->range_table [i] = *range;
450         }
451
452         g_ptr_array_free (symfile->_priv->range_table, TRUE);
453         symfile->_priv->range_table = NULL;
454 }
455
456 static void
457 free_method_entry (MonoSymbolFileMethodEntryPriv *mep)
458 {
459         g_free (mep->name);
460         g_free (mep->entry);
461         g_free (mep);
462 }
463
464 static void
465 create_method (MonoSymbolFile *symfile, guint32 token, MonoMethod *method)
466 {
467         MonoSymbolFileMethodEntryPriv *mep;
468         MonoDebugMethodInfo *minfo;
469
470         g_assert (method->klass->image == symfile->_priv->image);
471
472         mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
473         mep->entry = g_new0 (MonoSymbolFileMethodEntry, 1);
474         mep->entry->token = token;
475         mep->entry->source_file_offset = symfile->_priv->offset_table->source_table_offset;
476
477         mep->method_name_offset = symfile->_priv->string_table_size;
478         mep->name = g_strdup_printf ("%s%s.%s", method->klass->name_space,
479                                      method->klass->name, method->name);
480         symfile->_priv->string_table_size += strlen (mep->name) + 1;
481
482         minfo = g_new0 (MonoDebugMethodInfo, 1);
483         minfo->method = method;
484         minfo->symfile = symfile;
485
486         mep->minfo = minfo;
487         mep->method = method;
488
489         symfile->_priv->offset_table->method_count++;
490
491         g_hash_table_insert (symfile->_priv->method_table, method, mep);
492         g_hash_table_insert (symfile->_priv->method_hash, method, minfo);
493 }
494
495 static void
496 write_method (gpointer key, gpointer value, gpointer user_data)
497 {
498         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
499         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
500
501         if (symfile->_priv->error)
502                 return;
503
504         mep->minfo->file_offset = lseek (symfile->_priv->fd, 0, SEEK_CUR);
505
506         if (write (symfile->_priv->fd, mep->entry, sizeof (MonoSymbolFileMethodEntry)) < 0) {
507                 symfile->_priv->error = TRUE;
508                 return;
509         }
510 }
511
512 static void
513 write_line_numbers (gpointer key, gpointer value, gpointer user_data)
514 {
515         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
516         MonoSymbolFilePriv *priv = symfile->_priv;
517         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
518         MonoSymbolFileLineNumberEntry lne;
519         const unsigned char *ip, *start, *end;
520         MonoMethodHeader *header;
521
522         if (priv->error)
523                 return;
524
525         if ((mep->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
526             (mep->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
527             (mep->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
528                 g_assert_not_reached ();
529
530         header = ((MonoMethodNormal *) mep->method)->header;
531         g_assert (header);
532
533         mep->entry->line_number_table_offset = lseek (priv->fd, 0, SEEK_CUR);
534         ++mep->entry->num_line_numbers;
535
536         lne.offset = 0;
537         lne.row = -1;
538
539         if (write (priv->fd, &lne, sizeof (MonoSymbolFileLineNumberEntry)) < 0) {
540                 priv->error = TRUE;
541                 return;
542         }
543
544         ip = start = header->code;
545         end = ip + header->code_size;
546
547         while (ip < end) {
548                 gchar *line;
549
550                 ++mep->entry->num_line_numbers;
551                 lne.offset = ip - start;
552                 lne.row = -1;
553
554                 if (write (priv->fd, &lne, sizeof (MonoSymbolFileLineNumberEntry)) < 0) {
555                         priv->error = TRUE;
556                         return;
557                 }
558
559                 line = mono_disasm_code_one (NULL, mep->method, ip, &ip);
560                 g_free (line);
561         }
562
563         mep->entry->address_table_offset = symfile->address_table_size;
564         mep->entry->address_table_size = sizeof (MonoSymbolFileMethodAddress) +
565                 mep->entry->num_line_numbers * sizeof (guint32);
566
567         symfile->address_table_size += mep->entry->address_table_size;
568 }
569
570 static void
571 create_methods (MonoSymbolFile *symfile)
572 {
573         MonoImage *image = symfile->_priv->image;
574         MonoTableInfo *table = &image->tables [MONO_TABLE_METHOD];
575         int idx;
576
577         for (idx = 1; idx <= table->rows; idx++) {
578                 guint32 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
579                 MonoMethod *method = mono_get_method (image, token, NULL);
580
581                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
582                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
583                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
584                         continue;
585
586                 if (method->wrapper_type != MONO_WRAPPER_NONE)
587                         continue;
588
589                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
590                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
591                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
592                         g_assert_not_reached ();
593
594                 if (!((MonoMethodNormal *) method)->header) {
595                         g_warning (G_STRLOC ": Internal error: method %s.%s doesn't have a header",
596                                    method->klass->name, method->name);
597                         continue;
598                 }
599
600                 create_method (symfile, token, method);
601         }
602 }
603
604 static void
605 load_line_numbers (gpointer key, gpointer value, gpointer user_data)
606 {
607         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
608         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
609
610         mep->minfo->num_il_offsets = mep->entry->num_line_numbers;
611         mep->minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
612                 (symfile->raw_contents + mep->entry->line_number_table_offset);
613 }
614
615 static int
616 create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings)
617 {
618         MonoSymbolFilePriv *priv = symfile->_priv;
619         char *ptr;
620         guint64 magic;
621         long version;
622         off_t offset;
623
624         priv->fd = g_file_open_tmp (NULL, &priv->file_name, NULL);
625         if (priv->fd == -1) {
626                 if (emit_warnings)
627                         g_warning ("Can't create symbol file");
628                 return FALSE;
629         }
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         priv->offset_table->address_table_size = symfile->address_table_size;
699
700         lseek (priv->fd, offset, SEEK_SET);
701         if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
702                 return FALSE;
703
704         lseek (priv->fd, symfile->raw_contents_size, SEEK_SET);
705
706         ptr = mono_raw_buffer_load (priv->fd, TRUE, 0, symfile->raw_contents_size);
707         if (!ptr)
708                 return FALSE;
709
710         symfile->raw_contents = ptr;
711
712         symfile->type_table_size = symfile->_priv->offset_table->type_count * sizeof (guint8 *);
713         symfile->type_table = g_malloc0 (symfile->type_table_size);
714
715         //
716         // Load line number table.
717         //
718         g_hash_table_foreach (priv->method_table, load_line_numbers, symfile);
719         if (priv->error)
720                 return FALSE;
721
722         if (!write_string_table (symfile))
723                 return FALSE;
724
725         return TRUE;
726 }
727
728 MonoSymbolFile *
729 mono_debug_create_mono_symbol_file (MonoImage *image)
730 {
731         MonoSymbolFile *symfile;
732
733         symfile = g_new0 (MonoSymbolFile, 1);
734         symfile->magic = MONO_SYMBOL_FILE_MAGIC;
735         symfile->version = MONO_SYMBOL_FILE_VERSION;
736         symfile->is_dynamic = TRUE;
737         symfile->image_file = g_strdup (image->name);
738
739         symfile->_priv = g_new0 (MonoSymbolFilePriv, 1);
740         symfile->_priv->image = image;
741
742         if (!create_symfile (symfile, TRUE)) {
743                 mono_debug_close_mono_symbol_file (symfile);
744                 return NULL;
745         }
746
747         return symfile;
748 }
749
750 MonoDebugMethodInfo *
751 mono_debug_find_method (MonoSymbolFile *symfile, MonoMethod *method)
752 {
753         return g_hash_table_lookup (symfile->_priv->method_hash, method);
754 }
755
756 static void
757 write_method_name (gpointer key, gpointer value, gpointer user_data)
758 {
759         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
760         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
761         MonoSymbolFilePriv *priv = symfile->_priv;
762         guint8 *offset_ptr, *string_ptr;
763         guint32 offset;
764
765         offset = mep->method_name_offset + priv->string_offset_size;
766
767         offset_ptr = symfile->string_table + mep->index * 4;
768         string_ptr = symfile->string_table + offset;
769
770         *((guint32 *) offset_ptr) = offset;
771         strcpy (string_ptr, mep->name);
772 }
773
774 static int
775 write_string_table (MonoSymbolFile *symfile)
776 {
777         MonoSymbolFilePriv *priv = symfile->_priv;
778
779         priv->string_offset_size = priv->offset_table->method_count * 4;
780
781         symfile->string_table_size = priv->string_table_size + priv->string_offset_size;
782         symfile->string_table = g_malloc0 (symfile->string_table_size);
783
784         g_hash_table_foreach (symfile->_priv->method_table, write_method_name, symfile);
785         return TRUE;
786 }
787
788 MonoReflectionMethod *
789 ves_icall_MonoDebugger_GetMethod (MonoReflectionAssembly *assembly, guint32 token)
790 {
791         MonoMethod *method;
792
793         method = mono_get_method (assembly->assembly->image, token, NULL);
794
795         return mono_method_get_object (mono_domain_get (), method, NULL);
796 }
797
798 MonoReflectionType *
799 ves_icall_MonoDebugger_GetLocalTypeFromSignature (MonoReflectionAssembly *assembly, MonoArray *signature)
800 {
801         MonoDomain *domain; 
802         MonoImage *image;
803         MonoType *type;
804         const char *ptr;
805         int len = 0;
806
807         MONO_CHECK_ARG_NULL (assembly);
808         MONO_CHECK_ARG_NULL (signature);
809
810         domain = mono_domain_get();
811         image = assembly->assembly->image;
812
813         ptr = mono_array_addr (signature, char, 0);
814         g_assert (*ptr++ == 0x07);
815         len = mono_metadata_decode_value (ptr, &ptr);
816         g_assert (len == 1);
817
818         type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
819
820         return mono_type_get_object (domain, type);
821 }