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