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