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