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>
19 /* Keep in sync with Mono.CSharp.Debugger.MonoDwarfFileWriter */
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
41 #define MRI_string_offset_length 0x00
42 #define MRI_string_offset_chars 0x01
44 #define MRI_array_offset_bounds 0x00
45 #define MRI_array_offset_max_length 0x01
46 #define MRI_array_offset_vector 0x02
48 #define MRI_array_bounds_offset_lower 0x00
49 #define MRI_array_bounds_offset_length 0x01
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
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
67 get_sections_elf32 (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
70 Elf32_Shdr *section, *strtab_section;
74 header = (Elf32_Ehdr *)symfile->raw_contents;
75 if (header->e_version != EV_CURRENT) {
77 g_warning ("Symbol file %s has unknown ELF version %d",
78 symfile->file_name, header->e_version);
82 if (header->e_machine != EM_386) {
84 g_warning ("ELF file %s is for unknown architecture %d",
85 symfile->file_name, header->e_machine);
89 if (header->e_shentsize != sizeof (*section)) {
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);
97 symfile->section_offsets = g_new0 (MonoDebugSymbolFileSection, MONO_DEBUG_SYMBOL_SECTION_MAX);
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;
103 for (i = 0; i < header->e_shnum; i++, section++) {
104 const gchar *name = strtab + section->sh_name;
106 if (!strcmp (name, ".debug_info")) {
107 MonoDebugSymbolFileSection *sfs;
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;
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;
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;
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;
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;
147 #endif /* HAVE_ELF_H */
150 get_sections (MonoDebugSymbolFile *symfile, gboolean emit_warnings)
154 static const char ELFMAG[] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, 0 };
156 if (!strncmp (symfile->raw_contents, ELFMAG, strlen (ELFMAG)))
157 return get_sections_elf32 (symfile, emit_warnings);
161 g_warning ("Symbol file %s has unknown file format", symfile->file_name);
167 read_line_numbers (MonoDebugSymbolFile *symfile)
169 const char *ptr, *start, *end;
173 if (!symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset)
176 ptr = start = symfile->raw_contents +
177 symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset;
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);
187 section_size = *((guint32 *) ptr)++;
188 end = ptr + section_size;
190 symfile->line_number_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
191 NULL, (GDestroyNotify) g_free);
194 MonoDebugLineNumberBlock *lnb;
195 guint32 token, source_offset;
198 token = * ((guint32 *) ptr)++;
199 method = mono_get_method (symfile->image, token, NULL);
203 lnb = g_new0 (MonoDebugLineNumberBlock, 1);
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)++;
210 g_hash_table_insert (symfile->line_number_table, method, lnb);
215 mono_debug_class_get (MonoDebugSymbolFile *symfile, guint32 type_token)
219 if ((klass = g_hash_table_lookup (symfile->image->class_cache, GUINT_TO_POINTER (type_token))))
225 MonoDebugSymbolFile *
226 mono_debug_open_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
228 MonoDebugSymbolFile *symfile;
233 fd = open (filename, O_RDWR);
236 g_warning ("Can't open symbol file: %s", filename);
240 file_size = lseek (fd, 0, SEEK_END);
241 lseek (fd, 0, SEEK_SET);
243 if (file_size == (off_t) -1) {
245 g_warning ("Can't get size of symbol file: %s", filename);
249 ptr = mono_raw_buffer_load (fd, 1, 0, file_size);
252 g_warning ("Can't read symbol file: %s", filename);
256 symfile = g_new0 (MonoDebugSymbolFile, 1);
258 symfile->file_name = g_strdup (filename);
259 symfile->image = image;
260 symfile->raw_contents = ptr;
261 symfile->raw_contents_size = file_size;
263 if (!get_sections (symfile, emit_warnings)) {
264 mono_debug_close_symbol_file (symfile);
268 read_line_numbers (symfile);
274 mono_debug_close_symbol_file (MonoDebugSymbolFile *symfile)
279 if (symfile->raw_contents)
280 mono_raw_buffer_free (symfile->raw_contents);
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);
292 relocate_variable (MonoDebugVarInfo *var, void *base_ptr)
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;
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.
312 switch (var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) {
313 case MONO_DEBUG_VAR_ADDRESS_MODE_STACK:
315 * Variable is on the stack.
317 * If `index' is zero, use the normal frame register. Otherwise, bits
318 * 0..4 of `index' contain the frame register.
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.
325 /* Use the normal frame register (%ebp on the i386). */
326 * ((guint8 *) base_ptr)++ = DW_OP_fbreg;
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;
336 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
338 * Variable is in the register whose number is contained in bits 0..4
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
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;
352 case MONO_DEBUG_VAR_ADDRESS_MODE_TWO_REGISTERS:
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.
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;
369 g_assert_not_reached ();
374 mono_debug_update_symbol_file (MonoDebugSymbolFile *symfile,
375 MonoDebugMethodInfoFunc method_info_func,
378 const char *reloc_ptr, *reloc_start, *reloc_end;
379 int version, already_relocated = 0;
382 if (!symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE].file_offset)
385 reloc_ptr = reloc_start = symfile->raw_contents +
386 symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_RELOC_TABLE].file_offset;
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);
396 already_relocated = *reloc_ptr;
397 *((char *) reloc_ptr)++ = 1;
399 reloc_size = *((guint32 *) reloc_ptr)++;
400 reloc_end = reloc_ptr + reloc_size;
402 while (reloc_ptr < reloc_end) {
403 int type, size, section, offset;
408 size = * ((guint32 *) reloc_ptr)++;
413 section = *tmp_ptr++;
414 offset = *((guint32 *) tmp_ptr)++;
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);
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);
428 base_ptr = symfile->raw_contents + symfile->section_offsets [section].file_offset;
429 base_ptr = base_ptr + offset;
432 case MRT_target_address_size:
433 * (guint8 *) base_ptr = sizeof (void *);
435 case MRT_method_start_address: {
436 int token = *((guint32 *) tmp_ptr)++;
437 MonoDebugMethodInfo *minfo;
439 minfo = method_info_func (symfile, token, user_data);
442 * (void **) base_ptr = 0;
447 g_message ("Start of `%s' (%ld) relocated to %p", minfo->method->name,
448 token, minfo->code_start);
451 * (void **) base_ptr = minfo->code_start;
455 case MRT_method_end_address: {
456 int token = *((guint32 *) tmp_ptr)++;
457 MonoDebugMethodInfo *minfo;
459 minfo = method_info_func (symfile, token, user_data);
462 * (void **) base_ptr = 0;
466 * (void **) base_ptr = (char *)minfo->code_start + minfo->code_size;
470 case MRT_il_offset: {
471 guint32 token = *((guint32 *) tmp_ptr)++;
472 guint32 original = *((guint32 *) tmp_ptr)++;
473 MonoDebugMethodInfo *minfo;
477 minfo = method_info_func (symfile, token, user_data);
480 * (void **) base_ptr = 0;
484 address = minfo->code_size;
486 for (i = 0; i < minfo->num_il_offsets; i++) {
487 MonoDebugILOffsetInfo *il = &minfo->il_offsets [i];
489 if (il->offset >= original) {
490 address = il->address;
496 g_message ("Relocating IL offset %04x in `%s' to %d (%p)",
497 original, minfo->method->name, address,
498 minfo->code_start + address);
501 * (void **) base_ptr = minfo->code_start + address;
505 case MRT_local_variable: {
506 guint32 token = *((guint32 *) tmp_ptr)++;
507 guint32 original = *((guint32 *) tmp_ptr)++;
508 MonoDebugMethodInfo *minfo;
510 minfo = method_info_func (symfile, token, user_data);
513 relocate_variable (NULL, base_ptr);
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,
522 g_message (G_STRLOC ": %d", token);
527 relocate_variable (&minfo->locals [original], base_ptr);
531 case MRT_method_parameter: {
532 guint32 token = *((guint32 *) tmp_ptr)++;
533 guint32 original = *((guint32 *) tmp_ptr)++;
534 MonoDebugMethodInfo *minfo;
536 minfo = method_info_func (symfile, token, user_data);
539 relocate_variable (NULL, base_ptr);
543 if (minfo->method->signature->hasthis) {
545 relocate_variable (minfo->this_var, base_ptr);
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,
560 relocate_variable (&minfo->params [original], base_ptr);
564 case MRT_type_sizeof: {
565 guint32 token = *((guint32 *) tmp_ptr)++;
566 MonoClass *klass = mono_debug_class_get (symfile, token);
571 mono_class_init (klass);
573 if (klass->enumtype || klass->valuetype)
574 * (gint8 *) base_ptr = klass->instance_size - sizeof (MonoObject);
576 * (gint8 *) base_ptr = klass->instance_size;
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);
589 mono_class_init (klass);
591 if (original > klass->field.count) {
592 g_warning ("Symbol file %s contains invalid field offset entry.",
594 g_message (G_STRLOC ": %d", token);
595 /* G_BREAKPOINT (); */
602 off = klass->fields [original].offset;
603 if (klass->byval_arg.type == MONO_TYPE_VALUETYPE)
604 off -= sizeof (MonoObject);
607 g_message ("Setting field %d of type %u to offset %d", original,
611 * (guint32 *) base_ptr = off;
615 case MRT_mono_string_sizeof:
616 * (gint8 *) base_ptr = sizeof (MonoString);
619 case MRT_mono_string_offset: {
620 guint32 idx = *((guint32 *) tmp_ptr)++;
625 case MRI_string_offset_length:
626 off = (guchar *) &string.length - (guchar *) &string;
629 case MRI_string_offset_chars:
630 off = (guchar *) &string.chars - (guchar *) &string;
634 g_warning ("Symbol file %s contains invalid string offset entry",
639 * (guint32 *) base_ptr = off;
643 case MRT_mono_array_sizeof:
644 * (gint8 *) base_ptr = sizeof (MonoArray);
647 case MRT_mono_array_offset: {
648 guint32 idx = *((guint32 *) tmp_ptr)++;
653 case MRI_array_offset_bounds:
654 off = (guchar *) &array.bounds - (guchar *) &array;
657 case MRI_array_offset_max_length:
658 off = (guchar *) &array.max_length - (guchar *) &array;
661 case MRI_array_offset_vector:
662 off = (guchar *) &array.vector - (guchar *) &array;
666 g_warning ("Symbol file %s contains invalid array offset entry",
671 * (guint32 *) base_ptr = off;
676 case MRT_mono_array_bounds_sizeof:
677 * (gint8 *) base_ptr = sizeof (MonoArrayBounds);
680 case MRT_mono_array_bounds_offset: {
681 guint32 idx = *((guint32 *) tmp_ptr)++;
682 MonoArrayBounds bounds;
686 case MRI_array_bounds_offset_lower:
687 off = (guchar *) &bounds.lower_bound - (guchar *) &bounds;
690 case MRI_array_bounds_offset_length:
691 off = (guchar *) &bounds.length - (guchar *) &bounds;
695 g_warning ("Symbol file %s contains invalid array bounds offset entry",
700 * (guint32 *) base_ptr = off;
705 case MRT_variable_start_scope: {
706 guint32 token = *((guint32 *) tmp_ptr)++;
707 guint32 original = *((guint32 *) tmp_ptr)++;
708 MonoDebugMethodInfo *minfo;
711 minfo = method_info_func (symfile, token, user_data);
713 if (!minfo || !minfo->locals) {
714 * (void **) base_ptr = 0;
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,
726 address = minfo->locals [original].begin_scope;
728 * (void **) base_ptr = minfo->code_start + address;
733 case MRT_variable_end_scope: {
734 guint32 token = *((guint32 *) tmp_ptr)++;
735 guint32 original = *((guint32 *) tmp_ptr)++;
736 MonoDebugMethodInfo *minfo;
739 minfo = method_info_func (symfile, token, user_data);
741 if (!minfo || !minfo->locals) {
742 * (void **) base_ptr = 0;
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,
754 address = minfo->locals [original].end_scope;
756 * (void **) base_ptr = minfo->code_start + address;
761 case MRT_mono_string_fieldsize: {
762 guint32 idx = *((guint32 *) tmp_ptr)++;
767 case MRI_string_offset_length:
768 fieldsize = sizeof (string.length);
772 g_warning ("Symbol file %s contains invalid string fieldsize entry",
777 * (guint32 *) base_ptr = fieldsize;
782 case MRT_mono_array_fieldsize: {
783 guint32 idx = *((guint32 *) tmp_ptr)++;
788 case MRI_array_offset_bounds:
789 fieldsize = sizeof (array.bounds);
792 case MRI_array_offset_max_length:
793 fieldsize = sizeof (array.max_length);
796 case MRI_array_offset_vector:
797 fieldsize = sizeof (array.vector);
801 g_warning ("Symbol file %s contains invalid array fieldsize entry",
806 * (guint32 *) base_ptr = fieldsize;
813 g_warning ("Symbol file %s contains unknown relocation entry %d",
814 symfile->file_name, type);
819 mono_raw_buffer_update (symfile->raw_contents, symfile->raw_contents_size);
823 mono_debug_find_source_location (MonoDebugSymbolFile *symfile, MonoMethod *method, guint32 offset)
825 MonoDebugLineNumberBlock *lnb;
828 if (!symfile->line_number_table)
831 lnb = g_hash_table_lookup (symfile->line_number_table, method);
835 ptr = symfile->raw_contents +
836 symfile->section_offsets [MONO_DEBUG_SYMBOL_SECTION_MONO_LINE_NUMBERS].file_offset;
838 ptr += lnb->file_offset;
841 guint32 row, iloffset;
843 row = * ((guint32 *) ptr)++;
844 iloffset = * ((guint32 *) ptr)++;
851 if (iloffset >= offset)
852 return g_strdup_printf ("%s:%d", lnb->source_file, row);