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