8 #include <mono/metadata/class.h>
9 #include <mono/metadata/assembly.h>
10 #include <mono/metadata/tabledefs.h>
11 #include <mono/metadata/tokentype.h>
12 #include <mono/metadata/debug-helpers.h>
13 #include <mono/metadata/debug-mono-symfile.h>
14 #include <mono/jit/codegen.h>
15 #include <mono/jit/debug.h>
17 #include "debug-private.h"
21 * NOTE: Functions and variables starting with `mono_debug_' and `debug_' are
22 * part of the general debugging code.
24 * Functions and variables starting with `mono_debugger_' and `debugger_'
25 * are only used when the JIT is running inside the Mono Debugger.
27 * FIXME: This file needs some API loving.
30 /* This is incremented each time the symbol table is modified.
31 * The debugger looks at this variable and if it has a higher value than its current
32 * copy of the symbol table, it must call mono_debug_update_symbol_file_table().
34 guint32 mono_debugger_symbol_file_table_generation = 0;
35 guint32 mono_debugger_symbol_file_table_modified = 0;
37 /* Caution: This variable may be accessed at any time from the debugger;
38 * it is very important not to modify the memory it is pointing to
39 * without previously setting this pointer back to NULL.
41 MonoDebuggerSymbolFileTable *mono_debugger_symbol_file_table = NULL;
43 /* Caution: This function MUST be called before touching the symbol table! */
44 static void release_symbol_file_table (void);
46 static MonoDebugHandle *mono_debug_handle = NULL;
47 static gboolean mono_debug_initialized = FALSE;
49 static CRITICAL_SECTION debugger_lock_mutex;
51 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
53 static void mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data);
54 static void mono_debug_close_assembly (AssemblyDebugInfo* info);
55 static AssemblyDebugInfo *mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image);
57 static int running_in_the_mono_debugger = FALSE;
58 void (*mono_debugger_event_handler) (MonoDebuggerEvent event, gpointer data, gpointer data2) = NULL;
60 #ifndef PLATFORM_WIN32
62 MonoDebuggerIOLayer mono_debugger_io_layer = {
63 InitializeCriticalSection, DeleteCriticalSection, TryEnterCriticalSection,
64 EnterCriticalSection, LeaveCriticalSection, WaitForSingleObject, SignalObjectAndWait,
65 WaitForMultipleObjects, CreateSemaphore, ReleaseSemaphore, CreateThread
71 mono_debugger_event (MonoDebuggerEvent event, gpointer data, gpointer data2)
73 if (mono_debugger_event_handler)
74 (* mono_debugger_event_handler) (event, data, data2);
78 mono_debug_init (int in_the_debugger)
80 if (mono_debug_initialized)
83 InitializeCriticalSection (&debugger_lock_mutex);
84 mono_debug_initialized = TRUE;
85 running_in_the_mono_debugger = in_the_debugger;
89 mono_debug_create_notification_function (gpointer *notification_address)
93 ptr = buf = g_malloc0 (16);
95 if (notification_address)
96 *notification_address = buf;
103 mono_debug_lock (void)
105 if (mono_debug_initialized)
106 EnterCriticalSection (&debugger_lock_mutex);
110 mono_debug_unlock (void)
112 if (mono_debug_initialized)
113 LeaveCriticalSection (&debugger_lock_mutex);
117 free_method_info (MonoDebugMethodInfo *minfo)
119 DebugMethodInfo *priv = minfo->user_data;
127 g_array_free (minfo->jit->line_numbers, TRUE);
128 g_free (minfo->jit->this_var);
129 g_free (minfo->jit->params);
130 g_free (minfo->jit->locals);
134 g_free (minfo->il_offsets);
139 free_wrapper_info (DebugWrapperInfo *winfo)
145 debug_arg_warning (const char *message)
147 g_warning ("Error while processing --debug-args arguments: %s", message);
151 replace_suffix (const char *filename, const char *new_suffix)
153 const char *pos = strrchr (filename, '.');
156 return g_strdup_printf ("%s.%s", filename, new_suffix);
158 int len = pos - filename;
159 gchar *retval = g_malloc0 (len + strlen (new_suffix) + 2);
160 memcpy (retval, filename, len);
162 memcpy (retval + len + 1, new_suffix, strlen (new_suffix) + 1);
168 mono_debug_open (MonoAssembly *assembly, MonoDebugFormat format, const char **args)
170 MonoDebugHandle *debug;
173 g_assert (!mono_debug_handle);
175 debug = g_new0 (MonoDebugHandle, 1);
176 debug->name = g_strdup (assembly->image->name);
177 debug->format = format;
178 debug->source_files = g_ptr_array_new ();
179 debug->producer_name = g_strdup_printf ("Mono JIT compiler version %s", VERSION);
180 debug->next_idx = 100;
183 debug->type_hash = g_hash_table_new (NULL, NULL);
185 debug->images = g_hash_table_new_full (NULL, NULL, NULL,
186 (GDestroyNotify) mono_debug_close_assembly);
188 for (ptr = args; ptr && *ptr; ptr++) {
189 const char *arg = *ptr;
192 switch (debug->format) {
193 case MONO_DEBUG_FORMAT_STABS:
194 case MONO_DEBUG_FORMAT_DWARF2:
195 if (!strncmp (arg, "filename=", 9)) {
197 debug_arg_warning ("The `filename' argument can be given only once.");
198 debug->filename = g_strdup (arg + 9);
200 } else if (!strncmp (arg, "objfile=", 8)) {
202 debug_arg_warning ("The `objfile' argument can be given only once.");
203 debug->objfile = g_strdup (arg + 8);
207 case MONO_DEBUG_FORMAT_MONO:
208 debug->flags |= MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES |
209 MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
215 if (debug->format != MONO_DEBUG_FORMAT_MONO) {
216 if (!strcmp (arg, "dont_assemble")) {
217 debug->flags |= MONO_DEBUG_FLAGS_DONT_ASSEMBLE;
219 } else if (!strcmp (arg, "update_on_exit")) {
220 debug->flags |= MONO_DEBUG_FLAGS_UPDATE_ON_EXIT;
222 } else if (!strcmp (arg, "install_il_files")) {
223 debug->flags |= MONO_DEBUG_FLAGS_INSTALL_IL_FILES;
225 } else if (!strcmp (arg, "dont_update_il_files")) {
226 debug->flags |= MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES;
228 } else if (!strcmp (arg, "dont_create_il_files")) {
229 debug->flags |= MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
234 message = g_strdup_printf ("Unknown argument `%s'.", arg);
235 debug_arg_warning (message);
239 switch (debug->format) {
240 case MONO_DEBUG_FORMAT_STABS:
241 if (!debug->filename)
242 debug->filename = g_strdup_printf ("%s-stabs.s", g_basename (debug->name));
244 debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
246 case MONO_DEBUG_FORMAT_DWARF2:
247 if (!debug->filename)
248 debug->filename = g_strdup_printf ("%s-dwarf.s", g_basename (debug->name));
250 debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
252 case MONO_DEBUG_FORMAT_MONO:
253 mono_debugger_class_init_func = mono_debug_add_type;
256 g_assert_not_reached ();
260 release_symbol_file_table ();
262 mono_debug_handle = debug;
263 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
265 mono_debug_open_image (mono_debug_handle, assembly->image);
266 mono_debug_open_image (mono_debug_handle, mono_defaults.corlib);
268 mono_debug_add_type (mono_defaults.object_class);
269 mono_debug_add_type (mono_defaults.object_class);
270 mono_debug_add_type (mono_defaults.byte_class);
271 mono_debug_add_type (mono_defaults.void_class);
272 mono_debug_add_type (mono_defaults.boolean_class);
273 mono_debug_add_type (mono_defaults.sbyte_class);
274 mono_debug_add_type (mono_defaults.int16_class);
275 mono_debug_add_type (mono_defaults.uint16_class);
276 mono_debug_add_type (mono_defaults.int32_class);
277 mono_debug_add_type (mono_defaults.uint32_class);
278 mono_debug_add_type (mono_defaults.int_class);
279 mono_debug_add_type (mono_defaults.uint_class);
280 mono_debug_add_type (mono_defaults.int64_class);
281 mono_debug_add_type (mono_defaults.uint64_class);
282 mono_debug_add_type (mono_defaults.single_class);
283 mono_debug_add_type (mono_defaults.double_class);
284 mono_debug_add_type (mono_defaults.char_class);
285 mono_debug_add_type (mono_defaults.string_class);
286 mono_debug_add_type (mono_defaults.enum_class);
287 mono_debug_add_type (mono_defaults.array_class);
288 mono_debug_add_type (mono_defaults.multicastdelegate_class);
289 mono_debug_add_type (mono_defaults.asyncresult_class);
290 mono_debug_add_type (mono_defaults.waithandle_class);
291 mono_debug_add_type (mono_defaults.typehandle_class);
292 mono_debug_add_type (mono_defaults.fieldhandle_class);
293 mono_debug_add_type (mono_defaults.methodhandle_class);
294 mono_debug_add_type (mono_defaults.monotype_class);
295 mono_debug_add_type (mono_defaults.exception_class);
296 mono_debug_add_type (mono_defaults.threadabortexception_class);
297 mono_debug_add_type (mono_defaults.thread_class);
298 mono_debug_add_type (mono_defaults.transparent_proxy_class);
299 mono_debug_add_type (mono_defaults.real_proxy_class);
300 mono_debug_add_type (mono_defaults.mono_method_message_class);
301 mono_debug_add_type (mono_defaults.appdomain_class);
302 mono_debug_add_type (mono_defaults.field_info_class);
303 mono_debug_add_type (mono_defaults.stringbuilder_class);
304 mono_debug_add_type (mono_defaults.math_class);
305 mono_debug_add_type (mono_defaults.stack_frame_class);
306 mono_debug_add_type (mono_defaults.stack_trace_class);
307 mono_debug_add_type (mono_defaults.marshal_class);
308 mono_debug_add_type (mono_defaults.iserializeable_class);
309 mono_debug_add_type (mono_defaults.serializationinfo_class);
310 mono_debug_add_type (mono_defaults.streamingcontext_class);
312 mono_debug_update_symbol_file_table ();
314 mono_debug_unlock ();
320 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
322 if (!mono_debug_handle)
326 mono_debug_open_image (mono_debug_handle, assembly->image);
327 mono_debug_unlock ();
331 generate_il_offsets (AssemblyDebugInfo *info, MonoMethod *method)
333 GPtrArray *il_offsets = g_ptr_array_new ();
334 MonoClass *klass = method->klass;
335 MonoDebugMethodInfo *minfo;
336 DebugMethodInfo *priv;
339 g_assert (klass->image == info->image);
341 /* FIXME: doesn't work yet. */
342 if (!strcmp (klass->name_space, "System.Runtime.Remoting.Proxies"))
345 mono_class_init (klass);
347 minfo = g_new0 (MonoDebugMethodInfo, 1);
348 minfo->method = method;
349 minfo->user_data = priv = g_new0 (DebugMethodInfo, 1);
351 priv->name = g_strdup_printf ("%s%s%s.%s", klass->name_space, klass->name_space [0]? ".": "",
352 klass->name, method->name);
353 priv->source_file = info->source_file;
357 * Find the method index in the image.
359 for (i = 0; klass->methods && i < klass->method.count; ++i) {
360 if (klass->methods [i] == minfo->method) {
361 priv->method_number = klass->method.first + i + 1;
362 priv->first_line = info->mlines [priv->method_number];
367 g_assert (priv->method_number);
369 /* info->moffsets contains -1 "outside" of functions. */
370 for (i = priv->first_line; (i > 0) && (info->moffsets [i] == 0); i--)
372 priv->start_line = i + 1;
374 for (i = priv->start_line; info->moffsets [i] != -1; i++) {
375 MonoSymbolFileLineNumberEntry *lne = g_new0 (MonoSymbolFileLineNumberEntry, 1);
377 if (!info->moffsets [i] && (i > priv->start_line))
380 lne->offset = info->moffsets [i];
383 g_ptr_array_add (il_offsets, lne);
388 minfo->start_line = priv->first_line;
389 minfo->end_line = priv->last_line;
391 minfo->num_il_offsets = il_offsets->len;
392 minfo->il_offsets = g_new0 (MonoSymbolFileLineNumberEntry, il_offsets->len);
393 for (i = 0; i < il_offsets->len; i++) {
394 MonoSymbolFileLineNumberEntry *il = g_ptr_array_index (il_offsets, i);
396 minfo->il_offsets [i] = *il;
399 g_ptr_array_free (il_offsets, TRUE);
401 g_hash_table_insert (info->methods, method, minfo);
405 debug_load_method_lines (AssemblyDebugInfo* info)
407 MonoTableInfo *table = &info->image->tables [MONO_TABLE_METHOD];
413 if (info->always_create_il || !(info->handle->flags & MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES)) {
414 char *command = g_strdup_printf ("monodis --output=%s %s",
415 info->ilfile, info->image->name);
416 struct stat stata, statb;
417 int need_update = FALSE;
419 if (stat (info->image->name, &stata)) {
420 g_warning ("cannot access assembly file (%s): %s",
421 info->image->name, g_strerror (errno));
426 /* If the stat() failed or the file is older. */
427 if (stat (info->ilfile, &statb)) {
429 } else if (statb.st_mtime < stata.st_mtime)
433 #ifndef PLATFORM_WIN32
434 struct sigaction act, oldact;
439 #ifndef PLATFORM_WIN32
440 act.sa_handler = SIG_IGN;
441 act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
442 sigemptyset (&act.sa_mask);
443 sigaddset (&act.sa_mask, SIGCHLD);
444 sigprocmask (SIG_BLOCK, &act.sa_mask, &old_set);
445 sigaction (SIGCHLD, &act, &oldact);
448 g_print ("Recreating %s from %s.\n", info->ilfile, info->image->name);
450 ret = system (command);
452 #ifndef PLATFORM_WIN32
453 sigaction (SIGCHLD, &oldact, NULL);
454 sigprocmask (SIG_SETMASK, &old_set, NULL);
458 g_warning ("cannot create IL assembly file (%s): %s",
459 command, g_strerror (errno));
466 /* use an env var with directories for searching. */
467 if (!(f = fopen (info->ilfile, "r"))) {
468 g_warning ("cannot open IL assembly file %s", info->ilfile);
472 info->total_lines = 100;
473 info->moffsets = g_malloc (info->total_lines * sizeof (int));
476 while (fgets (buf, sizeof (buf), f)) {
479 info->moffsets [i++] = offset;
480 if (i + 2 >= info->total_lines) {
481 info->total_lines += 100;
482 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
483 g_assert (info->moffsets);
486 if (!sscanf (buf, " // method line %d", &mnum))
491 if (mnum >= info->nmethods)
494 while (fgets (buf, sizeof (buf), f)) {
498 if (i + 2 >= info->total_lines) {
499 info->total_lines += 100;
500 info->moffsets = g_realloc (info->moffsets, info->total_lines * sizeof (int));
501 g_assert (info->moffsets);
504 if (strstr (buf, "}")) {
509 if (sscanf (buf, " IL_%x:", &newoffset)) {
515 info->moffsets [i] = offset;
517 /* g_print ("method %d found at %d\n", mnum, pos); */
518 info->mlines [mnum] = pos;
522 for (idx = 1; idx <= table->rows; idx++) {
523 guint32 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
524 MonoMethod *method = mono_get_method (info->image, token, NULL);
526 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
527 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
528 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
531 if (method->wrapper_type != MONO_WRAPPER_NONE)
534 generate_il_offsets (info, method);
539 record_line_number (MonoDebugMethodInfo *minfo, guint32 address, guint32 offset, guint32 line)
541 MonoDebugLineNumberEntry *lne = g_new0 (MonoDebugLineNumberEntry, 1);
543 lne->address = address;
544 lne->offset = offset;
547 g_array_append_val (minfo->jit->line_numbers, *lne);
551 debug_generate_method_lines (AssemblyDebugInfo *info, MonoDebugMethodInfo *minfo, MonoFlowGraph* cfg)
553 guint32 st_address, st_line;
554 DebugMethodInfo *priv = minfo->user_data;
557 if (!priv || !info->moffsets)
560 minfo->jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
562 st_line = priv->first_line;
563 st_address = minfo->jit->prologue_end;
565 /* This is the first actual code line of the method. */
566 record_line_number (minfo, st_address, 0, st_line);
568 /* start lines of basic blocks */
569 for (i = 0; i < cfg->block_count; ++i) {
572 for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
573 MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
574 gint32 line_inc = 0, addr_inc;
577 st_line = priv->first_line;
578 st_address = t->addr;
581 addr_inc = t->addr - st_address;
582 st_address += addr_inc;
584 if (t->cli_addr != -1) {
585 int *lines = info->moffsets + st_line;
588 while ((*k != -1) && (*k < t->cli_addr))
591 line_inc = k - lines;
596 if (t->cli_addr != -1)
597 record_line_number (minfo, st_address, t->cli_addr, st_line);
603 generate_line_number (MonoDebugMethodInfo *minfo, guint32 address, guint32 offset, int debug)
608 g_message (G_STRLOC ": searching IL offset %x", offset);
610 for (i = minfo->num_il_offsets - 1; i >= 0; i--) {
611 MonoDebugLineNumberEntry *lne;
613 if (minfo->il_offsets [i].offset > offset)
617 g_message (G_STRLOC ": found entry %d: offset = %x, row = %d",
618 i, minfo->il_offsets [i].offset, minfo->il_offsets [i].row);
620 if (minfo->jit->line_numbers->len) {
621 MonoDebugLineNumberEntry last = g_array_index (
622 minfo->jit->line_numbers, MonoDebugLineNumberEntry,
623 minfo->jit->line_numbers->len - 1);
625 /* Avoid writing more than one entry for the same line. */
626 if (minfo->il_offsets [i].row == last.line) {
628 g_message (G_STRLOC ": skipping line: line = %d, last line = %d, "
629 "last address = %x, address = %x, "
630 "last offset = %x, offset = %x",
631 last.line, minfo->il_offsets [i].row,
632 last.address, address, last.offset, offset);
639 g_message (G_STRLOC ": writing entry: line = %d, offfset = %x, address = %x",
640 minfo->il_offsets [i].row, offset, address);
642 lne = g_new0 (MonoDebugLineNumberEntry, 1);
643 lne->address = address;
644 lne->offset = offset;
645 lne->line = minfo->il_offsets [i].row;
647 g_array_append_val (minfo->jit->line_numbers, *lne);
653 debug_update_il_offsets (AssemblyDebugInfo *info, MonoDebugMethodInfo *minfo, MonoFlowGraph* cfg)
655 MonoMethodHeader *header;
656 guint32 address, offset;
660 g_assert (info->symfile);
661 g_assert (!minfo->jit->line_numbers);
662 minfo->jit->line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry));
664 address = minfo->jit->prologue_end;
667 g_assert (((MonoMethodNormal*)minfo->method)->header);
668 header = ((MonoMethodNormal*)minfo->method)->header;
671 if (!strcmp (minfo->method->name, "Test") || !strcmp (minfo->method->name, "Main")) {
672 MonoMethodHeader *header = ((MonoMethodNormal*)minfo->method)->header;
675 mono_disassemble_code (minfo->jit->code_start, minfo->jit->code_size,
676 minfo->method->name);
678 printf ("\nDisassembly:\n%s\n", mono_disasm_code (
679 NULL, minfo->method, header->code, header->code + header->code_size));
680 g_message (G_STRLOC ": %x - %x", minfo->jit->prologue_end, minfo->jit->epilogue_begin);
684 generate_line_number (minfo, address, offset, debug);
686 /* start lines of basic blocks */
687 for (i = 0; i < cfg->block_count; ++i) {
690 for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
691 MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
693 if ((t->cli_addr == -1) || (t->cli_addr == offset) || (t->addr == address))
696 offset = t->cli_addr;
699 generate_line_number (minfo, address, offset, debug);
703 generate_line_number (minfo, minfo->jit->epilogue_begin, header->code_size, debug);
706 for (i = 0; i < minfo->jit->line_numbers->len; i++) {
707 MonoDebugLineNumberEntry lne = g_array_index (
708 minfo->jit->line_numbers, MonoDebugLineNumberEntry, i);
710 g_message (G_STRLOC ": %x,%x,%d", lne.address, lne.offset, lne.line);
714 if (minfo->jit->line_numbers->len) {
715 MonoDebugLineNumberEntry lne = g_array_index (
716 minfo->jit->line_numbers, MonoDebugLineNumberEntry, 0);
718 minfo->jit->prologue_end = lne.address;
722 static AssemblyDebugInfo *
723 mono_debug_get_image (MonoDebugHandle* debug, MonoImage *image)
725 return g_hash_table_lookup (debug->images, image);
728 static AssemblyDebugInfo *
729 mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image)
731 AssemblyDebugInfo *info;
734 info = mono_debug_get_image (debug, image);
740 info = g_new0 (AssemblyDebugInfo, 1);
742 info->image->ref_count++;
743 info->name = g_strdup (image->assembly_name);
744 info->format = debug->format;
745 info->handle = debug;
746 info->methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
747 NULL, (GDestroyNotify) free_method_info);
748 info->wrapper_methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
749 NULL, (GDestroyNotify) free_wrapper_info);
751 g_hash_table_insert (debug->images, image, info);
753 info->nmethods = image->tables [MONO_TABLE_METHOD].rows + 1;
754 info->mlines = g_new0 (int, info->nmethods);
756 for (ptr = image->references; ptr && *ptr; ptr++)
757 mono_debug_add_assembly (*ptr, NULL);
759 if (image->assembly->dynamic)
762 switch (info->format) {
763 case MONO_DEBUG_FORMAT_STABS:
764 case MONO_DEBUG_FORMAT_DWARF2:
765 if (debug->flags & MONO_DEBUG_FLAGS_INSTALL_IL_FILES) {
766 gchar *dirname = g_path_get_dirname (image->name);
767 info->ilfile = g_strdup_printf ("%s/%s.il", dirname, info->name);
770 info->ilfile = g_strdup_printf ("%s.il", info->name);
771 info->source_file = debug->source_files->len;
772 g_ptr_array_add (debug->source_files, info->ilfile);
774 case MONO_DEBUG_FORMAT_MONO:
775 info->symfile = mono_debug_open_mono_symbol_file (info->image, running_in_the_mono_debugger);
776 mono_debugger_symbol_file_table_generation++;
783 if (debug->format != MONO_DEBUG_FORMAT_MONO)
784 debug_load_method_lines (info);
790 mono_debug_write_symbols (MonoDebugHandle *debug)
792 if (!debug || !debug->dirty)
795 release_symbol_file_table ();
797 switch (debug->format) {
798 case MONO_DEBUG_FORMAT_STABS:
799 mono_debug_write_stabs (debug);
801 case MONO_DEBUG_FORMAT_DWARF2:
802 mono_debug_write_dwarf2 (debug);
804 case MONO_DEBUG_FORMAT_MONO:
807 g_assert_not_reached ();
810 debug->dirty = FALSE;
814 mono_debug_make_symbols (void)
816 if (!mono_debug_handle || !mono_debug_handle->dirty)
819 switch (mono_debug_handle->format) {
820 case MONO_DEBUG_FORMAT_STABS:
821 mono_debug_write_stabs (mono_debug_handle);
823 case MONO_DEBUG_FORMAT_DWARF2:
824 mono_debug_write_dwarf2 (mono_debug_handle);
826 case MONO_DEBUG_FORMAT_MONO:
827 mono_debug_update_symbol_file_table ();
830 g_assert_not_reached ();
833 mono_debug_handle->dirty = FALSE;
837 mono_debug_close_assembly (AssemblyDebugInfo* info)
839 switch (info->format) {
840 case MONO_DEBUG_FORMAT_MONO:
841 if (info->symfile != NULL)
842 mono_debug_close_mono_symbol_file (info->symfile);
847 g_hash_table_destroy (info->methods);
848 g_hash_table_destroy (info->wrapper_methods);
849 g_free (info->mlines);
850 g_free (info->moffsets);
852 g_free (info->ilfile);
853 g_free (info->filename);
854 g_free (info->objfile);
859 mono_debug_cleanup (void)
861 release_symbol_file_table ();
863 if (!mono_debug_handle)
866 if (mono_debug_handle->flags & MONO_DEBUG_FLAGS_UPDATE_ON_EXIT)
867 mono_debug_write_symbols (mono_debug_handle);
869 g_hash_table_destroy (mono_debug_handle->images);
870 g_ptr_array_free (mono_debug_handle->source_files, FALSE);
871 g_hash_table_destroy (mono_debug_handle->type_hash);
872 g_free (mono_debug_handle->producer_name);
873 g_free (mono_debug_handle->name);
874 g_free (mono_debug_handle);
876 mono_debug_handle = NULL;
880 mono_debug_get_type (MonoDebugHandle *debug, MonoClass *klass)
884 mono_class_init (klass);
886 index = GPOINTER_TO_INT (g_hash_table_lookup (debug->type_hash, klass));
892 index = ++debug->next_klass_idx;
893 g_hash_table_insert (debug->type_hash, klass, GINT_TO_POINTER (index));
898 switch (klass->byval_arg.type) {
899 case MONO_TYPE_CLASS:
901 mono_debug_get_type (debug, klass->parent);
903 for (i = 0; i < klass->method.count; i++) {
904 MonoMethod *method = klass->methods [i];
905 MonoType *ret_type = NULL;
908 if (method->signature->ret->type != MONO_TYPE_VOID)
909 ret_type = method->signature->ret;
912 MonoClass *ret_klass = mono_class_from_mono_type (ret_type);
913 mono_debug_get_type (debug, ret_klass);
916 for (j = 0; j < method->signature->param_count; j++) {
917 MonoType *sub_type = method->signature->params [j];
918 MonoClass *sub_klass = mono_class_from_mono_type (sub_type);
919 mono_debug_get_type (debug, sub_klass);
923 case MONO_TYPE_VALUETYPE:
924 for (i = 0; i < klass->field.count; i++) {
925 MonoClass *subclass = mono_class_from_mono_type (klass->fields [i].type);
926 mono_debug_get_type (debug, subclass);
929 case MONO_TYPE_ARRAY:
930 case MONO_TYPE_SZARRAY:
931 mono_debug_get_type (debug, klass->element_class);
941 il_offset_from_address (MonoDebugMethodInfo *minfo, guint32 address)
945 if (!minfo->jit || !minfo->jit->line_numbers)
948 for (i = minfo->jit->line_numbers->len - 1; i >= 0; i--) {
949 MonoDebugLineNumberEntry lne = g_array_index (
950 minfo->jit->line_numbers, MonoDebugLineNumberEntry, i);
952 if (lne.address <= address)
960 address_from_il_offset (MonoDebugMethodInfo *minfo, guint32 il_offset)
964 if (!minfo->jit || !minfo->jit->line_numbers)
967 for (i = minfo->jit->line_numbers->len - 1; i >= 0; i--) {
968 MonoDebugLineNumberEntry lne = g_array_index (
969 minfo->jit->line_numbers, MonoDebugLineNumberEntry, i);
971 if (lne.offset <= il_offset)
979 mono_debug_add_type (MonoClass *klass)
981 AssemblyDebugInfo* info;
983 if (!mono_debug_handle)
986 info = mono_debug_get_image (mono_debug_handle, klass->image);
989 if (mono_debug_handle->format != MONO_DEBUG_FORMAT_MONO)
994 mono_debug_symfile_add_type (info->symfile, klass);
995 mono_debugger_event (MONO_DEBUGGER_EVENT_TYPE_ADDED, info->symfile, klass);
996 mono_debug_unlock ();
1001 il_offset_from_position (MonoFlowGraph *cfg, MonoPosition *pos)
1006 if (pos->abs_pos == 0)
1009 if (pos->pos.bid >= cfg->block_count)
1012 bblock = &cfg->bblocks [pos->pos.bid];
1013 if (pos->pos.tid >= bblock->forest->len)
1016 tree = (MBTree *) g_ptr_array_index (bblock->forest, pos->pos.tid);
1018 return tree->cli_addr;
1021 struct LookupMethodData
1023 MonoDebugMethodInfo *minfo;
1028 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
1030 AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
1031 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
1037 data->minfo = mono_debug_find_method (info->symfile, data->method);
1039 data->minfo = g_hash_table_lookup (info->methods, data->method);
1042 static MonoDebugMethodInfo *
1043 lookup_method (MonoMethod *method)
1045 struct LookupMethodData data = { NULL, method };
1047 if (!mono_debug_handle)
1050 g_hash_table_foreach (mono_debug_handle->images, lookup_method_func, &data);
1055 mono_debug_add_method (MonoFlowGraph *cfg)
1057 MonoMethod *method = cfg->method;
1058 MonoClass *klass = method->klass;
1059 AssemblyDebugInfo* info;
1060 MonoDebugMethodJitInfo *jit;
1061 MonoDebugMethodInfo *minfo;
1064 if (!mono_debug_handle)
1067 mono_class_init (klass);
1069 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1070 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1071 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1072 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
1075 info = mono_debug_get_image (mono_debug_handle, klass->image);
1078 if (method->wrapper_type != MONO_WRAPPER_NONE) {
1079 DebugWrapperInfo *winfo = g_new0 (DebugWrapperInfo, 1);
1081 winfo->method = method;
1082 winfo->code_start = cfg->start;
1083 winfo->code_size = cfg->epilogue_end;
1085 g_hash_table_insert (info->wrapper_methods, method, winfo);
1089 minfo = lookup_method (method);
1090 if (!minfo || minfo->jit)
1095 mono_debug_handle->dirty = TRUE;
1097 minfo->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
1098 jit->code_start = cfg->start;
1099 jit->code_size = cfg->epilogue_end;
1100 jit->prologue_end = cfg->prologue_end;
1101 jit->epilogue_begin = cfg->epilog;
1102 jit->num_params = method->signature->param_count;
1103 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
1105 if (method->signature->hasthis) {
1106 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index;
1108 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
1109 jit->this_var->offset = ptr->offset;
1110 jit->this_var->size = ptr->size;
1113 for (i = 0; i < jit->num_params; i++) {
1114 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index +
1115 method->signature->hasthis;
1117 jit->params [i].offset = ptr [i].offset;
1118 jit->params [i].size = ptr [i].size;
1121 debug_generate_method_lines (info, minfo, cfg);
1122 if (info->format == MONO_DEBUG_FORMAT_MONO)
1123 debug_update_il_offsets (info, minfo, cfg);
1125 if (!method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
1126 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
1127 MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->locals_start_index;
1128 MonoDebugVarInfo *locals;
1130 locals = g_new0 (MonoDebugVarInfo, header->num_locals);
1131 for (i = 0; i < header->num_locals; i++) {
1132 gint32 begin_offset, end_offset;
1133 gint32 begin_scope, end_scope;
1135 if (ptr [i].reg >= 0) {
1136 locals [i].index = ptr [i].reg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
1137 locals [i].offset = 0;
1139 locals [i].offset = ptr [i].offset;
1141 locals [i].size = ptr [i].size;
1143 begin_offset = il_offset_from_position (cfg, &ptr [i].range.first_use);
1144 end_offset = il_offset_from_position (cfg, &ptr [i].range.last_use);
1145 if (end_offset >= 0)
1148 if (begin_offset >= 0)
1149 begin_scope = address_from_il_offset (minfo, begin_offset);
1152 if (end_offset >= 0)
1153 end_scope = address_from_il_offset (minfo, end_offset);
1157 if (begin_scope > 0)
1158 locals [i].begin_scope = begin_scope;
1160 locals [i].begin_scope = jit->prologue_end;
1162 locals [i].end_scope = end_scope;
1164 locals [i].end_scope = jit->epilogue_begin;
1167 jit->num_locals = header->num_locals;
1168 jit->locals = locals;
1171 if (info->symfile) {
1172 mono_debug_symfile_add_method (info->symfile, method);
1173 mono_debugger_event (MONO_DEBUGGER_EVENT_METHOD_ADDED, info->symfile, method);
1176 mono_debug_unlock ();
1180 mono_debug_add_wrapper (MonoMethod *method, MonoMethod *wrapper_method)
1182 MonoClass *klass = method->klass;
1183 AssemblyDebugInfo* info;
1184 MonoDebugMethodInfo *minfo;
1185 DebugWrapperInfo *winfo;
1186 MonoDebugMethodJitInfo *jit;
1188 if (!mono_debug_handle)
1191 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
1194 mono_class_init (klass);
1196 info = mono_debug_get_image (mono_debug_handle, klass->image);
1199 minfo = lookup_method (method);
1200 if (!minfo || minfo->jit)
1203 winfo = g_hash_table_lookup (info->wrapper_methods, wrapper_method);
1208 mono_debug_handle->dirty = TRUE;
1210 minfo->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
1211 jit->code_start = winfo->code_start;
1212 jit->code_size = winfo->code_size;
1213 jit->prologue_end = 0;
1214 jit->epilogue_begin = winfo->code_size;
1215 jit->num_params = 0;
1216 jit->wrapper_addr = method->addr;
1218 if (info->symfile) {
1219 mono_debug_symfile_add_method (info->symfile, method);
1220 mono_debugger_event (MONO_DEBUGGER_EVENT_METHOD_ADDED, info->symfile, method);
1223 mono_debug_unlock ();
1227 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number)
1229 MonoDebugMethodInfo *minfo = lookup_method (method);
1234 if (minfo->symfile) {
1235 gint32 offset = il_offset_from_address (minfo, address);
1240 return mono_debug_find_source_location (minfo->symfile, method, offset, line_number);
1247 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address)
1249 MonoDebugMethodInfo *minfo;
1254 minfo = lookup_method (method);
1255 if (!minfo || !minfo->il_offsets)
1258 return il_offset_from_address (minfo, address);
1262 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset)
1264 MonoDebugMethodInfo *minfo;
1269 minfo = lookup_method (method);
1270 if (!minfo || !minfo->il_offsets)
1273 return address_from_il_offset (minfo, il_offset);
1277 release_symbol_file_table ()
1279 MonoDebuggerSymbolFileTable *temp;
1281 if (!mono_debugger_symbol_file_table)
1285 * Caution: The debugger may access the memory pointed to by this variable
1286 * at any time. It is very important to set the pointer to NULL
1287 * before freeing the area.
1290 temp = mono_debugger_symbol_file_table;
1291 mono_debugger_symbol_file_table = NULL;
1292 g_free (mono_debugger_symbol_file_table);
1296 update_symbol_file_table_count_func (gpointer key, gpointer value, gpointer user_data)
1298 AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
1302 if (info->format != MONO_DEBUG_FORMAT_MONO)
1305 ++ (* (int *) user_data);
1308 struct SymfileTableData
1310 MonoDebuggerSymbolFileTable *symfile_table;
1315 update_symbol_file_table_func (gpointer key, gpointer value, gpointer user_data)
1317 AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
1318 struct SymfileTableData *data = (struct SymfileTableData *) user_data;
1322 if (info->format != MONO_DEBUG_FORMAT_MONO)
1325 data->symfile_table->symfiles [data->index++] = info->symfile;
1329 mono_debug_update_symbol_file_table (void)
1332 MonoDebuggerSymbolFileTable *symfile_table;
1333 struct SymfileTableData data;
1336 if (!mono_debug_handle)
1341 g_hash_table_foreach (mono_debug_handle->images, update_symbol_file_table_count_func, &count);
1343 release_symbol_file_table ();
1345 size = sizeof (MonoDebuggerSymbolFileTable) + count * sizeof (MonoSymbolFile *);
1346 symfile_table = g_malloc0 (size);
1347 symfile_table->magic = MONO_SYMBOL_FILE_DYNAMIC_MAGIC;
1348 symfile_table->version = MONO_SYMBOL_FILE_DYNAMIC_VERSION;
1349 symfile_table->total_size = size;
1350 symfile_table->count = count;
1351 symfile_table->generation = mono_debugger_symbol_file_table_generation;
1352 symfile_table->global_symfile = mono_debugger_global_symbol_file;
1354 data.symfile_table = symfile_table;
1357 g_hash_table_foreach (mono_debug_handle->images, update_symbol_file_table_func, &data);
1359 mono_debugger_symbol_file_table = symfile_table;
1361 mono_debug_unlock ();
1366 static GPtrArray *breakpoints = NULL;
1369 mono_insert_breakpoint_full (MonoMethodDesc *desc, gboolean use_trampoline)
1371 static int last_breakpoint_id = 0;
1372 MonoDebuggerBreakpointInfo *info;
1374 info = g_new0 (MonoDebuggerBreakpointInfo, 1);
1376 info->use_trampoline = use_trampoline;
1377 info->index = ++last_breakpoint_id;
1380 breakpoints = g_ptr_array_new ();
1382 g_ptr_array_add (breakpoints, info);
1388 mono_remove_breakpoint (int breakpoint_id)
1395 for (i = 0; i < breakpoints->len; i++) {
1396 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
1398 if (info->index != breakpoint_id)
1401 mono_method_desc_free (info->desc);
1402 g_ptr_array_remove (breakpoints, info);
1411 mono_insert_breakpoint (const gchar *method_name, gboolean include_namespace)
1413 MonoMethodDesc *desc;
1415 desc = mono_method_desc_new (method_name, include_namespace);
1419 return mono_insert_breakpoint_full (desc, running_in_the_mono_debugger);
1423 mono_method_has_breakpoint (MonoMethod* method, gboolean use_trampoline)
1427 if (!breakpoints || (method->wrapper_type != MONO_WRAPPER_NONE))
1430 for (i = 0; i < breakpoints->len; i++) {
1431 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
1433 if (info->use_trampoline != use_trampoline)
1436 if (!mono_method_desc_full_match (info->desc, method))
1446 mono_debugger_trampoline_breakpoint_callback (void)
1448 mono_debugger_event (MONO_DEBUGGER_EVENT_BREAKPOINT_TRAMPOLINE, NULL, NULL);