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-mono-symfile.h>
15 struct MonoSymbolFilePriv
22 GHashTable *method_table;
23 GHashTable *method_hash;
24 MonoSymbolFileOffsetTable *offset_table;
31 MonoDebugMethodInfo *minfo;
32 MonoSymbolFileMethodEntry *entry;
33 } MonoSymbolFileMethodEntryPriv;
35 static int create_symfile (MonoSymbolFile *symfile, GHashTable *method_hash, gboolean emit_warnings);
36 static void close_symfile (MonoSymbolFile *symfile);
39 load_symfile (MonoSymbolFile *symfile)
41 MonoSymbolFilePriv *priv = symfile->_priv;
42 MonoSymbolFileMethodEntry *me;
43 const char *ptr, *start;
48 ptr = start = symfile->raw_contents;
50 magic = *((guint64 *) ptr)++;
51 if (magic != MONO_SYMBOL_FILE_MAGIC) {
52 g_warning ("Symbol file %s has is not a mono symbol file", priv->file_name);
56 version = *((guint32 *) ptr)++;
57 if (version != MONO_SYMBOL_FILE_VERSION) {
58 g_warning ("Symbol file %s has incorrect line number table version "
59 "(expected %d, got %ld)", priv->file_name,
60 MONO_SYMBOL_FILE_VERSION, version);
64 priv->offset_table = (MonoSymbolFileOffsetTable *) ptr;
65 symfile->address_table_size = priv->offset_table->address_table_size;
72 priv->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
73 (GDestroyNotify) g_free);
75 ptr = symfile->raw_contents + priv->offset_table->method_table_offset;
76 me = (MonoSymbolFileMethodEntry *) ptr;
78 for (i = 0; i < priv->offset_table->method_count; i++, me++) {
79 MonoMethod *method = mono_get_method (priv->image, me->token, NULL);
80 MonoSymbolFileMethodEntryPriv *mep;
85 mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
89 g_hash_table_insert (priv->method_table, method, mep);
96 mono_debug_open_mono_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
98 MonoSymbolFile *symfile;
99 MonoSymbolFilePriv *priv;
104 fd = open (filename, O_RDONLY);
107 g_warning ("Can't open symbol file: %s", filename);
111 file_size = lseek (fd, 0, SEEK_END);
112 lseek (fd, 0, SEEK_SET);
114 if (file_size == (off_t) -1) {
116 g_warning ("Can't get size of symbol file: %s", filename);
120 ptr = mono_raw_buffer_load (fd, FALSE, FALSE, 0, file_size);
123 g_warning ("Can't read symbol file: %s", filename);
127 symfile = g_new0 (MonoSymbolFile, 1);
128 symfile->magic = MONO_SYMBOL_FILE_MAGIC;
129 symfile->version = MONO_SYMBOL_FILE_VERSION;
130 symfile->raw_contents = ptr;
131 symfile->raw_contents_size = file_size;
133 symfile->_priv = priv = g_new0 (MonoSymbolFilePriv, 1);
137 priv->file_name = g_strdup (filename);
139 if (!load_symfile (symfile)) {
140 mono_debug_close_mono_symbol_file (symfile);
148 close_symfile (MonoSymbolFile *symfile)
150 MonoSymbolFilePriv *priv = symfile->_priv;
152 if (symfile->raw_contents) {
153 mono_raw_buffer_free (symfile->raw_contents);
154 symfile->raw_contents = NULL;
162 if (priv->method_table) {
163 g_hash_table_destroy (priv->method_table);
164 priv->method_table = NULL;
167 if (symfile->is_dynamic)
168 unlink (priv->file_name);
172 if (priv->file_name) {
173 g_free (priv->file_name);
174 priv->file_name = NULL;
179 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
184 close_symfile (symfile);
186 g_free (symfile->_priv->source_file);
187 g_free (symfile->_priv);
192 read_7bit_encoded_int (const char **ptr)
201 ret = ret | ((b & 0x7f) << shift);
203 } while ((b & 0x80) == 0x80);
209 write_7bit_encoded_int (int fd, int value)
212 int high = (value >> 7) & 0x01ffffff;
213 char b = (char)(value & 0x7f);
216 b = (char)(b | 0x80);
218 if (write (fd, &b, 1) < 0)
222 } while (value != 0);
227 write_string (int fd, const char *string)
229 if (!write_7bit_encoded_int (fd, strlen (string)))
232 if (write (fd, string, strlen (string)) < 0)
239 read_string (const char *ptr)
241 int len = read_7bit_encoded_int (&ptr);
244 retval = g_malloc0 (len+1);
245 memcpy (retval, ptr, len);
250 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
251 guint32 *line_number)
253 MonoSymbolFilePriv *priv = symfile->_priv;
254 MonoSymbolFileLineNumberEntry *lne;
255 MonoSymbolFileMethodEntryPriv *mep;
256 gchar *source_file = NULL;
260 if (!priv->method_table || symfile->is_dynamic)
263 mep = g_hash_table_lookup (priv->method_table, method);
267 if (mep->entry->source_file_offset)
268 source_file = read_string (symfile->raw_contents + mep->entry->source_file_offset);
270 ptr = symfile->raw_contents + mep->entry->line_number_table_offset;
272 lne = (MonoSymbolFileLineNumberEntry *) ptr;
274 for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
275 if (lne->offset < offset)
279 *line_number = lne->row;
284 } else if (source_file) {
285 gchar *retval = g_strdup_printf ("%s:%d", source_file, lne->row);
286 g_free (source_file);
289 return g_strdup_printf ("%d", lne->row);
297 MonoSymbolFile *symfile;
298 GHashTable *method_hash;
302 update_method_func (gpointer key, gpointer value, gpointer user_data)
304 struct MyData *mydata = (struct MyData *) user_data;
305 MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
306 MonoSymbolFileMethodAddress *address;
307 MonoSymbolFileLineNumberEntry *lne;
311 mep->minfo = g_hash_table_lookup (mydata->method_hash, mep->method);
313 address = (MonoSymbolFileMethodAddress *)
314 (mydata->symfile->address_table + mep->entry->address_table_offset);
316 address->is_valid = TRUE;
317 address->trampoline_address = GPOINTER_TO_UINT (mep->method->info);
320 address->start_address = address->end_address = 0;
321 fprintf (mydata->symfile->_priv->f, "%s.%s - %d - 0x%lx\n", mep->method->klass->name,
322 mep->method->name, mep->method->wrapper_type,
323 (long) address->trampoline_address);
327 address->start_address = GPOINTER_TO_UINT (mep->minfo->code_start);
328 address->end_address = GPOINTER_TO_UINT (mep->minfo->code_start + mep->minfo->code_size);
330 fprintf (mydata->symfile->_priv->f, "%s.%s - %d - 0x%lx - 0x%lx - 0x%lx\n", mep->method->klass->name,
331 mep->method->name, mep->method->wrapper_type,
332 (long) address->start_address, (long) address->end_address,
333 (long) address->trampoline_address);
335 lne = (MonoSymbolFileLineNumberEntry *)
336 (mydata->symfile->raw_contents + mep->entry->line_number_table_offset);
338 for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
342 address->line_addresses [i] = 0;
344 } else if (lne->offset == 0) {
345 address->line_addresses [i] = mep->minfo->prologue_end;
349 address->line_addresses [i] = mep->minfo->code_size;
351 for (j = 0; j < mep->minfo->num_il_offsets; j++) {
352 MonoDebugILOffsetInfo *il = &mep->minfo->il_offsets [j];
354 if (il->offset >= lne->offset) {
355 address->line_addresses [i] = il->address;
363 mono_debug_update_mono_symbol_file (MonoSymbolFile *symfile, GHashTable *method_hash)
365 g_message (G_STRLOC);
367 if (symfile->is_dynamic) {
368 close_symfile (symfile);
370 symfile->_priv->method_hash = method_hash;
372 if (!create_symfile (symfile, method_hash, TRUE)) {
373 symfile->_priv->method_hash = NULL;
374 close_symfile (symfile);
378 symfile->_priv->method_hash = NULL;
381 if (symfile->_priv->method_table) {
382 struct MyData mydata = { symfile, method_hash };
384 if (!symfile->address_table)
385 symfile->address_table = g_malloc0 (symfile->address_table_size);
387 symfile->_priv->f = fopen ("log", "at");
388 fprintf (symfile->_priv->f, "STARTING UPDATE\n");
389 g_hash_table_foreach (symfile->_priv->method_table, update_method_func, &mydata);
390 fclose (symfile->_priv->f);
395 free_method_entry (MonoSymbolFileMethodEntryPriv *mep)
402 create_method (gpointer key, gpointer value, gpointer user_data)
404 MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
405 MonoMethod *method = (MonoMethod *) value;
406 MonoSymbolFileMethodEntryPriv *mep;
408 if (method->klass->image != symfile->_priv->image)
411 mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
412 mep->entry = g_new0 (MonoSymbolFileMethodEntry, 1);
413 mep->entry->token = GPOINTER_TO_UINT (key);
414 mep->entry->source_file_offset = symfile->_priv->offset_table->source_table_offset;
416 mep->method = method;
418 if (!symfile->_priv->method_hash)
419 mep->minfo = g_hash_table_lookup (symfile->_priv->method_hash, method);
421 symfile->_priv->offset_table->method_count++;
423 g_hash_table_insert (symfile->_priv->method_table, method, mep);
427 write_method (gpointer key, gpointer value, gpointer user_data)
429 MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
430 MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
432 if (symfile->_priv->error)
435 if (write (symfile->_priv->fd, mep->entry, sizeof (MonoSymbolFileMethodEntry)) < 0) {
436 symfile->_priv->error = TRUE;
442 write_line_numbers (gpointer key, gpointer value, gpointer user_data)
444 MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
445 MonoSymbolFilePriv *priv = symfile->_priv;
446 MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
447 MonoSymbolFileLineNumberEntry lne;
454 mep->entry->address_table_size = sizeof (MonoSymbolFileMethodAddress);
455 symfile->address_table_size += mep->entry->address_table_size;
459 mep->entry->num_line_numbers = mep->minfo->num_il_offsets;
460 mep->entry->line_number_table_offset = lseek (priv->fd, 0, SEEK_CUR);
462 for (i = 0; i < mep->minfo->num_il_offsets; i++) {
463 MonoDebugILOffsetInfo *il = &mep->minfo->il_offsets [i];
466 lne.offset = il->offset;
468 if (write (priv->fd, &lne, sizeof (MonoSymbolFileLineNumberEntry)) < 0) {
474 mep->entry->address_table_offset = symfile->address_table_size;
475 mep->entry->address_table_size = sizeof (MonoSymbolFileMethodAddress) +
476 mep->entry->num_line_numbers * sizeof (guint32);
478 symfile->address_table_size += mep->entry->address_table_size;
482 create_symfile (MonoSymbolFile *symfile, GHashTable *method_hash, gboolean emit_warnings)
484 MonoSymbolFilePriv *priv = symfile->_priv;
490 priv->fd = g_file_open_tmp (NULL, &priv->file_name, NULL);
491 if (priv->fd == -1) {
493 g_warning ("Can't create symbol file");
497 magic = MONO_SYMBOL_FILE_MAGIC;
498 if (write (priv->fd, &magic, sizeof (magic)) < 0)
501 version = MONO_SYMBOL_FILE_VERSION;
502 if (write (priv->fd, &version, sizeof (version)) < 0)
505 offset = lseek (priv->fd, 0, SEEK_CUR);
507 priv->offset_table = g_new0 (MonoSymbolFileOffsetTable, 1);
508 if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
512 // Write source file table.
514 if (priv->source_file) {
515 priv->offset_table->source_table_offset = lseek (priv->fd, 0, SEEK_CUR);
516 if (!write_string (priv->fd, priv->source_file))
518 priv->offset_table->source_table_size = lseek (priv->fd, 0, SEEK_CUR) -
519 priv->offset_table->source_table_offset;
523 // Create method table.
526 priv->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
527 (GDestroyNotify) free_method_entry);
529 g_hash_table_foreach (priv->image->method_cache, create_method, symfile);
532 // Write line numbers.
535 priv->offset_table->line_number_table_offset = lseek (priv->fd, 0, SEEK_CUR);
537 g_hash_table_foreach (priv->method_table, write_line_numbers, symfile);
541 priv->offset_table->line_number_table_size = lseek (priv->fd, 0, SEEK_CUR) -
542 priv->offset_table->line_number_table_offset;
545 // Write method table.
548 priv->offset_table->method_table_offset = lseek (priv->fd, 0, SEEK_CUR);
550 g_hash_table_foreach (priv->method_table, write_method, symfile);
554 priv->offset_table->method_table_size = lseek (priv->fd, 0, SEEK_CUR) -
555 priv->offset_table->method_table_offset;
558 // Write offset table.
561 symfile->raw_contents_size = lseek (priv->fd, 0, SEEK_CUR);
562 priv->offset_table->address_table_size = symfile->address_table_size;
564 lseek (priv->fd, offset, SEEK_SET);
565 if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
568 lseek (priv->fd, symfile->raw_contents_size, SEEK_SET);
570 ptr = mono_raw_buffer_load (priv->fd, TRUE, FALSE, 0, symfile->raw_contents_size);
574 symfile->raw_contents = ptr;
580 mono_debug_create_mono_symbol_file (MonoImage *image, const char *source_file)
582 MonoSymbolFile *symfile;
584 symfile = g_new0 (MonoSymbolFile, 1);
585 symfile->magic = MONO_SYMBOL_FILE_MAGIC;
586 symfile->version = MONO_SYMBOL_FILE_VERSION;
587 symfile->is_dynamic = TRUE;
589 symfile->_priv = g_new0 (MonoSymbolFilePriv, 1);
590 symfile->_priv->image = image;
591 symfile->_priv->source_file = g_strdup (source_file);