more c*****y windows issues.
[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_array_free (info->line_numbers, TRUE);
259         g_free (info);
260 }
261
262 void
263 mono_debug_record_line_number (MonoCompile *cfg, MonoInst *ins, guint32 address)
264 {
265         MiniDebugMethodInfo *info;
266         MonoMethodHeader *header;
267         guint32 offset;
268
269         info = (MiniDebugMethodInfo *) cfg->debug_info;
270         if (!info || !info->jit || !ins->cil_code)
271                 return;
272
273         header = mono_method_get_header (cfg->method);
274         g_assert (header);
275
276         if ((ins->cil_code < header->code) ||
277             (ins->cil_code > header->code + header->code_size))
278                 return;
279
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;
284         }
285
286         record_line_number (info, address, offset);
287 }
288
289 static inline void
290 encode_value (gint32 value, char *buf, char **endbuf)
291 {
292         char *p = buf;
293
294         //printf ("ENCODE: %d 0x%x.\n", value, value);
295
296         /* 
297          * Same encoding as the one used in the metadata, extended to handle values
298          * greater than 0x1fffffff.
299          */
300         if ((value >= 0) && (value <= 127))
301                 *p++ = value;
302         else if ((value >= 0) && (value <= 16383)) {
303                 p [0] = 0x80 | (value >> 8);
304                 p [1] = value & 0xff;
305                 p += 2;
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;
311                 p += 4;
312         }
313         else {
314                 p [0] = 0xff;
315                 p [1] = (value >> 24) & 0xff;
316                 p [2] = (value >> 16) & 0xff;
317                 p [3] = (value >> 8) & 0xff;
318                 p [4] = value & 0xff;
319                 p += 5;
320         }
321         if (endbuf)
322                 *endbuf = p;
323 }
324
325 static inline gint32
326 decode_value (char *_ptr, char **rptr)
327 {
328         unsigned char *ptr = (unsigned char *) _ptr;
329         unsigned char b = *ptr;
330         gint32 len;
331         
332         if ((b & 0x80) == 0){
333                 len = b;
334                 ++ptr;
335         } else if ((b & 0x40) == 0){
336                 len = ((b & 0x3f) << 8 | ptr [1]);
337                 ptr += 2;
338         } else if (b != 0xff) {
339                 len = ((b & 0x1f) << 24) |
340                         (ptr [1] << 16) |
341                         (ptr [2] << 8) |
342                         ptr [3];
343                 ptr += 4;
344         }
345         else {
346                 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
347                 ptr += 5;
348         }
349         if (rptr)
350                 *rptr = ptr;
351
352         //printf ("DECODE: %d.\n", len);
353         return len;
354 }
355
356 static void
357 serialize_variable (MonoDebugVarInfo *var, char *p, char **endbuf)
358 {
359         guint32 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
360
361         switch (flags) {
362         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
363                 encode_value (var->index, p, &p);
364                 break;
365         case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
366                 encode_value (var->index, p, &p);
367                 encode_value (var->offset, p, &p);
368                 break;
369         default:
370                 g_assert_not_reached ();
371         }
372         *endbuf = p;
373 }
374
375 void
376 mono_debug_serialize_debug_info (MonoCompile *cfg, guint8 **out_buf, guint32 *buf_len)
377 {
378         MiniDebugMethodInfo *info;
379         MonoDebugMethodJitInfo *jit;
380         guint32 size, prev_offset, prev_native_offset;
381         char *buf;
382         char *p;
383         int i;
384
385         info = (MiniDebugMethodInfo *) cfg->debug_info;
386         if (!info || !info->jit) {
387                 *buf_len = 0;
388                 return;
389         }
390         jit = info->jit;
391
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);
397
398         for (i = 0; i < jit->num_params; ++i)
399                 serialize_variable (&jit->params [i], p, &p);
400
401         if (mono_method_signature (cfg->method)->hasthis)
402                 serialize_variable (jit->this_var, p, &p);
403
404         for (i = 0; i < jit->num_locals; i++)
405                 serialize_variable (&jit->locals [i], p, &p);
406
407         encode_value (jit->num_line_numbers, p, &p);
408
409         prev_offset = 0;
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;
418         }
419
420         g_assert (p - buf < size);
421
422         *out_buf = buf;
423         *buf_len = p - buf;
424 }
425
426 static void
427 deserialize_variable (MonoDebugVarInfo *var, char *p, char **endbuf)
428 {
429         guint32 flags;
430
431         var->index = decode_value (p, &p);
432
433         flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
434
435         switch (flags) {
436         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
437                 break;
438         case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
439                 var->offset = decode_value (p, &p);
440                 break;
441         default:
442                 g_assert_not_reached ();
443         }
444         *endbuf = p;
445 }
446
447 static MonoDebugMethodJitInfo *
448 deserialize_debug_info (MonoMethod *method, guint8 *code_start, guint8 *buf, guint32 buf_len)
449 {
450         MonoMethodHeader *header;
451         gint32 offset, native_offset, prev_offset, prev_native_offset;
452         MonoDebugMethodJitInfo *jit;
453         char *p;
454         int i;
455
456         header = mono_method_get_header (method);
457         g_assert (header);
458
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);
465
466         p = buf;
467         jit->epilogue_begin = decode_value (p, &p);
468         jit->prologue_end = decode_value (p, &p);
469         jit->code_size = decode_value (p, &p);
470
471         for (i = 0; i < jit->num_params; ++i)
472                 deserialize_variable (&jit->params [i], p, &p);
473
474         if (mono_method_signature (method)->hasthis) {
475                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
476                 deserialize_variable (jit->this_var, p, &p);
477         }
478
479         for (i = 0; i < jit->num_locals; i++)
480                 deserialize_variable (&jit->locals [i], p, &p);
481
482         jit->num_line_numbers = decode_value (p, &p);
483         jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
484
485         prev_offset = 0;
486         prev_native_offset = 0;
487         for (i = 0; i < jit->num_line_numbers; ++i) {
488                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
489
490                 offset = prev_offset + decode_value (p, &p);
491                 native_offset = prev_native_offset + decode_value (p, &p);
492
493                 lne->native_offset = native_offset;
494                 lne->il_offset = offset;
495
496                 prev_offset = offset;
497                 prev_native_offset = native_offset;
498         }
499
500         return jit;
501 }
502
503 void
504 mono_debug_add_aot_method (MonoDomain *domain, MonoMethod *method, guint8 *code_start, 
505                            guint8 *debug_info, guint32 debug_info_len)
506 {
507         MonoDebugMethodJitInfo *jit;
508
509         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
510                 return;
511
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))
517                 return;
518
519         if (debug_info_len == 0)
520                 return;
521
522         jit = deserialize_debug_info (method, code_start, debug_info, debug_info_len);
523
524 #if 0
525         jit = mono_debug_read_method ((MonoDebugMethodAddress *) debug_info);
526         jit->code_start = code_start;
527         jit->wrapper_addr = NULL;
528 #endif
529
530         mono_debug_add_method (method, jit, domain);
531
532         mono_debug_add_vg_method (method, jit);
533
534         free_jit_debug_info (jit);
535 }
536
537 MonoDomain *
538 mono_init_debugger (const char *file, const char *opt_flags)
539 {
540         MonoDomain *domain;
541         const guchar *error;
542         int opt;
543
544         g_set_prgname (file);
545
546         opt = mono_parse_default_optimizations (opt_flags);
547         opt |= MONO_OPT_SHARED;
548
549         mono_set_defaults (0, opt);
550
551         domain = mono_jit_init (file);
552
553         mono_config_parse (NULL);
554
555         error = mono_check_corlib_version ();
556         if (error) {
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");
559                 exit (1);
560         }
561
562         return domain;
563 }
564
565 void
566 mono_debug_add_icall_wrapper (MonoMethod *method, MonoJitICallInfo* callinfo)
567 {
568         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
569                 return;
570
571         // mono_debug_add_wrapper (method, callinfo->func, mono_get_root_domain ());
572 }