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