2007-09-25 Martin Baulig <martin@ximian.com>
[mono.git] / mono / mini / debug-mini.c
1 /*
2  * debug-mini.c: Mini-specific debugging stuff.
3  *
4  * Author:
5  *   Martin Baulig (martin@ximian.com)
6  *
7  * (C) 2003 Ximian, Inc.
8  */
9
10 #include "mini.h"
11 #include "jit.h"
12 #include "config.h"
13 #include <mono/metadata/verify.h>
14 #include <mono/metadata/mono-config.h>
15 #include <mono/metadata/mono-debug.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/threads-types.h>
18
19 #define _IN_THE_MONO_DEBUGGER
20 #include <mono/metadata/mono-debug-debugger.h>
21 #include "debug-mini.h"
22
23 #ifdef HAVE_VALGRIND_H
24 #include <valgrind/valgrind.h>
25 #endif
26
27 #ifdef MONO_DEBUGGER_SUPPORTED
28 #include <libgc/include/libgc-mono-debugger.h>
29 #endif
30
31 typedef struct {
32         guint32 index;
33         MonoMethodDesc *desc;
34 } MiniDebugBreakpointInfo;
35
36 typedef struct
37 {
38         guint64 index;
39         MonoMethod *method;
40         MonoDebugMethodAddressList *address_list;
41 } MiniDebugMethodBreakpointInfo;
42
43 typedef struct
44 {
45         MonoDebugMethodJitInfo *jit;
46         GArray *line_numbers;
47         guint32 has_line_numbers;
48         guint32 breakpoint_id;
49 } MiniDebugMethodInfo;
50
51 struct _MonoDebuggerThreadInfo {
52         guint64 tid;
53         guint64 lmf_addr;
54         guint64 end_stack;
55
56         /* Next pointer. */
57         MonoDebuggerThreadInfo *next;
58
59         /*
60          * The stack bounds are only used when reading a core file.
61          */
62         guint64 stack_start;
63         guint64 signal_stack_start;
64         guint32 stack_size;
65         guint32 signal_stack_size;
66
67         /*
68          * The debugger doesn't access anything beyond this point.
69          */
70         MonoJitTlsData *jit_tls;
71 };
72
73 MonoDebuggerThreadInfo *mono_debugger_thread_table = NULL;
74
75 static void
76 mono_debugger_check_breakpoints (MonoMethod *method, MonoDebugMethodAddress *debug_info);
77
78 static inline void
79 record_line_number (MiniDebugMethodInfo *info, guint32 address, guint32 offset)
80 {
81         MonoDebugLineNumberEntry lne;
82
83         lne.native_offset = address;
84         lne.il_offset = offset;
85
86         g_array_append_val (info->line_numbers, lne);
87 }
88
89 static void
90 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
91 {
92         g_free (jit->line_numbers);
93         g_free (jit->lexical_blocks);
94         g_free (jit->this_var);
95         g_free (jit->params);
96         g_free (jit->locals);
97         g_free (jit);
98 }
99
100 void
101 mono_debug_init_method (MonoCompile *cfg, MonoBasicBlock *start_block, guint32 breakpoint_id)
102 {
103         MiniDebugMethodInfo *info;
104
105         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
106                 return;
107
108         info = g_new0 (MiniDebugMethodInfo, 1);
109         info->breakpoint_id = breakpoint_id;
110
111         cfg->debug_info = info;
112 }
113
114 void
115 mono_debug_open_method (MonoCompile *cfg)
116 {
117         MiniDebugMethodInfo *info;
118         MonoDebugMethodJitInfo *jit;
119         MonoMethodHeader *header;
120
121         info = (MiniDebugMethodInfo *) cfg->debug_info;
122         if (!info)
123                 return;
124
125         mono_class_init (cfg->method->klass);
126
127         header = mono_method_get_header (cfg->method);
128         g_assert (header);
129         
130         info->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
131         info->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
132         jit->num_locals = header->num_locals;
133         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
134 }
135
136 static void
137 write_variable (MonoInst *inst, MonoDebugVarInfo *var)
138 {
139         var->type = inst->inst_vtype;
140
141         if (inst->opcode == OP_REGVAR)
142                 var->index = inst->dreg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
143         else {
144                 /* the debug interface needs fixing to allow 0(%base) address */
145                 var->index = inst->inst_basereg | MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET;
146                 var->offset = inst->inst_offset;
147         }
148 }
149
150 /*
151  * mono_debug_add_vg_method:
152  *
153  *  Register symbol information for the method with valgrind
154  */
155 static void 
156 mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit)
157 {
158 #ifdef VALGRIND_ADD_LINE_INFO
159         MonoMethodHeader *header;
160         MonoDebugMethodInfo *minfo;
161         int i;
162         char *filename = NULL;
163         guint32 address, line_number;
164         const char *full_name;
165         guint32 *addresses;
166         guint32 *lines;
167
168         if (!RUNNING_ON_VALGRIND)
169                 return;
170
171         header = mono_method_get_header (method);
172
173         full_name = mono_method_full_name (method, TRUE);
174
175         addresses = g_new0 (guint32, header->code_size + 1);
176         lines = g_new0 (guint32, header->code_size + 1);
177
178         /* 
179          * Very simple code to convert the addr->offset mappings that mono has
180          * into [addr-addr] ->line number mappings.
181          */
182
183         minfo = mono_debug_lookup_method (method);
184         if (minfo) {
185                 /* Create offset->line number mapping */
186                 for (i = 0; i < header->code_size; ++i) {
187                         MonoDebugSourceLocation *location;
188
189                         location = mono_debug_symfile_lookup_location (minfo, i);
190                         if (!location)
191                                 continue;
192
193                         lines [i] = location.row;
194                         if (!filename)
195                                 filename = location.source_file;
196
197                         mono_debug_free_source_location (location);
198                 }
199         }
200
201         /* Create address->offset mapping */
202         for (i = 0; i < jit->num_line_numbers; ++i) {
203                 MonoDebugLineNumberEntry *lne = jit->line_numbers [i];
204
205                 g_assert (lne->offset <= header->code_size);
206
207                 if ((addresses [lne->offset] == 0) || (lne->address < addresses [lne->offset]))
208                         addresses [lne->offset] = lne->address;
209         }
210         /* Fill out missing addresses */
211         address = 0;
212         for (i = 0; i < header->code_size; ++i) {
213                 if (addresses [i] == 0)
214                         addresses [i] = address;
215                 else
216                         address = addresses [i];
217         }
218         
219         address = 0;
220         line_number = 0;
221         i = 0;
222         while (i < header->code_size) {
223                 if (lines [i] == line_number)
224                         i ++;
225                 else {
226                         if (line_number > 0) {
227                                 //g_assert (addresses [i] - 1 >= address);
228                                 
229                                 if (addresses [i] - 1 >= address) {
230                                         VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + addresses [i] - 1, filename, line_number);
231                                         //printf ("[%d-%d] -> %d.\n", address, addresses [i] - 1, line_number);
232                                 }
233                         }
234                         address = addresses [i];
235                         line_number = lines [i];
236                 }
237         }
238
239         if (line_number > 0) {
240                 VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + jit->code_size - 1, filename, line_number);
241                 //printf ("[%d-%d] -> %d.\n", address, jit->code_size - 1, line_number);
242         }
243
244         VALGRIND_ADD_SYMBOL (jit->code_start, jit->code_size, full_name);
245
246         g_free (addresses);
247         g_free (lines);
248 #endif /* VALGRIND_ADD_LINE_INFO */
249 }
250
251 void
252 mono_debug_close_method (MonoCompile *cfg)
253 {
254         MiniDebugMethodInfo *info;
255         MonoDebugMethodJitInfo *jit;
256         MonoMethodHeader *header;
257         MonoMethodSignature *sig;
258         MonoDebugMethodAddress *debug_info;
259         MonoMethod *method;
260         int i;
261
262         info = (MiniDebugMethodInfo *) cfg->debug_info;
263         if (!info || !info->jit) {
264                 if (info)
265                         g_free (info);
266                 return;
267         }
268
269         method = cfg->method;
270         header = mono_method_get_header (method);
271         sig = mono_method_signature (method);
272
273         jit = info->jit;
274         jit->code_start = cfg->native_code;
275         jit->epilogue_begin = cfg->epilog_begin;
276         jit->code_size = cfg->code_len;
277
278         record_line_number (info, jit->epilogue_begin, header->code_size);
279
280         jit->num_params = sig->param_count;
281         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
282
283         for (i = 0; i < jit->num_locals; i++)
284                 write_variable (cfg->varinfo [cfg->locals_start + i], &jit->locals [i]);
285
286         if (sig->hasthis) {
287                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
288                 write_variable (cfg->varinfo [0], jit->this_var);
289         }
290
291         for (i = 0; i < jit->num_params; i++)
292                 write_variable (cfg->varinfo [i + sig->hasthis], &jit->params [i]);
293
294         jit->num_line_numbers = info->line_numbers->len;
295         jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
296
297         for (i = 0; i < jit->num_line_numbers; i++)
298                 jit->line_numbers [i] = g_array_index (info->line_numbers, MonoDebugLineNumberEntry, i);
299
300         debug_info = mono_debug_add_method (method, jit, cfg->domain);
301
302         mono_debug_add_vg_method (method, jit);
303
304         if (info->breakpoint_id)
305                 mono_debugger_breakpoint_callback (method, info->breakpoint_id);
306
307         mono_debugger_check_breakpoints (method, debug_info);
308
309         mono_debug_free_method_jit_info (jit);
310         g_array_free (info->line_numbers, TRUE);
311         g_free (info);
312 }
313
314 void
315 mono_debug_record_line_number (MonoCompile *cfg, MonoInst *ins, guint32 address)
316 {
317         MiniDebugMethodInfo *info;
318         MonoMethodHeader *header;
319         guint32 offset;
320
321         info = (MiniDebugMethodInfo *) cfg->debug_info;
322         if (!info || !info->jit || !ins->cil_code)
323                 return;
324
325         header = mono_method_get_header (cfg->method);
326         g_assert (header);
327
328         if ((ins->cil_code < header->code) ||
329             (ins->cil_code > header->code + header->code_size))
330                 return;
331
332         offset = ins->cil_code - header->code;
333         if (!info->has_line_numbers) {
334                 info->jit->prologue_end = address;
335                 info->has_line_numbers = TRUE;
336         }
337
338         record_line_number (info, address, offset);
339 }
340
341 void
342 mono_debug_open_block (MonoCompile *cfg, MonoBasicBlock *bb, guint32 address)
343 {
344         MiniDebugMethodInfo *info;
345         MonoMethodHeader *header;
346         guint32 offset;
347
348         info = (MiniDebugMethodInfo *) cfg->debug_info;
349         if (!info || !info->jit || !bb->cil_code)
350                 return;
351
352         header = mono_method_get_header (cfg->method);
353         g_assert (header);
354
355         if ((bb->cil_code < header->code) ||
356             (bb->cil_code > header->code + header->code_size))
357                 return;
358
359         offset = bb->cil_code - header->code;
360         if (!info->has_line_numbers) {
361                 info->jit->prologue_end = address;
362                 info->has_line_numbers = TRUE;
363         }
364
365         record_line_number (info, address, offset);
366 }
367
368 static inline void
369 encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
370 {
371         guint8 *p = buf;
372
373         //printf ("ENCODE: %d 0x%x.\n", value, value);
374
375         /* 
376          * Same encoding as the one used in the metadata, extended to handle values
377          * greater than 0x1fffffff.
378          */
379         if ((value >= 0) && (value <= 127))
380                 *p++ = value;
381         else if ((value >= 0) && (value <= 16383)) {
382                 p [0] = 0x80 | (value >> 8);
383                 p [1] = value & 0xff;
384                 p += 2;
385         } else if ((value >= 0) && (value <= 0x1fffffff)) {
386                 p [0] = (value >> 24) | 0xc0;
387                 p [1] = (value >> 16) & 0xff;
388                 p [2] = (value >> 8) & 0xff;
389                 p [3] = value & 0xff;
390                 p += 4;
391         }
392         else {
393                 p [0] = 0xff;
394                 p [1] = (value >> 24) & 0xff;
395                 p [2] = (value >> 16) & 0xff;
396                 p [3] = (value >> 8) & 0xff;
397                 p [4] = value & 0xff;
398                 p += 5;
399         }
400         if (endbuf)
401                 *endbuf = p;
402 }
403
404 static inline gint32
405 decode_value (guint8 *ptr, guint8 **rptr)
406 {
407         guint8 b = *ptr;
408         gint32 len;
409         
410         if ((b & 0x80) == 0){
411                 len = b;
412                 ++ptr;
413         } else if ((b & 0x40) == 0){
414                 len = ((b & 0x3f) << 8 | ptr [1]);
415                 ptr += 2;
416         } else if (b != 0xff) {
417                 len = ((b & 0x1f) << 24) |
418                         (ptr [1] << 16) |
419                         (ptr [2] << 8) |
420                         ptr [3];
421                 ptr += 4;
422         }
423         else {
424                 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
425                 ptr += 5;
426         }
427         if (rptr)
428                 *rptr = ptr;
429
430         //printf ("DECODE: %d.\n", len);
431         return len;
432 }
433
434 static void
435 serialize_variable (MonoDebugVarInfo *var, guint8 *p, guint8 **endbuf)
436 {
437         guint32 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
438
439         switch (flags) {
440         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
441                 encode_value (var->index, p, &p);
442                 break;
443         case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
444                 encode_value (var->index, p, &p);
445                 encode_value (var->offset, p, &p);
446                 break;
447         default:
448                 g_assert_not_reached ();
449         }
450         *endbuf = p;
451 }
452
453 void
454 mono_debug_serialize_debug_info (MonoCompile *cfg, guint8 **out_buf, guint32 *buf_len)
455 {
456         MiniDebugMethodInfo *info;
457         MonoDebugMethodJitInfo *jit;
458         guint32 size, prev_offset, prev_native_offset;
459         guint8 *buf, *p;
460         int i;
461
462         info = (MiniDebugMethodInfo *) cfg->debug_info;
463         if (!info || !info->jit) {
464                 *buf_len = 0;
465                 return;
466         }
467         jit = info->jit;
468
469         size = ((jit->num_params + jit->num_locals + 1) * 10) + (jit->num_line_numbers * 10) + 64;
470         p = buf = g_malloc (size);
471         encode_value (jit->epilogue_begin, p, &p);
472         encode_value (jit->prologue_end, p, &p);
473         encode_value (jit->code_size, p, &p);
474
475         for (i = 0; i < jit->num_params; ++i)
476                 serialize_variable (&jit->params [i], p, &p);
477
478         if (mono_method_signature (cfg->method)->hasthis)
479                 serialize_variable (jit->this_var, p, &p);
480
481         for (i = 0; i < jit->num_locals; i++)
482                 serialize_variable (&jit->locals [i], p, &p);
483
484         encode_value (jit->num_line_numbers, p, &p);
485
486         prev_offset = 0;
487         prev_native_offset = 0;
488         for (i = 0; i < jit->num_line_numbers; ++i) {
489                 /* Sometimes, the offset values are not in increasing order */
490                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
491                 encode_value (lne->il_offset - prev_offset, p, &p);
492                 encode_value (lne->native_offset - prev_native_offset, p, &p);
493                 prev_offset = lne->il_offset;
494                 prev_native_offset = lne->native_offset;
495         }
496
497         g_assert (p - buf < size);
498
499         *out_buf = buf;
500         *buf_len = p - buf;
501 }
502
503 static void
504 deserialize_variable (MonoDebugVarInfo *var, guint8 *p, guint8 **endbuf)
505 {
506         guint32 flags;
507
508         var->index = decode_value (p, &p);
509
510         flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
511
512         switch (flags) {
513         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
514                 break;
515         case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
516                 var->offset = decode_value (p, &p);
517                 break;
518         default:
519                 g_assert_not_reached ();
520         }
521         *endbuf = p;
522 }
523
524 static MonoDebugMethodJitInfo *
525 deserialize_debug_info (MonoMethod *method, guint8 *code_start, guint8 *buf, guint32 buf_len)
526 {
527         MonoMethodHeader *header;
528         gint32 offset, native_offset, prev_offset, prev_native_offset;
529         MonoDebugMethodJitInfo *jit;
530         guint8 *p;
531         int i;
532
533         header = mono_method_get_header (method);
534         g_assert (header);
535
536         jit = g_new0 (MonoDebugMethodJitInfo, 1);
537         jit->code_start = code_start;
538         jit->num_locals = header->num_locals;
539         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
540         jit->num_params = mono_method_signature (method)->param_count;
541         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
542
543         p = buf;
544         jit->epilogue_begin = decode_value (p, &p);
545         jit->prologue_end = decode_value (p, &p);
546         jit->code_size = decode_value (p, &p);
547
548         for (i = 0; i < jit->num_params; ++i)
549                 deserialize_variable (&jit->params [i], p, &p);
550
551         if (mono_method_signature (method)->hasthis) {
552                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
553                 deserialize_variable (jit->this_var, p, &p);
554         }
555
556         for (i = 0; i < jit->num_locals; i++)
557                 deserialize_variable (&jit->locals [i], p, &p);
558
559         jit->num_line_numbers = decode_value (p, &p);
560         jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
561
562         prev_offset = 0;
563         prev_native_offset = 0;
564         for (i = 0; i < jit->num_line_numbers; ++i) {
565                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
566
567                 offset = prev_offset + decode_value (p, &p);
568                 native_offset = prev_native_offset + decode_value (p, &p);
569
570                 lne->native_offset = native_offset;
571                 lne->il_offset = offset;
572
573                 prev_offset = offset;
574                 prev_native_offset = native_offset;
575         }
576
577         return jit;
578 }
579
580 void
581 mono_debug_add_aot_method (MonoDomain *domain, MonoMethod *method, guint8 *code_start, 
582                            guint8 *debug_info, guint32 debug_info_len)
583 {
584         MonoDebugMethodJitInfo *jit;
585
586         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
587                 return;
588
589         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
590             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
591             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
592             (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
593             (method->wrapper_type != MONO_WRAPPER_NONE))
594                 return;
595
596         if (debug_info_len == 0)
597                 return;
598
599         jit = deserialize_debug_info (method, code_start, debug_info, debug_info_len);
600
601         mono_debug_add_method (method, jit, domain);
602
603         mono_debug_add_vg_method (method, jit);
604
605         mono_debug_free_method_jit_info (jit);
606 }
607
608 void
609 mono_debug_add_icall_wrapper (MonoMethod *method, MonoJitICallInfo* callinfo)
610 {
611         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
612                 return;
613
614         // mono_debug_add_wrapper (method, callinfo->wrapper, callinfo->func);
615 }
616
617 static void
618 print_var_info (MonoDebugVarInfo *info, int idx, const char *name, const char *type)
619 {
620         switch (info->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) {
621         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
622                 g_print ("%s %s (%d) in register %s\n", type, name, idx, mono_arch_regname (info->index & (~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS)));
623                 break;
624         case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
625                 g_print ("%s %s (%d) in memory: base register %s + %d\n", type, name, idx, mono_arch_regname (info->index & (~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS)), info->offset);
626                 break;
627         case MONO_DEBUG_VAR_ADDRESS_MODE_TWO_REGISTERS:
628         default:
629                 g_assert_not_reached ();
630         }
631 }
632
633 /**
634  * mono_debug_print_locals:
635  *
636  * Prints to stdout the information about the local variables in
637  * a method (if @only_arguments is false) or about the arguments.
638  * The information includes the storage info (where the variable 
639  * lives, in a register or in memory).
640  * The method is found by looking up what method has been emitted at
641  * the instruction address @ip.
642  * This is for use inside a debugger.
643  */
644 void
645 mono_debug_print_vars (gpointer ip, gboolean only_arguments)
646 {
647         MonoDomain *domain = mono_domain_get ();
648         MonoJitInfo *ji = mono_jit_info_table_find (domain, ip);
649         MonoDebugMethodJitInfo *jit;
650         int i;
651
652         if (!ji)
653                 return;
654
655         jit = mono_debug_find_method (mono_jit_info_get_method (ji), domain);
656         if (!jit)
657                 return;
658
659         if (only_arguments) {
660                 char **names;
661                 names = g_new (char *, jit->num_params);
662                 mono_method_get_param_names (mono_jit_info_get_method (ji), (const char **) names);
663                 if (jit->this_var)
664                         print_var_info (jit->this_var, 0, "this", "Arg");
665                 for (i = 0; i < jit->num_params; ++i) {
666                         print_var_info (&jit->params [i], i, names [i]? names [i]: "unknown name", "Arg");
667                 }
668                 g_free (names);
669         } else {
670                 for (i = 0; i < jit->num_locals; ++i) {
671                         print_var_info (&jit->locals [i], i, "", "Local");
672                 }
673         }
674 }
675
676
677 /*
678  * Debugger breakpoint interface.
679  *
680  * This interface is used to insert breakpoints on methods which are not yet JITed.
681  * The debugging code keeps a list of all such breakpoints and automatically inserts the
682  * breakpoint when the method is JITed.
683  */
684
685 static GPtrArray *method_breakpoints = NULL;
686
687 MonoDebugMethodAddressList *
688 mono_debugger_insert_method_breakpoint (MonoMethod *method, guint64 index)
689 {
690         MiniDebugMethodBreakpointInfo *info;
691
692         info = g_new0 (MiniDebugMethodBreakpointInfo, 1);
693         info->method = method;
694         info->index = index;
695
696         info->address_list = mono_debug_lookup_method_addresses (method);
697
698         if (!method_breakpoints)
699                 method_breakpoints = g_ptr_array_new ();
700
701         g_ptr_array_add (method_breakpoints, info);
702
703         return info->address_list;
704 }
705
706 int
707 mono_debugger_remove_method_breakpoint (guint64 index)
708 {
709         int i;
710
711         if (!method_breakpoints)
712                 return 0;
713
714         for (i = 0; i < method_breakpoints->len; i++) {
715                 MiniDebugMethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
716
717                 if (info->index != index)
718                         continue;
719
720                 g_ptr_array_remove (method_breakpoints, info);
721                 g_free (info->address_list);
722                 g_free (info);
723                 return 1;
724         }
725
726         return 0;
727 }
728
729 static void
730 mono_debugger_check_breakpoints (MonoMethod *method, MonoDebugMethodAddress *debug_info)
731 {
732         int i;
733
734         if (!method_breakpoints)
735                 return;
736
737         if (method->is_inflated)
738                 method = ((MonoMethodInflated *) method)->declaring;
739
740         for (i = 0; i < method_breakpoints->len; i++) {
741                 MiniDebugMethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i);
742
743                 if (method != info->method)
744                         continue;
745
746                 mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT,
747                                      (guint64) (gsize) debug_info, info->index);
748         }
749 }
750
751 /*
752  * The old Debugger breakpoint interface.
753  *
754  * This interface is used to insert breakpoints on methods which are not yet JITed.
755  * The debugging code keeps a list of all such breakpoints and automatically inserts the
756  * breakpoint when the method is JITed.
757  */
758
759 static GPtrArray *breakpoints = NULL;
760
761 int
762 mono_debugger_insert_breakpoint_full (MonoMethodDesc *desc)
763 {
764         static int last_breakpoint_id = 0;
765         MiniDebugBreakpointInfo *info;
766
767         info = g_new0 (MiniDebugBreakpointInfo, 1);
768         info->desc = desc;
769         info->index = ++last_breakpoint_id;
770
771         if (!breakpoints)
772                 breakpoints = g_ptr_array_new ();
773
774         g_ptr_array_add (breakpoints, info);
775
776         return info->index;
777 }
778
779 int
780 mono_debugger_remove_breakpoint (int breakpoint_id)
781 {
782         int i;
783
784         if (!breakpoints)
785                 return 0;
786
787         for (i = 0; i < breakpoints->len; i++) {
788                 MiniDebugBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
789
790                 if (info->index != breakpoint_id)
791                         continue;
792
793                 mono_method_desc_free (info->desc);
794                 g_ptr_array_remove (breakpoints, info);
795                 g_free (info);
796                 return 1;
797         }
798
799         return 0;
800 }
801
802 int
803 mono_debugger_insert_breakpoint (const gchar *method_name, gboolean include_namespace)
804 {
805         MonoMethodDesc *desc;
806
807         desc = mono_method_desc_new (method_name, include_namespace);
808         if (!desc)
809                 return 0;
810
811         return mono_debugger_insert_breakpoint_full (desc);
812 }
813
814 int
815 mono_debugger_method_has_breakpoint (MonoMethod *method)
816 {
817         int i;
818
819         if (!breakpoints || (method->wrapper_type != MONO_WRAPPER_NONE))
820                 return 0;
821
822         for (i = 0; i < breakpoints->len; i++) {
823                 MiniDebugBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
824
825                 if (!mono_method_desc_full_match (info->desc, method))
826                         continue;
827
828                 return info->index;
829         }
830
831         return 0;
832 }
833
834 void
835 mono_debugger_breakpoint_callback (MonoMethod *method, guint32 index)
836 {
837         mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT, (guint64) (gsize) method, index);
838 }
839
840 void
841 mono_debugger_thread_created (gsize tid, MonoJitTlsData *jit_tls)
842 {
843 #ifdef MONO_DEBUGGER_SUPPORTED
844         size_t stsize = 0;
845         guint8 *staddr = NULL;
846         MonoDebuggerThreadInfo *info;
847
848         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
849                 return;
850
851         mono_thread_get_stack_bounds (&staddr, &stsize);
852
853         info = g_new0 (MonoDebuggerThreadInfo, 1);
854         info->tid = tid;
855         info->stack_start = (guint64) (gsize) staddr;
856         info->signal_stack_start = (guint64) (gsize) jit_tls->signal_stack;
857         info->stack_size = stsize;
858         info->signal_stack_size = jit_tls->signal_stack_size;
859         info->end_stack = (guint64) (gsize) GC_mono_debugger_get_stack_ptr ();
860         info->lmf_addr = (guint64) (gsize) mono_get_lmf_addr ();
861         info->jit_tls = jit_tls;
862
863         info->next = mono_debugger_thread_table;
864         mono_debugger_thread_table = info;
865
866         mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CREATED,
867                              tid, (guint64) (gsize) info);
868 #endif /* MONO_DEBUGGER_SUPPORTED */
869 }
870
871 void
872 mono_debugger_thread_cleanup (MonoJitTlsData *jit_tls)
873 {
874 #ifdef MONO_DEBUGGER_SUPPORTED
875         MonoDebuggerThreadInfo **ptr;
876
877         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
878                 return;
879
880         for (ptr = &mono_debugger_thread_table; *ptr; ptr = &(*ptr)->next) {
881                 MonoDebuggerThreadInfo *info = *ptr;
882
883                 if (info->jit_tls != jit_tls)
884                         continue;
885
886                 mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CLEANUP,
887                                      info->tid, (guint64) (gsize) info);
888
889                 *ptr = info->next;
890                 g_free (info);
891                 break;
892         }
893 #endif
894 }