5 #include <mono/metadata/metadata.h>
6 #include <mono/metadata/tabledefs.h>
7 #include <mono/metadata/rawbuffer.h>
8 #include <mono/metadata/tokentype.h>
9 #include <mono/metadata/appdomain.h>
10 #include <mono/metadata/exception.h>
11 #include <mono/metadata/debug-helpers.h>
12 #include <mono/metadata/debug-mono-symfile.h>
17 struct MonoSymbolFilePriv
24 GHashTable *method_table;
25 GHashTable *method_hash;
26 MonoSymbolFileOffsetTable *offset_table;
27 GPtrArray *range_table;
33 MonoDebugMethodInfo *minfo;
34 MonoSymbolFileMethodEntry *entry;
35 } MonoSymbolFileMethodEntryPriv;
37 static int create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings);
38 static void close_symfile (MonoSymbolFile *symfile);
41 free_method_info (MonoDebugMethodInfo *minfo)
48 load_symfile (MonoSymbolFile *symfile)
50 MonoSymbolFilePriv *priv = symfile->_priv;
51 MonoSymbolFileMethodEntry *me;
52 const char *ptr, *start;
57 ptr = start = symfile->raw_contents;
59 magic = *((guint64 *) ptr)++;
60 if (magic != MONO_SYMBOL_FILE_MAGIC) {
61 g_warning ("Symbol file %s has is not a mono symbol file", priv->file_name);
65 version = *((guint32 *) ptr)++;
66 if (version != MONO_SYMBOL_FILE_VERSION) {
67 g_warning ("Symbol file %s has incorrect line number table version "
68 "(expected %d, got %ld)", priv->file_name,
69 MONO_SYMBOL_FILE_VERSION, version);
73 priv->offset_table = (MonoSymbolFileOffsetTable *) ptr;
74 symfile->address_table_size = priv->offset_table->address_table_size;
81 priv->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
82 (GDestroyNotify) g_free);
83 priv->method_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
84 (GDestroyNotify) free_method_info);
86 ptr = symfile->raw_contents + priv->offset_table->method_table_offset;
87 me = (MonoSymbolFileMethodEntry *) ptr;
89 for (i = 0; i < priv->offset_table->method_count; i++, me++) {
90 MonoMethod *method = mono_get_method (priv->image, me->token, NULL);
91 MonoSymbolFileMethodEntryPriv *mep;
92 MonoDebugMethodInfo *minfo;
97 minfo = g_new0 (MonoDebugMethodInfo, 1);
98 minfo->file_offset = ((const char *) me) - start;
99 minfo->method = method;
100 minfo->symfile = symfile;
101 minfo->num_il_offsets = me->num_line_numbers;
102 minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
103 (symfile->raw_contents + me->line_number_table_offset);
105 mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
106 mep->method = method;
110 g_hash_table_insert (priv->method_table, method, mep);
111 g_hash_table_insert (priv->method_hash, method, minfo);
118 mono_debug_open_mono_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
120 MonoSymbolFile *symfile;
121 MonoSymbolFilePriv *priv;
126 g_message (G_STRLOC ": %s - %s", image->name, filename);
128 fd = open (filename, O_RDONLY);
131 g_warning ("Can't open symbol file: %s", filename);
135 file_size = lseek (fd, 0, SEEK_END);
136 lseek (fd, 0, SEEK_SET);
138 if (file_size == (off_t) -1) {
140 g_warning ("Can't get size of symbol file: %s", filename);
144 ptr = mono_raw_buffer_load (fd, FALSE, 0, file_size);
147 g_warning ("Can't read symbol file: %s", filename);
151 symfile = g_new0 (MonoSymbolFile, 1);
152 symfile->magic = MONO_SYMBOL_FILE_MAGIC;
153 symfile->version = MONO_SYMBOL_FILE_VERSION;
154 symfile->image_file = g_strdup (image->name);
155 symfile->raw_contents = ptr;
156 symfile->raw_contents_size = file_size;
158 symfile->_priv = priv = g_new0 (MonoSymbolFilePriv, 1);
162 priv->file_name = g_strdup (filename);
164 if (!load_symfile (symfile)) {
165 mono_debug_close_mono_symbol_file (symfile);
173 close_symfile (MonoSymbolFile *symfile)
175 MonoSymbolFilePriv *priv = symfile->_priv;
177 if (symfile->raw_contents) {
178 mono_raw_buffer_free (symfile->raw_contents);
179 symfile->raw_contents = NULL;
187 if (priv->method_table) {
188 g_hash_table_destroy (priv->method_table);
189 priv->method_table = NULL;
192 if (priv->method_hash) {
193 g_hash_table_destroy (priv->method_hash);
194 priv->method_hash = NULL;
197 if (symfile->is_dynamic)
198 unlink (priv->file_name);
200 if (symfile->image_file) {
201 g_free (symfile->image_file);
202 symfile->image_file = NULL;
205 if (priv->file_name) {
206 g_free (priv->file_name);
207 priv->file_name = NULL;
214 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
219 close_symfile (symfile);
221 g_free (symfile->_priv->source_file);
222 g_free (symfile->_priv);
227 read_7bit_encoded_int (const char **ptr)
236 ret = ret | ((b & 0x7f) << shift);
238 } while ((b & 0x80) == 0x80);
244 write_7bit_encoded_int (int fd, int value)
247 int high = (value >> 7) & 0x01ffffff;
248 char b = (char)(value & 0x7f);
251 b = (char)(b | 0x80);
253 if (write (fd, &b, 1) < 0)
257 } while (value != 0);
262 write_string (int fd, const char *string)
264 if (!write_7bit_encoded_int (fd, strlen (string)))
267 if (write (fd, string, strlen (string)) < 0)
274 read_string (const char *ptr)
276 int len = read_7bit_encoded_int (&ptr);
279 retval = g_malloc0 (len+1);
280 memcpy (retval, ptr, len);
285 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
286 guint32 *line_number)
288 MonoSymbolFilePriv *priv = symfile->_priv;
289 MonoSymbolFileLineNumberEntry *lne;
290 MonoSymbolFileMethodEntryPriv *mep;
291 gchar *source_file = NULL;
295 if (!priv->method_table || symfile->is_dynamic)
298 mep = g_hash_table_lookup (priv->method_table, method);
302 if (mep->entry->source_file_offset)
303 source_file = read_string (symfile->raw_contents + mep->entry->source_file_offset);
305 ptr = symfile->raw_contents + mep->entry->line_number_table_offset;
307 lne = (MonoSymbolFileLineNumberEntry *) ptr;
309 for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
310 if (lne->offset < offset)
314 *line_number = lne->row;
319 } else if (source_file) {
320 gchar *retval = g_strdup_printf ("%s:%d", source_file, lne->row);
321 g_free (source_file);
324 return g_strdup_printf ("%d", lne->row);
331 update_method_func (gpointer key, gpointer value, gpointer user_data)
333 MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
334 MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
335 MonoSymbolFileMethodAddress *address;
336 MonoSymbolFileLineNumberEntry *lne;
337 MonoDebugRangeInfo *range;
341 mep->minfo = g_hash_table_lookup (symfile->_priv->method_hash, mep->method);
346 if (!mep->minfo->jit)
349 address = (MonoSymbolFileMethodAddress *)
350 (symfile->address_table + mep->entry->address_table_offset);
352 address->is_valid = TRUE;
353 address->start_address = GPOINTER_TO_UINT (mep->minfo->jit->code_start);
354 address->end_address = GPOINTER_TO_UINT (mep->minfo->jit->code_start + mep->minfo->jit->code_size);
356 range = g_new0 (MonoDebugRangeInfo, 1);
357 range->start_address = address->start_address;
358 range->end_address = address->end_address;
359 range->file_offset = mep->minfo->file_offset;
361 g_ptr_array_add (symfile->_priv->range_table, range);
363 lne = (MonoSymbolFileLineNumberEntry *)
364 (symfile->raw_contents + mep->entry->line_number_table_offset);
366 for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
370 address->line_addresses [i] = 0;
372 } else if (lne->offset == 0) {
373 address->line_addresses [i] = mep->minfo->jit->prologue_end;
377 address->line_addresses [i] = mep->minfo->jit->code_size;
379 for (j = 0; j < mep->minfo->num_il_offsets; j++) {
380 MonoSymbolFileLineNumberEntry *il = &mep->minfo->il_offsets [j];
382 if (il->offset >= lne->offset) {
383 address->line_addresses [i] = mep->minfo->jit->il_addresses [j];
391 range_table_compare_func (gconstpointer a, gconstpointer b)
393 const MonoDebugRangeInfo *r1 = (const MonoDebugRangeInfo *) a;
394 const MonoDebugRangeInfo *r2 = (const MonoDebugRangeInfo *) b;
396 if (r1->start_address < r2->start_address)
398 else if (r1->start_address > r2->start_address)
405 mono_debug_update_mono_symbol_file (MonoSymbolFile *symfile)
409 if (!symfile->_priv->method_table)
412 symfile->_priv->range_table = g_ptr_array_new ();
414 if (!symfile->address_table)
415 symfile->address_table = g_malloc0 (symfile->address_table_size);
417 g_hash_table_foreach (symfile->_priv->method_table, update_method_func, symfile);
419 symfile->range_table_size = symfile->_priv->range_table->len * sizeof (MonoDebugRangeInfo);
420 symfile->range_table = g_malloc0 (symfile->range_table_size);
422 g_ptr_array_sort (symfile->_priv->range_table, range_table_compare_func);
424 for (i = 0; i < symfile->_priv->range_table->len; i++) {
425 MonoDebugRangeInfo *range = g_ptr_array_index (symfile->_priv->range_table, i);
427 symfile->range_table [i] = *range;
430 g_ptr_array_free (symfile->_priv->range_table, TRUE);
431 symfile->_priv->range_table = NULL;
435 free_method_entry (MonoSymbolFileMethodEntryPriv *mep)
442 create_method (MonoSymbolFile *symfile, guint32 token, MonoMethod *method)
444 MonoSymbolFileMethodEntryPriv *mep;
445 MonoDebugMethodInfo *minfo;
447 g_assert (method->klass->image == symfile->_priv->image);
449 mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
450 mep->entry = g_new0 (MonoSymbolFileMethodEntry, 1);
451 mep->entry->token = token;
452 mep->entry->source_file_offset = symfile->_priv->offset_table->source_table_offset;
454 minfo = g_new0 (MonoDebugMethodInfo, 1);
455 minfo->method = method;
456 minfo->symfile = symfile;
459 mep->method = method;
461 symfile->_priv->offset_table->method_count++;
463 g_hash_table_insert (symfile->_priv->method_table, method, mep);
464 g_hash_table_insert (symfile->_priv->method_hash, method, minfo);
468 write_method (gpointer key, gpointer value, gpointer user_data)
470 MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
471 MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
473 if (symfile->_priv->error)
476 mep->minfo->file_offset = lseek (symfile->_priv->fd, 0, SEEK_CUR);
478 if (write (symfile->_priv->fd, mep->entry, sizeof (MonoSymbolFileMethodEntry)) < 0) {
479 symfile->_priv->error = TRUE;
485 write_line_numbers (gpointer key, gpointer value, gpointer user_data)
487 MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
488 MonoSymbolFilePriv *priv = symfile->_priv;
489 MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
490 MonoSymbolFileLineNumberEntry lne;
491 const unsigned char *ip, *start, *end;
492 MonoMethodHeader *header;
497 if ((mep->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
498 (mep->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
499 (mep->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
500 g_assert_not_reached ();
502 header = ((MonoMethodNormal *) mep->method)->header;
504 mep->entry->line_number_table_offset = lseek (priv->fd, 0, SEEK_CUR);
505 ++mep->entry->num_line_numbers;
510 if (write (priv->fd, &lne, sizeof (MonoSymbolFileLineNumberEntry)) < 0) {
515 ip = start = header->code;
516 end = ip + header->code_size;
521 ++mep->entry->num_line_numbers;
522 lne.offset = ip - start;
525 if (write (priv->fd, &lne, sizeof (MonoSymbolFileLineNumberEntry)) < 0) {
530 line = mono_disasm_code_one (NULL, mep->method, ip, &ip);
534 mep->entry->address_table_offset = symfile->address_table_size;
535 mep->entry->address_table_size = sizeof (MonoSymbolFileMethodAddress) +
536 mep->entry->num_line_numbers * sizeof (guint32);
538 symfile->address_table_size += mep->entry->address_table_size;
542 create_methods (MonoSymbolFile *symfile)
544 MonoImage *image = symfile->_priv->image;
545 MonoTableInfo *table = &image->tables [MONO_TABLE_METHOD];
548 for (idx = 1; idx <= table->rows; idx++) {
549 guint32 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
550 MonoMethod *method = mono_get_method (image, token, NULL);
552 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
553 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
554 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
557 if (method->wrapper_type != MONO_WRAPPER_NONE)
560 create_method (symfile, token, method);
565 load_line_numbers (gpointer key, gpointer value, gpointer user_data)
567 MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
568 MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
570 mep->minfo->num_il_offsets = mep->entry->num_line_numbers;
571 mep->minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
572 (symfile->raw_contents + mep->entry->line_number_table_offset);
576 create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings)
578 MonoSymbolFilePriv *priv = symfile->_priv;
584 priv->fd = g_file_open_tmp (NULL, &priv->file_name, NULL);
585 if (priv->fd == -1) {
587 g_warning ("Can't create symbol file");
591 magic = MONO_SYMBOL_FILE_MAGIC;
592 if (write (priv->fd, &magic, sizeof (magic)) < 0)
595 version = MONO_SYMBOL_FILE_VERSION;
596 if (write (priv->fd, &version, sizeof (version)) < 0)
599 offset = lseek (priv->fd, 0, SEEK_CUR);
601 priv->offset_table = g_new0 (MonoSymbolFileOffsetTable, 1);
602 if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
606 // Write source file table.
608 if (priv->source_file) {
609 priv->offset_table->source_table_offset = lseek (priv->fd, 0, SEEK_CUR);
610 if (!write_string (priv->fd, priv->source_file))
612 priv->offset_table->source_table_size = lseek (priv->fd, 0, SEEK_CUR) -
613 priv->offset_table->source_table_offset;
617 // Create method table.
620 priv->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
621 (GDestroyNotify) free_method_entry);
622 priv->method_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
623 (GDestroyNotify) free_method_info);
625 create_methods (symfile);
628 // Write line numbers.
631 priv->offset_table->line_number_table_offset = lseek (priv->fd, 0, SEEK_CUR);
633 g_hash_table_foreach (priv->method_table, write_line_numbers, symfile);
637 priv->offset_table->line_number_table_size = lseek (priv->fd, 0, SEEK_CUR) -
638 priv->offset_table->line_number_table_offset;
641 // Write method table.
644 priv->offset_table->method_table_offset = lseek (priv->fd, 0, SEEK_CUR);
646 g_hash_table_foreach (priv->method_table, write_method, symfile);
650 priv->offset_table->method_table_size = lseek (priv->fd, 0, SEEK_CUR) -
651 priv->offset_table->method_table_offset;
654 // Write offset table.
657 symfile->raw_contents_size = lseek (priv->fd, 0, SEEK_CUR);
658 priv->offset_table->address_table_size = symfile->address_table_size;
660 lseek (priv->fd, offset, SEEK_SET);
661 if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
664 lseek (priv->fd, symfile->raw_contents_size, SEEK_SET);
666 ptr = mono_raw_buffer_load (priv->fd, TRUE, 0, symfile->raw_contents_size);
670 symfile->raw_contents = ptr;
673 // Load line number table.
675 g_hash_table_foreach (priv->method_table, load_line_numbers, symfile);
683 mono_debug_create_mono_symbol_file (MonoImage *image)
685 MonoSymbolFile *symfile;
687 symfile = g_new0 (MonoSymbolFile, 1);
688 symfile->magic = MONO_SYMBOL_FILE_MAGIC;
689 symfile->version = MONO_SYMBOL_FILE_VERSION;
690 symfile->is_dynamic = TRUE;
691 symfile->image_file = g_strdup (image->name);
693 symfile->_priv = g_new0 (MonoSymbolFilePriv, 1);
694 symfile->_priv->image = image;
696 g_message (G_STRLOC ": %s", image->name);
698 if (!create_symfile (symfile, TRUE)) {
699 mono_debug_close_mono_symbol_file (symfile);
706 MonoDebugMethodInfo *
707 mono_debug_find_method (MonoSymbolFile *symfile, MonoMethod *method)
709 return g_hash_table_lookup (symfile->_priv->method_hash, method);