2002-08-24 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 static MonoDebugHandle *mono_debug_handles = NULL;
15 static MonoDebugHandle *mono_default_debug_handle = NULL;
16
17 static void
18 free_method_info (DebugMethodInfo *minfo)
19 {
20         if (minfo->line_numbers)
21                 g_ptr_array_free (minfo->line_numbers, TRUE);
22         g_free (minfo->method_info.params);
23         g_free (minfo->method_info.locals);
24         g_free (minfo);
25 }
26
27 static MonoDebugMethodInfo *
28 method_info_func (MonoSymbolFile *symfile, MonoMethod *method, gpointer user_data)
29 {
30         AssemblyDebugInfo *info = user_data;
31         DebugMethodInfo *minfo;
32
33         return (MonoDebugMethodInfo *) g_hash_table_lookup (info->handle->methods, method);
34 }
35
36 static void
37 debug_arg_warning (const char *message)
38 {
39         g_warning ("Error while processing --debug-args arguments: %s", message);
40 }
41
42 MonoDebugHandle*
43 mono_debug_open (MonoAssembly *assembly, MonoDebugFormat format, const char **args)
44 {
45         MonoDebugHandle *debug;
46         const char **ptr;
47         
48         debug = g_new0 (MonoDebugHandle, 1);
49         debug->name = g_strdup (assembly->image->name);
50         debug->format = format;
51         debug->producer_name = g_strdup_printf ("Mono JIT compiler version %s", VERSION);
52         debug->next_idx = 100;
53         debug->dirty = TRUE;
54
55         debug->type_hash = g_hash_table_new (NULL, NULL);
56         debug->methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
57                                                 NULL, (GDestroyNotify) free_method_info);
58         debug->source_files = g_ptr_array_new ();
59
60         for (ptr = args; ptr && *ptr; ptr++) {
61                 const char *arg = *ptr;
62                 gchar *message;
63
64                 switch (debug->format) {
65                 case MONO_DEBUG_FORMAT_STABS:
66                 case MONO_DEBUG_FORMAT_DWARF2:
67                         if (!strncmp (arg, "filename=", 9)) {
68                                 if (debug->filename)
69                                         debug_arg_warning ("The `filename' argument can be given only once.");
70                                 debug->filename = g_strdup (arg + 9);
71                                 continue;
72                         } else if (!strncmp (arg, "objfile=", 8)) {
73                                 if (debug->objfile)
74                                         debug_arg_warning ("The `objfile' argument can be given only once.");
75                                 debug->objfile = g_strdup (arg + 8);
76                                 continue;
77                         }
78                         break;
79                 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
80                         if (!strcmp (arg, "dont_fallback")) {
81                                 debug->flags |= MONO_DEBUG_FLAGS_DONT_FALLBACK;
82                                 continue;
83                         } else if (!strcmp (arg, "dont_precompile")) {
84                                 debug->flags |= MONO_DEBUG_FLAGS_DONT_PRECOMPILE;
85                                 continue;
86                         }
87                         debug->flags |= MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES |
88                                 MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
89                         break;
90                 case MONO_DEBUG_FORMAT_MONO:
91                         debug->flags |= MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES |
92                                 MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
93                         break;
94                 default:
95                         break;
96                 }
97
98                 if (debug->format != MONO_DEBUG_FORMAT_MONO) {
99                         if (!strcmp (arg, "dont_assemble")) {
100                                 debug->flags |= MONO_DEBUG_FLAGS_DONT_ASSEMBLE;
101                                 continue;
102                         } else if (!strcmp (arg, "update_on_exit")) {
103                                 debug->flags |= MONO_DEBUG_FLAGS_UPDATE_ON_EXIT;
104                                 continue;
105                         } else if (!strcmp (arg, "install_il_files")) {
106                                 debug->flags |= MONO_DEBUG_FLAGS_INSTALL_IL_FILES;
107                                 continue;
108                         } else if (!strcmp (arg, "dont_update_il_files")) {
109                                 debug->flags |= MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES;
110                                 continue;
111                         } else if (!strcmp (arg, "dont_create_il_files")) {
112                                 debug->flags |= MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
113                                 continue;
114                         }
115                 }
116
117                 message = g_strdup_printf ("Unknown argument `%s'.", arg);
118                 debug_arg_warning (message);
119                 g_free (message);
120         }
121
122         switch (debug->format) {
123         case MONO_DEBUG_FORMAT_STABS:
124                 if (!debug->filename)
125                         debug->filename = g_strdup_printf ("%s-stabs.s", g_basename (debug->name));
126                 if (!debug->objfile)
127                         debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
128                 break;
129         case MONO_DEBUG_FORMAT_DWARF2:
130                 if (!debug->filename)
131                         debug->filename = g_strdup_printf ("%s-dwarf.s", g_basename (debug->name));
132                 if (!debug->objfile)
133                         debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
134                 break;
135         case MONO_DEBUG_FORMAT_DWARF2_PLUS:
136                 if (!mono_default_debug_handle && !(debug->flags & MONO_DEBUG_FLAGS_DONT_FALLBACK))
137                         mono_debug_open (assembly, MONO_DEBUG_FORMAT_DWARF2, NULL);
138                 break;
139         case MONO_DEBUG_FORMAT_MONO:
140                 if (!debug->filename)
141                         debug->filename = g_strdup_printf ("%s.dbg", g_basename (debug->name));
142                 break;
143         default:
144                 g_assert_not_reached ();
145         }
146
147         debug->next = mono_debug_handles;
148         mono_debug_handles = debug;
149
150         if (!mono_default_debug_handle && (debug->format != MONO_DEBUG_FORMAT_DWARF2_PLUS))
151                 mono_default_debug_handle = debug;
152
153         return debug;
154 }
155
156 static void
157 debug_load_method_lines (AssemblyDebugInfo* info)
158 {
159         FILE *f;
160         char buf [1024];
161         int i, mnum;
162         int offset = -1;
163
164         if (!(info->handle->flags & MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES)) {
165                 char *command = g_strdup_printf ("monodis --output=%s %s",
166                                                  info->ilfile, info->image->name);
167                 struct stat stata, statb;
168                 int need_update = FALSE;
169
170                 if (stat (info->image->name, &stata)) {
171                         g_warning ("cannot access assembly file (%s): %s",
172                                    info->image->name, g_strerror (errno));
173                         g_free (command);
174                         return;
175                 }
176
177                 /* If the stat() failed or the file is older. */
178                 if (stat (info->ilfile, &statb)) {
179                         /* Don't create any new *.il files if the user told us not to do so. */
180                         if (!(info->handle->flags & MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES))
181                                 need_update = TRUE;
182                 } else if (statb.st_mtime < stata.st_mtime)
183                         need_update = TRUE;
184
185                 if (need_update) {
186                         g_print ("Recreating %s from %s.\n", info->ilfile, info->image->name);
187                         if (system (command)) {
188                                 g_warning ("cannot create IL assembly file (%s): %s",
189                                            command, g_strerror (errno));
190                                 g_free (command);
191                                 return;
192                         }
193                 }
194         }
195
196         /* use an env var with directories for searching. */
197         if (!(f = fopen (info->ilfile, "r"))) {
198                 g_warning ("cannot open IL assembly file %s", info->ilfile);
199                 return;
200         }
201
202         info->total_lines = 100;
203         info->moffsets = g_malloc (info->total_lines * sizeof (int));
204
205         i = 0;
206         while (fgets (buf, sizeof (buf), f)) {
207                 int pos = i;
208
209                 info->moffsets [i++] = offset;
210                 if (i + 2 >= info->total_lines) {
211                         info->total_lines += 100;
212                         info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
213                         g_assert (info->moffsets);
214                 }
215
216                 if (!sscanf (buf, " // method line %d", &mnum))
217                         continue;
218
219                 offset = 0;
220
221                 if (mnum >= info->nmethods)
222                         break;
223
224                 while (fgets (buf, sizeof (buf), f)) {
225                         int newoffset;
226
227                         ++i;
228                         if (i + 2 >= info->total_lines) {
229                                 info->total_lines += 100;
230                                 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
231                                 g_assert (info->moffsets);
232                         }
233
234                         if (strstr (buf, "}")) {
235                                 offset = -1;
236                                 break;
237                         }
238
239                         if (sscanf (buf, " IL_%x:", &newoffset)) {
240                                 offset = newoffset;
241                                 if (!offset)
242                                         pos = i;
243                         }
244
245                         info->moffsets [i] = offset;
246                 }
247                 /* g_print ("method %d found at %d\n", mnum, pos); */
248                 info->mlines [mnum] = pos;
249         }
250         fclose (f);
251 }
252
253 static void
254 record_line_number (DebugMethodInfo *minfo, gpointer address, guint32 line, int is_basic_block)
255 {
256         DebugLineNumberInfo *lni = g_new0 (DebugLineNumberInfo, 1);
257
258         lni->address = address;
259         lni->line = line;
260         lni->is_basic_block = is_basic_block;
261         lni->source_file = minfo->source_file;
262
263         g_ptr_array_add (minfo->line_numbers, lni);
264 }
265
266 static void
267 record_il_offset (GPtrArray *array, guint32 offset, guint32 address)
268 {
269         MonoDebugILOffsetInfo *info = g_new0 (MonoDebugILOffsetInfo, 1);
270
271         info->offset = offset;
272         info->address = address;
273
274         g_ptr_array_add (array, info);
275 }
276
277 static void
278 debug_generate_method_lines (AssemblyDebugInfo *info, DebugMethodInfo *minfo, MonoFlowGraph* cfg)
279 {
280         guint32 st_address, st_line;
281         GPtrArray *il_offsets;
282         int i;
283
284         il_offsets = g_ptr_array_new ();
285         minfo->line_numbers = g_ptr_array_new ();
286
287         st_line = minfo->first_line;
288         st_address = minfo->method_info.prologue_end;
289
290         /* record_line_number takes absolute memory addresses. */
291         record_line_number (minfo, minfo->method_info.code_start, minfo->start_line, FALSE);
292         /* record_il_offsets uses offsets relative to minfo->method_info.code_start. */
293         record_il_offset (il_offsets, 0, st_address);
294
295         /* This is the first actual code line of the method. */
296         record_line_number (minfo, minfo->method_info.code_start + st_address, st_line, TRUE);
297
298         /* start lines of basic blocks */
299         for (i = 0; i < cfg->block_count; ++i) {
300                 int j;
301
302                 for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
303                         MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
304                         gint32 line_inc = 0, addr_inc;
305
306                         if (!i && !j) {
307                                 st_line = minfo->first_line;
308                                 st_address = t->addr;
309
310                                 record_line_number (minfo, cfg->start + st_address, st_line, TRUE);
311                         }
312
313                         addr_inc = t->addr - st_address;
314                         st_address += addr_inc;
315
316                         if (t->cli_addr != -1)
317                                 record_il_offset (il_offsets, t->cli_addr, st_address);
318
319                         if (!info->moffsets)
320                                 continue;
321
322
323                         if (t->cli_addr != -1) {
324                                 int *lines = info->moffsets + st_line;
325                                 int *k = lines;
326
327                                 while ((*k != -1) && (*k < t->cli_addr))
328                                         k++;
329
330                                 line_inc = k - lines;
331                         }
332
333                         st_line += line_inc;
334
335                         record_line_number (minfo, minfo->method_info.code_start + st_address,
336                                             st_line, j == 0);
337                 }
338         }
339
340         minfo->method_info.num_il_offsets = il_offsets->len;
341         minfo->method_info.il_offsets = g_new0 (MonoDebugILOffsetInfo, il_offsets->len);
342         for (i = 0; i < il_offsets->len; i++) {
343                 MonoDebugILOffsetInfo *il = (MonoDebugILOffsetInfo *) g_ptr_array_index (il_offsets, i);
344
345                 minfo->method_info.il_offsets [i] = *il;
346         }
347
348         g_ptr_array_free (il_offsets, TRUE);
349 }
350
351 static AssemblyDebugInfo *
352 mono_debug_get_image (MonoDebugHandle* debug, MonoImage *image)
353 {
354         GList *tmp;
355         AssemblyDebugInfo *info;
356
357         if (debug->format == MONO_DEBUG_FORMAT_NONE)
358                 return NULL;
359
360         for (tmp = debug->info; tmp; tmp = tmp->next) {
361                 info = (AssemblyDebugInfo*)tmp->data;
362
363                 if (info->image == image)
364                         return info;
365         }
366
367         return NULL;
368 }
369
370 static AssemblyDebugInfo *
371 mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image)
372 {
373         AssemblyDebugInfo *info;
374
375         info = mono_debug_get_image (debug, image);
376         if (info != NULL)
377                 return info;
378
379         debug->dirty = TRUE;
380
381         info = g_new0 (AssemblyDebugInfo, 1);
382         info->image = image;
383         info->image->ref_count++;
384         info->name = g_strdup (image->assembly_name);
385         info->format = debug->format;
386         info->handle = debug;
387
388         info->source_file = debug->source_files->len;
389         g_ptr_array_add (debug->source_files, g_strdup_printf ("%s.il", image->assembly_name));
390
391         debug->info = g_list_prepend (debug->info, info);
392
393         info->nmethods = image->tables [MONO_TABLE_METHOD].rows + 1;
394         info->mlines = g_new0 (int, info->nmethods);
395
396         switch (info->format) {
397         case MONO_DEBUG_FORMAT_STABS:
398         case MONO_DEBUG_FORMAT_DWARF2:
399                 if (debug->flags & MONO_DEBUG_FLAGS_INSTALL_IL_FILES) {
400                         gchar *dirname = g_path_get_dirname (image->name);
401                         info->ilfile = g_strdup_printf ("%s/%s.il", dirname, info->name);
402                         g_free (dirname);
403                 } else
404                         info->ilfile = g_strdup_printf ("%s.il", info->name);
405                 break;
406         case MONO_DEBUG_FORMAT_DWARF2_PLUS: {
407                 gchar *dirname = g_path_get_dirname (image->name);
408                 info->filename = g_strdup_printf ("%s/%s-debug.s", dirname, info->name);
409                 info->objfile = g_strdup_printf ("%s-debug.o", info->name);
410                 mono_debug_open_assembly_dwarf2_plus (info);
411                 g_free (dirname);
412                 break;
413         }
414
415         case MONO_DEBUG_FORMAT_MONO:
416                 info->filename = g_strdup_printf ("%s.dbg", info->name);
417                 info->mono_symfile = mono_debug_open_mono_symbol_file (info->image, info->filename, TRUE);
418                 break;
419
420         default:
421                 break;
422         }
423
424         if ((debug->format != MONO_DEBUG_FORMAT_DWARF2_PLUS) &&
425             (debug->format != MONO_DEBUG_FORMAT_MONO))
426                 debug_load_method_lines (info);
427
428         return info;
429 }
430
431 void
432 mono_debug_add_image (MonoDebugHandle* debug, MonoImage *image)
433 {
434         mono_debug_open_image (debug, image);
435 }
436
437 void
438 mono_debug_write_symbols (MonoDebugHandle *debug)
439 {
440         GList *tmp;
441
442         if (!debug || !debug->dirty)
443                 return;
444
445         switch (debug->format) {
446         case MONO_DEBUG_FORMAT_STABS:
447                 mono_debug_write_stabs (debug);
448                 break;
449         case MONO_DEBUG_FORMAT_DWARF2:
450                 mono_debug_write_dwarf2 (debug);
451                 break;
452         case MONO_DEBUG_FORMAT_DWARF2_PLUS:
453                 for (tmp = debug->info; tmp; tmp = tmp->next) {
454                         AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
455
456                         mono_debug_write_assembly_dwarf2_plus (info);
457                 }
458                 break;
459         case MONO_DEBUG_FORMAT_MONO:
460                 for (tmp = debug->info; tmp; tmp = tmp->next) {
461                         AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
462
463                         if (!info->mono_symfile)
464                                 continue;
465
466                         mono_debug_update_mono_symbol_file (info->mono_symfile, method_info_func, info);
467                 }
468                 break;
469         default:
470                 g_assert_not_reached ();
471         }
472
473         debug->dirty = FALSE;
474 }
475
476 void
477 mono_debug_make_symbols (void)
478 {
479         MonoDebugHandle *debug;
480
481         for (debug = mono_debug_handles; debug; debug = debug->next)
482                 mono_debug_write_symbols (debug);
483 }
484
485 static void
486 mono_debug_close_assembly (AssemblyDebugInfo* info)
487 {
488         switch (info->format) {
489         case MONO_DEBUG_FORMAT_DWARF2_PLUS:
490                 mono_debug_close_assembly_dwarf2_plus (info);
491                 break;
492         case MONO_DEBUG_FORMAT_MONO:
493                 if (info->mono_symfile != NULL)
494                         mono_debug_close_mono_symbol_file (info->mono_symfile);
495                 break;
496         default:
497                 break;
498         }
499         g_free (info->mlines);
500         g_free (info->moffsets);
501         g_free (info->name);
502         g_free (info->ilfile);
503         g_free (info->filename);
504         g_free (info->objfile);
505         g_free (info);
506 }
507
508 void
509 mono_debug_cleanup (void)
510 {
511         MonoDebugHandle *debug, *temp;
512
513         for (debug = mono_debug_handles; debug; debug = temp) {
514                 GList *tmp;
515
516                 if (debug->flags & MONO_DEBUG_FLAGS_UPDATE_ON_EXIT)
517                         mono_debug_write_symbols (debug);
518
519
520                 for (tmp = debug->info; tmp; tmp = tmp->next) {
521                         AssemblyDebugInfo* info = (AssemblyDebugInfo*)tmp->data;
522
523                         mono_debug_close_assembly (info);
524                 }
525
526                 g_ptr_array_free (debug->source_files, TRUE);
527                 g_hash_table_destroy (debug->methods);
528                 g_hash_table_destroy (debug->type_hash);
529                 g_free (debug->producer_name);
530                 g_free (debug->name);
531
532                 temp = debug->next;
533                 g_free (debug);
534         }
535
536         mono_debug_handles = NULL;
537         mono_default_debug_handle = NULL;
538 }
539
540 guint32
541 mono_debug_get_type (MonoDebugHandle *debug, MonoClass *klass)
542 {
543         guint index, i;
544
545         mono_class_init (klass);
546
547         index = GPOINTER_TO_INT (g_hash_table_lookup (debug->type_hash, klass));
548         if (index)
549                 return index;
550
551         debug->dirty = TRUE;
552
553         index = ++debug->next_klass_idx;
554         g_hash_table_insert (debug->type_hash, klass, GINT_TO_POINTER (index));
555
556         if (klass->enumtype)
557                 return index;
558
559         switch (klass->byval_arg.type) {
560         case MONO_TYPE_CLASS:
561                 if (klass->parent)
562                         mono_debug_get_type (debug, klass->parent);
563
564                 for (i = 0; i < klass->method.count; i++) {
565                         MonoMethod *method = klass->methods [i];
566                         MonoType *ret_type = NULL;
567                         int j;
568
569                         if (method->signature->ret->type != MONO_TYPE_VOID)
570                                 ret_type = method->signature->ret;
571
572                         if (ret_type) {
573                                 MonoClass *ret_klass = mono_class_from_mono_type (ret_type);
574                                 mono_debug_get_type (debug, ret_klass);
575                         }
576
577                         for (j = 0; j < method->signature->param_count; j++) {
578                                 MonoType *sub_type = method->signature->params [j];
579                                 MonoClass *sub_klass = mono_class_from_mono_type (sub_type);
580                                 mono_debug_get_type (debug, sub_klass);
581                         }
582                 }
583                 // fall through
584         case MONO_TYPE_VALUETYPE:
585                 for (i = 0; i < klass->field.count; i++) {
586                         MonoClass *subclass = mono_class_from_mono_type (klass->fields [i].type);
587                         mono_debug_get_type (debug, subclass);
588                 }
589                 break;
590         case MONO_TYPE_ARRAY:
591         case MONO_TYPE_SZARRAY:
592                 mono_debug_get_type (debug, klass->element_class);
593                 break;
594         default:
595                 break;
596         }
597
598         return index;
599 }
600
601 MonoDebugHandle *
602 mono_debug_handle_from_class (MonoClass *klass)
603 {
604         MonoDebugHandle *debug;
605
606         mono_class_init (klass);
607
608         for (debug = mono_debug_handles; debug; debug = debug->next) {
609                 GList *tmp;
610
611                 for (tmp = debug->info; tmp; tmp = tmp->next) {
612                         AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
613
614                         if (info->image == klass->image)
615                                 return debug;
616                 }
617         }
618
619         return NULL;
620 }
621
622 static gint32
623 il_offset_from_address (DebugMethodInfo *minfo, guint32 address)
624 {
625         int i;
626
627         for (i = 0; i < minfo->method_info.num_il_offsets; i++) {
628                 MonoDebugILOffsetInfo *ilo = &minfo->method_info.il_offsets [i];
629
630                 if (ilo->address > address)
631                         return ilo->offset;
632         }
633
634         return -1;
635 }
636
637 static gint32
638 address_from_il_offset (DebugMethodInfo *minfo, guint32 il_offset)
639 {
640         int i;
641
642         for (i = 0; i < minfo->method_info.num_il_offsets; i++) {
643                 MonoDebugILOffsetInfo *ilo = &minfo->method_info.il_offsets [i];
644
645                 if (ilo->offset > il_offset)
646                         return ilo->address;
647         }
648
649         return -1;
650 }
651
652 void
653 mono_debug_add_type (MonoClass *klass)
654 {
655         MonoDebugHandle *debug = mono_debug_handle_from_class (klass);
656
657         g_assert (debug != NULL);
658
659         mono_debug_get_type (debug, klass);
660 }
661
662 static gint32
663 il_offset_from_position (MonoFlowGraph *cfg, MonoPosition *pos)
664 {
665         MonoBBlock *bblock;
666         MBTree *tree;
667
668         if (pos->abs_pos == 0)
669                 return -1;
670
671         if (pos->pos.bid >= cfg->block_count)
672                 return -1;
673
674         bblock = &cfg->bblocks [pos->pos.bid];
675         if (pos->pos.tid >= bblock->forest->len)
676                 return -1;
677
678         tree = (MBTree *) g_ptr_array_index (bblock->forest, pos->pos.tid);
679
680         return tree->cli_addr;
681 }
682
683 void
684 mono_debug_add_method (MonoFlowGraph *cfg)
685 {
686         MonoMethod *method = cfg->method;
687         MonoClass *klass = method->klass;
688         int method_number = 0, line = 0, start_line = 0, end_line = 0, i;
689         MonoDebugHandle* debug;
690         AssemblyDebugInfo* info;
691         DebugMethodInfo *minfo;
692         char *name;
693
694         mono_class_init (klass);
695
696         debug = mono_debug_handle_from_class (klass);
697         if (!debug) {
698                 if (mono_default_debug_handle)
699                         debug = mono_default_debug_handle;
700                 else
701                         return;
702         }
703
704         info = mono_debug_open_image (debug, klass->image);
705
706         /*
707          * Find the method index in the image.
708          */
709         for (i = 0; klass->methods && i < klass->method.count; ++i) {
710                 if (klass->methods [i] == method) {
711                         method_number = klass->method.first + i + 1;
712                         line = info->mlines [method_number];
713                         break;
714                 }
715         }
716
717         if (g_hash_table_lookup (debug->methods, method))
718                 return;
719
720         debug->dirty = TRUE;
721
722         if (info->moffsets) {
723                 /* info->moffsets contains -1 "outside" of functions. */
724                 for (i = line; (i > 0) && (info->moffsets [i] == 0); i--)
725                         ;
726                 start_line = i + 1;
727
728                 for (i = start_line; info->moffsets [i] != -1; i++)
729                         ;
730                 end_line = i;
731         }
732
733         name = g_strdup_printf ("%s%s%s.%s", klass->name_space, klass->name_space [0]? ".": "",
734                                 klass->name, method->name);
735
736         minfo = g_new0 (DebugMethodInfo, 1);
737         minfo->name = name;
738         minfo->start_line = start_line;
739         minfo->first_line = line;
740         minfo->last_line = end_line;
741         minfo->source_file = info->source_file;
742         minfo->info = info;
743         minfo->method_info.code_start = cfg->start;
744         minfo->method_info.code_size = cfg->epilogue_end;
745         minfo->method_number = method_number;
746         minfo->method_info.method = method;
747         minfo->method_info.num_params = method->signature->param_count;
748         minfo->method_info.params = g_new0 (MonoDebugVarInfo, minfo->method_info.num_params);
749         minfo->method_info.prologue_end = cfg->prologue_end;
750         minfo->method_info.epilogue_begin = cfg->epilog;
751
752         if (method->signature->hasthis) {
753                 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index;
754
755                 minfo->method_info.this_var = g_new0 (MonoDebugVarInfo, 1);
756                 minfo->method_info.this_var->offset = ptr->offset;
757         }
758
759         for (i = 0; i < minfo->method_info.num_params; i++) {
760                 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index +
761                         method->signature->hasthis;
762
763                 minfo->method_info.params [i].offset = ptr [i].offset;
764         }
765
766         debug_generate_method_lines (info, minfo, cfg);
767
768         if (!method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
769                 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
770                 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->locals_start_index;
771                 MonoDebugVarInfo *locals;
772
773                 locals = g_new0 (MonoDebugVarInfo, header->num_locals);
774                 for (i = 0; i < header->num_locals; i++) {
775                         gint32 begin_offset, end_offset;
776                         gint32 begin_scope, end_scope;
777
778                         if (ptr [i].reg >= 0) {
779                                 locals [i].index = ptr [i].reg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
780                                 locals [i].offset = 0;
781                         } else
782                                 locals [i].offset = ptr [i].offset;
783
784                         begin_offset = il_offset_from_position (cfg, &ptr [i].range.first_use);
785                         end_offset = il_offset_from_position (cfg, &ptr [i].range.last_use);
786                         if (end_offset >= 0)
787                                 end_offset++;
788
789                         begin_scope = address_from_il_offset (minfo, begin_offset);
790                         end_scope = address_from_il_offset (minfo, end_offset);
791
792                         if (begin_scope > 0)
793                                 locals [i].begin_scope = begin_scope;
794                         else
795                                 locals [i].begin_scope = minfo->method_info.prologue_end;
796                         if (end_scope > 0)
797                                 locals [i].end_scope = end_scope;
798                         else
799                                 locals [i].end_scope = minfo->method_info.epilogue_begin;
800                 }
801
802                 minfo->method_info.num_locals = header->num_locals;
803                 minfo->method_info.locals = locals;
804         }
805
806         g_hash_table_insert (debug->methods, method, minfo);
807 }
808
809 gchar *
810 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number)
811 {
812         MonoDebugHandle *debug;
813         DebugMethodInfo *minfo = NULL;
814         int i;
815
816         for (debug = mono_debug_handles; debug; debug = debug->next) {
817                 minfo = g_hash_table_lookup (debug->methods, method);
818
819                 if (minfo)
820                         break;
821         }
822
823         if (!minfo)
824                 return NULL;
825
826         if (minfo->info->mono_symfile) {
827                 gint32 offset = il_offset_from_address (minfo, address);
828                 
829                 if (offset < 0)
830                         return NULL;
831
832                 return mono_debug_find_source_location (minfo->info->mono_symfile, method, offset, line_number);
833         }
834
835         if (!minfo->line_numbers)
836                 return NULL;
837
838         for (i = 0; i < minfo->line_numbers->len; i++) {
839                 DebugLineNumberInfo *lni = g_ptr_array_index (minfo->line_numbers, i);
840
841                 if ((gchar *)lni->address > minfo->method_info.code_start + address) {
842                         gchar *source_file = g_ptr_array_index (debug->source_files, lni->source_file);
843
844                         if (line_number) {
845                                 *line_number = lni->line;
846                                 return g_strdup (source_file);
847                         } else
848                                 return g_strdup_printf ("%s:%d", source_file, lni->line);
849                 }
850         }
851
852         return NULL;
853 }
854
855 gint32
856 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address)
857 {
858         MonoDebugHandle *debug;
859         DebugMethodInfo *minfo = NULL;
860
861         if (address < 0)
862                 return -1;
863
864         for (debug = mono_debug_handles; debug; debug = debug->next) {
865                 minfo = g_hash_table_lookup (debug->methods, method);
866
867                 if (minfo)
868                         break;
869         }
870
871         if (!minfo || !minfo->method_info.il_offsets)
872                 return -1;
873
874         return il_offset_from_address (minfo, address);
875 }
876
877 gint32
878 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset)
879 {
880         MonoDebugHandle *debug;
881         DebugMethodInfo *minfo = NULL;
882
883         if (il_offset < 0)
884                 return -1;
885
886         for (debug = mono_debug_handles; debug; debug = debug->next) {
887                 minfo = g_hash_table_lookup (debug->methods, method);
888
889                 if (minfo)
890                         break;
891         }
892
893         if (!minfo || !minfo->method_info.il_offsets)
894                 return -1;
895
896         return address_from_il_offset (minfo, il_offset);
897 }