4b606eabfc5df9462e049e8e209a244b24f4894a
[mono.git] / mono / jit / debug-jit.c
1 #include <mono/jit/debug.h>
2 #include <mono/jit/debug-jit.h>
3 #include "debug-private.h"
4
5 void
6 mono_debug_codegen_breakpoint (guint8 **buf)
7 {
8         x86_breakpoint (*buf);
9 }
10
11 void
12 mono_debug_codegen_ret (guint8 **buf)
13 {
14         x86_ret (*buf);
15 }
16
17 static void
18 record_line_number (MonoDebugMethodInfo *minfo, guint32 address, guint32 offset, guint32 line)
19 {
20         MonoDebugLineNumberEntry *lne = g_new0 (MonoDebugLineNumberEntry, 1);
21
22         lne->address = address;
23         lne->offset = offset;
24         lne->line = line;
25
26         g_array_append_val (minfo->jit->line_numbers, *lne);
27 }
28
29 static void
30 debug_generate_method_lines (AssemblyDebugInfo *info, MonoDebugMethodInfo *minfo, MonoFlowGraph* cfg)
31 {
32         guint32 st_address, st_line;
33         DebugMethodInfo *priv = minfo->user_data;
34         int i;
35
36         if (!priv || !info->moffsets)
37                 return;
38
39         minfo->jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
40
41         st_line = priv->first_line;
42         st_address = minfo->jit->prologue_end;
43
44         /* This is the first actual code line of the method. */
45         record_line_number (minfo, st_address, 0, st_line);
46
47         /* start lines of basic blocks */
48         for (i = 0; i < cfg->block_count; ++i) {
49                 int j;
50
51                 for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
52                         MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
53                         gint32 line_inc = 0, addr_inc;
54
55                         if (!i && !j) {
56                                 st_line = priv->first_line;
57                                 st_address = t->addr;
58                         }
59
60                         addr_inc = t->addr - st_address;
61                         st_address += addr_inc;
62
63                         if (t->cli_addr != -1) {
64                                 int *lines = info->moffsets + st_line;
65                                 int *k = lines;
66
67                                 while ((*k != -1) && (*k < t->cli_addr))
68                                         k++;
69
70                                 line_inc = k - lines;
71                         }
72
73                         st_line += line_inc;
74
75                         if (t->cli_addr != -1)
76                                 record_line_number (minfo, st_address, t->cli_addr, st_line);
77                 }
78         }
79 }
80
81 static void
82 debug_update_il_offsets (AssemblyDebugInfo *info, MonoDebugMethodInfo *minfo, MonoFlowGraph* cfg)
83 {
84         MonoMethodHeader *header;
85         guint32 address, offset;
86         int debug = 0;
87         int i;
88
89         g_assert (info->symfile);
90         g_assert (!minfo->jit->line_numbers);
91         minfo->jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
92
93         address = minfo->jit->prologue_end;
94         offset = 0;
95
96         g_assert (((MonoMethodNormal*)minfo->method)->header);
97         header = ((MonoMethodNormal*)minfo->method)->header;
98
99 #if 0
100         if (!strcmp (minfo->method->name, "Test") || !strcmp (minfo->method->name, "Main")) {
101                 MonoMethodHeader *header = ((MonoMethodNormal*)minfo->method)->header;
102
103                 debug = 1;
104                 mono_disassemble_code (minfo->jit->code_start, minfo->jit->code_size,
105                                        minfo->method->name);
106
107                 printf ("\nDisassembly:\n%s\n", mono_disasm_code (
108                         NULL, minfo->method, header->code, header->code + header->code_size));
109                 g_message (G_STRLOC ": %x - %x", minfo->jit->prologue_end, minfo->jit->epilogue_begin);
110         }
111 #endif
112
113         _mono_debug_generate_line_number (minfo, address, offset, debug);
114
115         /* start lines of basic blocks */
116         for (i = 0; i < cfg->block_count; ++i) {
117                 int j;
118
119                 for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
120                         MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
121
122                         if ((t->cli_addr == -1) || (t->cli_addr == offset) || (t->addr == address))
123                                 continue;
124
125                         offset = t->cli_addr;
126                         address = t->addr;
127
128                         _mono_debug_generate_line_number (minfo, address, offset, debug);
129                 }
130         }
131
132         _mono_debug_generate_line_number (minfo, minfo->jit->epilogue_begin, header->code_size, debug);
133
134         if (debug) {
135                 for (i = 0; i < minfo->jit->line_numbers->len; i++) {
136                         MonoDebugLineNumberEntry lne = g_array_index (
137                                 minfo->jit->line_numbers, MonoDebugLineNumberEntry, i);
138
139                         g_message (G_STRLOC ": %x,%x,%d", lne.address, lne.offset, lne.line);
140                 }
141         }
142
143         if (minfo->jit->line_numbers->len) {
144                 MonoDebugLineNumberEntry lne = g_array_index (
145                         minfo->jit->line_numbers, MonoDebugLineNumberEntry, 0);
146
147                 minfo->jit->prologue_end = lne.address;
148         }
149 }
150
151 static gint32
152 il_offset_from_position (MonoFlowGraph *cfg, MonoPosition *pos)
153 {
154         MonoBBlock *bblock;
155         MBTree *tree;
156
157         if (pos->abs_pos == 0)
158                 return -1;
159
160         if (pos->pos.bid >= cfg->block_count)
161                 return -1;
162
163         bblock = &cfg->bblocks [pos->pos.bid];
164         if (pos->pos.tid >= bblock->forest->len)
165                 return -1;
166
167         tree = (MBTree *) g_ptr_array_index (bblock->forest, pos->pos.tid);
168
169         return tree->cli_addr;
170 }
171
172 void
173 mono_debug_add_method (MonoFlowGraph *cfg)
174 {
175         MonoMethod *method = cfg->method;
176         MonoClass *klass = method->klass;
177         AssemblyDebugInfo* info;
178         MonoDebugMethodJitInfo *jit;
179         MonoDebugMethodInfo *minfo;
180         int i;
181
182         if (!mono_debug_handle)
183                 return;
184
185         mono_class_init (klass);
186
187         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
188             (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
189             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
190             (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
191                 return;
192
193         info = _mono_debug_get_image (mono_debug_handle, klass->image);
194         g_assert (info);
195
196         if (method->wrapper_type != MONO_WRAPPER_NONE) {
197                 DebugWrapperInfo *winfo = g_new0 (DebugWrapperInfo, 1);
198
199                 winfo->method = method;
200                 winfo->code_start = cfg->start;
201                 winfo->code_size = cfg->epilogue_end;
202
203                 g_hash_table_insert (info->wrapper_methods, method, winfo);
204                 return;
205         }
206
207         minfo = _mono_debug_lookup_method (method);
208         if (!minfo || minfo->jit)
209                 return;
210
211         mono_debug_lock ();
212
213         mono_debug_handle->dirty = TRUE;
214
215         minfo->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
216         jit->code_start = cfg->start;
217         jit->code_size = cfg->epilogue_end;
218         jit->prologue_end = cfg->prologue_end;
219         jit->epilogue_begin = cfg->epilog;
220         jit->num_params = method->signature->param_count;
221         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
222
223         if (method->signature->hasthis) {
224                 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index;
225
226                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
227                 jit->this_var->offset = ptr->offset;
228                 jit->this_var->size = ptr->size;
229         }
230
231         for (i = 0; i < jit->num_params; i++) {
232                 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index +
233                         method->signature->hasthis;
234
235                 jit->params [i].offset = ptr [i].offset;
236                 jit->params [i].size = ptr [i].size;
237         }
238
239         debug_generate_method_lines (info, minfo, cfg);
240         if (info->format == MONO_DEBUG_FORMAT_MONO)
241                 debug_update_il_offsets (info, minfo, cfg);
242
243         if (!method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
244                 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
245                 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->locals_start_index;
246                 MonoDebugVarInfo *locals;
247
248                 locals = g_new0 (MonoDebugVarInfo, header->num_locals);
249                 for (i = 0; i < header->num_locals; i++) {
250                         gint32 begin_offset, end_offset;
251                         gint32 begin_scope, end_scope;
252
253                         if (ptr [i].reg >= 0) {
254                                 locals [i].index = ptr [i].reg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
255                                 locals [i].offset = 0;
256                         } else
257                                 locals [i].offset = ptr [i].offset;
258
259                         locals [i].size = ptr [i].size;
260
261                         begin_offset = il_offset_from_position (cfg, &ptr [i].range.first_use);
262                         end_offset = il_offset_from_position (cfg, &ptr [i].range.last_use);
263                         if (end_offset >= 0)
264                                 end_offset++;
265
266                         if (begin_offset >= 0)
267                                 begin_scope = _mono_debug_address_from_il_offset (minfo, begin_offset);
268                         else
269                                 begin_scope = -1;
270                         if (end_offset >= 0)
271                                 end_scope = _mono_debug_address_from_il_offset (minfo, end_offset);
272                         else
273                                 end_scope = -1;
274
275                         if (begin_scope > 0)
276                                 locals [i].begin_scope = begin_scope;
277                         else
278                                 locals [i].begin_scope = jit->prologue_end;
279                         if (end_scope > 0)
280                                 locals [i].end_scope = end_scope;
281                         else
282                                 locals [i].end_scope = jit->epilogue_begin;
283                 }
284
285                 jit->num_locals = header->num_locals;
286                 jit->locals = locals;
287         }
288
289         if (info->symfile) {
290                 mono_debug_symfile_add_method (info->symfile, method);
291                 mono_debugger_event (MONO_DEBUGGER_EVENT_METHOD_ADDED, info->symfile, method);
292         }
293
294         mono_debug_unlock ();
295 }
296