3 #include <mono/metadata/class.h>
4 #include <mono/metadata/tabledefs.h>
5 #include <mono/metadata/tokentype.h>
6 #include <mono/jit/codegen.h>
7 #include <mono/jit/debug.h>
9 #include "debug-private.h"
12 mono_debug_open_file (char *filename, MonoDebugFormat format)
14 MonoDebugHandle *debug;
16 debug = g_new0 (MonoDebugHandle, 1);
17 debug->name = g_strdup (filename);
18 debug->format = format;
23 debug_load_method_lines (AssemblyDebugInfo* info)
28 char *name = g_strdup_printf ("%s.il", info->name);
31 /* use an env var with directories for searching. */
32 if (!(f = fopen (name, "r"))) {
33 g_warning ("cannot open IL assembly file %s", name);
38 info->total_lines = 100;
39 info->moffsets = g_malloc (info->total_lines * sizeof (int));
43 while (fgets (buf, sizeof (buf), f)) {
46 info->moffsets [i++] = offset;
47 if (i + 2 >= info->total_lines) {
48 info->total_lines += 100;
49 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
50 g_assert (info->moffsets);
53 if (!sscanf (buf, " // method line %d", &mnum))
58 if (mnum >= info->nmethods)
61 while (fgets (buf, sizeof (buf), f)) {
65 if (i + 2 >= info->total_lines) {
66 info->total_lines += 100;
67 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
68 g_assert (info->moffsets);
71 if (strstr (buf, "}")) {
76 if (sscanf (buf, " IL_%x:", &newoffset)) {
82 info->moffsets [i] = offset;
84 /* g_print ("method %d found at %d\n", mnum, pos); */
85 info->mlines [mnum] = pos;
91 record_line_number (DebugMethodInfo *minfo, gpointer address, guint32 line, int is_basic_block)
93 DebugLineNumberInfo *lni = g_new0 (DebugLineNumberInfo, 1);
95 lni->address = address;
97 lni->is_basic_block = is_basic_block;
100 g_ptr_array_add (minfo->line_numbers, lni);
104 record_il_offset (GPtrArray *array, guint32 offset, guint32 address)
106 MonoDebugILOffsetInfo *info = g_new0 (MonoDebugILOffsetInfo, 1);
108 info->offset = offset;
109 info->address = address;
111 g_ptr_array_add (array, info);
115 debug_generate_method_lines (AssemblyDebugInfo *info, DebugMethodInfo *minfo, MonoFlowGraph* cfg)
117 guint32 st_address, st_line;
118 GPtrArray *il_offsets;
121 il_offsets = g_ptr_array_new ();
122 minfo->line_numbers = g_ptr_array_new ();
124 st_line = minfo->start_line;
127 record_line_number (minfo, cfg->start + st_address, st_line, FALSE);
128 record_il_offset (il_offsets, 0, 0);
130 /* start lines of basic blocks */
131 for (i = 0; i < cfg->block_count; ++i) {
134 for (j = 0; j < cfg->bblocks [i].forest->len; ++j) {
135 MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
136 gint32 line_inc = 0, addr_inc;
139 st_line = minfo->first_line;
140 st_address = t->addr;
142 minfo->frame_start_offset = st_address;
144 record_line_number (minfo, cfg->start + st_address, st_line, TRUE);
147 if (t->cli_addr != -1) {
148 int *lines = info->moffsets + st_line;
151 while ((*k != -1) && (*k < t->cli_addr))
154 line_inc = k - lines;
156 addr_inc = t->addr - st_address;
159 st_address += addr_inc;
161 record_line_number (minfo, cfg->start + st_address, st_line, j == 0);
163 if (t->cli_addr != -1)
164 record_il_offset (il_offsets, t->cli_addr, st_address + 1);
168 minfo->method_info.num_il_offsets = il_offsets->len;
169 minfo->method_info.il_offsets = g_new0 (MonoDebugILOffsetInfo, il_offsets->len);
170 for (i = 0; i < il_offsets->len; i++) {
171 MonoDebugILOffsetInfo *il = (MonoDebugILOffsetInfo *) g_ptr_array_index (il_offsets, i);
173 minfo->method_info.il_offsets [i] = *il;
176 g_ptr_array_free (il_offsets, TRUE);
180 free_method_info (DebugMethodInfo *minfo)
182 if (minfo->line_numbers)
183 g_ptr_array_free (minfo->line_numbers, TRUE);
184 g_free (minfo->method_info.param_offsets);
185 g_free (minfo->method_info.local_offsets);
189 static AssemblyDebugInfo*
190 mono_debug_open_assembly (MonoDebugHandle* handle, MonoImage *image)
193 AssemblyDebugInfo* info;
195 for (tmp = handle->info; tmp; tmp = tmp->next) {
196 info = (AssemblyDebugInfo*)tmp->data;
197 if (strcmp (info->name, image->assembly_name) == 0)
200 info = g_new0 (AssemblyDebugInfo, 1);
201 switch (handle->format) {
202 case MONO_DEBUG_FORMAT_STABS:
203 info->filename = g_strdup_printf ("%s-stabs.s", image->assembly_name);
205 case MONO_DEBUG_FORMAT_DWARF2:
206 info->filename = g_strdup_printf ("%s-dwarf.s", image->assembly_name);
208 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
209 info->filename = g_strdup_printf ("%s-debug.o", image->assembly_name);
213 info->name = g_strdup (image->assembly_name);
214 info->methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
215 NULL, (GDestroyNotify) free_method_info);
216 info->source_files = g_ptr_array_new ();
217 info->type_hash = g_hash_table_new (NULL, NULL);
219 g_ptr_array_add (info->source_files, g_strdup_printf ("%s.il", image->assembly_name));
220 info->producer_name = g_strdup_printf ("Mono JIT compiler version %s", VERSION);
222 mono_debug_get_type (info, mono_defaults.void_class);
223 mono_debug_get_type (info, mono_defaults.object_class);
224 mono_debug_get_type (info, mono_defaults.void_class);
225 mono_debug_get_type (info, mono_defaults.boolean_class);
226 mono_debug_get_type (info, mono_defaults.char_class);
227 mono_debug_get_type (info, mono_defaults.sbyte_class);
228 mono_debug_get_type (info, mono_defaults.byte_class);
229 mono_debug_get_type (info, mono_defaults.int16_class);
230 mono_debug_get_type (info, mono_defaults.uint16_class);
231 mono_debug_get_type (info, mono_defaults.int32_class);
232 mono_debug_get_type (info, mono_defaults.uint32_class);
233 mono_debug_get_type (info, mono_defaults.int_class);
234 mono_debug_get_type (info, mono_defaults.uint_class);
235 mono_debug_get_type (info, mono_defaults.int64_class);
236 mono_debug_get_type (info, mono_defaults.uint64_class);
237 mono_debug_get_type (info, mono_defaults.single_class);
238 mono_debug_get_type (info, mono_defaults.double_class);
239 mono_debug_get_type (info, mono_defaults.string_class);
241 switch (handle->format) {
242 case MONO_DEBUG_FORMAT_STABS:
243 mono_debug_open_assembly_stabs (info);
245 case MONO_DEBUG_FORMAT_DWARF2:
246 mono_debug_open_assembly_dwarf2 (info);
248 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
249 mono_debug_open_assembly_dwarf2_plus (info);
253 info->next_idx = 100;
254 handle->info = g_list_prepend (handle->info, info);
256 info->nmethods = image->tables [MONO_TABLE_METHOD].rows + 1;
257 info->mlines = g_new0 (int, info->nmethods);
258 debug_load_method_lines (info);
263 mono_debug_make_symbols (void)
266 AssemblyDebugInfo* info;
268 if (!mono_debug_handle)
271 for (tmp = mono_debug_handle->info; tmp; tmp = tmp->next) {
272 info = (AssemblyDebugInfo*)tmp->data;
274 switch (mono_debug_handle->format) {
275 case MONO_DEBUG_FORMAT_STABS:
276 mono_debug_write_assembly_stabs (info);
278 case MONO_DEBUG_FORMAT_DWARF2:
279 mono_debug_write_assembly_dwarf2 (info);
281 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
282 mono_debug_write_assembly_dwarf2_plus (info);
289 mono_debug_close_assembly (AssemblyDebugInfo* info)
291 g_free (info->mlines);
292 g_free (info->moffsets);
294 g_free (info->filename);
295 g_ptr_array_free (info->source_files, TRUE);
296 g_hash_table_destroy (info->type_hash);
297 g_hash_table_destroy (info->methods);
298 g_free (info->producer_name);
303 mono_debug_close (MonoDebugHandle* debug)
306 AssemblyDebugInfo* info;
308 mono_debug_make_symbols ();
310 for (tmp = debug->info; tmp; tmp = tmp->next) {
311 info = (AssemblyDebugInfo*)tmp->data;
313 switch (debug->format) {
314 case MONO_DEBUG_FORMAT_STABS:
315 mono_debug_close_assembly_stabs (info);
317 case MONO_DEBUG_FORMAT_DWARF2:
318 mono_debug_close_assembly_dwarf2 (info);
320 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
321 mono_debug_close_assembly_dwarf2_plus (info);
325 mono_debug_close_assembly (info);
328 g_free (debug->name);
333 mono_debug_get_type (AssemblyDebugInfo* info, MonoClass *klass)
337 mono_class_init (klass);
339 index = GPOINTER_TO_INT (g_hash_table_lookup (info->type_hash, klass));
343 index = ++info->next_klass_idx;
344 g_hash_table_insert (info->type_hash, klass, GINT_TO_POINTER (index));
349 switch (klass->byval_arg.type) {
350 case MONO_TYPE_CLASS:
352 mono_debug_get_type (info, klass->parent);
354 for (i = 0; i < klass->method.count; i++) {
355 MonoMethod *method = klass->methods [i];
356 MonoType *ret_type = NULL;
359 if (method->signature->ret->type != MONO_TYPE_VOID)
360 ret_type = method->signature->ret;
363 MonoClass *ret_klass = mono_class_from_mono_type (ret_type);
364 mono_debug_get_type (info, ret_klass);
367 for (j = 0; j < method->signature->param_count; j++) {
368 MonoType *sub_type = method->signature->params [j];
369 MonoClass *sub_klass = mono_class_from_mono_type (sub_type);
370 mono_debug_get_type (info, sub_klass);
374 case MONO_TYPE_VALUETYPE:
375 for (i = 0; i < klass->field.count; i++) {
376 MonoClass *subclass = mono_class_from_mono_type (klass->fields [i].type);
377 mono_debug_get_type (info, subclass);
380 case MONO_TYPE_ARRAY:
381 case MONO_TYPE_SZARRAY:
382 mono_debug_get_type (info, klass->element_class);
392 mono_debug_add_type (MonoDebugHandle* debug, MonoClass *klass)
394 AssemblyDebugInfo* info = mono_debug_open_assembly (debug, klass->image);
396 mono_debug_get_type (info, klass);
400 mono_debug_add_method (MonoDebugHandle* debug, MonoFlowGraph *cfg)
402 MonoMethod *method = cfg->method;
403 MonoClass *klass = method->klass;
404 AssemblyDebugInfo* info = mono_debug_open_assembly (debug, klass->image);
405 int method_number = 0, line = 0, start_line, i;
406 DebugMethodInfo *minfo;
409 mono_class_init (klass);
411 * Find the method index in the image.
413 for (i = 0; klass->methods && i < klass->method.count; ++i) {
414 if (klass->methods [i] == method) {
415 method_number = klass->method.first + i + 1;
416 line = info->mlines [method_number];
421 if (g_hash_table_lookup (info->methods, method))
424 /* info->moffsets contains -1 "outside" of functions. */
425 for (i = line; (i > 0) && (info->moffsets [i] == 0); i--)
429 name = g_strdup_printf ("%s%s%s.%s", klass->name_space, klass->name_space [0]? ".": "",
430 klass->name, method->name);
432 minfo = g_new0 (DebugMethodInfo, 1);
434 minfo->start_line = start_line;
435 minfo->first_line = line;
436 minfo->method_info.code_start = cfg->start + 1;
437 minfo->method_info.code_size = cfg->code_size;
438 minfo->method_number = method_number;
439 minfo->method_info.method = method;
440 minfo->method_info.num_params = method->signature->param_count + method->signature->hasthis;
441 minfo->method_info.param_offsets = g_new0 (guint32, minfo->method_info.num_params + 1);
443 for (i = 0; i < minfo->method_info.num_params; i++) {
444 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index;
446 minfo->method_info.param_offsets [i] = ptr [i].offset;
449 if (!method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
450 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
451 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->locals_start_index;
453 minfo->method_info.num_locals = header->num_locals;
454 minfo->method_info.local_offsets = g_new0 (guint32, header->num_locals);
455 for (i = 0; i < minfo->method_info.num_locals; i++)
456 minfo->method_info.local_offsets [i] = ptr [i].offset;
459 debug_generate_method_lines (info, minfo, cfg);
461 g_hash_table_insert (info->methods, method, minfo);