Fri May 31 16:58:36 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 <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
41 #define MRI_string_offset_length        0x00
42 #define MRI_string_offset_chars         0x01
43
44 #define MRI_array_offset_bounds         0x00
45 #define MRI_array_offset_max_length     0x01
46 #define MRI_array_offset_vector         0x02
47
48 #define MRI_array_bounds_offset_lower   0x00
49 #define MRI_array_bounds_offset_length  0x01
50
51 #define MRS_debug_info                  0x01
52 #define MRS_debug_abbrev                0x02
53 #define MRS_debug_line                  0x03
54 #define MRS_mono_reloc_table            0x04
55
56 #define DW_OP_const4s                   0x0d
57 #define DW_OP_plus                      0x22
58 #define DW_OP_reg0                      0x50
59 #define DW_OP_breg0                     0x70
60 #define DW_OP_fbreg                     0x91
61 #define DW_OP_piece                     0x93
62 #define DW_OP_nop                       0x96
63
64 #ifdef HAVE_ELF_H
65
66 static gboolean
67 get_sections_elf32 (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
68 {
69         Elf32_Ehdr *header;
70         Elf32_Shdr *section, *strtab_section;
71         const char *strtab;
72         int i;
73
74         header = (Elf32_Ehdr *)symfile->raw_contents;
75         if (header->e_version != EV_CURRENT) {
76                 if (emit_warnings)
77                         g_warning ("Symbol file %s has unknown ELF version %d",
78                                    symfile->file_name, header->e_version);
79                 return FALSE;
80         }
81
82         if (header->e_machine != EM_386) {
83                 if (emit_warnings)
84                         g_warning ("ELF file %s is for unknown architecture %d",
85                                    symfile->file_name, header->e_machine);
86                 return FALSE;
87         }
88
89         if (header->e_shentsize != sizeof (*section)) {
90                 if (emit_warnings)
91                         g_warning ("ELF file %s has unknown section header size "
92                                    "(expected %d, got %d)", symfile->file_name,
93                                    sizeof (*section), header->e_shentsize);
94                 return FALSE;
95         }
96
97         symfile->section_offsets = g_new0 (MonoDebugSymbolFileSection, MONO_DEBUG_SYMBOL_SECTION_MAX);
98
99         section = (Elf32_Shdr *)(symfile->raw_contents + header->e_shoff);
100         strtab_section = section + header->e_shstrndx;
101         strtab = symfile->raw_contents + strtab_section->sh_offset;
102
103         for (i = 0; i < header->e_shnum; i++, section++) {
104                 const gchar *name = strtab + section->sh_name;
105
106                 if (!strcmp (name, ".debug_info")) {
107                         MonoDebugSymbolFileSection *sfs;
108
109                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_INFO];
110                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_INFO;
111                         sfs->file_offset = section->sh_offset;
112                         sfs->size = section->sh_size;
113                 } else if (!strcmp (name, ".debug_line")) {
114                         MonoDebugSymbolFileSection *sfs;
115
116                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_LINE];
117                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_LINE;
118                         sfs->file_offset = section->sh_offset;
119                         sfs->size = section->sh_size;
120                 } else if (!strcmp (name, ".debug_abbrev")) {
121                         MonoDebugSymbolFileSection *sfs;
122
123                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_ABBREV];
124                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_ABBREV;
125                         sfs->file_offset = section->sh_offset;
126                         sfs->size = section->sh_size;
127                 } else if (!strcmp (name, ".mono_reloc_table")) {
128                         MonoDebugSymbolFileSection *sfs;
129
130                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE];
131                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE;
132                         sfs->file_offset = section->sh_offset;
133                         sfs->size = section->sh_size;
134                 } else if (!strcmp (name, ".mono_line_numbers")) {
135                         MonoDebugSymbolFileSection *sfs;
136
137                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS];
138                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS;
139                         sfs->file_offset = section->sh_offset;
140                         sfs->size = section->sh_size;
141                 }
142         }
143
144         return TRUE;
145 }
146
147 #endif /* HAVE_ELF_H */
148
149 static gboolean
150 get_sections (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
151 {
152 #ifdef HAVE_ELF_H
153 #ifdef __FreeBSD__
154         static const char ELFMAG[] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, 0 };
155 #endif
156         if (!strncmp (symfile->raw_contents, ELFMAG, strlen (ELFMAG)))
157                 return get_sections_elf32 (symfile, emit_warnings);
158 #endif
159
160         if (emit_warnings)
161                 g_warning ("Symbol file %s has unknown file format", symfile->file_name);
162
163         return FALSE;
164 }
165
166 static void
167 read_line_numbers (MonoDebugSymbolFile *symfile)
168 {
169         const char *ptr, *start, *end;
170         int version;
171         long section_size;
172
173         if (!symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset)
174                 return;
175
176         ptr = start = symfile->raw_contents +
177                 symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset;
178
179         version = *((guint16 *) ptr)++;
180         if (version != MONO_DEBUG_SYMBOL_FILE_VERSION) {
181                 g_warning ("Symbol file %s has incorrect line number table version "
182                            "(expected %d, got %d)", symfile->file_name,
183                            MONO_DEBUG_SYMBOL_FILE_VERSION, version);
184                 return;
185         }
186
187         section_size = *((guint32 *) ptr)++;
188         end = ptr + section_size;
189
190         symfile->line_number_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
191                                                             NULL, (GDestroyNotify) g_free);
192
193         while (ptr < end) {
194                 MonoDebugLineNumberBlock *lnb;
195                 guint32 token, source_offset;
196                 MonoMethod *method;
197
198                 token = * ((guint32 *) ptr)++;
199                 method = mono_get_method (symfile->image, token, NULL);
200                 if (!method)
201                         continue;
202
203                 lnb = g_new0 (MonoDebugLineNumberBlock, 1);
204                 lnb->token = token;
205                 source_offset = * ((guint32 *) ptr)++;
206                 lnb->source_file = (const char *) start + source_offset;
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' (%ld) relocated to %p", minfo->method->name,
448                                    token, minfo->code_start);
449 #endif
450
451                         * (void **) base_ptr = minfo->code_start;
452
453                         break;
454                 }
455                 case MRT_method_end_address: {
456                         int token = *((guint32 *) tmp_ptr)++;
457                         MonoDebugMethodInfo *minfo;
458
459                         minfo = method_info_func (symfile, token, user_data);
460
461                         if (!minfo) {
462                                 * (void **) base_ptr = 0;
463                                 continue;
464                         }
465
466                         * (void **) base_ptr = (char *)minfo->code_start + minfo->code_size;
467
468                         break;
469                 }
470                 case MRT_il_offset: {
471                         guint32 token = *((guint32 *) tmp_ptr)++;
472                         guint32 original = *((guint32 *) tmp_ptr)++;
473                         MonoDebugMethodInfo *minfo;
474                         guint32 address;
475                         int i;
476
477                         minfo = method_info_func (symfile, token, user_data);
478
479                         if (!minfo) {
480                                 * (void **) base_ptr = 0;
481                                 continue;
482                         }
483
484                         address = minfo->code_size;
485
486                         for (i = 0; i < minfo->num_il_offsets; i++) {
487                                 MonoDebugILOffsetInfo *il = &minfo->il_offsets [i];
488
489                                 if (il->offset >= original) {
490                                         address = il->address;
491                                         break;
492                                 }
493                         }
494
495 #if 0
496                         g_message ("Relocating IL offset %04x in `%s' to %d (%p)",
497                                    original, minfo->method->name, address,
498                                    minfo->code_start + address);
499 #endif
500
501                         * (void **) base_ptr = minfo->code_start + address;
502
503                         break;
504                 }
505                 case MRT_local_variable: {
506                         guint32 token = *((guint32 *) tmp_ptr)++;
507                         guint32 original = *((guint32 *) tmp_ptr)++;
508                         MonoDebugMethodInfo *minfo;
509
510                         minfo = method_info_func (symfile, token, user_data);
511
512                         if (!minfo) {
513                                 relocate_variable (NULL, base_ptr);
514                                 continue;
515                         }
516
517                         if (original > minfo->num_locals) {
518                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
519                                            "local variable %d, but method %s only has %d local variables.",
520                                            symfile->file_name, original, minfo->method->name,
521                                            minfo->num_locals);
522                                 g_message (G_STRLOC ": %d", token);
523                                 G_BREAKPOINT ();
524                                 continue;
525                         }
526
527                         relocate_variable (&minfo->locals [original], base_ptr);
528
529                         break;
530                 }
531                 case MRT_method_parameter: {
532                         guint32 token = *((guint32 *) tmp_ptr)++;
533                         guint32 original = *((guint32 *) tmp_ptr)++;
534                         MonoDebugMethodInfo *minfo;
535
536                         minfo = method_info_func (symfile, token, user_data);
537
538                         if (!minfo) {
539                                 relocate_variable (NULL, base_ptr);
540                                 continue;
541                         }
542
543                         if (minfo->method->signature->hasthis) {
544                                 if (original == 0) {
545                                         relocate_variable (minfo->this_var, base_ptr);
546                                         continue;
547                                 }
548
549                                 original--;
550                         }
551
552                         if (original > minfo->num_params) {
553                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
554                                            "parameter %d, but method %s only has %d parameters.",
555                                            symfile->file_name, original, minfo->method->name,
556                                            minfo->num_params);
557                                 continue;
558                         }
559
560                         relocate_variable (&minfo->params [original], base_ptr);
561
562                         break;
563                 }
564                 case MRT_type_sizeof: {
565                         guint32 token = *((guint32 *) tmp_ptr)++;
566                         MonoClass *klass = mono_debug_class_get (symfile, token);
567
568                         if (!klass)
569                                 continue;
570
571                         mono_class_init (klass);
572
573                         if (klass->enumtype || klass->valuetype)
574                                 * (gint8 *) base_ptr = klass->instance_size - sizeof (MonoObject);
575                         else
576                                 * (gint8 *) base_ptr = klass->instance_size;
577
578                         break;
579                 }
580                 case MRT_type_field_offset: {
581                         guint32 token = *((guint32 *) tmp_ptr)++;
582                         guint32 original = *((guint32 *) tmp_ptr)++;
583                         MonoClass *klass = mono_debug_class_get (symfile, token);
584                         guint32 off;
585
586                         if (!klass)
587                                 continue;
588
589                         mono_class_init (klass);
590
591                         if (original > klass->field.count) {
592                                 g_warning ("Symbol file %s contains invalid field offset entry.",
593                                            symfile->file_name);
594                                 g_message (G_STRLOC ": %d", token);
595                                 /* G_BREAKPOINT (); */
596                                 continue;
597                         }
598
599                         if (!klass->fields)
600                                 continue;
601
602                         off = klass->fields [original].offset;
603                         if (klass->byval_arg.type == MONO_TYPE_VALUETYPE)
604                                 off -= sizeof (MonoObject);
605
606 #if 0
607                         g_message ("Setting field %d of type %u to offset %d", original,
608                                    token, off);
609 #endif
610
611                         * (guint32 *) base_ptr = off;
612
613                         break;
614                 }
615                 case MRT_mono_string_sizeof:
616                         * (gint8 *) base_ptr = sizeof (MonoString);
617                         break;
618
619                 case MRT_mono_string_offset: {
620                         guint32 idx = *((guint32 *) tmp_ptr)++;
621                         MonoString string;
622                         guint32 off;
623
624                         switch (idx) {
625                         case MRI_string_offset_length:
626                                 off = (guchar *) &string.length - (guchar *) &string;
627                                 break;
628
629                         case MRI_string_offset_chars:
630                                 off = (guchar *) &string.chars - (guchar *) &string;
631                                 break;
632
633                         default:
634                                 g_warning ("Symbol file %s contains invalid string offset entry",
635                                            symfile->file_name);
636                                 continue;
637                         }
638
639                         * (guint32 *) base_ptr = off;
640
641                         break;
642                 }
643                 case MRT_mono_array_sizeof:
644                         * (gint8 *) base_ptr = sizeof (MonoArray);
645                         break;
646
647                 case MRT_mono_array_offset: {
648                         guint32 idx = *((guint32 *) tmp_ptr)++;
649                         MonoArray array;
650                         guint32 off;
651
652                         switch (idx) {
653                         case MRI_array_offset_bounds:
654                                 off = (guchar *) &array.bounds - (guchar *) &array;
655                                 break;
656
657                         case MRI_array_offset_max_length:
658                                 off = (guchar *) &array.max_length - (guchar *) &array;
659                                 break;
660
661                         case MRI_array_offset_vector:
662                                 off = (guchar *) &array.vector - (guchar *) &array;
663                                 break;
664
665                         default:
666                                 g_warning ("Symbol file %s contains invalid array offset entry",
667                                            symfile->file_name);
668                                 continue;
669                         }
670
671                         * (guint32 *) base_ptr = off;
672
673                         break;
674                 }
675
676                 case MRT_mono_array_bounds_sizeof:
677                         * (gint8 *) base_ptr = sizeof (MonoArrayBounds);
678                         break;
679
680                 case MRT_mono_array_bounds_offset: {
681                         guint32 idx = *((guint32 *) tmp_ptr)++;
682                         MonoArrayBounds bounds;
683                         guint32 off;
684
685                         switch (idx) {
686                         case MRI_array_bounds_offset_lower:
687                                 off = (guchar *) &bounds.lower_bound - (guchar *) &bounds;
688                                 break;
689
690                         case MRI_array_bounds_offset_length:
691                                 off = (guchar *) &bounds.length - (guchar *) &bounds;
692                                 break;
693
694                         default:
695                                 g_warning ("Symbol file %s contains invalid array bounds offset entry",
696                                            symfile->file_name);
697                                 continue;
698                         }
699
700                         * (guint32 *) base_ptr = off;
701
702                         break;
703                 }
704
705                 case MRT_variable_start_scope:  {
706                         guint32 token = *((guint32 *) tmp_ptr)++;
707                         guint32 original = *((guint32 *) tmp_ptr)++;
708                         MonoDebugMethodInfo *minfo;
709                         gint32 address;
710
711                         minfo = method_info_func (symfile, token, user_data);
712
713                         if (!minfo || !minfo->locals) {
714                                 * (void **) base_ptr = 0;
715                                 continue;
716                         }
717
718                         if (original > minfo->num_locals) {
719                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
720                                            "local variable %d, but method %s only has %d local variables.",
721                                            symfile->file_name, original, minfo->method->name,
722                                            minfo->num_locals);
723                                 continue;
724                         }
725
726                         address = minfo->locals [original].begin_scope;
727
728                         * (void **) base_ptr = minfo->code_start + address;
729
730                         break;
731                 }
732
733                 case MRT_variable_end_scope:  {
734                         guint32 token = *((guint32 *) tmp_ptr)++;
735                         guint32 original = *((guint32 *) tmp_ptr)++;
736                         MonoDebugMethodInfo *minfo;
737                         gint32 address;
738
739                         minfo = method_info_func (symfile, token, user_data);
740
741                         if (!minfo || !minfo->locals) {
742                                 * (void **) base_ptr = 0;
743                                 continue;
744                         }
745
746                         if (original > minfo->num_locals) {
747                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
748                                            "local variable %d, but method %s only has %d local variables.",
749                                            symfile->file_name, original, minfo->method->name,
750                                            minfo->num_locals);
751                                 continue;
752                         }
753
754                         address = minfo->locals [original].end_scope;
755
756                         * (void **) base_ptr = minfo->code_start + address;
757
758                         break;
759                 }
760
761                 case MRT_mono_string_fieldsize: {
762                         guint32 idx = *((guint32 *) tmp_ptr)++;
763                         MonoString string;
764                         guint32 fieldsize;
765
766                         switch (idx) {
767                         case MRI_string_offset_length:
768                                 fieldsize = sizeof (string.length);
769                                 break;
770
771                         default:
772                                 g_warning ("Symbol file %s contains invalid string fieldsize entry",
773                                            symfile->file_name);
774                                 continue;
775                         }
776
777                         * (guint32 *) base_ptr = fieldsize;
778
779                         break;
780                 }
781
782                 case MRT_mono_array_fieldsize: {
783                         guint32 idx = *((guint32 *) tmp_ptr)++;
784                         MonoArray array;
785                         guint32 fieldsize;
786
787                         switch (idx) {
788                         case MRI_array_offset_bounds:
789                                 fieldsize = sizeof (array.bounds);
790                                 break;
791
792                         case MRI_array_offset_max_length:
793                                 fieldsize = sizeof (array.max_length);
794                                 break;
795
796                         case MRI_array_offset_vector:
797                                 fieldsize = sizeof (array.vector);
798                                 break;
799
800                         default:
801                                 g_warning ("Symbol file %s contains invalid array fieldsize entry",
802                                            symfile->file_name);
803                                 continue;
804                         }
805
806                         * (guint32 *) base_ptr = fieldsize;
807
808                         break;
809                 }
810
811
812                 default:
813                         g_warning ("Symbol file %s contains unknown relocation entry %d",
814                                    symfile->file_name, type);
815                         break;
816                 }
817         }
818
819         mono_raw_buffer_update (symfile->raw_contents, symfile->raw_contents_size);
820 }
821
822 gchar *
823 mono_debug_find_source_location (MonoDebugSymbolFile *symfile, MonoMethod *method, guint32 offset)
824 {
825         MonoDebugLineNumberBlock *lnb;
826         const char *ptr;
827
828         if (!symfile->line_number_table)
829                 return NULL;
830
831         lnb = g_hash_table_lookup (symfile->line_number_table, method);
832         if (!lnb)
833                 return NULL;
834
835         ptr = symfile->raw_contents +
836                 symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset;
837
838         ptr += lnb->file_offset;
839
840         do {
841                 guint32 row, iloffset;
842
843                 row = * ((guint32 *) ptr)++;
844                 iloffset = * ((guint32 *) ptr)++;
845
846                 if (!row && !offset)
847                         return NULL;
848                 if (!row)
849                         continue;
850
851                 if (iloffset >= offset)
852                         return g_strdup_printf ("%s:%d", lnb->source_file, row);
853         } while (1);
854
855         return NULL;
856 }