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