2 * debug-mini.c: Mini-specific debugging stuff.
5 * Martin Baulig (martin@ximian.com)
7 * (C) 2003 Ximian, Inc.
12 #include <mono/metadata/verify.h>
13 #include <mono/metadata/mono-config.h>
14 #include <mono/metadata/mono-debug.h>
15 #include <mono/metadata/appdomain.h>
16 /* mono-debug-debugger.h needs config.h to work... */
18 #include <mono/metadata/mono-debug-debugger.h>
20 #ifdef HAVE_VALGRIND_H
21 #include <valgrind/valgrind.h>
26 MonoDebugMethodJitInfo *jit;
28 guint32 has_line_numbers;
29 guint32 breakpoint_id;
30 } MiniDebugMethodInfo;
33 record_line_number (MiniDebugMethodInfo *info, guint32 address, guint32 offset)
35 MonoDebugLineNumberEntry lne;
37 lne.native_offset = address;
38 lne.il_offset = offset;
40 g_array_append_val (info->line_numbers, lne);
44 mono_debug_init_method (MonoCompile *cfg, MonoBasicBlock *start_block, guint32 breakpoint_id)
46 MonoMethod *method = cfg->method;
47 MiniDebugMethodInfo *info;
49 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
52 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
53 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
54 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
55 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
57 if ((method->wrapper_type != MONO_WRAPPER_NONE) &&
58 (method->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE))
61 info = g_new0 (MiniDebugMethodInfo, 1);
62 info->breakpoint_id = breakpoint_id;
64 cfg->debug_info = info;
68 mono_debug_open_method (MonoCompile *cfg)
70 MiniDebugMethodInfo *info;
71 MonoDebugMethodJitInfo *jit;
72 MonoMethodHeader *header;
74 info = (MiniDebugMethodInfo *) cfg->debug_info;
78 mono_class_init (cfg->method->klass);
80 header = mono_method_get_header (cfg->method);
83 info->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
84 info->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
85 jit->num_locals = header->num_locals;
86 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
90 write_variable (MonoInst *inst, MonoDebugVarInfo *var)
92 if (inst->opcode == OP_REGVAR)
93 var->index = inst->dreg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
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;
102 * mono_debug_add_vg_method:
104 * Register symbol information for the method with valgrind
107 mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit)
109 #ifdef VALGRIND_ADD_LINE_INFO
110 MonoMethodHeader *header;
112 char *filename = NULL;
113 guint32 address, line_number;
114 const char *full_name;
118 if (!RUNNING_ON_VALGRIND)
121 header = mono_method_get_header (method);
123 full_name = mono_method_full_name (method, TRUE);
125 addresses = g_new0 (guint32, header->code_size + 1);
126 lines = g_new0 (guint32, header->code_size + 1);
129 * Very simple code to convert the addr->offset mappings that mono has
130 * into [addr-addr] ->line number mappings.
133 /* Create offset->line number mapping */
134 for (i = 0; i < header->code_size; ++i) {
137 fname = mono_debug_source_location_from_il_offset (method, i, &lines [i]);
142 /* Create address->offset mapping */
143 for (i = 0; i < jit->num_line_numbers; ++i) {
144 MonoDebugLineNumberEntry *lne = jit->line_numbers [i];
146 g_assert (lne->offset <= header->code_size);
148 if ((addresses [lne->offset] == 0) || (lne->address < addresses [lne->offset]))
149 addresses [lne->offset] = lne->address;
151 /* Fill out missing addresses */
153 for (i = 0; i < header->code_size; ++i) {
154 if (addresses [i] == 0)
155 addresses [i] = address;
157 address = addresses [i];
163 while (i < header->code_size) {
164 if (lines [i] == line_number)
167 if (line_number > 0) {
168 //g_assert (addresses [i] - 1 >= address);
170 if (addresses [i] - 1 >= address) {
171 VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + addresses [i] - 1, filename, line_number);
172 //printf ("[%d-%d] -> %d.\n", address, addresses [i] - 1, line_number);
175 address = addresses [i];
176 line_number = lines [i];
180 if (line_number > 0) {
181 VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + jit->code_size - 1, filename, line_number);
182 //printf ("[%d-%d] -> %d.\n", address, jit->code_size - 1, line_number);
185 VALGRIND_ADD_SYMBOL (jit->code_start, jit->code_size, full_name);
189 #endif /* VALGRIND_ADD_LINE_INFO */
193 free_jit_debug_info (MonoDebugMethodJitInfo *jit)
195 g_free (jit->line_numbers);
196 g_free (jit->this_var);
197 g_free (jit->params);
198 g_free (jit->locals);
203 mono_debug_close_method (MonoCompile *cfg)
205 MiniDebugMethodInfo *info;
206 MonoDebugMethodJitInfo *jit;
207 MonoMethodHeader *header;
208 MonoMethodSignature *sig;
212 info = (MiniDebugMethodInfo *) cfg->debug_info;
213 if (!info || !info->jit) {
219 method = cfg->method;
220 header = mono_method_get_header (method);
221 sig = mono_method_signature (method);
224 jit->code_start = cfg->native_code;
225 jit->epilogue_begin = cfg->epilog_begin;
226 jit->code_size = cfg->code_len;
228 record_line_number (info, jit->epilogue_begin, header->code_size);
230 jit->num_params = sig->param_count;
231 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
233 for (i = 0; i < jit->num_locals; i++)
234 write_variable (cfg->varinfo [cfg->locals_start + i], &jit->locals [i]);
237 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
238 write_variable (cfg->varinfo [0], jit->this_var);
241 for (i = 0; i < jit->num_params; i++)
242 write_variable (cfg->varinfo [i + sig->hasthis], &jit->params [i]);
244 jit->num_line_numbers = info->line_numbers->len;
245 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
247 for (i = 0; i < jit->num_line_numbers; i++)
248 jit->line_numbers [i] = g_array_index (info->line_numbers, MonoDebugLineNumberEntry, i);
250 mono_debug_add_method (method, jit, cfg->domain);
252 mono_debug_add_vg_method (method, jit);
254 if (info->breakpoint_id)
255 mono_debugger_breakpoint_callback (method, info->breakpoint_id);
257 free_jit_debug_info (jit);
258 g_array_free (info->line_numbers, TRUE);
263 mono_debug_record_line_number (MonoCompile *cfg, MonoInst *ins, guint32 address)
265 MiniDebugMethodInfo *info;
266 MonoMethodHeader *header;
269 info = (MiniDebugMethodInfo *) cfg->debug_info;
270 if (!info || !info->jit || !ins->cil_code)
273 header = mono_method_get_header (cfg->method);
276 if ((ins->cil_code < header->code) ||
277 (ins->cil_code > header->code + header->code_size))
280 offset = ins->cil_code - header->code;
281 if (!info->has_line_numbers) {
282 info->jit->prologue_end = address;
283 info->has_line_numbers = TRUE;
286 record_line_number (info, address, offset);
290 encode_value (gint32 value, char *buf, char **endbuf)
294 //printf ("ENCODE: %d 0x%x.\n", value, value);
297 * Same encoding as the one used in the metadata, extended to handle values
298 * greater than 0x1fffffff.
300 if ((value >= 0) && (value <= 127))
302 else if ((value >= 0) && (value <= 16383)) {
303 p [0] = 0x80 | (value >> 8);
304 p [1] = value & 0xff;
306 } else if ((value >= 0) && (value <= 0x1fffffff)) {
307 p [0] = (value >> 24) | 0xc0;
308 p [1] = (value >> 16) & 0xff;
309 p [2] = (value >> 8) & 0xff;
310 p [3] = value & 0xff;
315 p [1] = (value >> 24) & 0xff;
316 p [2] = (value >> 16) & 0xff;
317 p [3] = (value >> 8) & 0xff;
318 p [4] = value & 0xff;
326 decode_value (char *_ptr, char **rptr)
328 unsigned char *ptr = (unsigned char *) _ptr;
329 unsigned char b = *ptr;
332 if ((b & 0x80) == 0){
335 } else if ((b & 0x40) == 0){
336 len = ((b & 0x3f) << 8 | ptr [1]);
338 } else if (b != 0xff) {
339 len = ((b & 0x1f) << 24) |
346 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
352 //printf ("DECODE: %d.\n", len);
357 serialize_variable (MonoDebugVarInfo *var, char *p, char **endbuf)
359 guint32 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
362 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
363 encode_value (var->index, p, &p);
365 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
366 encode_value (var->index, p, &p);
367 encode_value (var->offset, p, &p);
370 g_assert_not_reached ();
376 mono_debug_serialize_debug_info (MonoCompile *cfg, guint8 **out_buf, guint32 *buf_len)
378 MiniDebugMethodInfo *info;
379 MonoDebugMethodJitInfo *jit;
380 guint32 size, prev_offset, prev_native_offset;
385 info = (MiniDebugMethodInfo *) cfg->debug_info;
386 if (!info || !info->jit) {
392 size = ((jit->num_params + jit->num_locals + 1) * 10) + (jit->num_line_numbers * 10) + 64;
393 p = buf = g_malloc (size);
394 encode_value (jit->epilogue_begin, p, &p);
395 encode_value (jit->prologue_end, p, &p);
396 encode_value (jit->code_size, p, &p);
398 for (i = 0; i < jit->num_params; ++i)
399 serialize_variable (&jit->params [i], p, &p);
401 if (mono_method_signature (cfg->method)->hasthis)
402 serialize_variable (jit->this_var, p, &p);
404 for (i = 0; i < jit->num_locals; i++)
405 serialize_variable (&jit->locals [i], p, &p);
407 encode_value (jit->num_line_numbers, p, &p);
410 prev_native_offset = 0;
411 for (i = 0; i < jit->num_line_numbers; ++i) {
412 /* Sometimes, the offset values are not in increasing order */
413 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
414 encode_value (lne->il_offset - prev_offset, p, &p);
415 encode_value (lne->native_offset - prev_native_offset, p, &p);
416 prev_offset = lne->il_offset;
417 prev_native_offset = lne->native_offset;
420 g_assert (p - buf < size);
427 deserialize_variable (MonoDebugVarInfo *var, char *p, char **endbuf)
431 var->index = decode_value (p, &p);
433 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
436 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
438 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
439 var->offset = decode_value (p, &p);
442 g_assert_not_reached ();
447 static MonoDebugMethodJitInfo *
448 deserialize_debug_info (MonoMethod *method, guint8 *code_start, guint8 *buf, guint32 buf_len)
450 MonoMethodHeader *header;
451 gint32 offset, native_offset, prev_offset, prev_native_offset;
452 MonoDebugMethodJitInfo *jit;
456 header = mono_method_get_header (method);
459 jit = g_new0 (MonoDebugMethodJitInfo, 1);
460 jit->code_start = code_start;
461 jit->num_locals = header->num_locals;
462 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
463 jit->num_params = mono_method_signature (method)->param_count;
464 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
467 jit->epilogue_begin = decode_value (p, &p);
468 jit->prologue_end = decode_value (p, &p);
469 jit->code_size = decode_value (p, &p);
471 for (i = 0; i < jit->num_params; ++i)
472 deserialize_variable (&jit->params [i], p, &p);
474 if (mono_method_signature (method)->hasthis) {
475 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
476 deserialize_variable (jit->this_var, p, &p);
479 for (i = 0; i < jit->num_locals; i++)
480 deserialize_variable (&jit->locals [i], p, &p);
482 jit->num_line_numbers = decode_value (p, &p);
483 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
486 prev_native_offset = 0;
487 for (i = 0; i < jit->num_line_numbers; ++i) {
488 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
490 offset = prev_offset + decode_value (p, &p);
491 native_offset = prev_native_offset + decode_value (p, &p);
493 lne->native_offset = native_offset;
494 lne->il_offset = offset;
496 prev_offset = offset;
497 prev_native_offset = native_offset;
504 mono_debug_add_aot_method (MonoDomain *domain, MonoMethod *method, guint8 *code_start,
505 guint8 *debug_info, guint32 debug_info_len)
507 MonoDebugMethodJitInfo *jit;
509 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
512 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
513 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
514 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
515 (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
516 (method->wrapper_type != MONO_WRAPPER_NONE))
519 if (debug_info_len == 0)
522 jit = deserialize_debug_info (method, code_start, debug_info, debug_info_len);
525 jit = mono_debug_read_method ((MonoDebugMethodAddress *) debug_info);
526 jit->code_start = code_start;
527 jit->wrapper_addr = NULL;
530 mono_debug_add_method (method, jit, domain);
532 mono_debug_add_vg_method (method, jit);
534 free_jit_debug_info (jit);
538 mono_init_debugger (const char *file, const char *opt_flags)
544 g_set_prgname (file);
546 opt = mono_parse_default_optimizations (opt_flags);
547 opt |= MONO_OPT_SHARED;
549 mono_set_defaults (0, opt);
551 domain = mono_jit_init (file);
553 mono_config_parse (NULL);
555 error = mono_check_corlib_version ();
557 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
558 fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.go-mono.com/daily.\n");
566 mono_debug_add_icall_wrapper (MonoMethod *method, MonoJitICallInfo* callinfo)
568 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
571 // mono_debug_add_wrapper (method, callinfo->func, mono_get_root_domain ());