2003-04-27 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 "mini-x86.h"
12 #include <mono/metadata/mono-debug.h>
13 #include <mono/metadata/mono-debug-debugger.h>
14
15 /*
16  * This method is only called when running in the Mono Debugger.
17  */
18 gpointer
19 mono_debugger_create_notification_function (gpointer *notification_address)
20 {
21         guint8 *ptr, *buf;
22
23         ptr = buf = g_malloc0 (16);
24         x86_breakpoint (buf);
25         if (notification_address)
26                 *notification_address = buf;
27         x86_ret (buf);
28
29         return ptr;
30 }
31
32 static void
33 record_line_number (MonoDebugMethodJitInfo *jit, guint32 address, guint32 offset)
34 {
35         MonoDebugLineNumberEntry *lne = g_new0 (MonoDebugLineNumberEntry, 1);
36
37         lne->address = address;
38         lne->offset = offset;
39
40         g_array_append_val (jit->line_numbers, *lne);
41 }
42
43 typedef struct
44 {
45         MonoDebugMethodJitInfo *jit;
46         guint32 has_line_numbers;
47         guint32 breakpoint_id;
48 } MiniDebugMethodInfo;
49
50 void
51 mono_debug_init_method (MonoCompile *cfg, MonoBasicBlock *start_block, guint32 breakpoint_id)
52 {
53         MonoMethod *method = cfg->method;
54         MiniDebugMethodInfo *info;
55
56         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
57                 return;
58
59         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
60             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
61             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
62             (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
63             (method->wrapper_type != MONO_WRAPPER_NONE))
64                 return;
65
66         info = g_new0 (MiniDebugMethodInfo, 1);
67         info->breakpoint_id = breakpoint_id;
68
69         cfg->debug_info = info;
70 }
71
72 void
73 mono_debug_open_method (MonoCompile *cfg)
74 {
75         MiniDebugMethodInfo *info;
76         MonoDebugMethodJitInfo *jit;
77         MonoMethodHeader *header;
78
79         info = (MiniDebugMethodInfo *) cfg->debug_info;
80         if (!info)
81                 return;
82
83         mono_class_init (cfg->method->klass);
84
85         g_assert (((MonoMethodNormal*)cfg->method)->header);
86         header = ((MonoMethodNormal*)cfg->method)->header;
87
88         info->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
89         jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
90         jit->num_locals = header->num_locals;
91         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
92 }
93
94 static void
95 write_variable (MonoInst *inst, MonoDebugVarInfo *var)
96 {
97         if (inst->opcode == OP_REGVAR)
98                 var->index = inst->dreg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
99         else if (inst->inst_basereg != X86_EBP) {
100                 g_message (G_STRLOC ": %d - %d", inst->inst_basereg, inst->inst_offset);
101                 var->index = inst->inst_basereg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
102                 var->offset = inst->inst_offset;
103         } else
104                 var->offset = inst->inst_offset;
105 }
106
107 void
108 mono_debug_close_method (MonoCompile *cfg)
109 {
110         MiniDebugMethodInfo *info;
111         MonoDebugMethodJitInfo *jit;
112         MonoMethodHeader *header;
113         MonoMethod *method;
114         int i;
115
116         info = (MiniDebugMethodInfo *) cfg->debug_info;
117         if (!info || !info->jit)
118                 return;
119
120         method = cfg->method;
121         header = ((MonoMethodNormal*)method)->header;
122
123         jit = info->jit;
124         jit->code_start = cfg->native_code;
125         jit->epilogue_begin = cfg->epilog_begin;
126         jit->code_size = cfg->code_len;
127
128         record_line_number (jit, jit->epilogue_begin, header->code_size);
129
130         jit->num_params = method->signature->param_count;
131         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
132
133         for (i = 0; i < jit->num_locals; i++)
134                 write_variable (cfg->varinfo [cfg->locals_start + i], &jit->locals [i]);
135
136         if (method->signature->hasthis) {
137                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
138                 write_variable (cfg->varinfo [0], jit->this_var);
139         }
140
141         for (i = 0; i < jit->num_params; i++)
142                 write_variable (cfg->varinfo [i + method->signature->hasthis], &jit->params [i]);
143
144         mono_debug_add_method (method, jit);
145
146         if (info->breakpoint_id)
147                 mono_debugger_breakpoint_callback (method, info->breakpoint_id);
148 }
149
150 void
151 mono_debug_record_line_number (MonoCompile *cfg, MonoInst *ins, guint32 address)
152 {
153         MiniDebugMethodInfo *info;
154         MonoMethodHeader *header;
155         guint32 offset;
156
157         info = (MiniDebugMethodInfo *) cfg->debug_info;
158         if (!info || !info->jit || !ins->cil_code)
159                 return;
160
161         g_assert (((MonoMethodNormal*)cfg->method)->header);
162         header = ((MonoMethodNormal*)cfg->method)->header;
163
164         if ((ins->cil_code < header->code) ||
165             (ins->cil_code > header->code + header->code_size))
166                 return;
167
168         offset = ins->cil_code - header->code;
169         if (!info->has_line_numbers) {
170                 info->jit->prologue_end = address;
171                 info->has_line_numbers = TRUE;
172         }
173
174         record_line_number (info->jit, address, offset);
175 }