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>
17 /* Keep in sync with Mono.CSharp.Debugger.MonoDwarfFileWriter */
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 #define MRT_variable_start_scope 0x0f
34 #define MRT_variable_end_scope 0x10
35 #define MRT_mono_string_fieldsize 0x11
36 #define MRT_mono_array_fieldsize 0x12
37 #define MRT_type_field_fieldsize 0x13
39 #define MRI_string_offset_length 0x00
40 #define MRI_string_offset_vector 0x01
42 #define MRI_array_offset_bounds 0x00
43 #define MRI_array_offset_max_length 0x01
44 #define MRI_array_offset_vector 0x02
46 #define MRI_array_bounds_offset_lower 0x00
47 #define MRI_array_bounds_offset_length 0x01
49 #define MRS_debug_info 0x01
50 #define MRS_debug_abbrev 0x02
51 #define MRS_debug_line 0x03
52 #define MRS_mono_reloc_table 0x04
54 #define DW_OP_const4s 0x0d
55 #define DW_OP_plus 0x22
56 #define DW_OP_reg0 0x50
57 #define DW_OP_breg0 0x70
58 #define DW_OP_fbreg 0x91
59 #define DW_OP_piece 0x93
60 #define DW_OP_nop 0x96
65 get_sections_elf32 (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
68 Elf32_Shdr *section, *strtab_section;
72 header = (Elf32_Ehdr *)symfile->raw_contents;
73 if (header->e_version != EV_CURRENT) {
75 g_warning ("Symbol file %s has unknown ELF version %d",
76 symfile->file_name, header->e_version);
80 if (header->e_machine != EM_386) {
82 g_warning ("ELF file %s is for unknown architecture %d",
83 symfile->file_name, header->e_machine);
87 if (header->e_shentsize != sizeof (*section)) {
89 g_warning ("ELF file %s has unknown section header size "
90 "(expected %d, got %d)", symfile->file_name,
91 sizeof (*section), header->e_shentsize);
95 symfile->section_offsets = g_new0 (MonoDebugSymbolFileSection, MONO_DEBUG_SYMBOL_SECTION_MAX);
97 section = (Elf32_Shdr *)(symfile->raw_contents + header->e_shoff);
98 strtab_section = section + header->e_shstrndx;
99 strtab = symfile->raw_contents + strtab_section->sh_offset;
101 for (i = 0; i < header->e_shnum; i++, section++) {
102 const gchar *name = strtab + section->sh_name;
104 if (!strcmp (name, ".debug_info")) {
105 MonoDebugSymbolFileSection *sfs;
107 sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_INFO];
108 sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_INFO;
109 sfs->file_offset = section->sh_offset;
110 sfs->size = section->sh_size;
111 } else if (!strcmp (name, ".debug_line")) {
112 MonoDebugSymbolFileSection *sfs;
114 sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_LINE];
115 sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_LINE;
116 sfs->file_offset = section->sh_offset;
117 sfs->size = section->sh_size;
118 } else if (!strcmp (name, ".debug_abbrev")) {
119 MonoDebugSymbolFileSection *sfs;
121 sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_DEBUG_ABBREV];
122 sfs->type = MONO_DEBUG_SYMBOL_SECTION_DEBUG_ABBREV;
123 sfs->file_offset = section->sh_offset;
124 sfs->size = section->sh_size;
125 } else if (!strcmp (name, ".mono_reloc_table")) {
126 MonoDebugSymbolFileSection *sfs;
128 sfs = &symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE];
129 sfs->type = MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE;
130 sfs->file_offset = section->sh_offset;
131 sfs->size = section->sh_size;
138 #endif /* HAVE_ELF_H */
141 get_sections (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
145 static const char ELFMAG[] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, 0 };
147 if (!strncmp (symfile->raw_contents, ELFMAG, strlen (ELFMAG)))
148 return get_sections_elf32 (symfile, emit_warnings);
152 g_warning ("Symbol file %s has unknown file format", symfile->file_name);
158 mono_debug_class_get (MonoDebugSymbolFile *symfile, guint32 type_token)
162 if ((klass = g_hash_table_lookup (symfile->image->class_cache, GUINT_TO_POINTER (type_token))))
168 MonoDebugSymbolFile *
169 mono_debug_open_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
171 MonoDebugSymbolFile *symfile;
176 fd = open (filename, O_RDWR);
179 g_warning ("Can't open symbol file: %s", filename);
183 file_size = lseek (fd, 0, SEEK_END);
184 lseek (fd, 0, SEEK_SET);
186 if (file_size == (off_t) -1) {
188 g_warning ("Can't get size of symbol file: %s", filename);
192 ptr = mono_raw_buffer_load (fd, 1, 0, file_size);
195 g_warning ("Can't read symbol file: %s", filename);
199 symfile = g_new0 (MonoDebugSymbolFile, 1);
201 symfile->file_name = g_strdup (filename);
202 symfile->image = image;
203 symfile->raw_contents = ptr;
204 symfile->raw_contents_size = file_size;
206 if (!get_sections (symfile, emit_warnings)) {
207 mono_debug_close_symbol_file (symfile);
215 mono_debug_close_symbol_file (MonoDebugSymbolFile *symfile)
220 if (symfile->raw_contents)
221 mono_raw_buffer_free (symfile->raw_contents);
225 g_free (symfile->file_name);
226 g_free (symfile->section_offsets);
231 relocate_variable (MonoDebugVarInfo *var, void *base_ptr)
234 * ((guint8 *) base_ptr)++ = DW_OP_nop;
235 * ((guint8 *) base_ptr)++ = DW_OP_nop;
236 * ((guint8 *) base_ptr)++ = DW_OP_nop;
237 * ((guint8 *) base_ptr)++ = DW_OP_nop;
238 * ((guint8 *) base_ptr)++ = DW_OP_nop;
239 * ((guint8 *) base_ptr)++ = DW_OP_nop;
240 * ((guint8 *) base_ptr)++ = DW_OP_nop;
241 * ((guint8 *) base_ptr)++ = DW_OP_nop;
246 * Update the location description for a local variable or method parameter.
247 * MCS always reserves 8 bytes for us to do this, if we don't need them all
248 * we just fill up the rest with DW_OP_nop's.
251 switch (var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) {
252 case MONO_DEBUG_VAR_ADDRESS_MODE_STACK:
254 * Variable is on the stack.
256 * If `index' is zero, use the normal frame register. Otherwise, bits
257 * 0..4 of `index' contain the frame register.
259 * Both DW_OP_fbreg and DW_OP_breg0 ... DW_OP_breg31 take an ULeb128
260 * argument - since this has an variable size, we set it to zero and
261 * manually add a 4 byte constant using DW_OP_plus.
264 /* Use the normal frame register (%ebp on the i386). */
265 * ((guint8 *) base_ptr)++ = DW_OP_fbreg;
267 /* Use a custom frame register. */
268 * ((guint8 *) base_ptr)++ = DW_OP_breg0 + (var->index & 0x001f);
269 * ((guint8 *) base_ptr)++ = 0;
270 * ((guint8 *) base_ptr)++ = DW_OP_const4s;
271 * ((gint32 *) base_ptr)++ = var->offset;
272 * ((guint8 *) base_ptr)++ = DW_OP_plus;
275 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
277 * Variable is in the register whose number is contained in bits 0..4
280 * We need to write exactly 8 bytes in this location description, so instead
281 * of filling up the rest with DW_OP_nop's just add the `offset' even if
284 * ((guint8 *) base_ptr)++ = DW_OP_reg0 + (var->index & 0x001f);
285 * ((guint8 *) base_ptr)++ = DW_OP_nop;
286 * ((guint8 *) base_ptr)++ = DW_OP_const4s;
287 * ((gint32 *) base_ptr)++ = var->offset;
288 * ((guint8 *) base_ptr)++ = DW_OP_plus;
291 case MONO_DEBUG_VAR_ADDRESS_MODE_TWO_REGISTERS:
293 * Variable is in two registers whose numbers are in bits 0..4 and 5..9 of
294 * the `index' field. Don't add `offset' since we have only two bytes left,
295 * fill them up with DW_OP_nop's.
297 * ((guint8 *) base_ptr)++ = DW_OP_reg0 + (var->index & 0x001f);
298 * ((guint8 *) base_ptr)++ = DW_OP_piece;
299 * ((guint8 *) base_ptr)++ = sizeof (int);
300 * ((guint8 *) base_ptr)++ = DW_OP_reg0 + ((var->index & 0x1f0) >> 5);
301 * ((guint8 *) base_ptr)++ = DW_OP_piece;
302 * ((guint8 *) base_ptr)++ = sizeof (int);
303 * ((guint8 *) base_ptr)++ = DW_OP_nop;
304 * ((guint8 *) base_ptr)++ = DW_OP_nop;
308 g_assert_not_reached ();
313 mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
314 MonoDebugMethodInfoFunc method_info_func,
317 const char *reloc_ptr, *reloc_start, *reloc_end;
318 int version, already_relocated = 0;
321 if (!symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE].file_offset)
324 reloc_ptr = reloc_start = symfile->raw_contents +
325 symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE].file_offset;
327 version = *((guint16 *) reloc_ptr)++;
328 if (version != MONO_DEBUG_SYMBOL_FILE_VERSION) {
329 g_warning ("Symbol file %s has incorrect relocation table version "
330 "(expected %d, got %d)", symfile->file_name,
331 MONO_DEBUG_SYMBOL_FILE_VERSION, version);
335 already_relocated = *reloc_ptr;
336 *((char *) reloc_ptr)++ = 1;
338 reloc_size = *((guint32 *) reloc_ptr)++;
339 reloc_end = reloc_ptr + reloc_size;
341 while (reloc_ptr < reloc_end) {
342 int type, size, section, offset;
347 size = * ((guint32 *) reloc_ptr)++;
352 section = *tmp_ptr++;
353 offset = *((guint32 *) tmp_ptr)++;
355 if (section >= MONO_DEBUG_SYMBOL_SECTION_MAX) {
356 g_warning ("Symbol file %s contains a relocation entry for unknown section %d",
357 symfile->file_name, section);
361 if (!symfile->section_offsets [section].file_offset) {
362 g_warning ("Symbol file %s contains a relocation entry for non-existing "
363 "section %d", symfile->file_name, section);
367 base_ptr = symfile->raw_contents + symfile->section_offsets [section].file_offset;
368 base_ptr = base_ptr + offset;
371 case MRT_target_address_size:
372 * (guint8 *) base_ptr = sizeof (void *);
374 case MRT_method_start_address: {
375 int token = *((guint32 *) tmp_ptr)++;
376 MonoDebugMethodInfo *minfo;
378 minfo = method_info_func (symfile, token, user_data);
381 * (void **) base_ptr = 0;
386 g_message ("Start of `%s' relocated to %p", minfo->method->name, minfo->code_start);
389 * (void **) base_ptr = minfo->code_start;
393 case MRT_method_end_address: {
394 int token = *((guint32 *) tmp_ptr)++;
395 MonoDebugMethodInfo *minfo;
397 minfo = method_info_func (symfile, token, user_data);
400 * (void **) base_ptr = 0;
404 * (void **) base_ptr = (char *)minfo->code_start + minfo->code_size;
408 case MRT_il_offset: {
409 guint32 token = *((guint32 *) tmp_ptr)++;
410 guint32 original = *((guint32 *) tmp_ptr)++;
411 MonoDebugMethodInfo *minfo;
415 minfo = method_info_func (symfile, token, user_data);
418 * (void **) base_ptr = 0;
422 address = minfo->code_size;
424 for (i = 0; i < minfo->num_il_offsets; i++) {
425 MonoDebugILOffsetInfo *il = &minfo->il_offsets [i];
427 if (il->offset >= original) {
428 address = il->address;
434 g_message ("Relocating IL offset %04x in `%s' to %d (%p)",
435 original, minfo->method->name, address,
436 minfo->code_start + address);
439 * (void **) base_ptr = minfo->code_start + address;
443 case MRT_local_variable: {
444 guint32 token = *((guint32 *) tmp_ptr)++;
445 guint32 original = *((guint32 *) tmp_ptr)++;
446 MonoDebugMethodInfo *minfo;
448 minfo = method_info_func (symfile, token, user_data);
451 relocate_variable (NULL, base_ptr);
455 if (original > minfo->num_locals) {
456 g_warning ("Symbol file %s contains relocation entry for non-existing "
457 "local variable %d, but method %s only has %d local variables.",
458 symfile->file_name, original, minfo->method->name,
463 relocate_variable (&minfo->locals [original], base_ptr);
467 case MRT_method_parameter: {
468 guint32 token = *((guint32 *) tmp_ptr)++;
469 guint32 original = *((guint32 *) tmp_ptr)++;
470 MonoDebugMethodInfo *minfo;
472 minfo = method_info_func (symfile, token, user_data);
475 relocate_variable (NULL, base_ptr);
479 if (minfo->method->signature->hasthis) {
481 relocate_variable (minfo->this_var, base_ptr);
488 if (original > minfo->num_params) {
489 g_warning ("Symbol file %s contains relocation entry for non-existing "
490 "parameter %d, but method %s only has %d parameters.",
491 symfile->file_name, original, minfo->method->name,
496 relocate_variable (&minfo->params [original], base_ptr);
500 case MRT_type_sizeof: {
501 guint32 token = *((guint32 *) tmp_ptr)++;
502 MonoClass *klass = mono_debug_class_get (symfile, token);
507 mono_class_init (klass);
509 if (klass->enumtype || klass->valuetype)
510 * (gint8 *) base_ptr = klass->instance_size - sizeof (MonoObject);
512 * (gint8 *) base_ptr = klass->instance_size;
516 case MRT_type_field_offset: {
517 guint32 token = *((guint32 *) tmp_ptr)++;
518 guint32 original = *((guint32 *) tmp_ptr)++;
519 MonoClass *klass = mono_debug_class_get (symfile, token);
525 mono_class_init (klass);
527 if (original > klass->field.count) {
528 g_warning ("Symbol file %s contains invalid field offset entry.",
536 off = klass->fields [original].offset;
537 if (klass->byval_arg.type == MONO_TYPE_VALUETYPE)
538 off -= sizeof (MonoObject);
541 g_message ("Setting field %d of type %u to offset %d", original,
545 * (guint32 *) base_ptr = off;
549 case MRT_mono_string_sizeof:
550 * (gint8 *) base_ptr = sizeof (MonoString);
553 case MRT_mono_string_offset: {
554 guint32 idx = *((guint32 *) tmp_ptr)++;
559 case MRI_string_offset_length:
560 off = (guchar *) &string.length - (guchar *) &string;
563 case MRI_string_offset_vector:
564 // fixme: don know how to fix this
565 g_assert_not_reached ();
566 //off = (guchar *) &string.c_str - (guchar *) &string;
570 g_warning ("Symbol file %s contains invalid string offset entry",
575 * (guint32 *) base_ptr = off;
579 case MRT_mono_array_sizeof:
580 * (gint8 *) base_ptr = sizeof (MonoArray);
583 case MRT_mono_array_offset: {
584 guint32 idx = *((guint32 *) tmp_ptr)++;
589 case MRI_array_offset_bounds:
590 off = (guchar *) &array.bounds - (guchar *) &array;
593 case MRI_array_offset_max_length:
594 off = (guchar *) &array.max_length - (guchar *) &array;
597 case MRI_array_offset_vector:
598 off = (guchar *) &array.vector - (guchar *) &array;
602 g_warning ("Symbol file %s contains invalid array offset entry",
607 * (guint32 *) base_ptr = off;
612 case MRT_mono_array_bounds_sizeof:
613 * (gint8 *) base_ptr = sizeof (MonoArrayBounds);
616 case MRT_mono_array_bounds_offset: {
617 guint32 idx = *((guint32 *) tmp_ptr)++;
618 MonoArrayBounds bounds;
622 case MRI_array_bounds_offset_lower:
623 off = (guchar *) &bounds.lower_bound - (guchar *) &bounds;
626 case MRI_array_bounds_offset_length:
627 off = (guchar *) &bounds.length - (guchar *) &bounds;
631 g_warning ("Symbol file %s contains invalid array bounds offset entry",
636 * (guint32 *) base_ptr = off;
641 case MRT_variable_start_scope: {
642 guint32 token = *((guint32 *) tmp_ptr)++;
643 guint32 original = *((guint32 *) tmp_ptr)++;
644 MonoDebugMethodInfo *minfo;
647 minfo = method_info_func (symfile, token, user_data);
650 * (void **) base_ptr = 0;
654 if (original > minfo->num_locals) {
655 g_warning ("Symbol file %s contains relocation entry for non-existing "
656 "local variable %d, but method %s only has %d local variables.",
657 symfile->file_name, original, minfo->method->name,
662 address = minfo->locals [original].begin_scope;
664 * (void **) base_ptr = minfo->code_start + address;
669 case MRT_variable_end_scope: {
670 guint32 token = *((guint32 *) tmp_ptr)++;
671 guint32 original = *((guint32 *) tmp_ptr)++;
672 MonoDebugMethodInfo *minfo;
675 minfo = method_info_func (symfile, token, user_data);
678 * (void **) base_ptr = 0;
682 if (original > minfo->num_locals) {
683 g_warning ("Symbol file %s contains relocation entry for non-existing "
684 "local variable %d, but method %s only has %d local variables.",
685 symfile->file_name, original, minfo->method->name,
690 address = minfo->locals [original].end_scope;
692 * (void **) base_ptr = minfo->code_start + address;
697 case MRT_mono_string_fieldsize: {
698 guint32 idx = *((guint32 *) tmp_ptr)++;
703 case MRI_string_offset_length:
704 fieldsize = sizeof (string.length);
707 case MRI_string_offset_vector:
709 //fieldsize = sizeof (string.c_str);
710 g_assert_not_reached ();
714 g_warning ("Symbol file %s contains invalid string fieldsize entry",
719 * (guint32 *) base_ptr = fieldsize;
724 case MRT_mono_array_fieldsize: {
725 guint32 idx = *((guint32 *) tmp_ptr)++;
730 case MRI_array_offset_bounds:
731 fieldsize = sizeof (array.bounds);
734 case MRI_array_offset_max_length:
735 fieldsize = sizeof (array.max_length);
738 case MRI_array_offset_vector:
739 fieldsize = sizeof (array.vector);
743 g_warning ("Symbol file %s contains invalid array fieldsize entry",
748 * (guint32 *) base_ptr = fieldsize;
755 g_warning ("Symbol file %s contains unknown relocation entry %d",
756 symfile->file_name, type);
761 mono_raw_buffer_update (symfile->raw_contents, symfile->raw_contents_size);
765 ves_icall_Debugger_MonoSymbolWriter_get_local_type_from_sig (MonoReflectionAssembly *assembly,
766 MonoArray *signature)
774 MONO_CHECK_ARG_NULL (assembly);
775 MONO_CHECK_ARG_NULL (signature);
777 domain = mono_domain_get();
778 image = assembly->assembly->image;
780 ptr = mono_array_addr (signature, char, 0);
781 g_assert (*ptr++ == 0x07);
782 len = mono_metadata_decode_value (ptr, &ptr);
785 type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
787 return mono_type_get_object (domain, type);
790 MonoReflectionMethod *
791 ves_icall_Debugger_MonoSymbolWriter_method_from_token (MonoReflectionAssembly *assembly, guint32 token)
797 MONO_CHECK_ARG_NULL (assembly);
799 domain = mono_domain_get();
800 image = assembly->assembly->image;
802 method = mono_get_method (image, token, NULL);
804 return mono_method_get_object (domain, method);
808 ves_icall_Debugger_DwarfFileWriter_get_type_token (MonoReflectionType *type)
810 MonoClass *klass = mono_class_from_mono_type (type->type);
812 mono_class_init (klass);
814 return klass->type_token;