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