2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[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 <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... */
17 #include "config.h"
18 #include <mono/metadata/mono-debug-debugger.h>
19
20 #ifdef HAVE_VALGRIND_H
21 #include <valgrind/valgrind.h>
22 #endif
23
24 static inline void
25 record_line_number (MonoDebugMethodJitInfo *jit, guint32 address, guint32 offset)
26 {
27         MonoDebugLineNumberEntry lne;
28
29         lne.native_offset = address;
30         lne.il_offset = offset;
31
32         g_array_append_val (jit->line_numbers, lne);
33 }
34
35 typedef struct
36 {
37         MonoDebugMethodJitInfo *jit;
38         guint32 has_line_numbers;
39         guint32 breakpoint_id;
40 } MiniDebugMethodInfo;
41
42 void
43 mono_debug_init_method (MonoCompile *cfg, MonoBasicBlock *start_block, guint32 breakpoint_id)
44 {
45         MonoMethod *method = cfg->method;
46         MiniDebugMethodInfo *info;
47
48         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
49                 return;
50
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))
55                 return;
56         if ((method->wrapper_type != MONO_WRAPPER_NONE) &&
57             (method->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE))
58                 return;
59
60         info = g_new0 (MiniDebugMethodInfo, 1);
61         info->breakpoint_id = breakpoint_id;
62
63         cfg->debug_info = info;
64 }
65
66 void
67 mono_debug_open_method (MonoCompile *cfg)
68 {
69         MiniDebugMethodInfo *info;
70         MonoDebugMethodJitInfo *jit;
71         MonoMethodHeader *header;
72
73         info = (MiniDebugMethodInfo *) cfg->debug_info;
74         if (!info)
75                 return;
76
77         mono_class_init (cfg->method->klass);
78
79         header = mono_method_get_header (cfg->method);
80         g_assert (header);
81         
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);
86 }
87
88 static void
89 write_variable (MonoInst *inst, MonoDebugVarInfo *var)
90 {
91         if (inst->opcode == OP_REGVAR)
92                 var->index = inst->dreg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
93         else {
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;
97         }
98 }
99
100 /*
101  * mono_debug_add_vg_method:
102  *
103  *  Register symbol information for the method with valgrind
104  */
105 static void 
106 mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit)
107 {
108 #ifdef VALGRIND_ADD_LINE_INFO
109         MonoMethodHeader *header;
110         int i;
111         char *filename = NULL;
112         guint32 address, line_number;
113         const char *full_name;
114         guint32 *addresses;
115         guint32 *lines;
116
117         if (!RUNNING_ON_VALGRIND)
118                 return;
119
120         header = mono_method_get_header (method);
121
122         full_name = mono_method_full_name (method, TRUE);
123
124         addresses = g_new0 (guint32, header->code_size + 1);
125         lines = g_new0 (guint32, header->code_size + 1);
126
127         /* 
128          * Very simple code to convert the addr->offset mappings that mono has
129          * into [addr-addr] ->line number mappings.
130          */
131
132         /* Create offset->line number mapping */
133         for (i = 0; i < header->code_size; ++i) {
134                 char *fname;
135
136                 fname = mono_debug_source_location_from_il_offset (method, i, &lines [i]);
137                 if (!filename)
138                         filename = fname;
139         }
140
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);
144
145                 g_assert (lne->offset <= header->code_size);
146
147                 if ((addresses [lne->offset] == 0) || (lne->address < addresses [lne->offset]))
148                         addresses [lne->offset] = lne->address;
149         }
150         /* Fill out missing addresses */
151         address = 0;
152         for (i = 0; i < header->code_size; ++i) {
153                 if (addresses [i] == 0)
154                         addresses [i] = address;
155                 else
156                         address = addresses [i];
157         }
158         
159         address = 0;
160         line_number = 0;
161         i = 0;
162         while (i < header->code_size) {
163                 if (lines [i] == line_number)
164                         i ++;
165                 else {
166                         if (line_number > 0) {
167                                 //g_assert (addresses [i] - 1 >= address);
168                                 
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);
172                                 }
173                         }
174                         address = addresses [i];
175                         line_number = lines [i];
176                 }
177         }
178
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);
182         }
183
184         VALGRIND_ADD_SYMBOL (jit->code_start, jit->code_size, full_name);
185
186         g_free (addresses);
187         g_free (lines);
188 #endif /* VALGRIND_ADD_LINE_INFO */
189 }
190
191 void
192 mono_debug_close_method (MonoCompile *cfg)
193 {
194         MiniDebugMethodInfo *info;
195         MonoDebugMethodJitInfo *jit;
196         MonoMethodHeader *header;
197         MonoMethodSignature *sig;
198         MonoMethod *method;
199         int i;
200
201         info = (MiniDebugMethodInfo *) cfg->debug_info;
202         if (!info || !info->jit) {
203                 if (info)
204                         g_free (info);
205                 return;
206         }
207
208         method = cfg->method;
209         header = mono_method_get_header (method);
210         sig = mono_method_signature (method);
211
212         jit = info->jit;
213         jit->code_start = cfg->native_code;
214         jit->epilogue_begin = cfg->epilog_begin;
215         jit->code_size = cfg->code_len;
216
217         record_line_number (jit, jit->epilogue_begin, header->code_size);
218
219         jit->num_params = sig->param_count;
220         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
221
222         for (i = 0; i < jit->num_locals; i++)
223                 write_variable (cfg->varinfo [cfg->locals_start + i], &jit->locals [i]);
224
225         if (sig->hasthis) {
226                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
227                 write_variable (cfg->varinfo [0], jit->this_var);
228         }
229
230         for (i = 0; i < jit->num_params; i++)
231                 write_variable (cfg->varinfo [i + sig->hasthis], &jit->params [i]);
232
233         mono_debug_add_method (method, jit, cfg->domain);
234
235         mono_debug_add_vg_method (method, jit);
236
237         if (info->breakpoint_id)
238                 mono_debugger_breakpoint_callback (method, info->breakpoint_id);
239
240         g_free (info);
241 }
242
243 void
244 mono_debug_record_line_number (MonoCompile *cfg, MonoInst *ins, guint32 address)
245 {
246         MiniDebugMethodInfo *info;
247         MonoMethodHeader *header;
248         guint32 offset;
249
250         info = (MiniDebugMethodInfo *) cfg->debug_info;
251         if (!info || !info->jit || !ins->cil_code)
252                 return;
253
254         header = mono_method_get_header (cfg->method);
255         g_assert (header);
256
257         if ((ins->cil_code < header->code) ||
258             (ins->cil_code > header->code + header->code_size))
259                 return;
260
261         offset = ins->cil_code - header->code;
262         if (!info->has_line_numbers) {
263                 info->jit->prologue_end = address;
264                 info->has_line_numbers = TRUE;
265         }
266
267         record_line_number (info->jit, address, offset);
268 }
269
270 static inline void
271 encode_value (gint32 value, char *buf, char **endbuf)
272 {
273         char *p = buf;
274
275         //printf ("ENCODE: %d 0x%x.\n", value, value);
276
277         /* 
278          * Same encoding as the one used in the metadata, extended to handle values
279          * greater than 0x1fffffff.
280          */
281         if ((value >= 0) && (value <= 127))
282                 *p++ = value;
283         else if ((value >= 0) && (value <= 16383)) {
284                 p [0] = 0x80 | (value >> 8);
285                 p [1] = value & 0xff;
286                 p += 2;
287         } else if ((value >= 0) && (value <= 0x1fffffff)) {
288                 p [0] = (value >> 24) | 0xc0;
289                 p [1] = (value >> 16) & 0xff;
290                 p [2] = (value >> 8) & 0xff;
291                 p [3] = value & 0xff;
292                 p += 4;
293         }
294         else {
295                 p [0] = 0xff;
296                 p [1] = (value >> 24) & 0xff;
297                 p [2] = (value >> 16) & 0xff;
298                 p [3] = (value >> 8) & 0xff;
299                 p [4] = value & 0xff;
300                 p += 5;
301         }
302         if (endbuf)
303                 *endbuf = p;
304 }
305
306 static inline gint32
307 decode_value (char *_ptr, char **rptr)
308 {
309         unsigned char *ptr = (unsigned char *) _ptr;
310         unsigned char b = *ptr;
311         gint32 len;
312         
313         if ((b & 0x80) == 0){
314                 len = b;
315                 ++ptr;
316         } else if ((b & 0x40) == 0){
317                 len = ((b & 0x3f) << 8 | ptr [1]);
318                 ptr += 2;
319         } else if (b != 0xff) {
320                 len = ((b & 0x1f) << 24) |
321                         (ptr [1] << 16) |
322                         (ptr [2] << 8) |
323                         ptr [3];
324                 ptr += 4;
325         }
326         else {
327                 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
328                 ptr += 5;
329         }
330         if (rptr)
331                 *rptr = ptr;
332
333         //printf ("DECODE: %d.\n", len);
334         return len;
335 }
336
337 static void
338 serialize_variable (MonoDebugVarInfo *var, char *p, char **endbuf)
339 {
340         guint32 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
341
342         switch (flags) {
343         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
344                 encode_value (var->index, p, &p);
345                 break;
346         case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
347                 encode_value (var->index, p, &p);
348                 encode_value (var->offset, p, &p);
349                 break;
350         default:
351                 g_assert_not_reached ();
352         }
353         *endbuf = p;
354 }
355
356 void
357 mono_debug_serialize_debug_info (MonoCompile *cfg, 
358                                                                  guint8 **out_buf, guint32 *buf_len)
359 {
360         MiniDebugMethodInfo *info;
361         MonoDebugMethodJitInfo *jit;
362         guint32 size, prev_offset, prev_native_offset;
363         char *buf;
364         char *p;
365         int i;
366
367         info = (MiniDebugMethodInfo *) cfg->debug_info;
368         if (!info || !info->jit) {
369                 *buf_len = 0;
370                 return;
371         }
372         jit = info->jit;
373
374         size = ((jit->num_params + jit->num_locals + 1) * 10) + (jit->line_numbers->len * 10) + 64;
375         p = buf = g_malloc (size);
376         encode_value (jit->epilogue_begin, p, &p);
377     encode_value (jit->prologue_end, p, &p);
378         encode_value (jit->code_size, p, &p);
379
380         for (i = 0; i < jit->num_params; ++i)
381                 serialize_variable (&jit->params [i], p, &p);
382
383         if (mono_method_signature (cfg->method)->hasthis)
384                 serialize_variable (jit->this_var, p, &p);
385
386         for (i = 0; i < jit->num_locals; i++)
387                 serialize_variable (&jit->locals [i], p, &p);
388
389         encode_value (jit->line_numbers->len, p, &p);
390
391         prev_offset = 0;
392         prev_native_offset = 0;
393         for (i = 0; i < jit->line_numbers->len; ++i) {
394                 /* Sometimes, the offset values are not in increasing order */
395                 MonoDebugLineNumberEntry *lne = &g_array_index (jit->line_numbers, 
396                                                                                                                 MonoDebugLineNumberEntry,
397                                                                                                                 i);
398                 encode_value (lne->il_offset - prev_offset, p, &p);
399                 encode_value (lne->native_offset - prev_native_offset, p, &p);
400                 prev_offset = lne->il_offset;
401                 prev_native_offset = lne->native_offset;
402         }
403
404         g_assert (p - buf < size);
405
406         *out_buf = buf;
407         *buf_len = p - buf;
408 }
409
410 static void
411 deserialize_variable (MonoDebugVarInfo *var, char *p, char **endbuf)
412 {
413         guint32 flags;
414
415         var->index = decode_value (p, &p);
416
417         flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
418
419         switch (flags) {
420         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
421                 break;
422         case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
423                 var->offset = decode_value (p, &p);
424                 break;
425         default:
426                 g_assert_not_reached ();
427         }
428         *endbuf = p;
429 }
430
431 static MonoDebugMethodJitInfo *
432 deserialize_debug_info (MonoMethod *method,
433                                                 guint8 *code_start, 
434                                                 guint8 *buf, guint32 buf_len)
435 {
436         MonoMethodHeader *header;
437         MonoDebugMethodJitInfo *jit;
438         gint32 offset, native_offset, prev_offset, prev_native_offset, len;
439         char *p;
440         int i;
441
442         header = mono_method_get_header (method);
443         g_assert (header);
444
445         jit = g_new0 (MonoDebugMethodJitInfo, 1);
446         jit->code_start = code_start;
447         jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
448         jit->num_locals = header->num_locals;
449         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
450         jit->num_params = mono_method_signature (method)->param_count;
451         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
452
453         p = buf;
454         jit->epilogue_begin = decode_value (p, &p);
455         jit->prologue_end = decode_value (p, &p);
456         jit->code_size = decode_value (p, &p);
457
458         for (i = 0; i < jit->num_params; ++i)
459                 deserialize_variable (&jit->params [i], p, &p);
460
461         if (mono_method_signature (method)->hasthis) {
462                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
463                 deserialize_variable (jit->this_var, p, &p);
464         }
465
466         for (i = 0; i < jit->num_locals; i++)
467                 deserialize_variable (&jit->locals [i], p, &p);
468
469         len = decode_value (p, &p);
470
471         prev_offset = 0;
472         prev_native_offset = 0;
473         for (i = 0; i < len; ++i) {
474                 offset = prev_offset + decode_value (p, &p);
475                 native_offset = prev_native_offset + decode_value (p, &p);
476                 record_line_number (jit, native_offset, offset);
477                 prev_offset = offset;
478                 prev_native_offset = native_offset;
479         }
480
481         return jit;
482 }
483
484 void
485 mono_debug_add_aot_method (MonoDomain *domain,
486                                                    MonoMethod *method, guint8 *code_start, 
487                                                    guint8 *debug_info, guint32 debug_info_len)
488 {
489         MonoDebugMethodJitInfo *jit;
490
491         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
492                 return;
493
494         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
495             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
496             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
497             (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
498             (method->wrapper_type != MONO_WRAPPER_NONE))
499                 return;
500
501         if (debug_info_len == 0)
502                 return;
503
504         jit = deserialize_debug_info (method, code_start,
505                                                                   debug_info,
506                                                                   debug_info_len);
507
508         mono_debug_add_method (method, jit, domain);
509
510         mono_debug_add_vg_method (method, jit);
511 }
512
513 MonoDomain *
514 mono_init_debugger (const char *file, const char *opt_flags)
515 {
516         MonoDomain *domain;
517         const guchar *error;
518         int opt;
519
520         g_set_prgname (file);
521
522         opt = mono_parse_default_optimizations (opt_flags);
523         opt |= MONO_OPT_SHARED;
524
525         mono_set_defaults (0, opt);
526
527         domain = mono_jit_init (file);
528
529         mono_config_parse (NULL);
530
531         error = mono_check_corlib_version ();
532         if (error) {
533                 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
534                 fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.go-mono.com/daily.\n");
535                 exit (1);
536         }
537
538         return domain;
539 }
540
541 void
542 mono_debug_add_icall_wrapper (MonoMethod *method, MonoJitICallInfo* callinfo)
543 {
544         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
545                 return;
546
547         mono_debug_add_wrapper (method, callinfo->func, mono_get_root_domain ());
548 }