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