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