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