6 #include <mono/metadata/class.h>
7 #include <mono/metadata/assembly.h>
8 #include <mono/metadata/tabledefs.h>
9 #include <mono/metadata/tokentype.h>
10 #include <mono/metadata/debug-helpers.h>
11 #include <mono/metadata/debug-mono-symfile.h>
12 #include <mono/jit/codegen.h>
13 #include <mono/jit/debug.h>
15 #include "debug-private.h"
18 /* This is incremented each time the symbol table is modified.
19 * The debugger looks at this variable and if it has a higher value than its current
20 * copy of the symbol table, it must call debugger_update_symbol_file_table().
22 static guint32 debugger_symbol_file_table_generation = 0;
24 /* Caution: This variable may be accessed at any time from the debugger;
25 * it is very important not to modify the memory it is pointing to
26 * without previously setting this pointer back to NULL.
28 static MonoDebuggerSymbolFileTable *debugger_symbol_file_table = NULL;
30 /* Caution: This function MUST be called before touching the symbol table! */
31 static void release_symbol_file_table (void);
33 static void initialize_debugger_support (void);
35 static MonoDebugHandle *mono_debug_handle = NULL;
37 static guint64 debugger_insert_breakpoint (guint64 method_argument, const gchar *string_argument);
38 static guint64 debugger_remove_breakpoint (guint64 breakpoint);
39 static int debugger_update_symbol_file_table (void);
41 static void mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data);
42 static void mono_debug_close_assembly (AssemblyDebugInfo* info);
43 static AssemblyDebugInfo *mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image);
46 * This is a global data symbol which is read by the debugger.
48 MonoDebuggerInfo MONO_DEBUGGER__debugger_info = {
49 MONO_SYMBOL_FILE_DYNAMIC_MAGIC,
50 MONO_SYMBOL_FILE_DYNAMIC_VERSION,
51 sizeof (MonoDebuggerInfo),
52 &mono_generic_trampoline_code,
53 &mono_breakpoint_trampoline_code,
54 &debugger_symbol_file_table_generation,
55 &debugger_symbol_file_table,
56 &debugger_update_symbol_file_table,
58 &debugger_insert_breakpoint,
59 &debugger_remove_breakpoint
63 free_method_info (MonoDebugMethodInfo *minfo)
65 DebugMethodInfo *priv = minfo->user_data;
73 g_array_free (minfo->jit->line_numbers, TRUE);
74 g_free (minfo->jit->this_var);
75 g_free (minfo->jit->params);
76 g_free (minfo->jit->locals);
80 g_free (minfo->il_offsets);
85 debug_arg_warning (const char *message)
87 g_warning ("Error while processing --debug-args arguments: %s", message);
91 replace_suffix (const char *filename, const char *new_suffix)
93 const char *pos = strrchr (filename, '.');
96 return g_strdup_printf ("%s.%s", filename, new_suffix);
98 int len = pos - filename;
99 gchar *retval = g_malloc0 (len + strlen (new_suffix) + 2);
100 memcpy (retval, filename, len);
102 memcpy (retval + len + 1, new_suffix, strlen (new_suffix) + 1);
108 mono_debug_open (MonoAssembly *assembly, MonoDebugFormat format, const char **args)
110 MonoDebugHandle *debug;
113 g_assert (!mono_debug_handle);
115 release_symbol_file_table ();
117 debug = g_new0 (MonoDebugHandle, 1);
118 debug->name = g_strdup (assembly->image->name);
119 debug->format = format;
120 debug->producer_name = g_strdup_printf ("Mono JIT compiler version %s", VERSION);
121 debug->next_idx = 100;
124 debug->type_hash = g_hash_table_new (NULL, NULL);
125 debug->source_files = g_ptr_array_new ();
127 debug->images = g_hash_table_new_full (NULL, NULL, NULL,
128 (GDestroyNotify) mono_debug_close_assembly);
130 for (ptr = args; ptr && *ptr; ptr++) {
131 const char *arg = *ptr;
134 switch (debug->format) {
135 case MONO_DEBUG_FORMAT_STABS:
136 case MONO_DEBUG_FORMAT_DWARF2:
137 if (!strncmp (arg, "filename=", 9)) {
139 debug_arg_warning ("The `filename' argument can be given only once.");
140 debug->filename = g_strdup (arg + 9);
142 } else if (!strncmp (arg, "objfile=", 8)) {
144 debug_arg_warning ("The `objfile' argument can be given only once.");
145 debug->objfile = g_strdup (arg + 8);
149 case MONO_DEBUG_FORMAT_MONO:
150 debug->flags |= MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES |
151 MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
157 if (debug->format != MONO_DEBUG_FORMAT_MONO) {
158 if (!strcmp (arg, "dont_assemble")) {
159 debug->flags |= MONO_DEBUG_FLAGS_DONT_ASSEMBLE;
161 } else if (!strcmp (arg, "update_on_exit")) {
162 debug->flags |= MONO_DEBUG_FLAGS_UPDATE_ON_EXIT;
164 } else if (!strcmp (arg, "install_il_files")) {
165 debug->flags |= MONO_DEBUG_FLAGS_INSTALL_IL_FILES;
167 } else if (!strcmp (arg, "dont_update_il_files")) {
168 debug->flags |= MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES;
170 } else if (!strcmp (arg, "dont_create_il_files")) {
171 debug->flags |= MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
175 if (!strcmp (arg, "internal_mono_debugger")) {
176 debug->flags |= MONO_DEBUG_FLAGS_MONO_DEBUGGER;
177 initialize_debugger_support ();
182 message = g_strdup_printf ("Unknown argument `%s'.", arg);
183 debug_arg_warning (message);
187 switch (debug->format) {
188 case MONO_DEBUG_FORMAT_STABS:
189 if (!debug->filename)
190 debug->filename = g_strdup_printf ("%s-stabs.s", g_basename (debug->name));
192 debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
194 case MONO_DEBUG_FORMAT_DWARF2:
195 if (!debug->filename)
196 debug->filename = g_strdup_printf ("%s-dwarf.s", g_basename (debug->name));
198 debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
200 case MONO_DEBUG_FORMAT_MONO:
203 g_assert_not_reached ();
206 mono_debug_handle = debug;
207 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
209 mono_debug_open_image (mono_debug_handle, assembly->image);
215 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
217 if (!mono_debug_handle)
220 mono_debug_open_image (mono_debug_handle, assembly->image);
224 generate_il_offsets (AssemblyDebugInfo *info, MonoMethod *method)
226 GPtrArray *il_offsets = g_ptr_array_new ();
227 MonoClass *klass = method->klass;
228 MonoDebugMethodInfo *minfo;
229 DebugMethodInfo *priv;
232 g_assert (klass->image == info->image);
234 /* FIXME: doesn't work yet. */
235 if (!strcmp (klass->name_space, "System.Runtime.Remoting.Proxies"))
238 mono_class_init (klass);
240 minfo = g_new0 (MonoDebugMethodInfo, 1);
241 minfo->method = method;
242 minfo->user_data = priv = g_new0 (DebugMethodInfo, 1);
244 priv->name = g_strdup_printf ("%s%s%s.%s", klass->name_space, klass->name_space [0]? ".": "",
245 klass->name, method->name);
246 priv->source_file = info->source_file;
250 * Find the method index in the image.
252 for (i = 0; klass->methods && i < klass->method.count; ++i) {
253 if (klass->methods [i] == minfo->method) {
254 priv->method_number = klass->method.first + i + 1;
255 priv->first_line = info->mlines [priv->method_number];
260 g_assert (priv->method_number);
262 /* info->moffsets contains -1 "outside" of functions. */
263 for (i = priv->first_line; (i > 0) && (info->moffsets [i] == 0); i--)
265 priv->start_line = i + 1;
267 for (i = priv->start_line; info->moffsets [i] != -1; i++) {
268 MonoSymbolFileLineNumberEntry *lne = g_new0 (MonoSymbolFileLineNumberEntry, 1);
270 if (!info->moffsets [i] && (i > priv->start_line))
273 lne->offset = info->moffsets [i];
276 g_ptr_array_add (il_offsets, lne);
281 minfo->start_line = priv->first_line;
282 minfo->end_line = priv->last_line;
284 minfo->num_il_offsets = il_offsets->len;
285 minfo->il_offsets = g_new0 (MonoSymbolFileLineNumberEntry, il_offsets->len);
286 for (i = 0; i < il_offsets->len; i++) {
287 MonoSymbolFileLineNumberEntry *il = g_ptr_array_index (il_offsets, i);
289 minfo->il_offsets [i] = *il;
292 g_ptr_array_free (il_offsets, TRUE);
294 g_hash_table_insert (info->methods, method, minfo);
298 debug_load_method_lines (AssemblyDebugInfo* info)
300 MonoTableInfo *table = &info->image->tables [MONO_TABLE_METHOD];
306 if (info->always_create_il || !(info->handle->flags & MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES)) {
307 char *command = g_strdup_printf ("monodis --output=%s %s",
308 info->ilfile, info->image->name);
309 struct stat stata, statb;
310 int need_update = FALSE;
312 if (stat (info->image->name, &stata)) {
313 g_warning ("cannot access assembly file (%s): %s",
314 info->image->name, g_strerror (errno));
319 /* If the stat() failed or the file is older. */
320 if (stat (info->ilfile, &statb)) {
322 } else if (statb.st_mtime < stata.st_mtime)
326 #ifndef PLATFORM_WIN32
327 struct sigaction act, oldact;
332 #ifndef PLATFORM_WIN32
333 act.sa_handler = SIG_IGN;
334 act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
335 sigemptyset (&act.sa_mask);
336 sigaddset (&act.sa_mask, SIGCHLD);
337 sigprocmask (SIG_BLOCK, &act.sa_mask, &old_set);
338 sigaction (SIGCHLD, &act, &oldact);
341 g_print ("Recreating %s from %s.\n", info->ilfile, info->image->name);
343 ret = system (command);
345 #ifndef PLATFORM_WIN32
346 sigaction (SIGCHLD, &oldact, NULL);
347 sigprocmask (SIG_SETMASK, &old_set, NULL);
351 g_warning ("cannot create IL assembly file (%s): %s",
352 command, g_strerror (errno));
359 /* use an env var with directories for searching. */
360 if (!(f = fopen (info->ilfile, "r"))) {
361 g_warning ("cannot open IL assembly file %s", info->ilfile);
365 info->total_lines = 100;
366 info->moffsets = g_malloc (info->total_lines * sizeof (int));
369 while (fgets (buf, sizeof (buf), f)) {
372 info->moffsets [i++] = offset;
373 if (i + 2 >= info->total_lines) {
374 info->total_lines += 100;
375 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
376 g_assert (info->moffsets);
379 if (!sscanf (buf, " // method line %d", &mnum))
384 if (mnum >= info->nmethods)
387 while (fgets (buf, sizeof (buf), f)) {
391 if (i + 2 >= info->total_lines) {
392 info->total_lines += 100;
393 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
394 g_assert (info->moffsets);
397 if (strstr (buf, "}")) {
402 if (sscanf (buf, " IL_%x:", &newoffset)) {
408 info->moffsets [i] = offset;
410 /* g_print ("method %d found at %d\n", mnum, pos); */
411 info->mlines [mnum] = pos;
415 for (idx = 1; idx <= table->rows; idx++) {
416 guint32 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
417 MonoMethod *method = mono_get_method (info->image, token, NULL);
419 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
420 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
421 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
424 if (method->wrapper_type != MONO_WRAPPER_NONE)
427 generate_il_offsets (info, method);
432 record_line_number (MonoDebugMethodInfo *minfo, guint32 address, guint32 offset, guint32 line)
434 MonoDebugLineNumberEntry *lne = g_new0 (MonoDebugLineNumberEntry, 1);
436 lne->address = address;
437 lne->offset = offset;
440 g_array_append_val (minfo->jit->line_numbers, *lne);
444 debug_generate_method_lines (AssemblyDebugInfo *info, MonoDebugMethodInfo *minfo, MonoFlowGraph* cfg)
446 guint32 st_address, st_line;
447 DebugMethodInfo *priv = minfo->user_data;
450 if (!priv || !info->moffsets)
453 minfo->jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
455 st_line = priv->first_line;
456 st_address = minfo->jit->prologue_end;
458 /* This is the first actual code line of the method. */
459 record_line_number (minfo, st_address, 0, st_line);
461 /* start lines of basic blocks */
462 for (i = 0; i < cfg->block_count; ++i) {
465 for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
466 MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
467 gint32 line_inc = 0, addr_inc;
470 st_line = priv->first_line;
471 st_address = t->addr;
474 addr_inc = t->addr - st_address;
475 st_address += addr_inc;
477 if (t->cli_addr != -1) {
478 int *lines = info->moffsets + st_line;
481 while ((*k != -1) && (*k < t->cli_addr))
484 line_inc = k - lines;
489 if (t->cli_addr != -1)
490 record_line_number (minfo, st_address, t->cli_addr, st_line);
496 generate_line_number (MonoDebugMethodInfo *minfo, guint32 address, guint32 offset)
500 for (i = minfo->num_il_offsets - 1; i >= 0; i--) {
501 MonoDebugLineNumberEntry *lne;
503 if (minfo->il_offsets [i].offset > offset)
506 if (minfo->jit->line_numbers->len) {
507 MonoDebugLineNumberEntry last = g_array_index (
508 minfo->jit->line_numbers, MonoDebugLineNumberEntry,
509 minfo->jit->line_numbers->len - 1);
511 if (minfo->il_offsets [i].row <= last.line)
515 lne = g_new0 (MonoDebugLineNumberEntry, 1);
516 lne->address = address;
517 lne->offset = offset;
518 lne->line = minfo->il_offsets [i].row;
520 g_array_append_val (minfo->jit->line_numbers, *lne);
526 debug_update_il_offsets (AssemblyDebugInfo *info, MonoDebugMethodInfo *minfo, MonoFlowGraph* cfg)
528 MonoMethodHeader *header;
529 guint32 address, offset;
533 g_assert (info->symfile);
534 if (info->symfile->is_dynamic)
537 g_assert (!minfo->jit->line_numbers);
538 minfo->jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
540 address = minfo->jit->prologue_end;
543 g_assert (((MonoMethodNormal*)minfo->method)->header);
544 header = ((MonoMethodNormal*)minfo->method)->header;
547 if (!strcmp (minfo->method->name, "Main")) {
548 MonoMethodHeader *header = ((MonoMethodNormal*)minfo->method)->header;
551 mono_disassemble_code (minfo->jit->code_start, minfo->jit->code_size,
552 minfo->method->name);
554 printf ("\nDisassembly:\n%s\n", mono_disasm_code (
555 NULL, minfo->method, header->code, header->code + header->code_size));
556 g_message (G_STRLOC ": %x - %x", minfo->jit->prologue_end, minfo->jit->epilogue_begin);
560 generate_line_number (minfo, address, offset);
562 /* start lines of basic blocks */
563 for (i = 0; i < cfg->block_count; ++i) {
566 for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
567 MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
569 if ((t->cli_addr == -1) || (t->cli_addr == offset) || (t->addr == address))
572 offset = t->cli_addr;
575 generate_line_number (minfo, address, offset);
579 generate_line_number (minfo, minfo->jit->epilogue_begin, header->code_size);
582 for (i = 0; i < minfo->jit->line_numbers->len; i++) {
583 MonoDebugLineNumberEntry lne = g_array_index (
584 minfo->jit->line_numbers, MonoDebugLineNumberEntry, i);
586 g_message (G_STRLOC ": %x,%x,%d", lne.address, lne.offset, lne.line);
591 static AssemblyDebugInfo *
592 mono_debug_get_image (MonoDebugHandle* debug, MonoImage *image)
594 return g_hash_table_lookup (debug->images, image);
597 static AssemblyDebugInfo *
598 mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image)
600 AssemblyDebugInfo *info;
603 info = mono_debug_get_image (debug, image);
609 info = g_new0 (AssemblyDebugInfo, 1);
611 info->image->ref_count++;
612 info->name = g_strdup (image->assembly_name);
613 info->format = debug->format;
614 info->handle = debug;
615 info->methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
616 NULL, (GDestroyNotify) free_method_info);
618 info->source_file = debug->source_files->len;
619 g_ptr_array_add (debug->source_files, g_strdup_printf ("%s.il", image->assembly_name));
621 g_hash_table_insert (debug->images, image, info);
623 info->nmethods = image->tables [MONO_TABLE_METHOD].rows + 1;
624 info->mlines = g_new0 (int, info->nmethods);
626 for (ptr = image->references; ptr && *ptr; ptr++)
627 mono_debug_add_assembly (*ptr, NULL);
629 switch (info->format) {
630 case MONO_DEBUG_FORMAT_STABS:
631 case MONO_DEBUG_FORMAT_DWARF2:
632 if (debug->flags & MONO_DEBUG_FLAGS_INSTALL_IL_FILES) {
633 gchar *dirname = g_path_get_dirname (image->name);
634 info->ilfile = g_strdup_printf ("%s/%s.il", dirname, info->name);
637 info->ilfile = g_strdup_printf ("%s.il", info->name);
639 case MONO_DEBUG_FORMAT_MONO:
640 info->filename = replace_suffix (image->name, "dbg");
641 if (g_file_test (info->filename, G_FILE_TEST_EXISTS))
642 info->symfile = mono_debug_open_mono_symbol_file (info->image, info->filename, TRUE);
643 else if (debug->flags & MONO_DEBUG_FLAGS_MONO_DEBUGGER) {
644 if (!strcmp (info->name, "corlib"))
646 info->ilfile = g_strdup_printf ("%s.il", info->name);
647 info->always_create_il = TRUE;
648 debug_load_method_lines (info);
649 g_assert (info->methods);
650 info->symfile = mono_debug_create_mono_symbol_file (
651 info->image, info->ilfile, info->methods);
653 debugger_symbol_file_table_generation++;
660 if (debug->format != MONO_DEBUG_FORMAT_MONO)
661 debug_load_method_lines (info);
667 mono_debug_write_symbols (MonoDebugHandle *debug)
669 if (!debug || !debug->dirty)
672 release_symbol_file_table ();
674 switch (debug->format) {
675 case MONO_DEBUG_FORMAT_STABS:
676 mono_debug_write_stabs (debug);
678 case MONO_DEBUG_FORMAT_DWARF2:
679 mono_debug_write_dwarf2 (debug);
681 case MONO_DEBUG_FORMAT_MONO:
684 g_assert_not_reached ();
687 debug->dirty = FALSE;
691 mono_debug_make_symbols (void)
693 release_symbol_file_table ();
695 if (!mono_debug_handle || !mono_debug_handle->dirty)
698 switch (mono_debug_handle->format) {
699 case MONO_DEBUG_FORMAT_STABS:
700 mono_debug_write_stabs (mono_debug_handle);
702 case MONO_DEBUG_FORMAT_DWARF2:
703 mono_debug_write_dwarf2 (mono_debug_handle);
705 case MONO_DEBUG_FORMAT_MONO:
706 debugger_update_symbol_file_table ();
709 g_assert_not_reached ();
712 mono_debug_handle->dirty = FALSE;
716 mono_debug_close_assembly (AssemblyDebugInfo* info)
718 switch (info->format) {
719 case MONO_DEBUG_FORMAT_MONO:
720 if (info->symfile != NULL)
721 mono_debug_close_mono_symbol_file (info->symfile);
726 g_hash_table_destroy (info->methods);
727 g_free (info->mlines);
728 g_free (info->moffsets);
730 g_free (info->ilfile);
731 g_free (info->filename);
732 g_free (info->objfile);
737 mono_debug_cleanup (void)
739 release_symbol_file_table ();
741 if (!mono_debug_handle)
744 if (mono_debug_handle->flags & MONO_DEBUG_FLAGS_UPDATE_ON_EXIT)
745 mono_debug_write_symbols (mono_debug_handle);
747 g_hash_table_destroy (mono_debug_handle->images);
748 g_ptr_array_free (mono_debug_handle->source_files, TRUE);
749 g_hash_table_destroy (mono_debug_handle->type_hash);
750 g_free (mono_debug_handle->producer_name);
751 g_free (mono_debug_handle->name);
752 g_free (mono_debug_handle);
754 mono_debug_handle = NULL;
758 mono_debug_get_type (MonoDebugHandle *debug, MonoClass *klass)
762 mono_class_init (klass);
764 index = GPOINTER_TO_INT (g_hash_table_lookup (debug->type_hash, klass));
770 index = ++debug->next_klass_idx;
771 g_hash_table_insert (debug->type_hash, klass, GINT_TO_POINTER (index));
776 switch (klass->byval_arg.type) {
777 case MONO_TYPE_CLASS:
779 mono_debug_get_type (debug, klass->parent);
781 for (i = 0; i < klass->method.count; i++) {
782 MonoMethod *method = klass->methods [i];
783 MonoType *ret_type = NULL;
786 if (method->signature->ret->type != MONO_TYPE_VOID)
787 ret_type = method->signature->ret;
790 MonoClass *ret_klass = mono_class_from_mono_type (ret_type);
791 mono_debug_get_type (debug, ret_klass);
794 for (j = 0; j < method->signature->param_count; j++) {
795 MonoType *sub_type = method->signature->params [j];
796 MonoClass *sub_klass = mono_class_from_mono_type (sub_type);
797 mono_debug_get_type (debug, sub_klass);
801 case MONO_TYPE_VALUETYPE:
802 for (i = 0; i < klass->field.count; i++) {
803 MonoClass *subclass = mono_class_from_mono_type (klass->fields [i].type);
804 mono_debug_get_type (debug, subclass);
807 case MONO_TYPE_ARRAY:
808 case MONO_TYPE_SZARRAY:
809 mono_debug_get_type (debug, klass->element_class);
819 il_offset_from_address (MonoDebugMethodInfo *minfo, guint32 address)
823 if (!minfo->jit || !minfo->jit->line_numbers)
826 for (i = minfo->jit->line_numbers->len - 1; i >= 0; i--) {
827 MonoDebugLineNumberEntry lne = g_array_index (
828 minfo->jit->line_numbers, MonoDebugLineNumberEntry, i);
830 if (lne.address <= address)
838 address_from_il_offset (MonoDebugMethodInfo *minfo, guint32 il_offset)
842 if (!minfo->jit || !minfo->jit->line_numbers)
845 for (i = minfo->jit->line_numbers->len - 1; i >= 0; i--) {
846 MonoDebugLineNumberEntry lne = g_array_index (
847 minfo->jit->line_numbers, MonoDebugLineNumberEntry, i);
849 if (lne.offset <= il_offset)
857 mono_debug_add_type (MonoClass *klass)
859 AssemblyDebugInfo* info;
861 if (!mono_debug_handle)
864 info = mono_debug_get_image (mono_debug_handle, klass->image);
867 if (mono_debug_handle->format != MONO_DEBUG_FORMAT_MONO)
871 mono_debug_symfile_add_type (info->symfile, klass);
875 il_offset_from_position (MonoFlowGraph *cfg, MonoPosition *pos)
880 if (pos->abs_pos == 0)
883 if (pos->pos.bid >= cfg->block_count)
886 bblock = &cfg->bblocks [pos->pos.bid];
887 if (pos->pos.tid >= bblock->forest->len)
890 tree = (MBTree *) g_ptr_array_index (bblock->forest, pos->pos.tid);
892 return tree->cli_addr;
895 struct LookupMethodData
897 MonoDebugMethodInfo *minfo;
902 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
904 AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
905 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
911 data->minfo = mono_debug_find_method (info->symfile, data->method);
913 data->minfo = g_hash_table_lookup (info->methods, data->method);
916 static MonoDebugMethodInfo *
917 lookup_method (MonoMethod *method)
919 struct LookupMethodData data = { NULL, method };
921 if (!mono_debug_handle)
924 g_hash_table_foreach (mono_debug_handle->images, lookup_method_func, &data);
929 mono_debug_add_method (MonoFlowGraph *cfg)
931 MonoMethod *method = cfg->method;
932 MonoClass *klass = method->klass;
933 AssemblyDebugInfo* info;
934 MonoDebugMethodJitInfo *jit;
935 MonoDebugMethodInfo *minfo;
938 if (!mono_debug_handle)
941 mono_class_init (klass);
943 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
944 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
945 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
946 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
949 if (method->wrapper_type != MONO_WRAPPER_NONE)
952 info = mono_debug_get_image (mono_debug_handle, klass->image);
955 minfo = lookup_method (method);
956 if (!minfo || minfo->jit)
959 mono_debug_handle->dirty = TRUE;
961 minfo->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
962 jit->code_start = cfg->start;
963 jit->code_size = cfg->epilogue_end;
964 jit->prologue_end = cfg->prologue_end;
965 jit->epilogue_begin = cfg->epilog;
966 jit->num_params = method->signature->param_count;
967 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
969 if (method->signature->hasthis) {
970 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index;
972 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
973 jit->this_var->offset = ptr->offset;
974 jit->this_var->size = ptr->size;
977 for (i = 0; i < jit->num_params; i++) {
978 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index +
979 method->signature->hasthis;
981 jit->params [i].offset = ptr [i].offset;
982 jit->params [i].size = ptr [i].size;
985 debug_generate_method_lines (info, minfo, cfg);
986 if (info->format == MONO_DEBUG_FORMAT_MONO)
987 debug_update_il_offsets (info, minfo, cfg);
989 if (!method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
990 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
991 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->locals_start_index;
992 MonoDebugVarInfo *locals;
994 locals = g_new0 (MonoDebugVarInfo, header->num_locals);
995 for (i = 0; i < header->num_locals; i++) {
996 gint32 begin_offset, end_offset;
997 gint32 begin_scope, end_scope;
999 if (ptr [i].reg >= 0) {
1000 locals [i].index = ptr [i].reg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
1001 locals [i].offset = 0;
1003 locals [i].offset = ptr [i].offset;
1005 locals [i].size = ptr [i].size;
1007 begin_offset = il_offset_from_position (cfg, &ptr [i].range.first_use);
1008 end_offset = il_offset_from_position (cfg, &ptr [i].range.last_use);
1009 if (end_offset >= 0)
1012 begin_scope = address_from_il_offset (minfo, begin_offset);
1013 end_scope = address_from_il_offset (minfo, end_offset);
1015 if (begin_scope > 0)
1016 locals [i].begin_scope = begin_scope;
1018 locals [i].begin_scope = jit->prologue_end;
1020 locals [i].end_scope = end_scope;
1022 locals [i].end_scope = jit->epilogue_begin;
1025 jit->num_locals = header->num_locals;
1026 jit->locals = locals;
1030 mono_debug_symfile_add_method (info->symfile, method);
1034 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number)
1036 MonoDebugMethodInfo *minfo = lookup_method (method);
1041 if (minfo->symfile) {
1042 gint32 offset = il_offset_from_address (minfo, address);
1047 return mono_debug_find_source_location (minfo->symfile, method, offset, line_number);
1054 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address)
1056 MonoDebugMethodInfo *minfo;
1061 minfo = lookup_method (method);
1062 if (!minfo || !minfo->il_offsets)
1065 return il_offset_from_address (minfo, address);
1069 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset)
1071 MonoDebugMethodInfo *minfo;
1076 minfo = lookup_method (method);
1077 if (!minfo || !minfo->il_offsets)
1080 return address_from_il_offset (minfo, il_offset);
1084 release_symbol_file_table ()
1086 MonoDebuggerSymbolFileTable *temp;
1088 if (!debugger_symbol_file_table)
1092 * Caution: The debugger may access the memory pointed to by this variable
1093 * at any time. It is very important to set the pointer to NULL
1094 * before freeing the area.
1097 temp = debugger_symbol_file_table;
1098 debugger_symbol_file_table = NULL;
1099 g_free (debugger_symbol_file_table);
1103 update_symbol_file_table_count_func (gpointer key, gpointer value, gpointer user_data)
1105 AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
1107 if (!info->symfile || (info->format != MONO_DEBUG_FORMAT_MONO))
1110 ++ (* (int *) user_data);
1113 struct SymfileTableData
1115 MonoDebuggerSymbolFileTable *symfile_table;
1120 update_symbol_file_table_func (gpointer key, gpointer value, gpointer user_data)
1122 AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
1123 struct SymfileTableData *data = (struct SymfileTableData *) user_data;
1125 if (!info->symfile || (info->format != MONO_DEBUG_FORMAT_MONO))
1128 data->symfile_table->symfiles [data->index++] = info->symfile;
1132 debugger_update_symbol_file_table (void)
1135 MonoDebuggerSymbolFileTable *symfile_table;
1136 struct SymfileTableData data;
1139 if (!mono_debug_handle)
1142 g_hash_table_foreach (mono_debug_handle->images, update_symbol_file_table_count_func, &count);
1144 release_symbol_file_table ();
1146 size = sizeof (MonoDebuggerSymbolFileTable) + count * sizeof (MonoSymbolFile *);
1147 symfile_table = g_malloc0 (size);
1148 symfile_table->magic = MONO_SYMBOL_FILE_DYNAMIC_MAGIC;
1149 symfile_table->version = MONO_SYMBOL_FILE_DYNAMIC_VERSION;
1150 symfile_table->total_size = size;
1151 symfile_table->count = count;
1152 symfile_table->generation = debugger_symbol_file_table_generation;
1154 data.symfile_table = symfile_table;
1157 g_hash_table_foreach (mono_debug_handle->images, update_symbol_file_table_func, &data);
1159 debugger_symbol_file_table = symfile_table;
1163 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
1165 static gboolean has_mono_debugger_support = FALSE;
1168 initialize_debugger_support ()
1170 if (has_mono_debugger_support)
1172 has_mono_debugger_support = TRUE;
1174 mono_debugger_class_init_func = mono_debug_add_type;
1177 static GPtrArray *breakpoints = NULL;
1180 mono_insert_breakpoint_full (MonoMethodDesc *desc, gboolean use_trampoline)
1182 static int last_breakpoint_id = 0;
1183 MonoDebuggerBreakpointInfo *info;
1185 info = g_new0 (MonoDebuggerBreakpointInfo, 1);
1187 info->use_trampoline = use_trampoline;
1188 info->index = ++last_breakpoint_id;
1191 breakpoints = g_ptr_array_new ();
1193 g_ptr_array_add (breakpoints, info);
1199 debugger_insert_breakpoint (guint64 method_argument, const gchar *string_argument)
1201 MonoMethodDesc *desc;
1203 desc = mono_method_desc_new (string_argument, FALSE);
1207 return mono_insert_breakpoint_full (desc, TRUE);
1211 debugger_remove_breakpoint (guint64 breakpoint)
1218 for (i = 0; i < breakpoints->len; i++) {
1219 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
1221 if (info->index != breakpoint)
1224 mono_method_desc_free (info->desc);
1225 g_ptr_array_remove (breakpoints, info);
1234 mono_remove_breakpoint (int breakpoint_id)
1236 return debugger_remove_breakpoint (breakpoint_id);
1240 mono_insert_breakpoint (const gchar *method_name, gboolean include_namespace)
1242 MonoMethodDesc *desc;
1244 desc = mono_method_desc_new (method_name, include_namespace);
1248 return mono_insert_breakpoint_full (desc, has_mono_debugger_support);
1252 mono_method_has_breakpoint (MonoMethod* method, gboolean use_trampoline)
1256 if (!breakpoints || (method->wrapper_type != MONO_WRAPPER_NONE))
1259 for (i = 0; i < breakpoints->len; i++) {
1260 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
1262 if (info->use_trampoline != use_trampoline)
1265 if (!mono_method_desc_full_match (info->desc, method))