2004-01-29 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 /* mono-debug-debugger.h nneds config.h to work... */
16 #include "config.h"
17 #include <mono/metadata/mono-debug-debugger.h>
18
19 static inline void
20 record_line_number (MonoDebugMethodJitInfo *jit, guint32 address, guint32 offset)
21 {
22         MonoDebugLineNumberEntry lne;
23
24         lne.address = address;
25         lne.offset = offset;
26
27         g_array_append_val (jit->line_numbers, lne);
28 }
29
30 typedef struct
31 {
32         MonoDebugMethodJitInfo *jit;
33         guint32 has_line_numbers;
34         guint32 breakpoint_id;
35 } MiniDebugMethodInfo;
36
37 void
38 mono_debug_init_method (MonoCompile *cfg, MonoBasicBlock *start_block, guint32 breakpoint_id)
39 {
40         MonoMethod *method = cfg->method;
41         MiniDebugMethodInfo *info;
42
43         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
44                 return;
45
46         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
47             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
48             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
49             (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
50             (method->wrapper_type != MONO_WRAPPER_NONE))
51                 return;
52
53         info = g_new0 (MiniDebugMethodInfo, 1);
54         info->breakpoint_id = breakpoint_id;
55
56         cfg->debug_info = info;
57 }
58
59 void
60 mono_debug_open_method (MonoCompile *cfg)
61 {
62         MiniDebugMethodInfo *info;
63         MonoDebugMethodJitInfo *jit;
64         MonoMethodHeader *header;
65
66         info = (MiniDebugMethodInfo *) cfg->debug_info;
67         if (!info)
68                 return;
69
70         mono_class_init (cfg->method->klass);
71
72         g_assert (((MonoMethodNormal*)cfg->method)->header);
73         header = ((MonoMethodNormal*)cfg->method)->header;
74
75         info->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
76         jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
77         jit->num_locals = header->num_locals;
78         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
79 }
80
81 static void
82 write_variable (MonoInst *inst, MonoDebugVarInfo *var)
83 {
84         if (inst->opcode == OP_REGVAR)
85                 var->index = inst->dreg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
86         else {
87                 /* the debug interface needs fixing to allow 0(%base) address */
88                 var->index = inst->inst_basereg | MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET;
89                 var->offset = inst->inst_offset;
90         }
91 }
92
93 void
94 mono_debug_close_method (MonoCompile *cfg)
95 {
96         MiniDebugMethodInfo *info;
97         MonoDebugMethodJitInfo *jit;
98         MonoMethodHeader *header;
99         MonoMethod *method;
100         int i;
101
102         info = (MiniDebugMethodInfo *) cfg->debug_info;
103         if (!info || !info->jit)
104                 return;
105
106         method = cfg->method;
107         header = ((MonoMethodNormal*)method)->header;
108
109         jit = info->jit;
110         jit->code_start = cfg->native_code;
111         jit->epilogue_begin = cfg->epilog_begin;
112         jit->code_size = cfg->code_len;
113
114         record_line_number (jit, jit->epilogue_begin, header->code_size);
115
116         jit->num_params = method->signature->param_count;
117         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
118
119         for (i = 0; i < jit->num_locals; i++)
120                 write_variable (cfg->varinfo [cfg->locals_start + i], &jit->locals [i]);
121
122         if (method->signature->hasthis) {
123                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
124                 write_variable (cfg->varinfo [0], jit->this_var);
125         }
126
127         for (i = 0; i < jit->num_params; i++)
128                 write_variable (cfg->varinfo [i + method->signature->hasthis], &jit->params [i]);
129
130         mono_debug_add_method (method, jit, cfg->domain);
131
132         if (info->breakpoint_id)
133                 mono_debugger_breakpoint_callback (method, info->breakpoint_id);
134 }
135
136 void
137 mono_debug_record_line_number (MonoCompile *cfg, MonoInst *ins, guint32 address)
138 {
139         MiniDebugMethodInfo *info;
140         MonoMethodHeader *header;
141         guint32 offset;
142
143         info = (MiniDebugMethodInfo *) cfg->debug_info;
144         if (!info || !info->jit || !ins->cil_code)
145                 return;
146
147         g_assert (((MonoMethodNormal*)cfg->method)->header);
148         header = ((MonoMethodNormal*)cfg->method)->header;
149
150         if ((ins->cil_code < header->code) ||
151             (ins->cil_code > header->code + header->code_size))
152                 return;
153
154         offset = ins->cil_code - header->code;
155         if (!info->has_line_numbers) {
156                 info->jit->prologue_end = address;
157                 info->has_line_numbers = TRUE;
158         }
159
160         record_line_number (info->jit, address, offset);
161 }
162
163 static inline void
164 encode_value (gint32 value, char *buf, char **endbuf)
165 {
166         char *p = buf;
167
168         //printf ("ENCODE: %d 0x%x.\n", value, value);
169
170         /* 
171          * Same encoding as the one used in the metadata, extended to handle values
172          * greater than 0x1fffffff.
173          */
174         if ((value >= 0) && (value <= 127))
175                 *p++ = value;
176         else if ((value >= 0) && (value <= 16384)) {
177                 p [0] = 0x80 | (value >> 8);
178                 p [1] = value & 0xff;
179                 p += 2;
180         } else if ((value >= 0) && (value <= 0x1fffffff)) {
181                 p [0] = (value >> 24) | 0xc0;
182                 p [1] = (value >> 16) & 0xff;
183                 p [2] = (value >> 8) & 0xff;
184                 p [3] = value & 0xff;
185                 p += 4;
186         }
187         else {
188                 p [0] = 0xff;
189                 p [1] = (value >> 24) & 0xff;
190                 p [2] = (value >> 16) & 0xff;
191                 p [3] = (value >> 8) & 0xff;
192                 p [4] = value & 0xff;
193                 p += 5;
194         }
195         if (endbuf)
196                 *endbuf = p;
197 }
198
199 static inline gint32
200 decode_value (char *_ptr, char **rptr)
201 {
202         unsigned char *ptr = (unsigned char *) _ptr;
203         unsigned char b = *ptr;
204         gint32 len;
205         
206         if ((b & 0x80) == 0){
207                 len = b;
208                 ++ptr;
209         } else if ((b & 0x40) == 0){
210                 len = ((b & 0x3f) << 8 | ptr [1]);
211                 ptr += 2;
212         } else if (b != 0xff) {
213                 len = ((b & 0x1f) << 24) |
214                         (ptr [1] << 16) |
215                         (ptr [2] << 8) |
216                         ptr [3];
217                 ptr += 4;
218         }
219         else {
220                 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
221                 ptr += 5;
222         }
223         if (rptr)
224                 *rptr = ptr;
225
226         //printf ("DECODE: %d.\n", len);
227         return len;
228 }
229
230 static void
231 serialize_variable (MonoDebugVarInfo *var, char *p, char **endbuf)
232 {
233         guint32 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
234
235         switch (flags) {
236         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
237                 encode_value (var->index, p, &p);
238                 break;
239         case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
240                 encode_value (var->index, p, &p);
241                 encode_value (var->offset, p, &p);
242                 break;
243         default:
244                 g_assert_not_reached ();
245         }
246         *endbuf = p;
247 }
248
249 void
250 mono_debug_serialize_debug_info (MonoCompile *cfg, 
251                                                                  guint8 **out_buf, guint32 *buf_len)
252 {
253         MiniDebugMethodInfo *info;
254         MonoDebugMethodJitInfo *jit;
255         guint32 size, prev_offset, prev_native_offset;
256         char *buf;
257         char *p;
258         int i;
259
260         info = (MiniDebugMethodInfo *) cfg->debug_info;
261         if (!info || !info->jit) {
262                 *buf_len = 0;
263                 return;
264         }
265         jit = info->jit;
266
267         size = ((jit->num_params + jit->num_locals + 1) * 10) + (jit->line_numbers->len * 10) + 64;
268         p = buf = g_malloc (size);
269         encode_value (jit->epilogue_begin, p, &p);
270     encode_value (jit->prologue_end, p, &p);
271         encode_value (jit->code_size, p, &p);
272
273         for (i = 0; i < jit->num_params; ++i)
274                 serialize_variable (&jit->params [i], p, &p);
275
276         if (cfg->method->signature->hasthis)
277                 serialize_variable (jit->this_var, p, &p);
278
279         for (i = 0; i < jit->num_locals; i++)
280                 serialize_variable (&jit->locals [i], p, &p);
281
282         encode_value (jit->line_numbers->len, p, &p);
283
284         prev_offset = 0;
285         prev_native_offset = 0;
286         for (i = 0; i < jit->line_numbers->len; ++i) {
287                 /* Sometimes, the offset values are not in increasing order */
288                 MonoDebugLineNumberEntry *lne = &g_array_index (jit->line_numbers, 
289                                                                                                                 MonoDebugLineNumberEntry,
290                                                                                                                 i);
291                 encode_value (lne->offset - prev_offset, p, &p);
292                 encode_value (lne->address - prev_native_offset, p, &p);
293                 prev_offset = lne->offset;
294                 prev_native_offset = lne->address;
295         }
296
297         g_assert (p - buf < size);
298
299         *out_buf = buf;
300         *buf_len = p - buf;
301 }
302
303 static void
304 deserialize_variable (MonoDebugVarInfo *var, char *p, char **endbuf)
305 {
306         guint32 flags;
307
308         var->index = decode_value (p, &p);
309
310         flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
311
312         switch (flags) {
313         case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
314                 break;
315         case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
316                 var->offset = decode_value (p, &p);
317                 break;
318         default:
319                 g_assert_not_reached ();
320         }
321         *endbuf = p;
322 }
323
324 static MonoDebugMethodJitInfo *
325 deserialize_debug_info (MonoMethod *method,
326                                                 guint8 *code_start, 
327                                                 guint8 *buf, guint32 buf_len)
328 {
329         MonoMethodHeader *header;
330         MonoDebugMethodJitInfo *jit;
331         gint32 offset, native_offset, prev_offset, prev_native_offset, len;
332         char *p;
333         int i;
334
335         g_assert (((MonoMethodNormal*)method)->header);
336         header = ((MonoMethodNormal*)method)->header;
337
338         jit = g_new0 (MonoDebugMethodJitInfo, 1);
339         jit->code_start = code_start;
340         jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
341         jit->num_locals = header->num_locals;
342         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
343         jit->num_params = method->signature->param_count;
344         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
345
346         p = buf;
347         jit->epilogue_begin = decode_value (p, &p);
348         jit->prologue_end = decode_value (p, &p);
349         jit->code_size = decode_value (p, &p);
350
351         for (i = 0; i < jit->num_params; ++i)
352                 deserialize_variable (&jit->params [i], p, &p);
353
354         if (method->signature->hasthis) {
355                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
356                 deserialize_variable (jit->this_var, p, &p);
357         }
358
359         for (i = 0; i < jit->num_locals; i++)
360                 deserialize_variable (&jit->locals [i], p, &p);
361
362         len = decode_value (p, &p);
363
364         prev_offset = 0;
365         prev_native_offset = 0;
366         for (i = 0; i < len; ++i) {
367                 offset = prev_offset + decode_value (p, &p);
368                 native_offset = prev_native_offset + decode_value (p, &p);
369                 record_line_number (jit, native_offset, offset);
370                 prev_offset = offset;
371                 prev_native_offset = native_offset;
372         }
373
374         return jit;
375 }
376
377 void
378 mono_debug_add_aot_method (MonoDomain *domain,
379                                                    MonoMethod *method, guint8 *code_start, 
380                                                    guint8 *debug_info, guint32 debug_info_len)
381 {
382         MonoDebugMethodJitInfo *jit;
383
384         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
385                 return;
386
387         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
388             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
389             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
390             (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
391             (method->wrapper_type != MONO_WRAPPER_NONE))
392                 return;
393
394         if (debug_info_len == 0)
395                 return;
396
397         jit = deserialize_debug_info (method, code_start,
398                                                                   debug_info,
399                                                                   debug_info_len);
400
401         mono_debug_add_method (method, jit, domain);
402 }
403
404 MonoDomain *
405 mono_init_debugger (const char *file, const char *opt_flags)
406 {
407         MonoDomain *domain;
408         const char *error;
409         int opt;
410
411         g_set_prgname (file);
412
413         opt = mono_parse_default_optimizations (opt_flags);
414         opt |= MONO_OPT_SHARED;
415
416         mono_set_defaults (0, opt);
417
418         domain = mono_jit_init (file);
419
420         mono_config_parse (NULL);
421
422         error = mono_verify_corlib ();
423         if (error) {
424                 fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
425                 exit (1);
426         }
427
428         return domain;
429 }