fixed more compiler warnings
[mono.git] / mono / metadata / debug-symfile.c
1 #include <config.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <mono/metadata/metadata.h>
5 #include <mono/metadata/rawbuffer.h>
6 #include <mono/metadata/appdomain.h>
7 #include <mono/metadata/exception.h>
8 #include <mono/metadata/debug-symfile.h>
9
10 #include <fcntl.h>
11 #include <unistd.h>
12
13 #ifdef HAVE_ELF_H
14 #include <elf.h>
15 #endif
16
17 /* Keep in sync with Mono.CSharp.Debugger.MonoDwarfFileWriter */
18 #define MRT_none                        0x00
19 #define MRT_target_address_size         0x01
20 #define MRT_il_offset                   0x02
21 #define MRT_method_start_address        0x03
22 #define MRT_method_end_address          0x04
23 #define MRT_local_variable              0x05
24 #define MRT_method_parameter            0x06
25 #define MRT_type_sizeof                 0x07
26 #define MRT_type_field_offset           0x08
27 #define MRT_mono_string_sizeof          0x09
28 #define MRT_mono_string_offset          0x0a
29 #define MRT_mono_array_sizeof           0x0b
30 #define MRT_mono_array_offset           0x0c
31 #define MRT_mono_array_bounds_sizeof    0x0d
32 #define MRT_mono_array_bounds_offset    0x0e
33
34 #define MRI_string_offset_length        0x00
35 #define MRI_string_offset_vector        0x01
36
37 #define MRI_array_offset_bounds         0x00
38 #define MRI_array_offset_max_length     0x01
39 #define MRI_array_offset_vector         0x02
40
41 #define MRI_array_bounds_offset_lower   0x00
42 #define MRI_array_bounds_offset_length  0x01
43
44 #define MRS_debug_info                  0x01
45 #define MRS_debug_abbrev                0x02
46 #define MRS_debug_line                  0x03
47 #define MRS_mono_reloc_table            0x04
48
49 #ifdef HAVE_ELF_H
50
51 static gboolean
52 get_sections_elf32 (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
53 {
54         Elf32_Ehdr *header;
55         Elf32_Shdr *section, *strtab_section;
56         const char *strtab;
57         int i;
58
59         header = symfile->raw_contents;
60         if (header->e_version != EV_CURRENT) {
61                 if (emit_warnings)
62                         g_warning ("Symbol file %s has unknown ELF version %d",
63                                    symfile->file_name, header->e_version);
64                 return FALSE;
65         }
66
67         if (header->e_machine != EM_386) {
68                 if (emit_warnings)
69                         g_warning ("ELF file %s is for unknown architecture %d",
70                                    symfile->file_name, header->e_machine);
71                 return FALSE;
72         }
73
74         if (header->e_shentsize != sizeof (*section)) {
75                 if (emit_warnings)
76                         g_warning ("ELF file %s has unknown section header size "
77                                    "(expected %d, got %d)", symfile->file_name,
78                                    sizeof (*section), header->e_shentsize);
79                 return FALSE;
80         }
81
82         symfile->section_offsets = g_new0 (MonoDebugSymbolFileSection, MONO_DEBUG_SYMBOL_SECTION_MAX);
83
84         section = (Elf32_Shdr *)((char *)symfile->raw_contents + header->e_shoff);
85         strtab_section = section + header->e_shstrndx;
86         strtab = (char *)symfile->raw_contents + strtab_section->sh_offset;
87
88         for (i = 0; i < header->e_shnum; i++, section++) {
89                 const gchar *name = strtab + section->sh_name;
90
91                 if (!strcmp (name, ".debug_info")) {
92                         MonoDebugSymbolFileSection *sfs;
93
94                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_INFO];
95                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_INFO;
96                         sfs->file_offset = section->sh_offset;
97                         sfs->size = section->sh_size;
98                 } else if (!strcmp (name, ".debug_line")) {
99                         MonoDebugSymbolFileSection *sfs;
100
101                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_LINE];
102                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_LINE;
103                         sfs->file_offset = section->sh_offset;
104                         sfs->size = section->sh_size;
105                 } else if (!strcmp (name, ".debug_abbrev")) {
106                         MonoDebugSymbolFileSection *sfs;
107
108                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_ABBREV];
109                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_ABBREV;
110                         sfs->file_offset = section->sh_offset;
111                         sfs->size = section->sh_size;
112                 } else if (!strcmp (name, ".mono_reloc_table")) {
113                         MonoDebugSymbolFileSection *sfs;
114
115                         sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE];
116                         sfs->type = MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE;
117                         sfs->file_offset = section->sh_offset;
118                         sfs->size = section->sh_size;
119                 }
120         }
121
122         return TRUE;
123 }
124
125 #endif /* HAVE_ELF_H */
126
127 static gboolean
128 get_sections (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
129 {
130 #ifdef HAVE_ELF_H
131         if (!strncmp (symfile->raw_contents, ELFMAG, strlen (ELFMAG)))
132                 return get_sections_elf32 (symfile, emit_warnings);
133 #endif
134
135         if (emit_warnings)
136                 g_warning ("Symbol file %s has unknown file format", symfile->file_name);
137
138         return FALSE;
139 }
140
141 static MonoClass *
142 mono_debug_class_get (MonoDebugSymbolFile *symfile, guint32 type_token)
143 {
144         MonoClass *klass;
145
146         if ((klass = g_hash_table_lookup (symfile->image->class_cache, GUINT_TO_POINTER (type_token))))
147                 return klass;
148
149         return NULL;
150 }
151
152 MonoDebugSymbolFile *
153 mono_debug_open_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
154 {
155         MonoDebugSymbolFile *symfile;
156         off_t file_size;
157         void *ptr;
158         int fd;
159
160         fd = open (filename, O_RDWR);
161         if (fd == -1) {
162                 if (emit_warnings)
163                         g_warning ("Can't open symbol file: %s", filename);
164                 return NULL;
165         }
166
167         file_size = lseek (fd, 0, SEEK_END);
168         lseek (fd, 0, SEEK_SET);
169
170         if (file_size == (off_t) -1) {
171                 if (emit_warnings)
172                         g_warning ("Can't get size of symbol file: %s", filename);
173                 return NULL;
174         }
175
176         ptr = mono_raw_buffer_load (fd, 1, 0, file_size);
177         if (!ptr) {
178                 if (emit_warnings)
179                         g_warning ("Can't read symbol file: %s", filename);
180                 return NULL;
181         }
182
183         symfile = g_new0 (MonoDebugSymbolFile, 1);
184         symfile->fd = fd;
185         symfile->file_name = g_strdup (filename);
186         symfile->image = image;
187         symfile->raw_contents = ptr;
188         symfile->raw_contents_size = file_size;
189
190         if (!get_sections (symfile, emit_warnings)) {
191                 mono_debug_close_symbol_file (symfile);
192                 return NULL;
193         }
194
195         return symfile;
196 }
197
198 void
199 mono_debug_close_symbol_file (MonoDebugSymbolFile *symfile)
200 {
201         if (!symfile)
202                 return;
203
204         if (symfile->raw_contents)
205                 mono_raw_buffer_free (symfile->raw_contents);
206         if (symfile->fd)
207                 close (symfile->fd);
208
209         g_free (symfile->file_name);
210         g_free (symfile->section_offsets);
211         g_free (symfile);
212 }
213
214 void
215 mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
216                                MonoDebugMethodInfoFunc method_info_func,
217                                gpointer  user_data)
218 {
219         const char *reloc_ptr, *reloc_start, *reloc_end;
220         int version, already_relocated = 0;
221         long reloc_size;
222
223         if (!symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE].file_offset)
224                 return;
225
226         reloc_ptr = reloc_start = (char *)symfile->raw_contents +
227                 symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE].file_offset;
228
229         version = *((guint16 *) reloc_ptr)++;
230         if (version != MONO_DEBUG_SYMBOL_FILE_VERSION) {
231                 g_warning ("Symbol file %s has incorrect relocation table version "
232                            "(expected %d, got %d)", symfile->file_name,
233                            MONO_DEBUG_SYMBOL_FILE_VERSION, version);
234                 return;
235         }
236
237         already_relocated = *reloc_ptr;
238         *((char *) reloc_ptr)++ = 1;
239
240         reloc_size = *((guint32 *) reloc_ptr)++;
241         reloc_end = reloc_ptr + reloc_size;
242
243         while (reloc_ptr < reloc_end) {
244                 int type, size, section, offset;
245                 const char *tmp_ptr;
246                 void *base_ptr;
247
248                 type = *reloc_ptr++;
249                 size = * ((guint32 *) reloc_ptr)++;
250
251                 tmp_ptr = reloc_ptr;
252                 reloc_ptr += size;
253
254                 section = *tmp_ptr++;
255                 offset = *((guint32 *) tmp_ptr)++;
256
257                 if (section >= MONO_DEBUG_SYMBOL_SECTION_MAX) {
258                         g_warning ("Symbol file %s contains a relocation entry for unknown section %d",
259                                    symfile->file_name, section);
260                         continue;
261                 }
262
263                 if (!symfile->section_offsets [section].file_offset) {
264                         g_warning ("Symbol file %s contains a relocation entry for non-existing "
265                                    "section %d", symfile->file_name, section);
266                         continue;
267                 }
268
269                 base_ptr = (char *)symfile->raw_contents + symfile->section_offsets [section].file_offset;
270                 base_ptr = (char *)base_ptr + offset;
271
272                 switch (type) {
273                 case MRT_target_address_size:
274                         * (guint8 *) base_ptr = sizeof (void *);
275                         break;
276                 case MRT_method_start_address: {
277                         int token = *((guint32 *) tmp_ptr)++;
278                         MonoDebugMethodInfo *minfo;
279
280                         minfo = method_info_func (symfile, token, user_data);
281
282                         if (!minfo) {
283                                 * (void **) base_ptr = 0;
284                                 continue;
285                         }
286
287 #if 0
288                         g_message ("Start of `%s' relocated to %p", minfo->method->name, minfo->code_start);
289 #endif
290
291                         * (void **) base_ptr = minfo->code_start;
292
293                         break;
294                 }
295                 case MRT_method_end_address: {
296                         int token = *((guint32 *) tmp_ptr)++;
297                         MonoDebugMethodInfo *minfo;
298
299                         minfo = method_info_func (symfile, token, user_data);
300
301                         if (!minfo) {
302                                 * (void **) base_ptr = 0;
303                                 continue;
304                         }
305
306                         * (void **) base_ptr = (char *)minfo->code_start + minfo->code_size;
307
308                         break;
309                 }
310                 case MRT_il_offset: {
311                         guint32 token = *((guint32 *) tmp_ptr)++;
312                         guint32 original = *((guint32 *) tmp_ptr)++;
313                         MonoDebugMethodInfo *minfo;
314                         guint32 address;
315                         int i;
316
317                         minfo = method_info_func (symfile, token, user_data);
318
319                         if (!minfo) {
320                                 * (void **) base_ptr = 0;
321                                 continue;
322                         }
323
324                         address = minfo->code_size;
325
326                         for (i = 0; i < minfo->num_il_offsets; i++) {
327                                 MonoDebugILOffsetInfo *il = &minfo->il_offsets [i];
328
329                                 if (il->offset >= original) {
330                                         address = il->address;
331                                         break;
332                                 }
333                         }
334
335 #if 0
336                         g_message ("Relocating IL offset %04x in `%s' to %d (%p)",
337                                    original, minfo->method->name, address,
338                                    minfo->code_start + address);
339 #endif
340
341                         * (void **) base_ptr = (char *)minfo->code_start + address;
342
343                         break;
344                 }
345                 case MRT_local_variable: {
346                         guint32 token = *((guint32 *) tmp_ptr)++;
347                         guint32 original = *((guint32 *) tmp_ptr)++;
348                         MonoDebugMethodInfo *minfo;
349                         gint32 address;
350
351                         minfo = method_info_func (symfile, token, user_data);
352
353                         if (!minfo) {
354                                 * (void **) base_ptr = 0;
355                                 continue;
356                         }
357
358                         if (original > minfo->num_locals) {
359                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
360                                            "local variable %d, but method %s only has %d local variables.",
361                                            symfile->file_name, original, minfo->method->name,
362                                            minfo->num_locals);
363                                 continue;
364                         }
365
366                         address = minfo->local_offsets [original];
367
368 #if 0
369                         g_message ("Relocating local variable %d (%s) to stack offset %d",
370                                    original, minfo->method->name, address);
371 #endif
372
373                         * (gint32 *) base_ptr = address;
374
375                         break;
376                 }
377                 case MRT_method_parameter: {
378                         guint32 token = *((guint32 *) tmp_ptr)++;
379                         guint32 original = *((guint32 *) tmp_ptr)++;
380                         MonoDebugMethodInfo *minfo;
381                         gint32 address;
382
383                         minfo = method_info_func (symfile, token, user_data);
384
385                         if (!minfo) {
386                                 * (void **) base_ptr = 0;
387                                 continue;
388                         }
389
390                         if (minfo->method->signature->hasthis) {
391                                 if (original == 0) {
392                                         * (gint32 *) base_ptr = minfo->this_offset;
393                                         continue;
394                                 }
395
396                                 original--;
397                         }
398
399                         if (original > minfo->num_params) {
400                                 g_warning ("Symbol file %s contains relocation entry for non-existing "
401                                            "parameter %d, but method %s only has %d parameters.",
402                                            symfile->file_name, original, minfo->method->name,
403                                            minfo->num_params);
404                                 continue;
405                         }
406
407                         address = minfo->param_offsets [original];
408
409 #if 0
410                         g_message ("Relocating parameter %d (%s) to stack offset %d",
411                                    original, minfo->method->name, address);
412 #endif
413
414                         * (gint32 *) base_ptr = address;
415
416                         break;
417                 }
418                 case MRT_type_sizeof: {
419                         guint32 token = *((guint32 *) tmp_ptr)++;
420                         MonoClass *klass = mono_debug_class_get (symfile, token);
421
422                         if (!klass)
423                                 continue;
424
425                         mono_class_init (klass);
426
427                         if (klass->enumtype || klass->valuetype)
428                                 * (gint8 *) base_ptr = klass->instance_size - sizeof (MonoObject);
429                         else
430                                 * (gint8 *) base_ptr = klass->instance_size;
431
432                         break;
433                 }
434                 case MRT_type_field_offset: {
435                         guint32 token = *((guint32 *) tmp_ptr)++;
436                         guint32 original = *((guint32 *) tmp_ptr)++;
437                         MonoClass *klass = mono_debug_class_get (symfile, token);
438                         guint32 off;
439
440                         if (!klass)
441                                 continue;
442
443                         mono_class_init (klass);
444
445                         if (original > klass->field.count) {
446                                 g_warning ("Symbol file %s contains invalid field offset entry.",
447                                            symfile->file_name);
448                                 continue;
449                         }
450
451                         if (!klass->fields)
452                                 continue;
453
454                         off = klass->fields [original].offset;
455                         if (klass->byval_arg.type == MONO_TYPE_VALUETYPE)
456                                 off -= sizeof (MonoObject);
457
458 #if 0
459                         g_message ("Setting field %d of type %u to offset %d", original,
460                                    token, off);
461 #endif
462
463                         * (guint32 *) base_ptr = off;
464
465                         break;
466                 }
467                 case MRT_mono_string_sizeof:
468                         * (gint8 *) base_ptr = sizeof (MonoString);
469                         break;
470
471                 case MRT_mono_string_offset: {
472                         guint32 idx = *((guint32 *) tmp_ptr)++;
473                         MonoString string;
474                         guint32 off;
475
476                         switch (idx) {
477                         case MRI_string_offset_length:
478                                 off = (guchar *) &string.length - (guchar *) &string;
479                                 break;
480
481                         case MRI_string_offset_vector:
482                                 off = (guchar *) &string.c_str - (guchar *) &string;
483                                 break;
484
485                         default:
486                                 g_warning ("Symbol file %s contains invalid string offset entry",
487                                            symfile->file_name);
488                                 continue;
489                         }
490
491                         * (guint32 *) base_ptr = off;
492
493                         break;
494                 }
495                 case MRT_mono_array_sizeof:
496                         * (gint8 *) base_ptr = sizeof (MonoArray);
497                         break;
498
499                 case MRT_mono_array_offset: {
500                         guint32 idx = *((guint32 *) tmp_ptr)++;
501                         MonoArray array;
502                         guint32 off;
503
504                         switch (idx) {
505                         case MRI_array_offset_bounds:
506                                 off = (guchar *) &array.bounds - (guchar *) &array;
507                                 break;
508
509                         case MRI_array_offset_max_length:
510                                 off = (guchar *) &array.max_length - (guchar *) &array;
511                                 break;
512
513                         case MRI_array_offset_vector:
514                                 off = (guchar *) &array.vector - (guchar *) &array;
515                                 break;
516
517                         default:
518                                 g_warning ("Symbol file %s contains invalid array offset entry",
519                                            symfile->file_name);
520                                 continue;
521                         }
522
523                         * (guint32 *) base_ptr = off;
524
525                         break;
526                 }
527
528                 case MRT_mono_array_bounds_sizeof:
529                         * (gint8 *) base_ptr = sizeof (MonoArrayBounds);
530                         break;
531
532                 case MRT_mono_array_bounds_offset: {
533                         guint32 idx = *((guint32 *) tmp_ptr)++;
534                         MonoArrayBounds bounds;
535                         guint32 off;
536
537                         switch (idx) {
538                         case MRI_array_bounds_offset_lower:
539                                 off = (guchar *) &bounds.lower_bound - (guchar *) &bounds;
540                                 break;
541
542                         case MRI_array_bounds_offset_length:
543                                 off = (guchar *) &bounds.length - (guchar *) &bounds;
544                                 break;
545
546                         default:
547                                 g_warning ("Symbol file %s contains invalid array bounds offset entry",
548                                            symfile->file_name);
549                                 continue;
550                         }
551
552                         * (guint32 *) base_ptr = off;
553
554                         break;
555                 }
556
557                 default:
558                         g_warning ("Symbol file %s contains unknown relocation entry %d",
559                                    symfile->file_name, type);
560                         break;
561                 }
562         }
563
564         mono_raw_buffer_update (symfile->raw_contents, symfile->raw_contents_size);
565 }
566
567 MonoReflectionType *
568 ves_icall_Debugger_MonoSymbolWriter_get_local_type_from_sig (MonoReflectionAssembly *assembly,
569                                                              MonoArray *signature)
570 {
571         MonoDomain *domain; 
572         MonoImage *image;
573         MonoType *type;
574         const char *ptr;
575         int len = 0;
576
577         MONO_CHECK_ARG_NULL (assembly);
578         MONO_CHECK_ARG_NULL (signature);
579
580         domain = mono_domain_get();
581         image = assembly->assembly->image;
582
583         ptr = mono_array_addr (signature, char, 0);
584         g_assert (*ptr++ == 0x07);
585         len = mono_metadata_decode_value (ptr, &ptr);
586         g_assert (len == 1);
587
588         type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
589
590         return mono_type_get_object (domain, type);
591 }
592
593 MonoReflectionMethod *
594 ves_icall_Debugger_MonoSymbolWriter_method_from_token (MonoReflectionAssembly *assembly, guint32 token)
595 {
596         MonoDomain *domain; 
597         MonoImage *image;
598         MonoMethod *method;
599
600         MONO_CHECK_ARG_NULL (assembly);
601
602         domain = mono_domain_get();
603         image = assembly->assembly->image;
604
605         method = mono_get_method (image, token, NULL);
606
607         return mono_method_get_object (domain, method);
608 }
609
610 guint32
611 ves_icall_Debugger_DwarfFileWriter_get_type_token (MonoReflectionType *type)
612 {
613         MonoClass *klass = mono_class_from_mono_type (type->type);
614
615         mono_class_init (klass);
616
617         return klass->type_token;
618 }