2002-04-25 Martin Baulig <martin@gnome.org>
[mono.git] / mono / metadata / debug-symfile.c
1 #include <config.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <mono/metadata/metadata.h>
5 #include <mono/metadata/rawbuffer.h>
6 #include <mono/metadata/appdomain.h>
7 #include <mono/metadata/exception.h>
8 #include <mono/metadata/debug-symfile.h>
9
10 #include <fcntl.h>
11 #include <unistd.h>
12
13 #ifdef HAVE_ELF_H
14 #include <elf.h>
15 #endif
16
17 /* Keep in sync with Mono.CSharp.Debugger.MonoDwarfFileWriter */
18 #define MRT_none                        0x00
19 #define MRT_target_address_size         0x01
20 #define MRT_il_offset                   0x02
21 #define MRT_method_start_address        0x03
22 #define MRT_method_end_address          0x04
23 #define MRT_local_variable              0x05
24 #define MRT_method_parameter            0x06
25 #define MRT_type_sizeof                 0x07
26 #define MRT_type_field_offset           0x08
27 #define MRT_mono_string_sizeof          0x09
28 #define MRT_mono_string_offset          0x0a
29 #define MRT_mono_array_sizeof           0x0b
30 #define MRT_mono_array_offset           0x0c
31 #define MRT_mono_array_bounds_sizeof    0x0d
32 #define MRT_mono_array_bounds_offset    0x0e
33 #define MRT_variable_start_scope        0x0f
34 #define MRT_variable_end_scope          0x10
35 #define MRT_mono_string_fieldsize       0x11
36 #define MRT_mono_array_fieldsize        0x12
37 #define MRT_type_field_fieldsize        0x13
38
39 #define MRI_string_offset_length        0x00
40 #define MRI_string_offset_chars         0x01
41
42 #define MRI_array_offset_bounds         0x00
43 #define MRI_array_offset_max_length     0x01
44 #define MRI_array_offset_vector         0x02
45
46 #define MRI_array_bounds_offset_lower   0x00
47 #define MRI_array_bounds_offset_length  0x01
48
49 #define MRS_debug_info                  0x01
50 #define MRS_debug_abbrev                0x02
51 #define MRS_debug_line                  0x03
52 #define MRS_mono_reloc_table            0x04
53
54 #define DW_OP_const4s                   0x0d
55 #define DW_OP_plus                      0x22
56 #define DW_OP_reg0                      0x50
57 #define DW_OP_breg0                     0x70
58 #define DW_OP_fbreg                     0x91
59 #define DW_OP_piece                     0x93
60 #define DW_OP_nop                       0x96
61
62 #ifdef HAVE_ELF_H
63
64 static gboolean
65 get_sections_elf32 (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
66 {
67         Elf32_Ehdr *header;
68         Elf32_Shdr *section, *strtab_section;
69         const char *strtab;
70         int i;
71
72         header = (Elf32_Ehdr *)symfile->raw_contents;
73         if (header->e_version != EV_CURRENT) {
74                 if (emit_warnings)
75                         g_warning ("Symbol file %s has unknown ELF version %d",
76                                    symfile->file_name, header->e_version);
77                 return FALSE;
78         }
79
80         if (header->e_machine != EM_386) {
81                 if (emit_warnings)
82                         g_warning ("ELF file %s is for unknown architecture %d",
83                                    symfile->file_name, header->e_machine);
84                 return FALSE;
85         }
86
87         if (header->e_shentsize != sizeof (*section)) {
88                 if (emit_warnings)
89                         g_warning ("ELF file %s has unknown section header size "
90                                    "(expected %d, got %d)", symfile->file_name,
91                                    sizeof (*section), header->e_shentsize);
92                 return FALSE;
93         }
94
95         symfile->section_offsets = g_new0 (MonoDebugSymbolFileSection, MONO_DEBUG_SYMBOL_SECTION_MAX);
96
97         section = (Elf32_Shdr *)(symfile->raw_contents + header->e_shoff);
98         strtab_section = section + header->e_shstrndx;
99         strtab = symfile->raw_contents + strtab_section->sh_offset;
100
101         for (i = 0; i < header->e_shnum; i++, section++) {
102                 const gchar *name = strtab + section->sh_name;
103
104                 if (!strcmp (name, ".debug_info")) {
105                         MonoDebugSymbolFileSection *sfs;
106
107                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_INFO];
108                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_INFO;
109                         sfs->file_offset = section->sh_offset;
110                         sfs->size = section->sh_size;
111                 } else if (!strcmp (name, ".debug_line")) {
112                         MonoDebugSymbolFileSection *sfs;
113
114                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_LINE];
115                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_LINE;
116                         sfs->file_offset = section->sh_offset;
117                         sfs->size = section->sh_size;
118                 } else if (!strcmp (name, ".debug_abbrev")) {
119                         MonoDebugSymbolFileSection *sfs;
120
121                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_ABBREV];
122                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_ABBREV;
123                         sfs->file_offset = section->sh_offset;
124                         sfs->size = section->sh_size;
125                 } else if (!strcmp (name, ".mono_reloc_table")) {
126                         MonoDebugSymbolFileSection *sfs;
127
128                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE];
129                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE;
130                         sfs->file_offset = section->sh_offset;
131                         sfs->size = section->sh_size;
132                 }
133         }
134
135         return TRUE;
136 }
137
138 #endif /* HAVE_ELF_H */
139
140 static gboolean
141 get_sections (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
142 {
143 #ifdef HAVE_ELF_H
144 #ifdef __FreeBSD__
145         static const char ELFMAG[] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, 0 };
146 #endif
147         if (!strncmp (symfile->raw_contents, ELFMAG, strlen (ELFMAG)))
148                 return get_sections_elf32 (symfile, emit_warnings);
149 #endif
150
151         if (emit_warnings)
152                 g_warning ("Symbol file %s has unknown file format", symfile->file_name);
153
154         return FALSE;
155 }
156
157 static MonoClass *
158 mono_debug_class_get (MonoDebugSymbolFile *symfile, guint32 type_token)
159 {
160         MonoClass *klass;
161
162         if ((klass = g_hash_table_lookup (symfile->image->class_cache, GUINT_TO_POINTER (type_token))))
163                 return klass;
164
165         return NULL;
166 }
167
168 MonoDebugSymbolFile *
169 mono_debug_open_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
170 {
171         MonoDebugSymbolFile *symfile;
172         off_t file_size;
173         void *ptr;
174         int fd;
175
176         fd = open (filename, O_RDWR);
177         if (fd == -1) {
178                 if (emit_warnings)
179                         g_warning ("Can't open symbol file: %s", filename);
180                 return NULL;
181         }
182
183         file_size = lseek (fd, 0, SEEK_END);
184         lseek (fd, 0, SEEK_SET);
185
186         if (file_size == (off_t) -1) {
187                 if (emit_warnings)
188                         g_warning ("Can't get size of symbol file: %s", filename);
189                 return NULL;
190         }
191
192         ptr = mono_raw_buffer_load (fd, 1, 0, file_size);
193         if (!ptr) {
194                 if (emit_warnings)
195                         g_warning ("Can't read symbol file: %s", filename);
196                 return NULL;
197         }
198
199         symfile = g_new0 (MonoDebugSymbolFile, 1);
200         symfile->fd = fd;
201         symfile->file_name = g_strdup (filename);
202         symfile->image = image;
203         symfile->raw_contents = ptr;
204         symfile->raw_contents_size = file_size;
205
206         if (!get_sections (symfile, emit_warnings)) {
207                 mono_debug_close_symbol_file (symfile);
208                 return NULL;
209         }
210
211         return symfile;
212 }
213
214 void
215 mono_debug_close_symbol_file (MonoDebugSymbolFile *symfile)
216 {
217         if (!symfile)
218                 return;
219
220         if (symfile->raw_contents)
221                 mono_raw_buffer_free (symfile->raw_contents);
222         if (symfile->fd)
223                 close (symfile->fd);
224
225         g_free (symfile->file_name);
226         g_free (symfile->section_offsets);
227         g_free (symfile);
228 }
229
230 static void
231 relocate_variable (MonoDebugVarInfo *var, void *base_ptr)
232 {
233         if (!var) {
234                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
235                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
236                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
237                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
238                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
239                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
240                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
241                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
242                 return;
243         }
244                 
245         /*
246          * Update the location description for a local variable or method parameter.
247          * MCS always reserves 8 bytes for us to do this, if we don't need them all
248          * we just fill up the rest with DW_OP_nop's.
249          */
250
251         switch (var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) {
252         case MONO_DEBUG_VAR_ADDRESS_MODE_STACK:
253                 /*
254                  * Variable is on the stack.
255                  *
256                  * If `index' is zero, use the normal frame register.  Otherwise, bits
257                  * 0..4 of `index' contain the frame register.
258                  *
259                  * Both DW_OP_fbreg and DW_OP_breg0 ... DW_OP_breg31 take an ULeb128
260                  * argument - since this has an variable size, we set it to zero and
261                  * manually add a 4 byte constant using DW_OP_plus.
262                  */
263                 if (!var->index)
264                         /* Use the normal frame register (%ebp on the i386). */
265                         * ((guint8 *) base_ptr)++ = DW_OP_fbreg;
266                 else
267                         /* Use a custom frame register. */
268                         * ((guint8 *) base_ptr)++ = DW_OP_breg0 + (var->index & 0x001f);
269                 * ((guint8 *) base_ptr)++ = 0;
270                 * ((guint8 *) base_ptr)++ = DW_OP_const4s;
271                 * ((gint32 *) base_ptr)++ = var->offset;
272                 * ((guint8 *) base_ptr)++ = DW_OP_plus;
273                 break;
274
275         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
276                 /*
277                  * Variable is in the register whose number is contained in bits 0..4
278                  * of `index'.
279                  *
280                  * We need to write exactly 8 bytes in this location description, so instead
281                  * of filling up the rest with DW_OP_nop's just add the `offset' even if
282                  * it's zero.
283                  */
284                 * ((guint8 *) base_ptr)++ = DW_OP_reg0 + (var->index & 0x001f);
285                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
286                 * ((guint8 *) base_ptr)++ = DW_OP_const4s;
287                 * ((gint32 *) base_ptr)++ = var->offset;
288                 * ((guint8 *) base_ptr)++ = DW_OP_plus;
289                 break;
290
291         case MONO_DEBUG_VAR_ADDRESS_MODE_TWO_REGISTERS:
292                 /*
293                  * Variable is in two registers whose numbers are in bits 0..4 and 5..9 of 
294                  * the `index' field.  Don't add `offset' since we have only two bytes left,
295                  * fill them up with DW_OP_nop's.
296                  */
297                 * ((guint8 *) base_ptr)++ = DW_OP_reg0 + (var->index & 0x001f);
298                 * ((guint8 *) base_ptr)++ = DW_OP_piece;
299                 * ((guint8 *) base_ptr)++ = sizeof (int);
300                 * ((guint8 *) base_ptr)++ = DW_OP_reg0 + ((var->index & 0x1f0) >> 5);
301                 * ((guint8 *) base_ptr)++ = DW_OP_piece;
302                 * ((guint8 *) base_ptr)++ = sizeof (int);
303                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
304                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
305                 break;
306
307         default:
308                 g_assert_not_reached ();
309         }
310 }
311
312 void
313 mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
314                                MonoDebugMethodInfoFunc method_info_func,
315                                gpointer  user_data)
316 {
317         const char *reloc_ptr, *reloc_start, *reloc_end;
318         int version, already_relocated = 0;
319         long reloc_size;
320
321         if (!symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE].file_offset)
322                 return;
323
324         reloc_ptr = reloc_start = symfile->raw_contents +
325                 symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE].file_offset;
326
327         version = *((guint16 *) reloc_ptr)++;
328         if (version != MONO_DEBUG_SYMBOL_FILE_VERSION) {
329                 g_warning ("Symbol file %s has incorrect relocation table version "
330                            "(expected %d, got %d)", symfile->file_name,
331                            MONO_DEBUG_SYMBOL_FILE_VERSION, version);
332                 return;
333         }
334
335         already_relocated = *reloc_ptr;
336         *((char *) reloc_ptr)++ = 1;
337
338         reloc_size = *((guint32 *) reloc_ptr)++;
339         reloc_end = reloc_ptr + reloc_size;
340
341         while (reloc_ptr < reloc_end) {
342                 int type, size, section, offset;
343                 const char *tmp_ptr;
344                 char *base_ptr;
345
346                 type = *reloc_ptr++;
347                 size = * ((guint32 *) reloc_ptr)++;
348
349                 tmp_ptr = reloc_ptr;
350                 reloc_ptr += size;
351
352                 section = *tmp_ptr++;
353                 offset = *((guint32 *) tmp_ptr)++;
354
355                 if (section >= MONO_DEBUG_SYMBOL_SECTION_MAX) {
356                         g_warning ("Symbol file %s contains a relocation entry for unknown section %d",
357                                    symfile->file_name, section);
358                         continue;
359                 }
360
361                 if (!symfile->section_offsets [section].file_offset) {
362                         g_warning ("Symbol file %s contains a relocation entry for non-existing "
363                                    "section %d", symfile->file_name, section);
364                         continue;
365                 }
366
367                 base_ptr = symfile->raw_contents + symfile->section_offsets [section].file_offset;
368                 base_ptr = base_ptr + offset;
369
370                 switch (type) {
371                 case MRT_target_address_size:
372                         * (guint8 *) base_ptr = sizeof (void *);
373                         break;
374                 case MRT_method_start_address: {
375                         int token = *((guint32 *) tmp_ptr)++;
376                         MonoDebugMethodInfo *minfo;
377
378                         minfo = method_info_func (symfile, token, user_data);
379
380                         if (!minfo) {
381                                 * (void **) base_ptr = 0;
382                                 continue;
383                         }
384
385 #if 0
386                         g_message ("Start of `%s' relocated to %p", minfo->method->name, minfo->code_start);
387 #endif
388
389                         * (void **) base_ptr = minfo->code_start;
390
391                         break;
392                 }
393                 case MRT_method_end_address: {
394                         int token = *((guint32 *) tmp_ptr)++;
395                         MonoDebugMethodInfo *minfo;
396
397                         minfo = method_info_func (symfile, token, user_data);
398
399                         if (!minfo) {
400                                 * (void **) base_ptr = 0;
401                                 continue;
402                         }
403
404                         * (void **) base_ptr = (char *)minfo->code_start + minfo->code_size;
405
406                         break;
407                 }
408                 case MRT_il_offset: {
409                         guint32 token = *((guint32 *) tmp_ptr)++;
410                         guint32 original = *((guint32 *) tmp_ptr)++;
411                         MonoDebugMethodInfo *minfo;
412                         guint32 address;
413                         int i;
414
415                         minfo = method_info_func (symfile, token, user_data);
416
417                         if (!minfo) {
418                                 * (void **) base_ptr = 0;
419                                 continue;
420                         }
421
422                         address = minfo->code_size;
423
424                         for (i = 0; i < minfo->num_il_offsets; i++) {
425                                 MonoDebugILOffsetInfo *il = &minfo->il_offsets [i];
426
427                                 if (il->offset >= original) {
428                                         address = il->address;
429                                         break;
430                                 }
431                         }
432
433 #if 0
434                         g_message ("Relocating IL offset %04x in `%s' to %d (%p)",
435                                    original, minfo->method->name, address,
436                                    minfo->code_start + address);
437 #endif
438
439                         * (void **) base_ptr = minfo->code_start + address;
440
441                         break;
442                 }
443                 case MRT_local_variable: {
444                         guint32 token = *((guint32 *) tmp_ptr)++;
445                         guint32 original = *((guint32 *) tmp_ptr)++;
446                         MonoDebugMethodInfo *minfo;
447
448                         minfo = method_info_func (symfile, token, user_data);
449
450                         if (!minfo) {
451                                 relocate_variable (NULL, base_ptr);
452                                 continue;
453                         }
454
455                         if (original > minfo->num_locals) {
456                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
457                                            "local variable %d, but method %s only has %d local variables.",
458                                            symfile->file_name, original, minfo->method->name,
459                                            minfo->num_locals);
460                                 continue;
461                         }
462
463                         relocate_variable (&minfo->locals [original], base_ptr);
464
465                         break;
466                 }
467                 case MRT_method_parameter: {
468                         guint32 token = *((guint32 *) tmp_ptr)++;
469                         guint32 original = *((guint32 *) tmp_ptr)++;
470                         MonoDebugMethodInfo *minfo;
471
472                         minfo = method_info_func (symfile, token, user_data);
473
474                         if (!minfo) {
475                                 relocate_variable (NULL, base_ptr);
476                                 continue;
477                         }
478
479                         if (minfo->method->signature->hasthis) {
480                                 if (original == 0) {
481                                         relocate_variable (minfo->this_var, base_ptr);
482                                         continue;
483                                 }
484
485                                 original--;
486                         }
487
488                         if (original > minfo->num_params) {
489                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
490                                            "parameter %d, but method %s only has %d parameters.",
491                                            symfile->file_name, original, minfo->method->name,
492                                            minfo->num_params);
493                                 continue;
494                         }
495
496                         relocate_variable (&minfo->params [original], base_ptr);
497
498                         break;
499                 }
500                 case MRT_type_sizeof: {
501                         guint32 token = *((guint32 *) tmp_ptr)++;
502                         MonoClass *klass = mono_debug_class_get (symfile, token);
503
504                         if (!klass)
505                                 continue;
506
507                         mono_class_init (klass);
508
509                         if (klass->enumtype || klass->valuetype)
510                                 * (gint8 *) base_ptr = klass->instance_size - sizeof (MonoObject);
511                         else
512                                 * (gint8 *) base_ptr = klass->instance_size;
513
514                         break;
515                 }
516                 case MRT_type_field_offset: {
517                         guint32 token = *((guint32 *) tmp_ptr)++;
518                         guint32 original = *((guint32 *) tmp_ptr)++;
519                         MonoClass *klass = mono_debug_class_get (symfile, token);
520                         guint32 off;
521
522                         if (!klass)
523                                 continue;
524
525                         mono_class_init (klass);
526
527                         if (original > klass->field.count) {
528                                 g_warning ("Symbol file %s contains invalid field offset entry.",
529                                            symfile->file_name);
530                                 continue;
531                         }
532
533                         if (!klass->fields)
534                                 continue;
535
536                         off = klass->fields [original].offset;
537                         if (klass->byval_arg.type == MONO_TYPE_VALUETYPE)
538                                 off -= sizeof (MonoObject);
539
540 #if 0
541                         g_message ("Setting field %d of type %u to offset %d", original,
542                                    token, off);
543 #endif
544
545                         * (guint32 *) base_ptr = off;
546
547                         break;
548                 }
549                 case MRT_mono_string_sizeof:
550                         * (gint8 *) base_ptr = sizeof (MonoString);
551                         break;
552
553                 case MRT_mono_string_offset: {
554                         guint32 idx = *((guint32 *) tmp_ptr)++;
555                         MonoString string;
556                         guint32 off;
557
558                         switch (idx) {
559                         case MRI_string_offset_length:
560                                 off = (guchar *) &string.length - (guchar *) &string;
561                                 break;
562
563                         case MRI_string_offset_chars:
564                                 off = (guchar *) &string.chars - (guchar *) &string;
565                                 break;
566
567                         default:
568                                 g_warning ("Symbol file %s contains invalid string offset entry",
569                                            symfile->file_name);
570                                 continue;
571                         }
572
573                         * (guint32 *) base_ptr = off;
574
575                         break;
576                 }
577                 case MRT_mono_array_sizeof:
578                         * (gint8 *) base_ptr = sizeof (MonoArray);
579                         break;
580
581                 case MRT_mono_array_offset: {
582                         guint32 idx = *((guint32 *) tmp_ptr)++;
583                         MonoArray array;
584                         guint32 off;
585
586                         switch (idx) {
587                         case MRI_array_offset_bounds:
588                                 off = (guchar *) &array.bounds - (guchar *) &array;
589                                 break;
590
591                         case MRI_array_offset_max_length:
592                                 off = (guchar *) &array.max_length - (guchar *) &array;
593                                 break;
594
595                         case MRI_array_offset_vector:
596                                 off = (guchar *) &array.vector - (guchar *) &array;
597                                 break;
598
599                         default:
600                                 g_warning ("Symbol file %s contains invalid array offset entry",
601                                            symfile->file_name);
602                                 continue;
603                         }
604
605                         * (guint32 *) base_ptr = off;
606
607                         break;
608                 }
609
610                 case MRT_mono_array_bounds_sizeof:
611                         * (gint8 *) base_ptr = sizeof (MonoArrayBounds);
612                         break;
613
614                 case MRT_mono_array_bounds_offset: {
615                         guint32 idx = *((guint32 *) tmp_ptr)++;
616                         MonoArrayBounds bounds;
617                         guint32 off;
618
619                         switch (idx) {
620                         case MRI_array_bounds_offset_lower:
621                                 off = (guchar *) &bounds.lower_bound - (guchar *) &bounds;
622                                 break;
623
624                         case MRI_array_bounds_offset_length:
625                                 off = (guchar *) &bounds.length - (guchar *) &bounds;
626                                 break;
627
628                         default:
629                                 g_warning ("Symbol file %s contains invalid array bounds offset entry",
630                                            symfile->file_name);
631                                 continue;
632                         }
633
634                         * (guint32 *) base_ptr = off;
635
636                         break;
637                 }
638
639                 case MRT_variable_start_scope:  {
640                         guint32 token = *((guint32 *) tmp_ptr)++;
641                         guint32 original = *((guint32 *) tmp_ptr)++;
642                         MonoDebugMethodInfo *minfo;
643                         gint32 address;
644
645                         minfo = method_info_func (symfile, token, user_data);
646
647                         if (!minfo) {
648                                 * (void **) base_ptr = 0;
649                                 continue;
650                         }
651
652                         if (original > minfo->num_locals) {
653                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
654                                            "local variable %d, but method %s only has %d local variables.",
655                                            symfile->file_name, original, minfo->method->name,
656                                            minfo->num_locals);
657                                 continue;
658                         }
659
660                         address = minfo->locals [original].begin_scope;
661
662                         * (void **) base_ptr = minfo->code_start + address;
663
664                         break;
665                 }
666
667                 case MRT_variable_end_scope:  {
668                         guint32 token = *((guint32 *) tmp_ptr)++;
669                         guint32 original = *((guint32 *) tmp_ptr)++;
670                         MonoDebugMethodInfo *minfo;
671                         gint32 address;
672
673                         minfo = method_info_func (symfile, token, user_data);
674
675                         if (!minfo) {
676                                 * (void **) base_ptr = 0;
677                                 continue;
678                         }
679
680                         if (original > minfo->num_locals) {
681                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
682                                            "local variable %d, but method %s only has %d local variables.",
683                                            symfile->file_name, original, minfo->method->name,
684                                            minfo->num_locals);
685                                 continue;
686                         }
687
688                         address = minfo->locals [original].end_scope;
689
690                         * (void **) base_ptr = minfo->code_start + address;
691
692                         break;
693                 }
694
695                 case MRT_mono_string_fieldsize: {
696                         guint32 idx = *((guint32 *) tmp_ptr)++;
697                         MonoString string;
698                         guint32 fieldsize;
699
700                         switch (idx) {
701                         case MRI_string_offset_length:
702                                 fieldsize = sizeof (string.length);
703                                 break;
704
705                         default:
706                                 g_warning ("Symbol file %s contains invalid string fieldsize entry",
707                                            symfile->file_name);
708                                 continue;
709                         }
710
711                         * (guint32 *) base_ptr = fieldsize;
712
713                         break;
714                 }
715
716                 case MRT_mono_array_fieldsize: {
717                         guint32 idx = *((guint32 *) tmp_ptr)++;
718                         MonoArray array;
719                         guint32 fieldsize;
720
721                         switch (idx) {
722                         case MRI_array_offset_bounds:
723                                 fieldsize = sizeof (array.bounds);
724                                 break;
725
726                         case MRI_array_offset_max_length:
727                                 fieldsize = sizeof (array.max_length);
728                                 break;
729
730                         case MRI_array_offset_vector:
731                                 fieldsize = sizeof (array.vector);
732                                 break;
733
734                         default:
735                                 g_warning ("Symbol file %s contains invalid array fieldsize entry",
736                                            symfile->file_name);
737                                 continue;
738                         }
739
740                         * (guint32 *) base_ptr = fieldsize;
741
742                         break;
743                 }
744
745
746                 default:
747                         g_warning ("Symbol file %s contains unknown relocation entry %d",
748                                    symfile->file_name, type);
749                         break;
750                 }
751         }
752
753         mono_raw_buffer_update (symfile->raw_contents, symfile->raw_contents_size);
754 }
755
756 MonoReflectionType *
757 ves_icall_Debugger_MonoSymbolWriter_get_local_type_from_sig (MonoReflectionAssembly *assembly,
758                                                              MonoArray *signature)
759 {
760         MonoDomain *domain; 
761         MonoImage *image;
762         MonoType *type;
763         const char *ptr;
764         int len = 0;
765
766         MONO_CHECK_ARG_NULL (assembly);
767         MONO_CHECK_ARG_NULL (signature);
768
769         domain = mono_domain_get();
770         image = assembly->assembly->image;
771
772         ptr = mono_array_addr (signature, char, 0);
773         g_assert (*ptr++ == 0x07);
774         len = mono_metadata_decode_value (ptr, &ptr);
775         g_assert (len == 1);
776
777         type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
778
779         return mono_type_get_object (domain, type);
780 }
781
782 MonoReflectionMethod *
783 ves_icall_Debugger_MonoSymbolWriter_method_from_token (MonoReflectionAssembly *assembly, guint32 token)
784 {
785         MonoDomain *domain; 
786         MonoImage *image;
787         MonoMethod *method;
788
789         MONO_CHECK_ARG_NULL (assembly);
790
791         domain = mono_domain_get();
792         image = assembly->assembly->image;
793
794         method = mono_get_method (image, token, NULL);
795
796         return mono_method_get_object (domain, method);
797 }
798
799 guint32
800 ves_icall_Debugger_DwarfFileWriter_get_type_token (MonoReflectionType *type)
801 {
802         MonoClass *klass = mono_class_from_mono_type (type->type);
803
804         mono_class_init (klass);
805
806         return klass->type_token;
807 }