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