Fri Sep 30 19:10:29 CEST 2005 Paolo Molaro <lupus@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         info = g_new0 (MiniDebugMethodInfo, 1);
53         info->breakpoint_id = breakpoint_id;
54
55         cfg->debug_info = info;
56 }
57
58 void
59 mono_debug_open_method (MonoCompile *cfg)
60 {
61         MiniDebugMethodInfo *info;
62         MonoDebugMethodJitInfo *jit;
63         MonoMethodHeader *header;
64
65         info = (MiniDebugMethodInfo *) cfg->debug_info;
66         if (!info)
67                 return;
68
69         mono_class_init (cfg->method->klass);
70
71         header = mono_method_get_header (cfg->method);
72         g_assert (header);
73         
74         info->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
75         info->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
76         jit->num_locals = header->num_locals;
77         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
78 }
79
80 static void
81 write_variable (MonoInst *inst, MonoDebugVarInfo *var)
82 {
83         if (inst->opcode == OP_REGVAR)
84                 var->index = inst->dreg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
85         else {
86                 /* the debug interface needs fixing to allow 0(%base) address */
87                 var->index = inst->inst_basereg | MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET;
88                 var->offset = inst->inst_offset;
89         }
90 }
91
92 /*
93  * mono_debug_add_vg_method:
94  *
95  *  Register symbol information for the method with valgrind
96  */
97 static void 
98 mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit)
99 {
100 #ifdef VALGRIND_ADD_LINE_INFO
101         MonoMethodHeader *header;
102         int i;
103         char *filename = NULL;
104         guint32 address, line_number;
105         const char *full_name;
106         guint32 *addresses;
107         guint32 *lines;
108
109         if (!RUNNING_ON_VALGRIND)
110                 return;
111
112         header = mono_method_get_header (method);
113
114         full_name = mono_method_full_name (method, TRUE);
115
116         addresses = g_new0 (guint32, header->code_size + 1);
117         lines = g_new0 (guint32, header->code_size + 1);
118
119         /* 
120          * Very simple code to convert the addr->offset mappings that mono has
121          * into [addr-addr] ->line number mappings.
122          */
123
124         /* Create offset->line number mapping */
125         for (i = 0; i < header->code_size; ++i) {
126                 char *fname;
127
128                 fname = mono_debug_source_location_from_il_offset (method, i, &lines [i]);
129                 if (!filename)
130                         filename = fname;
131         }
132
133         /* Create address->offset mapping */
134         for (i = 0; i < jit->num_line_numbers; ++i) {
135                 MonoDebugLineNumberEntry *lne = jit->line_numbers [i];
136
137                 g_assert (lne->offset <= header->code_size);
138
139                 if ((addresses [lne->offset] == 0) || (lne->address < addresses [lne->offset]))
140                         addresses [lne->offset] = lne->address;
141         }
142         /* Fill out missing addresses */
143         address = 0;
144         for (i = 0; i < header->code_size; ++i) {
145                 if (addresses [i] == 0)
146                         addresses [i] = address;
147                 else
148                         address = addresses [i];
149         }
150         
151         address = 0;
152         line_number = 0;
153         i = 0;
154         while (i < header->code_size) {
155                 if (lines [i] == line_number)
156                         i ++;
157                 else {
158                         if (line_number > 0) {
159                                 //g_assert (addresses [i] - 1 >= address);
160                                 
161                                 if (addresses [i] - 1 >= address) {
162                                         VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + addresses [i] - 1, filename, line_number);
163                                         //printf ("[%d-%d] -> %d.\n", address, addresses [i] - 1, line_number);
164                                 }
165                         }
166                         address = addresses [i];
167                         line_number = lines [i];
168                 }
169         }
170
171         if (line_number > 0) {
172                 VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + jit->code_size - 1, filename, line_number);
173                 //printf ("[%d-%d] -> %d.\n", address, jit->code_size - 1, line_number);
174         }
175
176         VALGRIND_ADD_SYMBOL (jit->code_start, jit->code_size, full_name);
177
178         g_free (addresses);
179         g_free (lines);
180 #endif /* VALGRIND_ADD_LINE_INFO */
181 }
182
183 void
184 mono_debug_close_method (MonoCompile *cfg)
185 {
186         MiniDebugMethodInfo *info;
187         MonoDebugMethodJitInfo *jit;
188         MonoMethodHeader *header;
189         MonoMethodSignature *sig;
190         MonoMethod *method;
191         int i;
192
193         info = (MiniDebugMethodInfo *) cfg->debug_info;
194         if (!info || !info->jit) {
195                 if (info)
196                         g_free (info);
197                 return;
198         }
199
200         method = cfg->method;
201         header = mono_method_get_header (method);
202         sig = mono_method_signature (method);
203
204         jit = info->jit;
205         jit->code_start = cfg->native_code;
206         jit->epilogue_begin = cfg->epilog_begin;
207         jit->code_size = cfg->code_len;
208
209         record_line_number (info, jit->epilogue_begin, header->code_size);
210
211         jit->num_params = sig->param_count;
212         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
213
214         for (i = 0; i < jit->num_locals; i++)
215                 write_variable (cfg->varinfo [cfg->locals_start + i], &jit->locals [i]);
216
217         if (sig->hasthis) {
218                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
219                 write_variable (cfg->varinfo [0], jit->this_var);
220         }
221
222         for (i = 0; i < jit->num_params; i++)
223                 write_variable (cfg->varinfo [i + sig->hasthis], &jit->params [i]);
224
225         jit->num_line_numbers = info->line_numbers->len;
226         jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
227
228         for (i = 0; i < jit->num_line_numbers; i++)
229                 jit->line_numbers [i] = g_array_index (info->line_numbers, MonoDebugLineNumberEntry, i);
230
231         mono_debug_add_method (method, jit, cfg->domain);
232
233         mono_debug_add_vg_method (method, jit);
234
235         if (info->breakpoint_id)
236                 mono_debugger_breakpoint_callback (method, info->breakpoint_id);
237
238         mono_debug_free_method_jit_info (jit);
239         g_array_free (info->line_numbers, TRUE);
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, address, offset);
268 }
269
270 static inline void
271 encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
272 {
273         guint8 *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 (guint8 *ptr, guint8 **rptr)
308 {
309         guint8 b = *ptr;
310         gint32 len;
311         
312         if ((b & 0x80) == 0){
313                 len = b;
314                 ++ptr;
315         } else if ((b & 0x40) == 0){
316                 len = ((b & 0x3f) << 8 | ptr [1]);
317                 ptr += 2;
318         } else if (b != 0xff) {
319                 len = ((b & 0x1f) << 24) |
320                         (ptr [1] << 16) |
321                         (ptr [2] << 8) |
322                         ptr [3];
323                 ptr += 4;
324         }
325         else {
326                 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
327                 ptr += 5;
328         }
329         if (rptr)
330                 *rptr = ptr;
331
332         //printf ("DECODE: %d.\n", len);
333         return len;
334 }
335
336 static void
337 serialize_variable (MonoDebugVarInfo *var, guint8 *p, guint8 **endbuf)
338 {
339         guint32 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
340
341         switch (flags) {
342         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
343                 encode_value (var->index, p, &p);
344                 break;
345         case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
346                 encode_value (var->index, p, &p);
347                 encode_value (var->offset, p, &p);
348                 break;
349         default:
350                 g_assert_not_reached ();
351         }
352         *endbuf = p;
353 }
354
355 void
356 mono_debug_serialize_debug_info (MonoCompile *cfg, guint8 **out_buf, guint32 *buf_len)
357 {
358         MiniDebugMethodInfo *info;
359         MonoDebugMethodJitInfo *jit;
360         guint32 size, prev_offset, prev_native_offset;
361         guint8 *buf, *p;
362         int i;
363
364         info = (MiniDebugMethodInfo *) cfg->debug_info;
365         if (!info || !info->jit) {
366                 *buf_len = 0;
367                 return;
368         }
369         jit = info->jit;
370
371         size = ((jit->num_params + jit->num_locals + 1) * 10) + (jit->num_line_numbers * 10) + 64;
372         p = buf = g_malloc (size);
373         encode_value (jit->epilogue_begin, p, &p);
374         encode_value (jit->prologue_end, p, &p);
375         encode_value (jit->code_size, p, &p);
376
377         for (i = 0; i < jit->num_params; ++i)
378                 serialize_variable (&jit->params [i], p, &p);
379
380         if (mono_method_signature (cfg->method)->hasthis)
381                 serialize_variable (jit->this_var, p, &p);
382
383         for (i = 0; i < jit->num_locals; i++)
384                 serialize_variable (&jit->locals [i], p, &p);
385
386         encode_value (jit->num_line_numbers, p, &p);
387
388         prev_offset = 0;
389         prev_native_offset = 0;
390         for (i = 0; i < jit->num_line_numbers; ++i) {
391                 /* Sometimes, the offset values are not in increasing order */
392                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
393                 encode_value (lne->il_offset - prev_offset, p, &p);
394                 encode_value (lne->native_offset - prev_native_offset, p, &p);
395                 prev_offset = lne->il_offset;
396                 prev_native_offset = lne->native_offset;
397         }
398
399         g_assert (p - buf < size);
400
401         *out_buf = buf;
402         *buf_len = p - buf;
403 }
404
405 static void
406 deserialize_variable (MonoDebugVarInfo *var, guint8 *p, guint8 **endbuf)
407 {
408         guint32 flags;
409
410         var->index = decode_value (p, &p);
411
412         flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
413
414         switch (flags) {
415         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
416                 break;
417         case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
418                 var->offset = decode_value (p, &p);
419                 break;
420         default:
421                 g_assert_not_reached ();
422         }
423         *endbuf = p;
424 }
425
426 static MonoDebugMethodJitInfo *
427 deserialize_debug_info (MonoMethod *method, guint8 *code_start, guint8 *buf, guint32 buf_len)
428 {
429         MonoMethodHeader *header;
430         gint32 offset, native_offset, prev_offset, prev_native_offset;
431         MonoDebugMethodJitInfo *jit;
432         guint8 *p;
433         int i;
434
435         header = mono_method_get_header (method);
436         g_assert (header);
437
438         jit = g_new0 (MonoDebugMethodJitInfo, 1);
439         jit->code_start = code_start;
440         jit->num_locals = header->num_locals;
441         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
442         jit->num_params = mono_method_signature (method)->param_count;
443         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
444
445         p = buf;
446         jit->epilogue_begin = decode_value (p, &p);
447         jit->prologue_end = decode_value (p, &p);
448         jit->code_size = decode_value (p, &p);
449
450         for (i = 0; i < jit->num_params; ++i)
451                 deserialize_variable (&jit->params [i], p, &p);
452
453         if (mono_method_signature (method)->hasthis) {
454                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
455                 deserialize_variable (jit->this_var, p, &p);
456         }
457
458         for (i = 0; i < jit->num_locals; i++)
459                 deserialize_variable (&jit->locals [i], p, &p);
460
461         jit->num_line_numbers = decode_value (p, &p);
462         jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
463
464         prev_offset = 0;
465         prev_native_offset = 0;
466         for (i = 0; i < jit->num_line_numbers; ++i) {
467                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
468
469                 offset = prev_offset + decode_value (p, &p);
470                 native_offset = prev_native_offset + decode_value (p, &p);
471
472                 lne->native_offset = native_offset;
473                 lne->il_offset = offset;
474
475                 prev_offset = offset;
476                 prev_native_offset = native_offset;
477         }
478
479         return jit;
480 }
481
482 void
483 mono_debug_add_aot_method (MonoDomain *domain, MonoMethod *method, guint8 *code_start, 
484                            guint8 *debug_info, guint32 debug_info_len)
485 {
486         MonoDebugMethodJitInfo *jit;
487
488         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
489                 return;
490
491         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
492             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
493             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
494             (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
495             (method->wrapper_type != MONO_WRAPPER_NONE))
496                 return;
497
498         if (debug_info_len == 0)
499                 return;
500
501         jit = deserialize_debug_info (method, code_start, debug_info, debug_info_len);
502
503 #if 0
504         jit = mono_debug_read_method ((MonoDebugMethodAddress *) debug_info);
505         jit->code_start = code_start;
506         jit->wrapper_addr = NULL;
507 #endif
508
509         mono_debug_add_method (method, jit, domain);
510
511         mono_debug_add_vg_method (method, jit);
512
513         mono_debug_free_method_jit_info (jit);
514 }
515
516 MonoDomain *
517 mono_init_debugger (const char *file, const char *opt_flags)
518 {
519         MonoDomain *domain;
520         const char *error;
521         int opt;
522
523         g_set_prgname (file);
524
525         opt = mono_parse_default_optimizations (opt_flags);
526         opt |= MONO_OPT_SHARED;
527
528         mono_set_defaults (0, opt);
529
530         domain = mono_jit_init (file);
531
532         mono_config_parse (NULL);
533
534         error = mono_check_corlib_version ();
535         if (error) {
536                 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
537                 fprintf (stderr, "Download a newer corlib or a newer runtime at http://www.go-mono.com/daily.\n");
538                 exit (1);
539         }
540
541         return domain;
542 }
543
544 void
545 mono_debug_add_icall_wrapper (MonoMethod *method, MonoJitICallInfo* callinfo)
546 {
547         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
548                 return;
549
550         // mono_debug_add_wrapper (method, callinfo->wrapper, callinfo->func);
551 }