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