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