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