5 #include <mono/metadata/class.h>
6 #include <mono/metadata/tabledefs.h>
7 #include <mono/metadata/tokentype.h>
8 #include <mono/jit/codegen.h>
9 #include <mono/jit/debug.h>
11 #include "debug-private.h"
13 static MonoDebugHandle *mono_debug_handles = NULL;
14 static MonoDebugHandle *mono_default_debug_handle = NULL;
17 free_method_info (DebugMethodInfo *minfo)
19 if (minfo->line_numbers)
20 g_ptr_array_free (minfo->line_numbers, TRUE);
21 g_free (minfo->method_info.params);
22 g_free (minfo->method_info.locals);
27 mono_debug_open_file (const char *filename, MonoDebugFormat format)
29 MonoDebugHandle *debug;
31 debug = g_new0 (MonoDebugHandle, 1);
32 debug->name = g_strdup (filename);
33 debug->format = format;
34 debug->producer_name = g_strdup_printf ("Mono JIT compiler version %s", VERSION);
35 debug->next_idx = 100;
37 debug->type_hash = g_hash_table_new (NULL, NULL);
38 debug->methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
39 NULL, (GDestroyNotify) free_method_info);
40 debug->source_files = g_ptr_array_new ();
42 switch (debug->format) {
43 case MONO_DEBUG_FORMAT_STABS:
44 debug->filename = g_strdup_printf ("%s-stabs.s", g_basename (debug->name));
45 debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
47 case MONO_DEBUG_FORMAT_DWARF2:
48 debug->filename = g_strdup_printf ("%s-dwarf.s", g_basename (debug->name));
49 debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
51 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
52 if (!mono_default_debug_handle)
53 mono_debug_open_file (filename, MONO_DEBUG_FORMAT_DWARF2);
56 g_assert_not_reached ();
59 debug->next = mono_debug_handles;
60 mono_debug_handles = debug;
62 if (!mono_default_debug_handle)
63 mono_default_debug_handle = debug;
69 debug_load_method_lines (AssemblyDebugInfo* info)
74 char *name = g_strdup_printf ("%s.il", info->name);
75 char *command = g_strdup_printf ("monodis --output=%s.il %s", info->name, info->image->name);
76 struct stat stata, statb;
79 if (stat (info->image->name, &stata)) {
80 g_warning ("cannot access assembly file (%s): %s", info->image->name, g_strerror (errno));
86 /* If the stat() failed or the file is older. */
87 if (stat (name, &statb) || (statb.st_mtime < stata.st_mtime)) {
88 g_print ("Recreating %s from %s.\n", name, info->image->name);
89 if (system (command)) {
90 g_warning ("cannot create IL assembly file (%s): %s", command, g_strerror (errno));
97 /* use an env var with directories for searching. */
98 if (!(f = fopen (name, "r"))) {
99 g_warning ("cannot open IL assembly file %s", name);
105 info->total_lines = 100;
106 info->moffsets = g_malloc (info->total_lines * sizeof (int));
111 while (fgets (buf, sizeof (buf), f)) {
114 info->moffsets [i++] = offset;
115 if (i + 2 >= info->total_lines) {
116 info->total_lines += 100;
117 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
118 g_assert (info->moffsets);
121 if (!sscanf (buf, " // method line %d", &mnum))
126 if (mnum >= info->nmethods)
129 while (fgets (buf, sizeof (buf), f)) {
133 if (i + 2 >= info->total_lines) {
134 info->total_lines += 100;
135 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
136 g_assert (info->moffsets);
139 if (strstr (buf, "}")) {
144 if (sscanf (buf, " IL_%x:", &newoffset)) {
150 info->moffsets [i] = offset;
152 /* g_print ("method %d found at %d\n", mnum, pos); */
153 info->mlines [mnum] = pos;
159 record_line_number (DebugMethodInfo *minfo, gpointer address, guint32 line, int is_basic_block)
161 DebugLineNumberInfo *lni = g_new0 (DebugLineNumberInfo, 1);
163 lni->address = address;
165 lni->is_basic_block = is_basic_block;
166 lni->source_file = 0;
168 g_ptr_array_add (minfo->line_numbers, lni);
172 record_il_offset (GPtrArray *array, guint32 offset, guint32 address)
174 MonoDebugILOffsetInfo *info = g_new0 (MonoDebugILOffsetInfo, 1);
176 info->offset = offset;
177 info->address = address;
179 g_ptr_array_add (array, info);
183 debug_generate_method_lines (AssemblyDebugInfo *info, DebugMethodInfo *minfo, MonoFlowGraph* cfg)
185 guint32 st_address, st_line;
186 GPtrArray *il_offsets;
189 il_offsets = g_ptr_array_new ();
190 minfo->line_numbers = g_ptr_array_new ();
192 st_line = minfo->first_line;
193 st_address = minfo->method_info.prologue_end;
195 /* record_line_number takes absolute memory addresses. */
196 record_line_number (minfo, minfo->method_info.code_start, minfo->start_line, FALSE);
197 /* record_il_offsets uses offsets relative to minfo->method_info.code_start. */
198 record_il_offset (il_offsets, 0, st_address);
200 /* This is the first actual code line of the method. */
201 record_line_number (minfo, minfo->method_info.code_start + st_address, st_line, TRUE);
203 /* start lines of basic blocks */
204 for (i = 0; i < cfg->block_count; ++i) {
207 for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
208 MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
209 gint32 line_inc = 0, addr_inc;
212 st_line = minfo->first_line;
213 st_address = t->addr - 1;
215 record_line_number (minfo, cfg->start + st_address, st_line, TRUE);
218 addr_inc = t->addr - st_address - 1;
219 st_address += addr_inc;
221 if (t->cli_addr != -1)
222 record_il_offset (il_offsets, t->cli_addr, st_address);
228 if (t->cli_addr != -1) {
229 int *lines = info->moffsets + st_line;
232 while ((*k != -1) && (*k < t->cli_addr))
235 line_inc = k - lines;
240 record_line_number (minfo, minfo->method_info.code_start + st_address,
245 minfo->method_info.num_il_offsets = il_offsets->len;
246 minfo->method_info.il_offsets = g_new0 (MonoDebugILOffsetInfo, il_offsets->len);
247 for (i = 0; i < il_offsets->len; i++) {
248 MonoDebugILOffsetInfo *il = (MonoDebugILOffsetInfo *) g_ptr_array_index (il_offsets, i);
250 minfo->method_info.il_offsets [i] = *il;
253 g_ptr_array_free (il_offsets, TRUE);
256 static AssemblyDebugInfo *
257 mono_debug_get_image (MonoDebugHandle* debug, MonoImage *image)
260 AssemblyDebugInfo *info;
262 if (debug->format == MONO_DEBUG_FORMAT_NONE)
265 for (tmp = debug->info; tmp; tmp = tmp->next) {
266 info = (AssemblyDebugInfo*)tmp->data;
268 if (info->image == image)
275 static AssemblyDebugInfo *
276 mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image)
278 AssemblyDebugInfo *info;
280 info = mono_debug_get_image (debug, image);
284 info = g_new0 (AssemblyDebugInfo, 1);
286 info->image->ref_count++;
287 info->name = g_strdup (image->assembly_name);
288 info->format = debug->format;
289 info->handle = debug;
291 info->source_file = debug->source_files->len;
292 g_ptr_array_add (debug->source_files, g_strdup_printf ("%s.il", image->assembly_name));
294 debug->info = g_list_prepend (debug->info, info);
296 info->nmethods = image->tables [MONO_TABLE_METHOD].rows + 1;
297 info->mlines = g_new0 (int, info->nmethods);
299 switch (info->format) {
300 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
301 info->filename = g_strdup_printf ("%s-debug.s", info->name);
302 info->objfile = g_strdup_printf ("%s-debug.o", info->name);
303 mono_debug_open_assembly_dwarf2_plus (info);
309 if (debug->format != MONO_DEBUG_FORMAT_DWARF2_PLUS)
310 debug_load_method_lines (info);
316 mono_debug_add_image (MonoDebugHandle* debug, MonoImage *image)
318 mono_debug_open_image (debug, image);
322 mono_debug_write_symbols (MonoDebugHandle *debug)
329 switch (debug->format) {
330 case MONO_DEBUG_FORMAT_STABS:
331 mono_debug_write_stabs (debug);
333 case MONO_DEBUG_FORMAT_DWARF2:
334 mono_debug_write_dwarf2 (debug);
336 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
337 for (tmp = debug->info; tmp; tmp = tmp->next) {
338 AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
340 mono_debug_write_assembly_dwarf2_plus (info);
344 g_assert_not_reached ();
349 mono_debug_make_symbols (void)
351 MonoDebugHandle *debug;
353 for (debug = mono_debug_handles; debug; debug = debug->next)
354 mono_debug_write_symbols (debug);
358 mono_debug_close_assembly (AssemblyDebugInfo* info)
360 switch (info->format) {
361 case MONO_DEBUG_FORMAT_DWARF2_PLUS:
362 mono_debug_close_assembly_dwarf2_plus (info);
367 g_free (info->mlines);
368 g_free (info->moffsets);
370 g_free (info->filename);
371 g_free (info->objfile);
376 mono_debug_cleanup (void)
378 MonoDebugHandle *debug, *temp;
380 mono_debug_make_symbols ();
382 for (debug = mono_debug_handles; debug; debug = temp) {
385 for (tmp = debug->info; tmp; tmp = tmp->next) {
386 AssemblyDebugInfo* info = (AssemblyDebugInfo*)tmp->data;
388 mono_debug_close_assembly (info);
391 g_ptr_array_free (debug->source_files, TRUE);
392 g_hash_table_destroy (debug->methods);
393 g_hash_table_destroy (debug->type_hash);
394 g_free (debug->producer_name);
395 g_free (debug->name);
401 mono_debug_handles = NULL;
402 mono_default_debug_handle = NULL;
406 mono_debug_get_type (MonoDebugHandle *debug, MonoClass *klass)
410 mono_class_init (klass);
412 index = GPOINTER_TO_INT (g_hash_table_lookup (debug->type_hash, klass));
416 index = ++debug->next_klass_idx;
417 g_hash_table_insert (debug->type_hash, klass, GINT_TO_POINTER (index));
422 switch (klass->byval_arg.type) {
423 case MONO_TYPE_CLASS:
425 mono_debug_get_type (debug, klass->parent);
427 for (i = 0; i < klass->method.count; i++) {
428 MonoMethod *method = klass->methods [i];
429 MonoType *ret_type = NULL;
432 if (method->signature->ret->type != MONO_TYPE_VOID)
433 ret_type = method->signature->ret;
436 MonoClass *ret_klass = mono_class_from_mono_type (ret_type);
437 mono_debug_get_type (debug, ret_klass);
440 for (j = 0; j < method->signature->param_count; j++) {
441 MonoType *sub_type = method->signature->params [j];
442 MonoClass *sub_klass = mono_class_from_mono_type (sub_type);
443 mono_debug_get_type (debug, sub_klass);
447 case MONO_TYPE_VALUETYPE:
448 for (i = 0; i < klass->field.count; i++) {
449 MonoClass *subclass = mono_class_from_mono_type (klass->fields [i].type);
450 mono_debug_get_type (debug, subclass);
453 case MONO_TYPE_ARRAY:
454 case MONO_TYPE_SZARRAY:
455 mono_debug_get_type (debug, klass->element_class);
465 mono_debug_handle_from_class (MonoClass *klass)
467 MonoDebugHandle *debug;
469 mono_class_init (klass);
471 for (debug = mono_debug_handles; debug; debug = debug->next) {
474 for (tmp = debug->info; tmp; tmp = tmp->next) {
475 AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
477 if (info->image == klass->image)
486 mono_debug_add_type (MonoClass *klass)
488 MonoDebugHandle *debug = mono_debug_handle_from_class (klass);
490 g_assert (debug != NULL);
492 mono_debug_get_type (debug, klass);
496 mono_debug_add_method (MonoFlowGraph *cfg)
498 MonoMethod *method = cfg->method;
499 MonoClass *klass = method->klass;
500 int method_number = 0, line = 0, start_line = 0, end_line = 0, i;
501 MonoDebugHandle* debug;
502 AssemblyDebugInfo* info;
503 DebugMethodInfo *minfo;
506 mono_class_init (klass);
508 debug = mono_debug_handle_from_class (klass);
510 if (mono_default_debug_handle)
511 debug = mono_default_debug_handle;
516 info = mono_debug_open_image (debug, klass->image);
519 * Find the method index in the image.
521 for (i = 0; klass->methods && i < klass->method.count; ++i) {
522 if (klass->methods [i] == method) {
523 method_number = klass->method.first + i + 1;
524 line = info->mlines [method_number];
529 if (g_hash_table_lookup (debug->methods, method))
532 if (info->moffsets) {
533 /* info->moffsets contains -1 "outside" of functions. */
534 for (i = line; (i > 0) && (info->moffsets [i] == 0); i--)
538 for (i = start_line; info->moffsets [i] != -1; i++)
543 name = g_strdup_printf ("%s%s%s.%s", klass->name_space, klass->name_space [0]? ".": "",
544 klass->name, method->name);
546 minfo = g_new0 (DebugMethodInfo, 1);
548 minfo->start_line = start_line;
549 minfo->first_line = line;
550 minfo->last_line = end_line;
551 minfo->source_file = info->source_file;
552 minfo->method_info.code_start = cfg->start + 1;
553 minfo->method_info.code_size = cfg->epilogue_end - 1;
554 minfo->method_number = method_number;
555 minfo->method_info.method = method;
556 minfo->method_info.num_params = method->signature->param_count;
557 minfo->method_info.params = g_new0 (MonoDebugVarInfo, minfo->method_info.num_params);
558 minfo->method_info.prologue_end = cfg->prologue_end - 1;
559 minfo->method_info.epilogue_begin = cfg->epilog - 1;
561 if (method->signature->hasthis) {
562 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index;
564 minfo->method_info.this_var = g_new0 (MonoDebugVarInfo, 1);
565 minfo->method_info.this_var->offset = ptr->offset;
568 for (i = 0; i < minfo->method_info.num_params; i++) {
569 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index +
570 method->signature->hasthis;
572 minfo->method_info.params [i].offset = ptr [i].offset;
575 if (!method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
576 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
577 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->locals_start_index;
579 minfo->method_info.num_locals = header->num_locals;
580 minfo->method_info.locals = g_new0 (MonoDebugVarInfo, header->num_locals);
581 for (i = 0; i < minfo->method_info.num_locals; i++) {
582 minfo->method_info.locals [i].offset = ptr [i].offset;
583 minfo->method_info.locals [i].begin_scope = minfo->method_info.prologue_end;
584 minfo->method_info.locals [i].end_scope = minfo->method_info.epilogue_begin;
588 debug_generate_method_lines (info, minfo, cfg);
590 g_hash_table_insert (debug->methods, method, minfo);