2002-09-06 Martin Baulig <martin@gnome.org>
[mono.git] / mono / jit / debug.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <sys/stat.h>
5 #include <mono/metadata/class.h>
6 #include <mono/metadata/tabledefs.h>
7 #include <mono/metadata/tokentype.h>
8 #include <mono/metadata/debug-mono-symfile.h>
9 #include <mono/jit/codegen.h>
10 #include <mono/jit/debug.h>
11
12 #include "debug-private.h"
13
14 /* See debug.h for documentation. */
15 guint32 mono_debugger_symbol_file_table_generation = 0;
16 guint8 *mono_debugger_symbol_file_table = NULL;
17
18 /* Caution: This function MUST be called before touching the symbol table! */
19 static void release_symbol_file_table (void);
20
21 static MonoDebugHandle *mono_debug_handles = NULL;
22 static MonoDebugHandle *mono_default_debug_handle = NULL;
23
24 /*
25  * This is a global data symbol which is read by the debugger.
26  */
27 MonoDebuggerInfo MONO_DEBUGGER__debugger_info = {
28         MONO_SYMBOL_FILE_MAGIC,
29         MONO_SYMBOL_FILE_VERSION,
30         sizeof (MonoDebuggerInfo),
31         &mono_generic_trampoline_code,
32         &mono_debugger_symbol_file_table_generation,
33         &mono_debugger_symbol_file_table,
34         &mono_debugger_update_symbol_file_table,
35         &mono_compile_method
36 };
37
38 static void
39 free_method_info (MonoDebugMethodInfo *minfo)
40 {
41         DebugMethodInfo *priv = minfo->user_data;
42
43         if (priv) {
44                 if (priv->line_numbers)
45                         g_ptr_array_free (priv->line_numbers, TRUE);
46
47                 g_free (priv->name);
48                 g_free (priv);
49         }
50
51         if (minfo->jit) {
52                 g_free (minfo->jit->il_addresses);
53                 g_free (minfo->jit->this_var);
54                 g_free (minfo->jit->params);
55                 g_free (minfo->jit->locals);
56                 g_free (minfo->jit);
57         }
58
59         g_free (minfo->il_offsets);
60         g_free (minfo);
61 }
62
63 static void
64 debug_arg_warning (const char *message)
65 {
66         g_warning ("Error while processing --debug-args arguments: %s", message);
67 }
68
69 static gchar *
70 replace_suffix (const char *filename, const char *new_suffix)
71 {
72         const char *pos = strrchr (filename, '.');
73
74         if (!pos)
75                 return g_strdup_printf ("%s.%s", filename, new_suffix);
76         else {
77                 int len = pos - filename;
78                 gchar *retval = g_malloc0 (len + strlen (new_suffix) + 2);
79                 memcpy (retval, filename, len);
80                 retval [len] = '.';
81                 memcpy (retval + len + 1, new_suffix, strlen (new_suffix) + 1);
82                 return retval;
83         }
84 }
85
86 MonoDebugHandle*
87 mono_debug_open (const char *name, MonoDebugFormat format, const char **args)
88 {
89         MonoDebugHandle *debug;
90         const char **ptr;
91
92         release_symbol_file_table ();
93         
94         debug = g_new0 (MonoDebugHandle, 1);
95         debug->name = g_strdup (name);
96         debug->format = format;
97         debug->producer_name = g_strdup_printf ("Mono JIT compiler version %s", VERSION);
98         debug->next_idx = 100;
99         debug->dirty = TRUE;
100
101         debug->type_hash = g_hash_table_new (NULL, NULL);
102         debug->source_files = g_ptr_array_new ();
103
104         for (ptr = args; ptr && *ptr; ptr++) {
105                 const char *arg = *ptr;
106                 gchar *message;
107
108                 switch (debug->format) {
109                 case MONO_DEBUG_FORMAT_STABS:
110                 case MONO_DEBUG_FORMAT_DWARF2:
111                         if (!strncmp (arg, "filename=", 9)) {
112                                 if (debug->filename)
113                                         debug_arg_warning ("The `filename' argument can be given only once.");
114                                 debug->filename = g_strdup (arg + 9);
115                                 continue;
116                         } else if (!strncmp (arg, "objfile=", 8)) {
117                                 if (debug->objfile)
118                                         debug_arg_warning ("The `objfile' argument can be given only once.");
119                                 debug->objfile = g_strdup (arg + 8);
120                                 continue;
121                         }
122                         break;
123                 case MONO_DEBUG_FORMAT_MONO:
124                         debug->flags |= MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES |
125                                 MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
126                         break;
127                 default:
128                         break;
129                 }
130
131                 if (debug->format != MONO_DEBUG_FORMAT_MONO) {
132                         if (!strcmp (arg, "dont_assemble")) {
133                                 debug->flags |= MONO_DEBUG_FLAGS_DONT_ASSEMBLE;
134                                 continue;
135                         } else if (!strcmp (arg, "update_on_exit")) {
136                                 debug->flags |= MONO_DEBUG_FLAGS_UPDATE_ON_EXIT;
137                                 continue;
138                         } else if (!strcmp (arg, "install_il_files")) {
139                                 debug->flags |= MONO_DEBUG_FLAGS_INSTALL_IL_FILES;
140                                 continue;
141                         } else if (!strcmp (arg, "dont_update_il_files")) {
142                                 debug->flags |= MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES;
143                                 continue;
144                         } else if (!strcmp (arg, "dont_create_il_files")) {
145                                 debug->flags |= MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
146                                 continue;
147                         }
148                 } else {
149                         if (!strcmp (arg, "internal_mono_debugger")) {
150                                 debug->flags |= MONO_DEBUG_FLAGS_MONO_DEBUGGER;
151                                 continue;
152                         }
153                 }
154
155                 message = g_strdup_printf ("Unknown argument `%s'.", arg);
156                 debug_arg_warning (message);
157                 g_free (message);
158         }
159
160         switch (debug->format) {
161         case MONO_DEBUG_FORMAT_STABS:
162                 if (!debug->filename)
163                         debug->filename = g_strdup_printf ("%s-stabs.s", g_basename (debug->name));
164                 if (!debug->objfile)
165                         debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
166                 break;
167         case MONO_DEBUG_FORMAT_DWARF2:
168                 if (!debug->filename)
169                         debug->filename = g_strdup_printf ("%s-dwarf.s", g_basename (debug->name));
170                 if (!debug->objfile)
171                         debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
172                 break;
173         case MONO_DEBUG_FORMAT_MONO:
174                 break;
175         default:
176                 g_assert_not_reached ();
177         }
178
179         debug->next = mono_debug_handles;
180         mono_debug_handles = debug;
181
182         if (!mono_default_debug_handle)
183                 mono_default_debug_handle = debug;
184
185         return debug;
186 }
187
188 static void
189 generate_il_offsets (AssemblyDebugInfo *info, MonoMethod *method)
190 {
191         GPtrArray *il_offsets = g_ptr_array_new ();
192         MonoClass *klass = method->klass;
193         MonoDebugMethodInfo *minfo;
194         DebugMethodInfo *priv;
195         int i;
196
197         g_assert (klass->image == info->image);
198
199         /* FIXME: doesn't work yet. */
200         if (!strcmp (klass->name_space, "System.Runtime.Remoting.Proxies"))
201                 return;
202
203         mono_class_init (klass);
204
205         minfo = g_new0 (MonoDebugMethodInfo, 1);
206         minfo->method = method;
207         minfo->user_data = priv = g_new0 (DebugMethodInfo, 1);
208
209         priv->name = g_strdup_printf ("%s%s%s.%s", klass->name_space, klass->name_space [0]? ".": "",
210                                       klass->name, method->name);
211         priv->source_file = info->source_file;
212         priv->info = info;
213
214         /*
215          * Find the method index in the image.
216          */
217         for (i = 0; klass->methods && i < klass->method.count; ++i) {
218                 if (klass->methods [i] == minfo->method) {
219                         priv->method_number = klass->method.first + i + 1;
220                         priv->first_line = info->mlines [priv->method_number];
221                         break;
222                 }
223         }
224
225         g_assert (priv->method_number);
226
227         /* info->moffsets contains -1 "outside" of functions. */
228         for (i = priv->first_line; (i > 0) && (info->moffsets [i] == 0); i--)
229                 ;
230         priv->start_line = i + 1;
231
232         for (i = priv->start_line; info->moffsets [i] != -1; i++) {
233                 MonoSymbolFileLineNumberEntry *lne = g_new0 (MonoSymbolFileLineNumberEntry, 1);
234
235                 if (!info->moffsets [i] && (i > priv->start_line))
236                         continue;
237
238                 lne->offset = info->moffsets [i];
239                 lne->row = i;
240
241                 g_ptr_array_add (il_offsets, lne);
242         }
243
244         priv->last_line = i;
245
246         minfo->num_il_offsets = il_offsets->len;
247         minfo->il_offsets = g_new0 (MonoSymbolFileLineNumberEntry, il_offsets->len);
248         for (i = 0; i < il_offsets->len; i++) {
249                 MonoSymbolFileLineNumberEntry *il = g_ptr_array_index (il_offsets, i);
250
251                 minfo->il_offsets [i] = *il;
252         }
253
254         g_ptr_array_free (il_offsets, TRUE);
255
256         g_hash_table_insert (info->methods, method, minfo);
257 }
258
259 static void
260 debug_load_method_lines (AssemblyDebugInfo* info)
261 {
262         MonoTableInfo *table = &info->image->tables [MONO_TABLE_METHOD];
263         FILE *f;
264         char buf [1024];
265         int i, mnum, idx;
266         int offset = -1;
267
268         if (info->always_create_il || !(info->handle->flags & MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES)) {
269                 char *command = g_strdup_printf ("monodis --output=%s %s",
270                                                  info->ilfile, info->image->name);
271                 struct stat stata, statb;
272                 int need_update = FALSE;
273
274                 if (stat (info->image->name, &stata)) {
275                         g_warning ("cannot access assembly file (%s): %s",
276                                    info->image->name, g_strerror (errno));
277                         g_free (command);
278                         return;
279                 }
280
281                 /* If the stat() failed or the file is older. */
282                 if (stat (info->ilfile, &statb)) {
283                         /* Don't create any new *.il files if the user told us not to do so. */
284                         if (!(info->handle->flags & MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES))
285                                 need_update = TRUE;
286                 } else if (statb.st_mtime < stata.st_mtime)
287                         need_update = TRUE;
288
289                 if (need_update) {
290                         g_print ("Recreating %s from %s.\n", info->ilfile, info->image->name);
291                         if (system (command)) {
292                                 g_warning ("cannot create IL assembly file (%s): %s",
293                                            command, g_strerror (errno));
294                                 g_free (command);
295                                 return;
296                         }
297                 }
298         }
299
300         /* use an env var with directories for searching. */
301         if (!(f = fopen (info->ilfile, "r"))) {
302                 g_warning ("cannot open IL assembly file %s", info->ilfile);
303                 return;
304         }
305
306         info->total_lines = 100;
307         info->moffsets = g_malloc (info->total_lines * sizeof (int));
308
309         i = 0;
310         while (fgets (buf, sizeof (buf), f)) {
311                 int pos = i;
312
313                 info->moffsets [i++] = offset;
314                 if (i + 2 >= info->total_lines) {
315                         info->total_lines += 100;
316                         info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
317                         g_assert (info->moffsets);
318                 }
319
320                 if (!sscanf (buf, " // method line %d", &mnum))
321                         continue;
322
323                 offset = 0;
324
325                 if (mnum >= info->nmethods)
326                         break;
327
328                 while (fgets (buf, sizeof (buf), f)) {
329                         int newoffset;
330
331                         ++i;
332                         if (i + 2 >= info->total_lines) {
333                                 info->total_lines += 100;
334                                 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
335                                 g_assert (info->moffsets);
336                         }
337
338                         if (strstr (buf, "}")) {
339                                 offset = -1;
340                                 break;
341                         }
342
343                         if (sscanf (buf, " IL_%x:", &newoffset)) {
344                                 offset = newoffset;
345                                 if (!offset)
346                                         pos = i;
347                         }
348
349                         info->moffsets [i] = offset;
350                 }
351                 /* g_print ("method %d found at %d\n", mnum, pos); */
352                 info->mlines [mnum] = pos;
353         }
354         fclose (f);
355
356         for (idx = 1; idx <= table->rows; idx++) {
357                 guint32 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
358                 MonoMethod *method = mono_get_method (info->image, token, NULL);
359
360                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
361                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
362                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
363                         continue;
364
365                 if (method->wrapper_type != MONO_WRAPPER_NONE)
366                         continue;
367
368                 generate_il_offsets (info, method);
369         }
370 }
371
372 static void
373 record_line_number (DebugMethodInfo *priv, gconstpointer address, guint32 line, int is_basic_block)
374 {
375         DebugLineNumberInfo *lni = g_new0 (DebugLineNumberInfo, 1);
376
377         lni->address = address;
378         lni->line = line;
379         lni->is_basic_block = is_basic_block;
380         lni->source_file = priv->source_file;
381
382         g_ptr_array_add (priv->line_numbers, lni);
383 }
384
385 static void
386 debug_generate_method_lines (AssemblyDebugInfo *info, MonoDebugMethodInfo *minfo, MonoFlowGraph* cfg)
387 {
388         guint32 st_address, st_line;
389         DebugMethodInfo *priv = minfo->user_data;
390         int i;
391
392         if (!priv)
393                 return;
394
395         priv->line_numbers = g_ptr_array_new ();
396
397         st_line = priv->first_line;
398         st_address = minfo->jit->prologue_end;
399
400         /* record_line_number takes absolute memory addresses. */
401         record_line_number (priv, minfo->jit->code_start, priv->start_line, FALSE);
402
403         /* This is the first actual code line of the method. */
404         record_line_number (priv, minfo->jit->code_start + st_address, st_line, TRUE);
405
406         /* start lines of basic blocks */
407         for (i = 0; i < cfg->block_count; ++i) {
408                 int j;
409
410                 for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
411                         MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
412                         gint32 line_inc = 0, addr_inc;
413
414                         if (!i && !j) {
415                                 st_line = priv->first_line;
416                                 st_address = t->addr;
417
418                                 record_line_number (priv, cfg->start + st_address, st_line, TRUE);
419                         }
420
421                         addr_inc = t->addr - st_address;
422                         st_address += addr_inc;
423
424                         if (!info->moffsets)
425                                 continue;
426
427                         if (t->cli_addr != -1) {
428                                 int *lines = info->moffsets + st_line;
429                                 int *k = lines;
430
431                                 while ((*k != -1) && (*k < t->cli_addr))
432                                         k++;
433
434                                 line_inc = k - lines;
435                         }
436
437                         st_line += line_inc;
438
439                         record_line_number (priv, minfo->jit->code_start + st_address,
440                                             st_line, j == 0);
441                 }
442         }
443 }
444
445 static void
446 debug_update_il_offsets (AssemblyDebugInfo *info, MonoDebugMethodInfo *minfo, MonoFlowGraph* cfg)
447 {
448         guint32 old_address, st_address;
449         int index, i;
450
451         minfo->jit->il_addresses = g_new0 (guint32, minfo->num_il_offsets);
452         if (minfo->num_il_offsets < 2)
453                 return;
454
455         st_address = old_address = minfo->jit->prologue_end;
456
457         minfo->jit->il_addresses [0] = 0;
458         minfo->jit->il_addresses [1] = st_address;
459         index = 2;
460
461         /* start lines of basic blocks */
462         for (i = 0; i < cfg->block_count; ++i) {
463                 int j;
464
465                 for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
466                         MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
467                         gint32 addr_inc;
468
469                         if (!i && !j)
470                                 st_address = t->addr;
471
472                         addr_inc = t->addr - st_address;
473                         st_address += addr_inc;
474
475                         if (t->cli_addr == -1)
476                                 continue;
477
478                         while (minfo->il_offsets [index].offset < t->cli_addr) {
479                                 minfo->jit->il_addresses [index] = old_address;
480                                 if (++index >= minfo->num_il_offsets)
481                                         return;
482                         }
483
484                         minfo->jit->il_addresses [index] = st_address;
485                         old_address = st_address;
486                 }
487         }
488
489         while (index < minfo->num_il_offsets)
490                 minfo->jit->il_addresses [index++] = minfo->jit->epilogue_begin;
491 }
492
493 static AssemblyDebugInfo *
494 mono_debug_get_image (MonoDebugHandle* debug, MonoImage *image)
495 {
496         GList *tmp;
497         AssemblyDebugInfo *info;
498
499         if (debug->format == MONO_DEBUG_FORMAT_NONE)
500                 return NULL;
501
502         for (tmp = debug->info; tmp; tmp = tmp->next) {
503                 info = (AssemblyDebugInfo*)tmp->data;
504
505                 if (info->image == image)
506                         return info;
507         }
508
509         return NULL;
510 }
511
512 static AssemblyDebugInfo *
513 mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image)
514 {
515         AssemblyDebugInfo *info;
516
517         info = mono_debug_get_image (debug, image);
518         if (info != NULL)
519                 return info;
520
521 #if 0
522         if (!strcmp (image->assembly_name, "corlib"))
523                 return NULL;
524 #endif
525
526         debug->dirty = TRUE;
527
528         info = g_new0 (AssemblyDebugInfo, 1);
529         info->image = image;
530         info->image->ref_count++;
531         info->name = g_strdup (image->assembly_name);
532         info->format = debug->format;
533         info->handle = debug;
534         info->methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
535                                                NULL, (GDestroyNotify) free_method_info);
536
537         info->source_file = debug->source_files->len;
538         g_ptr_array_add (debug->source_files, g_strdup_printf ("%s.il", image->assembly_name));
539
540         debug->info = g_list_prepend (debug->info, info);
541
542         info->nmethods = image->tables [MONO_TABLE_METHOD].rows + 1;
543         info->mlines = g_new0 (int, info->nmethods);
544
545         switch (info->format) {
546         case MONO_DEBUG_FORMAT_STABS:
547         case MONO_DEBUG_FORMAT_DWARF2:
548                 if (debug->flags & MONO_DEBUG_FLAGS_INSTALL_IL_FILES) {
549                         gchar *dirname = g_path_get_dirname (image->name);
550                         info->ilfile = g_strdup_printf ("%s/%s.il", dirname, info->name);
551                         g_free (dirname);
552                 } else
553                         info->ilfile = g_strdup_printf ("%s.il", info->name);
554                 break;
555         case MONO_DEBUG_FORMAT_MONO:
556                 info->filename = replace_suffix (image->name, "dbg");
557                 if (g_file_test (info->filename, G_FILE_TEST_EXISTS))
558                         info->symfile = mono_debug_open_mono_symbol_file (info->image, info->filename, TRUE);
559                 else if (debug->flags & MONO_DEBUG_FLAGS_MONO_DEBUGGER)
560                         info->symfile = mono_debug_create_mono_symbol_file (info->image);
561                 mono_debugger_symbol_file_table_generation++;
562                 break;
563
564         default:
565                 break;
566         }
567
568         if (debug->format != MONO_DEBUG_FORMAT_MONO)
569                 debug_load_method_lines (info);
570
571         return info;
572 }
573
574 void
575 mono_debug_add_image (MonoDebugHandle* debug, MonoImage *image)
576 {
577         mono_debug_open_image (debug, image);
578 }
579
580 void
581 mono_debug_write_symbols (MonoDebugHandle *debug)
582 {
583         GList *tmp;
584
585         if (!debug || !debug->dirty)
586                 return;
587
588         release_symbol_file_table ();
589         
590         switch (debug->format) {
591         case MONO_DEBUG_FORMAT_STABS:
592                 mono_debug_write_stabs (debug);
593                 break;
594         case MONO_DEBUG_FORMAT_DWARF2:
595                 mono_debug_write_dwarf2 (debug);
596                 break;
597         case MONO_DEBUG_FORMAT_MONO:
598                 for (tmp = debug->info; tmp; tmp = tmp->next) {
599                         AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
600
601                         if (!info->symfile)
602                                 continue;
603
604                         mono_debug_update_mono_symbol_file (info->symfile);
605                 }
606                 break;
607         default:
608                 g_assert_not_reached ();
609         }
610
611         debug->dirty = FALSE;
612 }
613
614 void
615 mono_debug_make_symbols (void)
616 {
617         MonoDebugHandle *debug;
618
619         for (debug = mono_debug_handles; debug; debug = debug->next)
620                 mono_debug_write_symbols (debug);
621 }
622
623 static void
624 mono_debug_close_assembly (AssemblyDebugInfo* info)
625 {
626         switch (info->format) {
627         case MONO_DEBUG_FORMAT_MONO:
628                 if (info->symfile != NULL)
629                         mono_debug_close_mono_symbol_file (info->symfile);
630                 break;
631         default:
632                 break;
633         }
634         g_hash_table_destroy (info->methods);
635         g_free (info->mlines);
636         g_free (info->moffsets);
637         g_free (info->name);
638         g_free (info->ilfile);
639         g_free (info->filename);
640         g_free (info->objfile);
641         g_free (info);
642 }
643
644 void
645 mono_debug_cleanup (void)
646 {
647         MonoDebugHandle *debug, *temp;
648
649         release_symbol_file_table ();
650         
651         for (debug = mono_debug_handles; debug; debug = temp) {
652                 GList *tmp;
653
654                 if (debug->flags & MONO_DEBUG_FLAGS_UPDATE_ON_EXIT)
655                         mono_debug_write_symbols (debug);
656
657
658                 for (tmp = debug->info; tmp; tmp = tmp->next) {
659                         AssemblyDebugInfo* info = (AssemblyDebugInfo*)tmp->data;
660
661                         mono_debug_close_assembly (info);
662                 }
663
664                 g_ptr_array_free (debug->source_files, TRUE);
665                 g_hash_table_destroy (debug->type_hash);
666                 g_free (debug->producer_name);
667                 g_free (debug->name);
668
669                 temp = debug->next;
670                 g_free (debug);
671         }
672
673         mono_debug_handles = NULL;
674         mono_default_debug_handle = NULL;
675 }
676
677 guint32
678 mono_debug_get_type (MonoDebugHandle *debug, MonoClass *klass)
679 {
680         guint index, i;
681
682         mono_class_init (klass);
683
684         index = GPOINTER_TO_INT (g_hash_table_lookup (debug->type_hash, klass));
685         if (index)
686                 return index;
687
688         debug->dirty = TRUE;
689
690         index = ++debug->next_klass_idx;
691         g_hash_table_insert (debug->type_hash, klass, GINT_TO_POINTER (index));
692
693         if (klass->enumtype)
694                 return index;
695
696         switch (klass->byval_arg.type) {
697         case MONO_TYPE_CLASS:
698                 if (klass->parent)
699                         mono_debug_get_type (debug, klass->parent);
700
701                 for (i = 0; i < klass->method.count; i++) {
702                         MonoMethod *method = klass->methods [i];
703                         MonoType *ret_type = NULL;
704                         int j;
705
706                         if (method->signature->ret->type != MONO_TYPE_VOID)
707                                 ret_type = method->signature->ret;
708
709                         if (ret_type) {
710                                 MonoClass *ret_klass = mono_class_from_mono_type (ret_type);
711                                 mono_debug_get_type (debug, ret_klass);
712                         }
713
714                         for (j = 0; j < method->signature->param_count; j++) {
715                                 MonoType *sub_type = method->signature->params [j];
716                                 MonoClass *sub_klass = mono_class_from_mono_type (sub_type);
717                                 mono_debug_get_type (debug, sub_klass);
718                         }
719                 }
720                 // fall through
721         case MONO_TYPE_VALUETYPE:
722                 for (i = 0; i < klass->field.count; i++) {
723                         MonoClass *subclass = mono_class_from_mono_type (klass->fields [i].type);
724                         mono_debug_get_type (debug, subclass);
725                 }
726                 break;
727         case MONO_TYPE_ARRAY:
728         case MONO_TYPE_SZARRAY:
729                 mono_debug_get_type (debug, klass->element_class);
730                 break;
731         default:
732                 break;
733         }
734
735         return index;
736 }
737
738 MonoDebugHandle *
739 mono_debug_handle_from_class (MonoClass *klass)
740 {
741         MonoDebugHandle *debug;
742
743         mono_class_init (klass);
744
745         for (debug = mono_debug_handles; debug; debug = debug->next) {
746                 GList *tmp;
747
748                 for (tmp = debug->info; tmp; tmp = tmp->next) {
749                         AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
750
751                         if (info->image == klass->image)
752                                 return debug;
753                 }
754         }
755
756         return NULL;
757 }
758
759 static gint32
760 il_offset_from_address (MonoDebugMethodInfo *minfo, guint32 address)
761 {
762         int i;
763
764         if (!minfo->jit)
765                 return -1;
766
767         for (i = 0; i < minfo->num_il_offsets; i++)
768                 if (minfo->jit->il_addresses [i] > address)
769                         return minfo->il_offsets [i].offset;
770
771         return -1;
772 }
773
774 static gint32
775 address_from_il_offset (MonoDebugMethodInfo *minfo, guint32 il_offset)
776 {
777         int i;
778
779         if (!minfo->jit)
780                 return -1;
781
782         for (i = 0; i < minfo->num_il_offsets; i++)
783                 if (minfo->il_offsets [i].offset > il_offset)
784                         return minfo->jit->il_addresses [i];
785
786         return -1;
787 }
788
789 void
790 mono_debug_add_type (MonoClass *klass)
791 {
792         MonoDebugHandle *debug = mono_debug_handle_from_class (klass);
793
794         g_assert (debug != NULL);
795
796         mono_debug_get_type (debug, klass);
797 }
798
799 static gint32
800 il_offset_from_position (MonoFlowGraph *cfg, MonoPosition *pos)
801 {
802         MonoBBlock *bblock;
803         MBTree *tree;
804
805         if (pos->abs_pos == 0)
806                 return -1;
807
808         if (pos->pos.bid >= cfg->block_count)
809                 return -1;
810
811         bblock = &cfg->bblocks [pos->pos.bid];
812         if (pos->pos.tid >= bblock->forest->len)
813                 return -1;
814
815         tree = (MBTree *) g_ptr_array_index (bblock->forest, pos->pos.tid);
816
817         return tree->cli_addr;
818 }
819
820 static MonoDebugMethodInfo *
821 lookup_method (MonoMethod *method)
822 {
823         MonoDebugHandle *debug;
824
825         for (debug = mono_debug_handles; debug; debug = debug->next) {
826                 GList *tmp;
827
828                 for (tmp = debug->info; tmp; tmp = tmp->next) {
829                         AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
830                         MonoDebugMethodInfo *minfo;
831
832                         if (info->symfile)
833                                 minfo = mono_debug_find_method (info->symfile, method);
834                         else
835                                 minfo = g_hash_table_lookup (info->methods, method);
836
837                         if (minfo)
838                                 return minfo;
839                 }
840         }
841
842         return NULL;
843 }
844
845 void
846 mono_debug_add_method (MonoFlowGraph *cfg)
847 {
848         MonoMethod *method = cfg->method;
849         MonoClass *klass = method->klass;
850         MonoDebugHandle* debug;
851         AssemblyDebugInfo* info;
852         MonoDebugMethodJitInfo *jit;
853         MonoDebugMethodInfo *minfo;
854         int i;
855
856         mono_class_init (klass);
857
858         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
859             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
860             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
861                 return;
862
863         if (method->wrapper_type != MONO_WRAPPER_NONE)
864                 return;
865
866         debug = mono_debug_handle_from_class (klass);
867         if (!debug) {
868                 if (mono_default_debug_handle)
869                         debug = mono_default_debug_handle;
870                 else
871                         return;
872         }
873
874         release_symbol_file_table ();
875
876         info = mono_debug_open_image (debug, klass->image);
877
878         minfo = lookup_method (method);
879         if (!minfo || minfo->jit)
880                 return;
881
882         debug->dirty = TRUE;
883
884         mono_debugger_symbol_file_table_generation++;
885
886         minfo->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
887         jit->code_start = cfg->start;
888         jit->code_size = cfg->epilogue_end;
889         jit->prologue_end = cfg->prologue_end;
890         jit->epilogue_begin = cfg->epilog;
891         jit->num_params = method->signature->param_count;
892         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
893
894         if (method->signature->hasthis) {
895                 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index;
896
897                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
898                 jit->this_var->offset = ptr->offset;
899         }
900
901         for (i = 0; i < jit->num_params; i++) {
902                 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index +
903                         method->signature->hasthis;
904
905                 jit->params [i].offset = ptr [i].offset;
906         }
907
908         debug_generate_method_lines (info, minfo, cfg);
909         debug_update_il_offsets (info, minfo, cfg);
910
911         if (!method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
912                 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
913                 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->locals_start_index;
914                 MonoDebugVarInfo *locals;
915
916                 locals = g_new0 (MonoDebugVarInfo, header->num_locals);
917                 for (i = 0; i < header->num_locals; i++) {
918                         gint32 begin_offset, end_offset;
919                         gint32 begin_scope, end_scope;
920
921                         if (ptr [i].reg >= 0) {
922                                 locals [i].index = ptr [i].reg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
923                                 locals [i].offset = 0;
924                         } else
925                                 locals [i].offset = ptr [i].offset;
926
927                         begin_offset = il_offset_from_position (cfg, &ptr [i].range.first_use);
928                         end_offset = il_offset_from_position (cfg, &ptr [i].range.last_use);
929                         if (end_offset >= 0)
930                                 end_offset++;
931
932                         begin_scope = address_from_il_offset (minfo, begin_offset);
933                         end_scope = address_from_il_offset (minfo, end_offset);
934
935                         if (begin_scope > 0)
936                                 locals [i].begin_scope = begin_scope;
937                         else
938                                 locals [i].begin_scope = jit->prologue_end;
939                         if (end_scope > 0)
940                                 locals [i].end_scope = end_scope;
941                         else
942                                 locals [i].end_scope = jit->epilogue_begin;
943                 }
944
945                 jit->num_locals = header->num_locals;
946                 jit->locals = locals;
947         }
948 }
949
950 gchar *
951 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number)
952 {
953         MonoDebugMethodInfo *minfo = lookup_method (method);
954
955         if (!minfo)
956                 return NULL;
957
958         if (minfo->symfile) {
959                 gint32 offset = il_offset_from_address (minfo, address);
960                 
961                 if (offset < 0)
962                         return NULL;
963
964                 return mono_debug_find_source_location (minfo->symfile, method, offset, line_number);
965         }
966
967         return NULL;
968 }
969
970 gint32
971 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address)
972 {
973         MonoDebugMethodInfo *minfo;
974
975         if (address < 0)
976                 return -1;
977
978         minfo = lookup_method (method);
979         if (!minfo || !minfo->il_offsets)
980                 return -1;
981
982         return il_offset_from_address (minfo, address);
983 }
984
985 gint32
986 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset)
987 {
988         MonoDebugMethodInfo *minfo;
989
990         if (il_offset < 0)
991                 return -1;
992
993         minfo = lookup_method (method);
994         if (!minfo || !minfo->il_offsets)
995                 return -1;
996
997         return address_from_il_offset (minfo, il_offset);
998 }
999
1000 static void
1001 release_symbol_file_table ()
1002 {
1003         guint8 *temp;
1004
1005         if (!mono_debugger_symbol_file_table)
1006                 return;
1007
1008         /*
1009          * Caution: The debugger may access the memory pointed to by this variable
1010          *          at any time.  It is very important to set the pointer to NULL
1011          *          before freeing the area.
1012          */
1013
1014         temp = mono_debugger_symbol_file_table;
1015         mono_debugger_symbol_file_table = NULL;
1016         g_free (mono_debugger_symbol_file_table);
1017 }
1018
1019 int
1020 mono_debugger_update_symbol_file_table (void)
1021 {
1022         MonoDebugHandle *debug;
1023         int dirty = 0, count = 0;
1024         guint8 *ptr, *symfiles;
1025         guint32 size;
1026
1027         for (debug = mono_debug_handles; debug; debug = debug->next) {
1028                 GList *tmp;
1029
1030                 if (debug->format != MONO_DEBUG_FORMAT_MONO)
1031                         continue;
1032
1033                 if (debug->dirty)
1034                         dirty = TRUE;
1035
1036                 for (tmp = debug->info; tmp; tmp = tmp->next) {
1037                         AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
1038                         MonoSymbolFile *symfile = info->symfile;
1039
1040                         if (!symfile)
1041                                 continue;
1042
1043                         count++;
1044                 }
1045         }
1046
1047         if (!dirty)
1048                 return FALSE;
1049
1050         release_symbol_file_table ();
1051
1052         size = 2 * sizeof (guint32) + count * sizeof (MonoSymbolFile);
1053         symfiles = ptr = g_malloc0 (size);
1054         *((guint32 *) ptr)++ = size;
1055         *((guint32 *) ptr)++ = count;
1056         *((guint32 *) ptr)++ = mono_debugger_symbol_file_table_generation;
1057
1058         for (debug = mono_debug_handles; debug; debug = debug->next) {
1059                 GList *tmp;
1060
1061                 if (debug->format != MONO_DEBUG_FORMAT_MONO)
1062                         continue;
1063
1064                 for (tmp = debug->info; tmp; tmp = tmp->next) {
1065                         AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
1066                         MonoSymbolFile *symfile = info->symfile;
1067
1068                         if (!symfile)
1069                                 continue;
1070
1071                         if (debug->dirty)
1072                                 mono_debug_update_mono_symbol_file (info->symfile);
1073
1074                         *((MonoSymbolFile *) ptr)++ = *symfile;
1075                 }
1076         }
1077         
1078         mono_debugger_symbol_file_table = symfiles;
1079         return TRUE;
1080 }