2002-09-20 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         /*
83          * Read method table.
84          *
85          */
86
87         priv->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
88                                                     (GDestroyNotify) g_free);
89         priv->method_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
90                                                    (GDestroyNotify) free_method_info);
91
92         ptr = symfile->raw_contents + priv->offset_table->method_table_offset;
93         me = (MonoSymbolFileMethodEntry *) ptr;
94
95         for (i = 0; i < priv->offset_table->method_count; i++, me++) {
96                 MonoMethod *method = mono_get_method (priv->image, me->token, NULL);
97                 MonoSymbolFileMethodEntryPriv *mep;
98                 MonoDebugMethodInfo *minfo;
99
100                 if (!method)
101                         continue;
102
103                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
104                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
105                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
106                         g_assert_not_reached ();
107
108                 if (!((MonoMethodNormal *) method)->header) {
109                         g_warning (G_STRLOC ": Internal error: method %s.%s doesn't have a header",
110                                    method->klass->name, method->name);
111                         continue;
112                 }
113
114                 minfo = g_new0 (MonoDebugMethodInfo, 1);
115                 minfo->file_offset = ((const char *) me) - start;
116                 minfo->method = method;
117                 minfo->symfile = symfile;
118                 minfo->num_il_offsets = me->num_line_numbers;
119                 minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
120                         (symfile->raw_contents + me->line_number_table_offset);
121
122                 mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
123                 mep->method = method;
124                 mep->minfo = minfo;
125                 mep->entry = me;
126                 mep->index = i;
127
128                 mep->method_name_offset = priv->string_table_size;
129                 mep->name = g_strdup_printf ("%s%s.%s", method->klass->name_space,
130                                              method->klass->name, method->name);
131                 priv->string_table_size += strlen (mep->name) + 1;
132
133                 g_hash_table_insert (priv->method_table, method, mep);
134                 g_hash_table_insert (priv->method_hash, method, minfo);
135         }
136
137         if (!write_string_table (symfile))
138                 return FALSE;
139
140         return TRUE;
141 }
142
143 MonoSymbolFile *
144 mono_debug_open_mono_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
145 {
146         MonoSymbolFile *symfile;
147         MonoSymbolFilePriv *priv;
148         off_t file_size;
149         void *ptr;
150         int fd;
151
152         fd = open (filename, O_RDONLY);
153         if (fd == -1) {
154                 if (emit_warnings)
155                         g_warning ("Can't open symbol file: %s", filename);
156                 return NULL;
157         }
158
159         file_size = lseek (fd, 0, SEEK_END);
160         lseek (fd, 0, SEEK_SET);
161
162         if (file_size == (off_t) -1) {
163                 if (emit_warnings)
164                         g_warning ("Can't get size of symbol file: %s", filename);
165                 return NULL;
166         }
167
168         ptr = mono_raw_buffer_load (fd, FALSE, 0, file_size);
169         if (!ptr) {
170                 if (emit_warnings)
171                         g_warning ("Can't read symbol file: %s", filename);
172                 return NULL;
173         }
174
175         symfile = g_new0 (MonoSymbolFile, 1);
176         symfile->magic = MONO_SYMBOL_FILE_MAGIC;
177         symfile->version = MONO_SYMBOL_FILE_VERSION;
178         symfile->image_file = g_strdup (image->name);
179         symfile->raw_contents = ptr;
180         symfile->raw_contents_size = file_size;
181
182         symfile->_priv = priv = g_new0 (MonoSymbolFilePriv, 1);
183
184         priv->fd = fd;
185         priv->image = image;
186         priv->file_name = g_strdup (filename);
187
188         if (!load_symfile (symfile)) {
189                 mono_debug_close_mono_symbol_file (symfile);
190                 return NULL;
191         }
192
193         return symfile;
194 }
195
196 static void
197 close_symfile (MonoSymbolFile *symfile)
198 {
199         MonoSymbolFilePriv *priv = symfile->_priv;
200
201         if (symfile->raw_contents) {
202                 mono_raw_buffer_free (symfile->raw_contents);
203                 symfile->raw_contents = NULL;
204         }
205
206         if (priv->fd) {
207                 close (priv->fd);
208                 priv->fd = 0;
209         }
210
211         if (priv->method_table) {
212                 g_hash_table_destroy (priv->method_table);
213                 priv->method_table = NULL;
214         }
215
216         if (priv->method_hash) {
217                 g_hash_table_destroy (priv->method_hash);
218                 priv->method_hash = NULL;
219         }
220
221         if (symfile->is_dynamic)
222                 unlink (priv->file_name);
223
224         if (symfile->image_file) {
225                 g_free (symfile->image_file);
226                 symfile->image_file = NULL;
227         }
228
229         if (priv->file_name) {
230                 g_free (priv->file_name);
231                 priv->file_name = NULL;
232         }
233
234         priv->error = FALSE;
235 }
236
237 void
238 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
239 {
240         if (!symfile)
241                 return;
242
243         close_symfile (symfile);
244
245         g_free (symfile->_priv->source_file);
246         g_free (symfile->_priv);
247         g_free (symfile);
248 }
249
250 static int
251 write_string (int fd, const char *string)
252 {
253         guint32 length = strlen (string);
254
255         if (write (fd, &length, sizeof (length)) < 0)
256                 return FALSE;
257
258         if (write (fd, string, strlen (string)) < 0)
259                 return FALSE;
260
261         return TRUE;
262 }
263
264 static gchar *
265 read_string (const char *ptr)
266 {
267         int len = *((guint32 *) ptr)++;
268
269         return g_filename_from_utf8 (ptr, len, NULL, NULL, NULL);
270 }
271
272 gchar *
273 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
274                                  guint32 *line_number)
275 {
276         MonoSymbolFilePriv *priv = symfile->_priv;
277         MonoSymbolFileLineNumberEntry *lne;
278         MonoSymbolFileMethodEntryPriv *mep;
279         gchar *source_file = NULL;
280         const char *ptr;
281         int i;
282
283         if (!priv->method_table || symfile->is_dynamic)
284                 return NULL;
285
286         mep = g_hash_table_lookup (priv->method_table, method);
287         if (!mep)
288                 return NULL;
289
290         if (mep->entry->source_file_offset)
291                 source_file = read_string (symfile->raw_contents + mep->entry->source_file_offset);
292
293         ptr = symfile->raw_contents + mep->entry->line_number_table_offset;
294
295         lne = (MonoSymbolFileLineNumberEntry *) ptr;
296
297         for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
298                 if (lne->offset < offset)
299                         continue;
300
301                 if (line_number) {
302                         *line_number = lne->row;
303                         if (source_file)
304                                 return source_file;
305                         else
306                                 return NULL;
307                 } else if (source_file) {
308                         gchar *retval = g_strdup_printf ("%s:%d", source_file, lne->row);
309                         g_free (source_file);
310                         return retval;
311                 } else
312                         return g_strdup_printf ("%d", lne->row);
313         }
314
315         return NULL;
316 }
317
318 static void
319 update_method_func (gpointer key, gpointer value, gpointer user_data)
320 {
321         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
322         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
323         MonoSymbolFileMethodAddress *address;
324         MonoDebugVarInfo *var_table;
325         MonoSymbolFileLineNumberEntry *lne;
326         MonoDebugRangeInfo *range;
327         int i;
328
329         if (!mep->minfo) {
330                 mep->minfo = g_hash_table_lookup (symfile->_priv->method_hash, mep->method);
331                 if (!mep->minfo)
332                         return;
333         }
334
335         if (!mep->minfo->jit)
336                 return;
337
338         address = (MonoSymbolFileMethodAddress *)
339                 (symfile->address_table + mep->entry->address_table_offset);
340
341         address->is_valid = TRUE;
342         address->start_address = GPOINTER_TO_UINT (mep->minfo->jit->code_start);
343         address->end_address = GPOINTER_TO_UINT (mep->minfo->jit->code_start + mep->minfo->jit->code_size);
344
345         range = g_new0 (MonoDebugRangeInfo, 1);
346         range->start_address = address->start_address;
347         range->end_address = address->end_address;
348         range->file_offset = mep->minfo->file_offset;
349
350         var_table = (MonoDebugVarInfo *)
351                 (symfile->address_table + mep->entry->variable_table_offset);
352
353         if (mep->entry->this_type_index) {
354                 if (!mep->minfo->jit->this_var) {
355                         g_warning (G_STRLOC ": Method %s.%s doesn't have `this'.",
356                                    mep->method->klass->name, mep->method->name);
357                         var_table++;
358                 } else
359                         *var_table++ = *mep->minfo->jit->this_var;
360         }
361
362         if (mep->minfo->jit->num_params != mep->entry->num_parameters) {
363                 g_warning (G_STRLOC ": Method %s.%s has %d parameters, but symbol file claims it has %d.",
364                            mep->method->klass->name, mep->method->name, mep->minfo->jit->num_params,
365                            mep->entry->num_parameters);
366                 var_table += mep->entry->num_parameters;
367         } else
368                 for (i = 0; i < mep->minfo->jit->num_params; i++)
369                         *var_table++ = mep->minfo->jit->params [i];
370
371         if (mep->minfo->jit->num_locals != mep->entry->num_locals) {
372                 g_warning (G_STRLOC ": Method %s.%s has %d locals, but symbol file claims it has %d.",
373                            mep->method->klass->name, mep->method->name, mep->minfo->jit->num_locals,
374                            mep->entry->num_locals);
375                 var_table += mep->entry->num_locals;
376         } else
377                 for (i = 0; i < mep->minfo->jit->num_locals; i++)
378                         *var_table++ = mep->minfo->jit->locals [i];
379
380         g_ptr_array_add (symfile->_priv->range_table, range);
381
382         lne = (MonoSymbolFileLineNumberEntry *)
383                 (symfile->raw_contents + mep->entry->line_number_table_offset);
384
385         for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
386                 int j;
387
388                 if (i == 0) {
389                         address->line_addresses [i] = 0;
390                         continue;
391                 } else if (lne->offset == 0) {
392                         address->line_addresses [i] = mep->minfo->jit->prologue_end;
393                         continue;
394                 }
395
396                 address->line_addresses [i] = mep->minfo->jit->code_size;
397
398                 for (j = 0; j < mep->minfo->num_il_offsets; j++) {
399                         MonoSymbolFileLineNumberEntry *il = &mep->minfo->il_offsets [j];
400
401                         if (il->offset >= lne->offset) {
402                                 address->line_addresses [i] = mep->minfo->jit->il_addresses [j];
403                                 break;
404                         }
405                 }
406         }
407 }
408
409 static gint
410 range_table_compare_func (gconstpointer a, gconstpointer b)
411 {
412         const MonoDebugRangeInfo *r1 = (const MonoDebugRangeInfo *) a;
413         const MonoDebugRangeInfo *r2 = (const MonoDebugRangeInfo *) b;
414
415         if (r1->start_address < r2->start_address)
416                 return -1;
417         else if (r1->start_address > r2->start_address)
418                 return 1;
419         else
420                 return 0;
421 }       
422
423 void
424 mono_debug_update_mono_symbol_file (MonoSymbolFile *symfile)
425 {
426         int i;
427
428         if (!symfile->_priv->method_table)
429                 return;
430
431         symfile->_priv->range_table = g_ptr_array_new ();
432
433         if (!symfile->address_table)
434                 symfile->address_table = g_malloc0 (symfile->address_table_size);
435
436         g_hash_table_foreach (symfile->_priv->method_table, update_method_func, symfile);
437
438         symfile->range_table_size = symfile->_priv->range_table->len * sizeof (MonoDebugRangeInfo);
439         symfile->range_table = g_malloc0 (symfile->range_table_size);
440
441         g_ptr_array_sort (symfile->_priv->range_table, range_table_compare_func);
442
443         for (i = 0; i < symfile->_priv->range_table->len; i++) {
444                 MonoDebugRangeInfo *range = g_ptr_array_index (symfile->_priv->range_table, i);
445
446                 symfile->range_table [i] = *range;
447         }
448
449         g_ptr_array_free (symfile->_priv->range_table, TRUE);
450         symfile->_priv->range_table = NULL;
451 }
452
453 static void
454 free_method_entry (MonoSymbolFileMethodEntryPriv *mep)
455 {
456         g_free (mep->name);
457         g_free (mep->entry);
458         g_free (mep);
459 }
460
461 static void
462 create_method (MonoSymbolFile *symfile, guint32 token, MonoMethod *method)
463 {
464         MonoSymbolFileMethodEntryPriv *mep;
465         MonoDebugMethodInfo *minfo;
466
467         g_assert (method->klass->image == symfile->_priv->image);
468
469         mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
470         mep->entry = g_new0 (MonoSymbolFileMethodEntry, 1);
471         mep->entry->token = token;
472         mep->entry->source_file_offset = symfile->_priv->offset_table->source_table_offset;
473
474         mep->method_name_offset = symfile->_priv->string_table_size;
475         mep->name = g_strdup_printf ("%s%s.%s", method->klass->name_space,
476                                      method->klass->name, method->name);
477         symfile->_priv->string_table_size += strlen (mep->name) + 1;
478
479         minfo = g_new0 (MonoDebugMethodInfo, 1);
480         minfo->method = method;
481         minfo->symfile = symfile;
482
483         mep->minfo = minfo;
484         mep->method = method;
485
486         symfile->_priv->offset_table->method_count++;
487
488         g_hash_table_insert (symfile->_priv->method_table, method, mep);
489         g_hash_table_insert (symfile->_priv->method_hash, method, minfo);
490 }
491
492 static void
493 write_method (gpointer key, gpointer value, gpointer user_data)
494 {
495         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
496         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
497
498         if (symfile->_priv->error)
499                 return;
500
501         mep->minfo->file_offset = lseek (symfile->_priv->fd, 0, SEEK_CUR);
502
503         if (write (symfile->_priv->fd, mep->entry, sizeof (MonoSymbolFileMethodEntry)) < 0) {
504                 symfile->_priv->error = TRUE;
505                 return;
506         }
507 }
508
509 static void
510 write_line_numbers (gpointer key, gpointer value, gpointer user_data)
511 {
512         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
513         MonoSymbolFilePriv *priv = symfile->_priv;
514         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
515         MonoSymbolFileLineNumberEntry lne;
516         const unsigned char *ip, *start, *end;
517         MonoMethodHeader *header;
518
519         if (priv->error)
520                 return;
521
522         if ((mep->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
523             (mep->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
524             (mep->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
525                 g_assert_not_reached ();
526
527         header = ((MonoMethodNormal *) mep->method)->header;
528         g_assert (header);
529
530         mep->entry->line_number_table_offset = lseek (priv->fd, 0, SEEK_CUR);
531         ++mep->entry->num_line_numbers;
532
533         lne.offset = 0;
534         lne.row = -1;
535
536         if (write (priv->fd, &lne, sizeof (MonoSymbolFileLineNumberEntry)) < 0) {
537                 priv->error = TRUE;
538                 return;
539         }
540
541         ip = start = header->code;
542         end = ip + header->code_size;
543
544         while (ip < end) {
545                 gchar *line;
546
547                 ++mep->entry->num_line_numbers;
548                 lne.offset = ip - start;
549                 lne.row = -1;
550
551                 if (write (priv->fd, &lne, sizeof (MonoSymbolFileLineNumberEntry)) < 0) {
552                         priv->error = TRUE;
553                         return;
554                 }
555
556                 line = mono_disasm_code_one (NULL, mep->method, ip, &ip);
557                 g_free (line);
558         }
559
560         mep->entry->address_table_offset = symfile->address_table_size;
561         mep->entry->address_table_size = sizeof (MonoSymbolFileMethodAddress) +
562                 mep->entry->num_line_numbers * sizeof (guint32);
563
564         symfile->address_table_size += mep->entry->address_table_size;
565 }
566
567 static void
568 create_methods (MonoSymbolFile *symfile)
569 {
570         MonoImage *image = symfile->_priv->image;
571         MonoTableInfo *table = &image->tables [MONO_TABLE_METHOD];
572         int idx;
573
574         for (idx = 1; idx <= table->rows; idx++) {
575                 guint32 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
576                 MonoMethod *method = mono_get_method (image, token, NULL);
577
578                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
579                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
580                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
581                         continue;
582
583                 if (method->wrapper_type != MONO_WRAPPER_NONE)
584                         continue;
585
586                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
587                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
588                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
589                         g_assert_not_reached ();
590
591                 if (!((MonoMethodNormal *) method)->header) {
592                         g_warning (G_STRLOC ": Internal error: method %s.%s doesn't have a header",
593                                    method->klass->name, method->name);
594                         continue;
595                 }
596
597                 create_method (symfile, token, method);
598         }
599 }
600
601 static void
602 load_line_numbers (gpointer key, gpointer value, gpointer user_data)
603 {
604         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
605         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
606
607         mep->minfo->num_il_offsets = mep->entry->num_line_numbers;
608         mep->minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
609                 (symfile->raw_contents + mep->entry->line_number_table_offset);
610 }
611
612 static int
613 create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings)
614 {
615         MonoSymbolFilePriv *priv = symfile->_priv;
616         char *ptr;
617         guint64 magic;
618         long version;
619         off_t offset;
620
621         priv->fd = g_file_open_tmp (NULL, &priv->file_name, NULL);
622         if (priv->fd == -1) {
623                 if (emit_warnings)
624                         g_warning ("Can't create symbol file");
625                 return FALSE;
626         }
627
628         magic = MONO_SYMBOL_FILE_MAGIC;
629         if (write (priv->fd, &magic, sizeof (magic)) < 0)
630                 return FALSE;
631
632         version = MONO_SYMBOL_FILE_VERSION;
633         if (write (priv->fd, &version, sizeof (version)) < 0)
634                 return FALSE;
635
636         offset = lseek (priv->fd, 0, SEEK_CUR);
637
638         priv->offset_table = g_new0 (MonoSymbolFileOffsetTable, 1);
639         if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
640                 return FALSE;
641
642         //
643         // Write source file table.
644         //
645         if (priv->source_file) {
646                 priv->offset_table->source_table_offset = lseek (priv->fd, 0, SEEK_CUR);
647                 if (!write_string (priv->fd, priv->source_file))
648                         return FALSE;
649                 priv->offset_table->source_table_size = lseek (priv->fd, 0, SEEK_CUR) -
650                         priv->offset_table->source_table_offset;
651         }
652
653         //
654         // Create method table.
655         //
656
657         priv->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
658                                                     (GDestroyNotify) free_method_entry);
659         priv->method_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
660                                                    (GDestroyNotify) free_method_info);
661
662         create_methods (symfile);
663
664         //
665         // Write line numbers.
666         //
667
668         priv->offset_table->line_number_table_offset = lseek (priv->fd, 0, SEEK_CUR);
669
670         g_hash_table_foreach (priv->method_table, write_line_numbers, symfile);
671         if (priv->error)
672                 return FALSE;
673
674         priv->offset_table->line_number_table_size = lseek (priv->fd, 0, SEEK_CUR) -
675                 priv->offset_table->line_number_table_offset;
676
677         //
678         // Write method table.
679         //
680
681         priv->offset_table->method_table_offset = lseek (priv->fd, 0, SEEK_CUR);
682
683         g_hash_table_foreach (priv->method_table, write_method, symfile);
684         if (priv->error)
685                 return FALSE;
686
687         priv->offset_table->method_table_size = lseek (priv->fd, 0, SEEK_CUR) -
688                 priv->offset_table->method_table_offset;
689
690         //
691         // Write offset table.
692         //
693
694         symfile->raw_contents_size = lseek (priv->fd, 0, SEEK_CUR);
695         priv->offset_table->address_table_size = symfile->address_table_size;
696
697         lseek (priv->fd, offset, SEEK_SET);
698         if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
699                 return FALSE;
700
701         lseek (priv->fd, symfile->raw_contents_size, SEEK_SET);
702
703         ptr = mono_raw_buffer_load (priv->fd, TRUE, 0, symfile->raw_contents_size);
704         if (!ptr)
705                 return FALSE;
706
707         symfile->raw_contents = ptr;
708
709         //
710         // Load line number table.
711         //
712         g_hash_table_foreach (priv->method_table, load_line_numbers, symfile);
713         if (priv->error)
714                 return FALSE;
715
716         if (!write_string_table (symfile))
717                 return FALSE;
718
719         return TRUE;
720 }
721
722 MonoSymbolFile *
723 mono_debug_create_mono_symbol_file (MonoImage *image)
724 {
725         MonoSymbolFile *symfile;
726
727         symfile = g_new0 (MonoSymbolFile, 1);
728         symfile->magic = MONO_SYMBOL_FILE_MAGIC;
729         symfile->version = MONO_SYMBOL_FILE_VERSION;
730         symfile->is_dynamic = TRUE;
731         symfile->image_file = g_strdup (image->name);
732
733         symfile->_priv = g_new0 (MonoSymbolFilePriv, 1);
734         symfile->_priv->image = image;
735
736         if (!create_symfile (symfile, TRUE)) {
737                 mono_debug_close_mono_symbol_file (symfile);
738                 return NULL;
739         }
740
741         return symfile;
742 }
743
744 MonoDebugMethodInfo *
745 mono_debug_find_method (MonoSymbolFile *symfile, MonoMethod *method)
746 {
747         return g_hash_table_lookup (symfile->_priv->method_hash, method);
748 }
749
750 static void
751 write_method_name (gpointer key, gpointer value, gpointer user_data)
752 {
753         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
754         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
755         MonoSymbolFilePriv *priv = symfile->_priv;
756         guint8 *offset_ptr, *string_ptr;
757         guint32 offset;
758
759         offset = mep->method_name_offset + priv->string_offset_size;
760
761         offset_ptr = symfile->string_table + mep->index * 4;
762         string_ptr = symfile->string_table + offset;
763
764         *((guint32 *) offset_ptr) = offset;
765         strcpy (string_ptr, mep->name);
766 }
767
768 static int
769 write_string_table (MonoSymbolFile *symfile)
770 {
771         MonoSymbolFilePriv *priv = symfile->_priv;
772
773         priv->string_offset_size = priv->offset_table->method_count * 4;
774
775         symfile->string_table_size = priv->string_table_size + priv->string_offset_size;
776         symfile->string_table = g_malloc0 (symfile->string_table_size);
777
778         g_hash_table_foreach (symfile->_priv->method_table, write_method_name, symfile);
779         return TRUE;
780 }
781
782 MonoReflectionMethod *
783 ves_icall_MonoDebugger_GetMethod (MonoReflectionAssembly *assembly, guint32 token)
784 {
785         MonoMethod *method;
786
787         method = mono_get_method (assembly->assembly->image, token, NULL);
788
789         return mono_method_get_object (mono_domain_get (), method, NULL);
790 }