2002-04-23 Patrik Torstensson <patrik.torstensson@labs2.com>
[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_vector        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_vector:
564                                 // fixme: don know how to fix this
565                                 g_assert_not_reached ();
566                                 //off = (guchar *) &string.c_str - (guchar *) &string;
567                                 break;
568
569                         default:
570                                 g_warning ("Symbol file %s contains invalid string offset entry",
571                                            symfile->file_name);
572                                 continue;
573                         }
574
575                         * (guint32 *) base_ptr = off;
576
577                         break;
578                 }
579                 case MRT_mono_array_sizeof:
580                         * (gint8 *) base_ptr = sizeof (MonoArray);
581                         break;
582
583                 case MRT_mono_array_offset: {
584                         guint32 idx = *((guint32 *) tmp_ptr)++;
585                         MonoArray array;
586                         guint32 off;
587
588                         switch (idx) {
589                         case MRI_array_offset_bounds:
590                                 off = (guchar *) &array.bounds - (guchar *) &array;
591                                 break;
592
593                         case MRI_array_offset_max_length:
594                                 off = (guchar *) &array.max_length - (guchar *) &array;
595                                 break;
596
597                         case MRI_array_offset_vector:
598                                 off = (guchar *) &array.vector - (guchar *) &array;
599                                 break;
600
601                         default:
602                                 g_warning ("Symbol file %s contains invalid array offset entry",
603                                            symfile->file_name);
604                                 continue;
605                         }
606
607                         * (guint32 *) base_ptr = off;
608
609                         break;
610                 }
611
612                 case MRT_mono_array_bounds_sizeof:
613                         * (gint8 *) base_ptr = sizeof (MonoArrayBounds);
614                         break;
615
616                 case MRT_mono_array_bounds_offset: {
617                         guint32 idx = *((guint32 *) tmp_ptr)++;
618                         MonoArrayBounds bounds;
619                         guint32 off;
620
621                         switch (idx) {
622                         case MRI_array_bounds_offset_lower:
623                                 off = (guchar *) &bounds.lower_bound - (guchar *) &bounds;
624                                 break;
625
626                         case MRI_array_bounds_offset_length:
627                                 off = (guchar *) &bounds.length - (guchar *) &bounds;
628                                 break;
629
630                         default:
631                                 g_warning ("Symbol file %s contains invalid array bounds offset entry",
632                                            symfile->file_name);
633                                 continue;
634                         }
635
636                         * (guint32 *) base_ptr = off;
637
638                         break;
639                 }
640
641                 case MRT_variable_start_scope:  {
642                         guint32 token = *((guint32 *) tmp_ptr)++;
643                         guint32 original = *((guint32 *) tmp_ptr)++;
644                         MonoDebugMethodInfo *minfo;
645                         gint32 address;
646
647                         minfo = method_info_func (symfile, token, user_data);
648
649                         if (!minfo) {
650                                 * (void **) base_ptr = 0;
651                                 continue;
652                         }
653
654                         if (original > minfo->num_locals) {
655                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
656                                            "local variable %d, but method %s only has %d local variables.",
657                                            symfile->file_name, original, minfo->method->name,
658                                            minfo->num_locals);
659                                 continue;
660                         }
661
662                         address = minfo->locals [original].begin_scope;
663
664                         * (void **) base_ptr = minfo->code_start + address;
665
666                         break;
667                 }
668
669                 case MRT_variable_end_scope:  {
670                         guint32 token = *((guint32 *) tmp_ptr)++;
671                         guint32 original = *((guint32 *) tmp_ptr)++;
672                         MonoDebugMethodInfo *minfo;
673                         gint32 address;
674
675                         minfo = method_info_func (symfile, token, user_data);
676
677                         if (!minfo) {
678                                 * (void **) base_ptr = 0;
679                                 continue;
680                         }
681
682                         if (original > minfo->num_locals) {
683                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
684                                            "local variable %d, but method %s only has %d local variables.",
685                                            symfile->file_name, original, minfo->method->name,
686                                            minfo->num_locals);
687                                 continue;
688                         }
689
690                         address = minfo->locals [original].end_scope;
691
692                         * (void **) base_ptr = minfo->code_start + address;
693
694                         break;
695                 }
696
697                 case MRT_mono_string_fieldsize: {
698                         guint32 idx = *((guint32 *) tmp_ptr)++;
699                         MonoString string;
700                         guint32 fieldsize;
701
702                         switch (idx) {
703                         case MRI_string_offset_length:
704                                 fieldsize = sizeof (string.length);
705                                 break;
706
707                         case MRI_string_offset_vector:
708                                 // fixme:
709                                 //fieldsize = sizeof (string.c_str);
710                                 g_assert_not_reached ();
711                                 break;
712
713                         default:
714                                 g_warning ("Symbol file %s contains invalid string fieldsize entry",
715                                            symfile->file_name);
716                                 continue;
717                         }
718
719                         * (guint32 *) base_ptr = fieldsize;
720
721                         break;
722                 }
723
724                 case MRT_mono_array_fieldsize: {
725                         guint32 idx = *((guint32 *) tmp_ptr)++;
726                         MonoArray array;
727                         guint32 fieldsize;
728
729                         switch (idx) {
730                         case MRI_array_offset_bounds:
731                                 fieldsize = sizeof (array.bounds);
732                                 break;
733
734                         case MRI_array_offset_max_length:
735                                 fieldsize = sizeof (array.max_length);
736                                 break;
737
738                         case MRI_array_offset_vector:
739                                 fieldsize = sizeof (array.vector);
740                                 break;
741
742                         default:
743                                 g_warning ("Symbol file %s contains invalid array fieldsize entry",
744                                            symfile->file_name);
745                                 continue;
746                         }
747
748                         * (guint32 *) base_ptr = fieldsize;
749
750                         break;
751                 }
752
753
754                 default:
755                         g_warning ("Symbol file %s contains unknown relocation entry %d",
756                                    symfile->file_name, type);
757                         break;
758                 }
759         }
760
761         mono_raw_buffer_update (symfile->raw_contents, symfile->raw_contents_size);
762 }
763
764 MonoReflectionType *
765 ves_icall_Debugger_MonoSymbolWriter_get_local_type_from_sig (MonoReflectionAssembly *assembly,
766                                                              MonoArray *signature)
767 {
768         MonoDomain *domain; 
769         MonoImage *image;
770         MonoType *type;
771         const char *ptr;
772         int len = 0;
773
774         MONO_CHECK_ARG_NULL (assembly);
775         MONO_CHECK_ARG_NULL (signature);
776
777         domain = mono_domain_get();
778         image = assembly->assembly->image;
779
780         ptr = mono_array_addr (signature, char, 0);
781         g_assert (*ptr++ == 0x07);
782         len = mono_metadata_decode_value (ptr, &ptr);
783         g_assert (len == 1);
784
785         type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
786
787         return mono_type_get_object (domain, type);
788 }
789
790 MonoReflectionMethod *
791 ves_icall_Debugger_MonoSymbolWriter_method_from_token (MonoReflectionAssembly *assembly, guint32 token)
792 {
793         MonoDomain *domain; 
794         MonoImage *image;
795         MonoMethod *method;
796
797         MONO_CHECK_ARG_NULL (assembly);
798
799         domain = mono_domain_get();
800         image = assembly->assembly->image;
801
802         method = mono_get_method (image, token, NULL);
803
804         return mono_method_get_object (domain, method);
805 }
806
807 guint32
808 ves_icall_Debugger_DwarfFileWriter_get_type_token (MonoReflectionType *type)
809 {
810         MonoClass *klass = mono_class_from_mono_type (type->type);
811
812         mono_class_init (klass);
813
814         return klass->type_token;
815 }