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>
25 record_line_number (MonoDebugMethodJitInfo *jit, guint32 address, guint32 offset)
27 MonoDebugLineNumberEntry lne;
29 lne.native_offset = address;
30 lne.il_offset = offset;
32 g_array_append_val (jit->line_numbers, lne);
37 MonoDebugMethodJitInfo *jit;
38 guint32 has_line_numbers;
39 guint32 breakpoint_id;
40 } MiniDebugMethodInfo;
43 mono_debug_init_method (MonoCompile *cfg, MonoBasicBlock *start_block, guint32 breakpoint_id)
45 MonoMethod *method = cfg->method;
46 MiniDebugMethodInfo *info;
48 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
51 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
52 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
53 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
54 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
56 if ((method->wrapper_type != MONO_WRAPPER_NONE) &&
57 (method->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE))
60 info = g_new0 (MiniDebugMethodInfo, 1);
61 info->breakpoint_id = breakpoint_id;
63 cfg->debug_info = info;
67 mono_debug_open_method (MonoCompile *cfg)
69 MiniDebugMethodInfo *info;
70 MonoDebugMethodJitInfo *jit;
71 MonoMethodHeader *header;
73 info = (MiniDebugMethodInfo *) cfg->debug_info;
77 mono_class_init (cfg->method->klass);
79 header = mono_method_get_header (cfg->method);
82 info->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
83 jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
84 jit->num_locals = header->num_locals;
85 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
89 write_variable (MonoInst *inst, MonoDebugVarInfo *var)
91 if (inst->opcode == OP_REGVAR)
92 var->index = inst->dreg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
94 /* the debug interface needs fixing to allow 0(%base) address */
95 var->index = inst->inst_basereg | MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET;
96 var->offset = inst->inst_offset;
101 * mono_debug_add_vg_method:
103 * Register symbol information for the method with valgrind
106 mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit)
108 #ifdef VALGRIND_ADD_LINE_INFO
109 MonoMethodHeader *header;
111 char *filename = NULL;
112 guint32 address, line_number;
113 const char *full_name;
117 if (!RUNNING_ON_VALGRIND)
120 header = mono_method_get_header (method);
122 full_name = mono_method_full_name (method, TRUE);
124 addresses = g_new0 (guint32, header->code_size + 1);
125 lines = g_new0 (guint32, header->code_size + 1);
128 * Very simple code to convert the addr->offset mappings that mono has
129 * into [addr-addr] ->line number mappings.
132 /* Create offset->line number mapping */
133 for (i = 0; i < header->code_size; ++i) {
136 fname = mono_debug_source_location_from_il_offset (method, i, &lines [i]);
141 /* Create address->offset mapping */
142 for (i = 0; i < jit->line_numbers->len; ++i) {
143 MonoDebugLineNumberEntry *lne = &g_array_index (jit->line_numbers, MonoDebugLineNumberEntry, i);
145 g_assert (lne->offset <= header->code_size);
147 if ((addresses [lne->offset] == 0) || (lne->address < addresses [lne->offset]))
148 addresses [lne->offset] = lne->address;
150 /* Fill out missing addresses */
152 for (i = 0; i < header->code_size; ++i) {
153 if (addresses [i] == 0)
154 addresses [i] = address;
156 address = addresses [i];
162 while (i < header->code_size) {
163 if (lines [i] == line_number)
166 if (line_number > 0) {
167 //g_assert (addresses [i] - 1 >= address);
169 if (addresses [i] - 1 >= address) {
170 VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + addresses [i] - 1, filename, line_number);
171 //printf ("[%d-%d] -> %d.\n", address, addresses [i] - 1, line_number);
174 address = addresses [i];
175 line_number = lines [i];
179 if (line_number > 0) {
180 VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + jit->code_size - 1, filename, line_number);
181 //printf ("[%d-%d] -> %d.\n", address, jit->code_size - 1, line_number);
184 VALGRIND_ADD_SYMBOL (jit->code_start, jit->code_size, full_name);
188 #endif /* VALGRIND_ADD_LINE_INFO */
192 mono_debug_close_method (MonoCompile *cfg)
194 MiniDebugMethodInfo *info;
195 MonoDebugMethodJitInfo *jit;
196 MonoMethodHeader *header;
200 info = (MiniDebugMethodInfo *) cfg->debug_info;
201 if (!info || !info->jit)
204 method = cfg->method;
205 header = mono_method_get_header (method);
208 jit->code_start = cfg->native_code;
209 jit->epilogue_begin = cfg->epilog_begin;
210 jit->code_size = cfg->code_len;
212 record_line_number (jit, jit->epilogue_begin, header->code_size);
214 jit->num_params = method->signature->param_count;
215 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
217 for (i = 0; i < jit->num_locals; i++)
218 write_variable (cfg->varinfo [cfg->locals_start + i], &jit->locals [i]);
220 if (method->signature->hasthis) {
221 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
222 write_variable (cfg->varinfo [0], jit->this_var);
225 for (i = 0; i < jit->num_params; i++)
226 write_variable (cfg->varinfo [i + method->signature->hasthis], &jit->params [i]);
228 mono_debug_add_method (method, jit, cfg->domain);
230 mono_debug_add_vg_method (method, jit);
232 if (info->breakpoint_id)
233 mono_debugger_breakpoint_callback (method, info->breakpoint_id);
237 mono_debug_record_line_number (MonoCompile *cfg, MonoInst *ins, guint32 address)
239 MiniDebugMethodInfo *info;
240 MonoMethodHeader *header;
243 info = (MiniDebugMethodInfo *) cfg->debug_info;
244 if (!info || !info->jit || !ins->cil_code)
247 header = mono_method_get_header (cfg->method);
250 if ((ins->cil_code < header->code) ||
251 (ins->cil_code > header->code + header->code_size))
254 offset = ins->cil_code - header->code;
255 if (!info->has_line_numbers) {
256 info->jit->prologue_end = address;
257 info->has_line_numbers = TRUE;
260 record_line_number (info->jit, address, offset);
264 encode_value (gint32 value, char *buf, char **endbuf)
268 //printf ("ENCODE: %d 0x%x.\n", value, value);
271 * Same encoding as the one used in the metadata, extended to handle values
272 * greater than 0x1fffffff.
274 if ((value >= 0) && (value <= 127))
276 else if ((value >= 0) && (value <= 16383)) {
277 p [0] = 0x80 | (value >> 8);
278 p [1] = value & 0xff;
280 } else if ((value >= 0) && (value <= 0x1fffffff)) {
281 p [0] = (value >> 24) | 0xc0;
282 p [1] = (value >> 16) & 0xff;
283 p [2] = (value >> 8) & 0xff;
284 p [3] = value & 0xff;
289 p [1] = (value >> 24) & 0xff;
290 p [2] = (value >> 16) & 0xff;
291 p [3] = (value >> 8) & 0xff;
292 p [4] = value & 0xff;
300 decode_value (char *_ptr, char **rptr)
302 unsigned char *ptr = (unsigned char *) _ptr;
303 unsigned char b = *ptr;
306 if ((b & 0x80) == 0){
309 } else if ((b & 0x40) == 0){
310 len = ((b & 0x3f) << 8 | ptr [1]);
312 } else if (b != 0xff) {
313 len = ((b & 0x1f) << 24) |
320 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
326 //printf ("DECODE: %d.\n", len);
331 serialize_variable (MonoDebugVarInfo *var, char *p, char **endbuf)
333 guint32 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
336 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
337 encode_value (var->index, p, &p);
339 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
340 encode_value (var->index, p, &p);
341 encode_value (var->offset, p, &p);
344 g_assert_not_reached ();
350 mono_debug_serialize_debug_info (MonoCompile *cfg,
351 guint8 **out_buf, guint32 *buf_len)
353 MiniDebugMethodInfo *info;
354 MonoDebugMethodJitInfo *jit;
355 guint32 size, prev_offset, prev_native_offset;
360 info = (MiniDebugMethodInfo *) cfg->debug_info;
361 if (!info || !info->jit) {
367 size = ((jit->num_params + jit->num_locals + 1) * 10) + (jit->line_numbers->len * 10) + 64;
368 p = buf = g_malloc (size);
369 encode_value (jit->epilogue_begin, p, &p);
370 encode_value (jit->prologue_end, p, &p);
371 encode_value (jit->code_size, p, &p);
373 for (i = 0; i < jit->num_params; ++i)
374 serialize_variable (&jit->params [i], p, &p);
376 if (cfg->method->signature->hasthis)
377 serialize_variable (jit->this_var, p, &p);
379 for (i = 0; i < jit->num_locals; i++)
380 serialize_variable (&jit->locals [i], p, &p);
382 encode_value (jit->line_numbers->len, p, &p);
385 prev_native_offset = 0;
386 for (i = 0; i < jit->line_numbers->len; ++i) {
387 /* Sometimes, the offset values are not in increasing order */
388 MonoDebugLineNumberEntry *lne = &g_array_index (jit->line_numbers,
389 MonoDebugLineNumberEntry,
391 encode_value (lne->il_offset - prev_offset, p, &p);
392 encode_value (lne->native_offset - prev_native_offset, p, &p);
393 prev_offset = lne->il_offset;
394 prev_native_offset = lne->native_offset;
397 g_assert (p - buf < size);
404 deserialize_variable (MonoDebugVarInfo *var, char *p, char **endbuf)
408 var->index = decode_value (p, &p);
410 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
413 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
415 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
416 var->offset = decode_value (p, &p);
419 g_assert_not_reached ();
424 static MonoDebugMethodJitInfo *
425 deserialize_debug_info (MonoMethod *method,
427 guint8 *buf, guint32 buf_len)
429 MonoMethodHeader *header;
430 MonoDebugMethodJitInfo *jit;
431 gint32 offset, native_offset, prev_offset, prev_native_offset, len;
435 header = mono_method_get_header (method);
438 jit = g_new0 (MonoDebugMethodJitInfo, 1);
439 jit->code_start = code_start;
440 jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
441 jit->num_locals = header->num_locals;
442 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
443 jit->num_params = method->signature->param_count;
444 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
447 jit->epilogue_begin = decode_value (p, &p);
448 jit->prologue_end = decode_value (p, &p);
449 jit->code_size = decode_value (p, &p);
451 for (i = 0; i < jit->num_params; ++i)
452 deserialize_variable (&jit->params [i], p, &p);
454 if (method->signature->hasthis) {
455 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
456 deserialize_variable (jit->this_var, p, &p);
459 for (i = 0; i < jit->num_locals; i++)
460 deserialize_variable (&jit->locals [i], p, &p);
462 len = decode_value (p, &p);
465 prev_native_offset = 0;
466 for (i = 0; i < len; ++i) {
467 offset = prev_offset + decode_value (p, &p);
468 native_offset = prev_native_offset + decode_value (p, &p);
469 record_line_number (jit, native_offset, offset);
470 prev_offset = offset;
471 prev_native_offset = native_offset;
478 mono_debug_add_aot_method (MonoDomain *domain,
479 MonoMethod *method, guint8 *code_start,
480 guint8 *debug_info, guint32 debug_info_len)
482 MonoDebugMethodJitInfo *jit;
484 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
487 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
488 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
489 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
490 (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
491 (method->wrapper_type != MONO_WRAPPER_NONE))
494 if (debug_info_len == 0)
497 jit = deserialize_debug_info (method, code_start,
501 mono_debug_add_method (method, jit, domain);
503 mono_debug_add_vg_method (method, jit);
507 mono_init_debugger (const char *file, const char *opt_flags)
513 g_set_prgname (file);
515 opt = mono_parse_default_optimizations (opt_flags);
516 opt |= MONO_OPT_SHARED;
518 mono_set_defaults (0, opt);
520 domain = mono_jit_init (file);
522 mono_config_parse (NULL);
524 error = mono_check_corlib_version ();
526 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
527 fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.go-mono.com/daily.\n");
535 mono_debug_add_icall_wrapper (MonoMethod *method, MonoJitICallInfo* callinfo)
537 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
540 mono_debug_add_wrapper (method, callinfo->func, mono_get_root_domain ());