2002-05-21 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                 } else if (!strcmp (name, ".mono_line_numbers")) {
133                         MonoDebugSymbolFileSection *sfs;
134
135                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS];
136                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS;
137                         sfs->file_offset = section->sh_offset;
138                         sfs->size = section->sh_size;
139                 }
140         }
141
142         return TRUE;
143 }
144
145 #endif /* HAVE_ELF_H */
146
147 static gboolean
148 get_sections (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
149 {
150 #ifdef HAVE_ELF_H
151 #ifdef __FreeBSD__
152         static const char ELFMAG[] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, 0 };
153 #endif
154         if (!strncmp (symfile->raw_contents, ELFMAG, strlen (ELFMAG)))
155                 return get_sections_elf32 (symfile, emit_warnings);
156 #endif
157
158         if (emit_warnings)
159                 g_warning ("Symbol file %s has unknown file format", symfile->file_name);
160
161         return FALSE;
162 }
163
164 static void
165 read_line_numbers (MonoDebugSymbolFile *symfile)
166 {
167         const char *ptr, *start, *end;
168         int version;
169         long section_size;
170
171         if (!symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset)
172                 return;
173
174         ptr = start = symfile->raw_contents +
175                 symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset;
176
177         version = *((guint16 *) ptr)++;
178         if (version != MONO_DEBUG_SYMBOL_FILE_VERSION) {
179                 g_warning ("Symbol file %s has incorrect line number table version "
180                            "(expected %d, got %d)", symfile->file_name,
181                            MONO_DEBUG_SYMBOL_FILE_VERSION, version);
182                 return;
183         }
184
185         section_size = *((guint32 *) ptr)++;
186         end = ptr + section_size;
187
188         symfile->line_number_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
189                                                             NULL, (GDestroyNotify) g_free);
190
191         while (ptr < end) {
192                 MonoDebugLineNumberBlock *lnb;
193                 guint32 token, length;
194                 MonoMethod *method;
195
196                 token = * ((guint32 *) ptr)++;
197                 method = mono_get_method (symfile->image, token, NULL);
198                 if (!method)
199                         continue;
200
201                 lnb = g_new0 (MonoDebugLineNumberBlock, 1);
202                 lnb->token = token;
203                 lnb->source_file_idx = * ((guint32 *) ptr)++;
204                 length = * ((guint32 *) ptr)++;
205                 lnb->source_file = (const char *) ptr;
206                 ptr += length;
207                 lnb->start_line = * ((guint32 *) ptr)++;
208                 lnb->file_offset = * ((guint32 *) ptr)++;
209
210                 g_hash_table_insert (symfile->line_number_table, method, lnb);
211         }
212 }
213
214 static MonoClass *
215 mono_debug_class_get (MonoDebugSymbolFile *symfile, guint32 type_token)
216 {
217         MonoClass *klass;
218
219         if ((klass = g_hash_table_lookup (symfile->image->class_cache, GUINT_TO_POINTER (type_token))))
220                 return klass;
221
222         return NULL;
223 }
224
225 MonoDebugSymbolFile *
226 mono_debug_open_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
227 {
228         MonoDebugSymbolFile *symfile;
229         off_t file_size;
230         void *ptr;
231         int fd;
232
233         fd = open (filename, O_RDWR);
234         if (fd == -1) {
235                 if (emit_warnings)
236                         g_warning ("Can't open symbol file: %s", filename);
237                 return NULL;
238         }
239
240         file_size = lseek (fd, 0, SEEK_END);
241         lseek (fd, 0, SEEK_SET);
242
243         if (file_size == (off_t) -1) {
244                 if (emit_warnings)
245                         g_warning ("Can't get size of symbol file: %s", filename);
246                 return NULL;
247         }
248
249         ptr = mono_raw_buffer_load (fd, 1, 0, file_size);
250         if (!ptr) {
251                 if (emit_warnings)
252                         g_warning ("Can't read symbol file: %s", filename);
253                 return NULL;
254         }
255
256         symfile = g_new0 (MonoDebugSymbolFile, 1);
257         symfile->fd = fd;
258         symfile->file_name = g_strdup (filename);
259         symfile->image = image;
260         symfile->raw_contents = ptr;
261         symfile->raw_contents_size = file_size;
262
263         if (!get_sections (symfile, emit_warnings)) {
264                 mono_debug_close_symbol_file (symfile);
265                 return NULL;
266         }
267
268         read_line_numbers (symfile);
269
270         return symfile;
271 }
272
273 void
274 mono_debug_close_symbol_file (MonoDebugSymbolFile *symfile)
275 {
276         if (!symfile)
277                 return;
278
279         if (symfile->raw_contents)
280                 mono_raw_buffer_free (symfile->raw_contents);
281         if (symfile->fd)
282                 close (symfile->fd);
283
284         if (symfile->line_number_table)
285                 g_hash_table_destroy (symfile->line_number_table);
286         g_free (symfile->file_name);
287         g_free (symfile->section_offsets);
288         g_free (symfile);
289 }
290
291 static void
292 relocate_variable (MonoDebugVarInfo *var, void *base_ptr)
293 {
294         if (!var) {
295                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
296                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
297                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
298                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
299                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
300                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
301                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
302                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
303                 return;
304         }
305                 
306         /*
307          * Update the location description for a local variable or method parameter.
308          * MCS always reserves 8 bytes for us to do this, if we don't need them all
309          * we just fill up the rest with DW_OP_nop's.
310          */
311
312         switch (var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) {
313         case MONO_DEBUG_VAR_ADDRESS_MODE_STACK:
314                 /*
315                  * Variable is on the stack.
316                  *
317                  * If `index' is zero, use the normal frame register.  Otherwise, bits
318                  * 0..4 of `index' contain the frame register.
319                  *
320                  * Both DW_OP_fbreg and DW_OP_breg0 ... DW_OP_breg31 take an ULeb128
321                  * argument - since this has an variable size, we set it to zero and
322                  * manually add a 4 byte constant using DW_OP_plus.
323                  */
324                 if (!var->index)
325                         /* Use the normal frame register (%ebp on the i386). */
326                         * ((guint8 *) base_ptr)++ = DW_OP_fbreg;
327                 else
328                         /* Use a custom frame register. */
329                         * ((guint8 *) base_ptr)++ = DW_OP_breg0 + (var->index & 0x001f);
330                 * ((guint8 *) base_ptr)++ = 0;
331                 * ((guint8 *) base_ptr)++ = DW_OP_const4s;
332                 * ((gint32 *) base_ptr)++ = var->offset;
333                 * ((guint8 *) base_ptr)++ = DW_OP_plus;
334                 break;
335
336         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
337                 /*
338                  * Variable is in the register whose number is contained in bits 0..4
339                  * of `index'.
340                  *
341                  * We need to write exactly 8 bytes in this location description, so instead
342                  * of filling up the rest with DW_OP_nop's just add the `offset' even if
343                  * it's zero.
344                  */
345                 * ((guint8 *) base_ptr)++ = DW_OP_reg0 + (var->index & 0x001f);
346                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
347                 * ((guint8 *) base_ptr)++ = DW_OP_const4s;
348                 * ((gint32 *) base_ptr)++ = var->offset;
349                 * ((guint8 *) base_ptr)++ = DW_OP_plus;
350                 break;
351
352         case MONO_DEBUG_VAR_ADDRESS_MODE_TWO_REGISTERS:
353                 /*
354                  * Variable is in two registers whose numbers are in bits 0..4 and 5..9 of 
355                  * the `index' field.  Don't add `offset' since we have only two bytes left,
356                  * fill them up with DW_OP_nop's.
357                  */
358                 * ((guint8 *) base_ptr)++ = DW_OP_reg0 + (var->index & 0x001f);
359                 * ((guint8 *) base_ptr)++ = DW_OP_piece;
360                 * ((guint8 *) base_ptr)++ = sizeof (int);
361                 * ((guint8 *) base_ptr)++ = DW_OP_reg0 + ((var->index & 0x1f0) >> 5);
362                 * ((guint8 *) base_ptr)++ = DW_OP_piece;
363                 * ((guint8 *) base_ptr)++ = sizeof (int);
364                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
365                 * ((guint8 *) base_ptr)++ = DW_OP_nop;
366                 break;
367
368         default:
369                 g_assert_not_reached ();
370         }
371 }
372
373 void
374 mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
375                                MonoDebugMethodInfoFunc method_info_func,
376                                gpointer  user_data)
377 {
378         const char *reloc_ptr, *reloc_start, *reloc_end;
379         int version, already_relocated = 0;
380         long reloc_size;
381
382         if (!symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE].file_offset)
383                 return;
384
385         reloc_ptr = reloc_start = symfile->raw_contents +
386                 symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE].file_offset;
387
388         version = *((guint16 *) reloc_ptr)++;
389         if (version != MONO_DEBUG_SYMBOL_FILE_VERSION) {
390                 g_warning ("Symbol file %s has incorrect relocation table version "
391                            "(expected %d, got %d)", symfile->file_name,
392                            MONO_DEBUG_SYMBOL_FILE_VERSION, version);
393                 return;
394         }
395
396         already_relocated = *reloc_ptr;
397         *((char *) reloc_ptr)++ = 1;
398
399         reloc_size = *((guint32 *) reloc_ptr)++;
400         reloc_end = reloc_ptr + reloc_size;
401
402         while (reloc_ptr < reloc_end) {
403                 int type, size, section, offset;
404                 const char *tmp_ptr;
405                 char *base_ptr;
406
407                 type = *reloc_ptr++;
408                 size = * ((guint32 *) reloc_ptr)++;
409
410                 tmp_ptr = reloc_ptr;
411                 reloc_ptr += size;
412
413                 section = *tmp_ptr++;
414                 offset = *((guint32 *) tmp_ptr)++;
415
416                 if (section >= MONO_DEBUG_SYMBOL_SECTION_MAX) {
417                         g_warning ("Symbol file %s contains a relocation entry for unknown section %d",
418                                    symfile->file_name, section);
419                         continue;
420                 }
421
422                 if (!symfile->section_offsets [section].file_offset) {
423                         g_warning ("Symbol file %s contains a relocation entry for non-existing "
424                                    "section %d", symfile->file_name, section);
425                         continue;
426                 }
427
428                 base_ptr = symfile->raw_contents + symfile->section_offsets [section].file_offset;
429                 base_ptr = base_ptr + offset;
430
431                 switch (type) {
432                 case MRT_target_address_size:
433                         * (guint8 *) base_ptr = sizeof (void *);
434                         break;
435                 case MRT_method_start_address: {
436                         int token = *((guint32 *) tmp_ptr)++;
437                         MonoDebugMethodInfo *minfo;
438
439                         minfo = method_info_func (symfile, token, user_data);
440
441                         if (!minfo) {
442                                 * (void **) base_ptr = 0;
443                                 continue;
444                         }
445
446 #if 0
447                         g_message ("Start of `%s' relocated to %p", minfo->method->name, minfo->code_start);
448 #endif
449
450                         * (void **) base_ptr = minfo->code_start;
451
452                         break;
453                 }
454                 case MRT_method_end_address: {
455                         int token = *((guint32 *) tmp_ptr)++;
456                         MonoDebugMethodInfo *minfo;
457
458                         minfo = method_info_func (symfile, token, user_data);
459
460                         if (!minfo) {
461                                 * (void **) base_ptr = 0;
462                                 continue;
463                         }
464
465                         * (void **) base_ptr = (char *)minfo->code_start + minfo->code_size;
466
467                         break;
468                 }
469                 case MRT_il_offset: {
470                         guint32 token = *((guint32 *) tmp_ptr)++;
471                         guint32 original = *((guint32 *) tmp_ptr)++;
472                         MonoDebugMethodInfo *minfo;
473                         guint32 address;
474                         int i;
475
476                         minfo = method_info_func (symfile, token, user_data);
477
478                         if (!minfo) {
479                                 * (void **) base_ptr = 0;
480                                 continue;
481                         }
482
483                         address = minfo->code_size;
484
485                         for (i = 0; i < minfo->num_il_offsets; i++) {
486                                 MonoDebugILOffsetInfo *il = &minfo->il_offsets [i];
487
488                                 if (il->offset >= original) {
489                                         address = il->address;
490                                         break;
491                                 }
492                         }
493
494 #if 0
495                         g_message ("Relocating IL offset %04x in `%s' to %d (%p)",
496                                    original, minfo->method->name, address,
497                                    minfo->code_start + address);
498 #endif
499
500                         * (void **) base_ptr = minfo->code_start + address;
501
502                         break;
503                 }
504                 case MRT_local_variable: {
505                         guint32 token = *((guint32 *) tmp_ptr)++;
506                         guint32 original = *((guint32 *) tmp_ptr)++;
507                         MonoDebugMethodInfo *minfo;
508
509                         minfo = method_info_func (symfile, token, user_data);
510
511                         if (!minfo) {
512                                 relocate_variable (NULL, base_ptr);
513                                 continue;
514                         }
515
516                         if (original > minfo->num_locals) {
517                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
518                                            "local variable %d, but method %s only has %d local variables.",
519                                            symfile->file_name, original, minfo->method->name,
520                                            minfo->num_locals);
521                                 continue;
522                         }
523
524                         relocate_variable (&minfo->locals [original], base_ptr);
525
526                         break;
527                 }
528                 case MRT_method_parameter: {
529                         guint32 token = *((guint32 *) tmp_ptr)++;
530                         guint32 original = *((guint32 *) tmp_ptr)++;
531                         MonoDebugMethodInfo *minfo;
532
533                         minfo = method_info_func (symfile, token, user_data);
534
535                         if (!minfo) {
536                                 relocate_variable (NULL, base_ptr);
537                                 continue;
538                         }
539
540                         if (minfo->method->signature->hasthis) {
541                                 if (original == 0) {
542                                         relocate_variable (minfo->this_var, base_ptr);
543                                         continue;
544                                 }
545
546                                 original--;
547                         }
548
549                         if (original > minfo->num_params) {
550                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
551                                            "parameter %d, but method %s only has %d parameters.",
552                                            symfile->file_name, original, minfo->method->name,
553                                            minfo->num_params);
554                                 continue;
555                         }
556
557                         relocate_variable (&minfo->params [original], base_ptr);
558
559                         break;
560                 }
561                 case MRT_type_sizeof: {
562                         guint32 token = *((guint32 *) tmp_ptr)++;
563                         MonoClass *klass = mono_debug_class_get (symfile, token);
564
565                         if (!klass)
566                                 continue;
567
568                         mono_class_init (klass);
569
570                         if (klass->enumtype || klass->valuetype)
571                                 * (gint8 *) base_ptr = klass->instance_size - sizeof (MonoObject);
572                         else
573                                 * (gint8 *) base_ptr = klass->instance_size;
574
575                         break;
576                 }
577                 case MRT_type_field_offset: {
578                         guint32 token = *((guint32 *) tmp_ptr)++;
579                         guint32 original = *((guint32 *) tmp_ptr)++;
580                         MonoClass *klass = mono_debug_class_get (symfile, token);
581                         guint32 off;
582
583                         if (!klass)
584                                 continue;
585
586                         mono_class_init (klass);
587
588                         if (original > klass->field.count) {
589                                 g_warning ("Symbol file %s contains invalid field offset entry.",
590                                            symfile->file_name);
591                                 continue;
592                         }
593
594                         if (!klass->fields)
595                                 continue;
596
597                         off = klass->fields [original].offset;
598                         if (klass->byval_arg.type == MONO_TYPE_VALUETYPE)
599                                 off -= sizeof (MonoObject);
600
601 #if 0
602                         g_message ("Setting field %d of type %u to offset %d", original,
603                                    token, off);
604 #endif
605
606                         * (guint32 *) base_ptr = off;
607
608                         break;
609                 }
610                 case MRT_mono_string_sizeof:
611                         * (gint8 *) base_ptr = sizeof (MonoString);
612                         break;
613
614                 case MRT_mono_string_offset: {
615                         guint32 idx = *((guint32 *) tmp_ptr)++;
616                         MonoString string;
617                         guint32 off;
618
619                         switch (idx) {
620                         case MRI_string_offset_length:
621                                 off = (guchar *) &string.length - (guchar *) &string;
622                                 break;
623
624                         case MRI_string_offset_chars:
625                                 off = (guchar *) &string.chars - (guchar *) &string;
626                                 break;
627
628                         default:
629                                 g_warning ("Symbol file %s contains invalid string offset entry",
630                                            symfile->file_name);
631                                 continue;
632                         }
633
634                         * (guint32 *) base_ptr = off;
635
636                         break;
637                 }
638                 case MRT_mono_array_sizeof:
639                         * (gint8 *) base_ptr = sizeof (MonoArray);
640                         break;
641
642                 case MRT_mono_array_offset: {
643                         guint32 idx = *((guint32 *) tmp_ptr)++;
644                         MonoArray array;
645                         guint32 off;
646
647                         switch (idx) {
648                         case MRI_array_offset_bounds:
649                                 off = (guchar *) &array.bounds - (guchar *) &array;
650                                 break;
651
652                         case MRI_array_offset_max_length:
653                                 off = (guchar *) &array.max_length - (guchar *) &array;
654                                 break;
655
656                         case MRI_array_offset_vector:
657                                 off = (guchar *) &array.vector - (guchar *) &array;
658                                 break;
659
660                         default:
661                                 g_warning ("Symbol file %s contains invalid array offset entry",
662                                            symfile->file_name);
663                                 continue;
664                         }
665
666                         * (guint32 *) base_ptr = off;
667
668                         break;
669                 }
670
671                 case MRT_mono_array_bounds_sizeof:
672                         * (gint8 *) base_ptr = sizeof (MonoArrayBounds);
673                         break;
674
675                 case MRT_mono_array_bounds_offset: {
676                         guint32 idx = *((guint32 *) tmp_ptr)++;
677                         MonoArrayBounds bounds;
678                         guint32 off;
679
680                         switch (idx) {
681                         case MRI_array_bounds_offset_lower:
682                                 off = (guchar *) &bounds.lower_bound - (guchar *) &bounds;
683                                 break;
684
685                         case MRI_array_bounds_offset_length:
686                                 off = (guchar *) &bounds.length - (guchar *) &bounds;
687                                 break;
688
689                         default:
690                                 g_warning ("Symbol file %s contains invalid array bounds offset entry",
691                                            symfile->file_name);
692                                 continue;
693                         }
694
695                         * (guint32 *) base_ptr = off;
696
697                         break;
698                 }
699
700                 case MRT_variable_start_scope:  {
701                         guint32 token = *((guint32 *) tmp_ptr)++;
702                         guint32 original = *((guint32 *) tmp_ptr)++;
703                         MonoDebugMethodInfo *minfo;
704                         gint32 address;
705
706                         minfo = method_info_func (symfile, token, user_data);
707
708                         if (!minfo) {
709                                 * (void **) base_ptr = 0;
710                                 continue;
711                         }
712
713                         if (original > minfo->num_locals) {
714                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
715                                            "local variable %d, but method %s only has %d local variables.",
716                                            symfile->file_name, original, minfo->method->name,
717                                            minfo->num_locals);
718                                 continue;
719                         }
720
721                         address = minfo->locals [original].begin_scope;
722
723                         * (void **) base_ptr = minfo->code_start + address;
724
725                         break;
726                 }
727
728                 case MRT_variable_end_scope:  {
729                         guint32 token = *((guint32 *) tmp_ptr)++;
730                         guint32 original = *((guint32 *) tmp_ptr)++;
731                         MonoDebugMethodInfo *minfo;
732                         gint32 address;
733
734                         minfo = method_info_func (symfile, token, user_data);
735
736                         if (!minfo) {
737                                 * (void **) base_ptr = 0;
738                                 continue;
739                         }
740
741                         if (original > minfo->num_locals) {
742                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
743                                            "local variable %d, but method %s only has %d local variables.",
744                                            symfile->file_name, original, minfo->method->name,
745                                            minfo->num_locals);
746                                 continue;
747                         }
748
749                         address = minfo->locals [original].end_scope;
750
751                         * (void **) base_ptr = minfo->code_start + address;
752
753                         break;
754                 }
755
756                 case MRT_mono_string_fieldsize: {
757                         guint32 idx = *((guint32 *) tmp_ptr)++;
758                         MonoString string;
759                         guint32 fieldsize;
760
761                         switch (idx) {
762                         case MRI_string_offset_length:
763                                 fieldsize = sizeof (string.length);
764                                 break;
765
766                         default:
767                                 g_warning ("Symbol file %s contains invalid string fieldsize entry",
768                                            symfile->file_name);
769                                 continue;
770                         }
771
772                         * (guint32 *) base_ptr = fieldsize;
773
774                         break;
775                 }
776
777                 case MRT_mono_array_fieldsize: {
778                         guint32 idx = *((guint32 *) tmp_ptr)++;
779                         MonoArray array;
780                         guint32 fieldsize;
781
782                         switch (idx) {
783                         case MRI_array_offset_bounds:
784                                 fieldsize = sizeof (array.bounds);
785                                 break;
786
787                         case MRI_array_offset_max_length:
788                                 fieldsize = sizeof (array.max_length);
789                                 break;
790
791                         case MRI_array_offset_vector:
792                                 fieldsize = sizeof (array.vector);
793                                 break;
794
795                         default:
796                                 g_warning ("Symbol file %s contains invalid array fieldsize entry",
797                                            symfile->file_name);
798                                 continue;
799                         }
800
801                         * (guint32 *) base_ptr = fieldsize;
802
803                         break;
804                 }
805
806
807                 default:
808                         g_warning ("Symbol file %s contains unknown relocation entry %d",
809                                    symfile->file_name, type);
810                         break;
811                 }
812         }
813
814         mono_raw_buffer_update (symfile->raw_contents, symfile->raw_contents_size);
815 }
816
817 MonoReflectionType *
818 ves_icall_Debugger_MonoSymbolWriter_get_local_type_from_sig (MonoReflectionAssembly *assembly,
819                                                              MonoArray *signature)
820 {
821         MonoDomain *domain; 
822         MonoImage *image;
823         MonoType *type;
824         const char *ptr;
825         int len = 0;
826
827         MONO_CHECK_ARG_NULL (assembly);
828         MONO_CHECK_ARG_NULL (signature);
829
830         domain = mono_domain_get();
831         image = assembly->assembly->image;
832
833         ptr = mono_array_addr (signature, char, 0);
834         g_assert (*ptr++ == 0x07);
835         len = mono_metadata_decode_value (ptr, &ptr);
836         g_assert (len == 1);
837
838         type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
839
840         return mono_type_get_object (domain, type);
841 }
842
843 MonoReflectionMethod *
844 ves_icall_Debugger_MonoSymbolWriter_method_from_token (MonoReflectionAssembly *assembly, guint32 token)
845 {
846         MonoDomain *domain; 
847         MonoImage *image;
848         MonoMethod *method;
849
850         MONO_CHECK_ARG_NULL (assembly);
851
852         domain = mono_domain_get();
853         image = assembly->assembly->image;
854
855         method = mono_get_method (image, token, NULL);
856
857         return mono_method_get_object (domain, method);
858 }
859
860 guint32
861 ves_icall_Debugger_DwarfFileWriter_get_type_token (MonoReflectionType *type)
862 {
863         MonoClass *klass = mono_class_from_mono_type (type->type);
864
865         mono_class_init (klass);
866
867         return klass->type_token;
868 }
869
870 gchar *
871 mono_debug_find_source_location (MonoDebugSymbolFile *symfile, MonoMethod *method, guint32 offset)
872 {
873         MonoDebugLineNumberBlock *lnb;
874         const char *ptr;
875
876         if (!symfile->line_number_table)
877                 return NULL;
878
879         lnb = g_hash_table_lookup (symfile->line_number_table, method);
880         if (!lnb)
881                 return NULL;
882
883         ptr = symfile->raw_contents +
884                 symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset;
885
886         ptr += lnb->file_offset;
887
888         do {
889                 guint32 row, iloffset;
890
891                 row = * ((guint32 *) ptr)++;
892                 iloffset = * ((guint32 *) ptr)++;
893
894                 if (!row && !offset)
895                         return NULL;
896                 if (!row)
897                         continue;
898
899                 if (iloffset >= offset)
900                         return g_strdup_printf ("%s:%d", lnb->source_file, row);
901         } while (1);
902
903         return NULL;
904 }