+#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <signal.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <mono/metadata/class.h>
+#include <mono/metadata/assembly.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/tokentype.h>
+#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/debug-mono-symfile.h>
-#include <mono/jit/codegen.h>
-#include <mono/jit/debug.h>
#include "debug-private.h"
-static MonoDebugHandle *mono_debug_handles = NULL;
-static MonoDebugHandle *mono_default_debug_handle = NULL;
+/*
+ * NOTE: Functions and variables starting with `mono_debug_' and `debug_' are
+ * part of the general debugging code.
+ *
+ * Functions and variables starting with `mono_debugger_' and `debugger_'
+ * are only used when the JIT is running inside the Mono Debugger.
+ *
+ * FIXME: This file needs some API loving.
+ */
+
+/* This is incremented each time the symbol table is modified.
+ * The debugger looks at this variable and if it has a higher value than its current
+ * copy of the symbol table, it must call mono_debug_update_symbol_file_table().
+ */
+guint32 mono_debugger_symbol_file_table_generation = 0;
+guint32 mono_debugger_symbol_file_table_modified = 0;
+
+/* Caution: This variable may be accessed at any time from the debugger;
+ * it is very important not to modify the memory it is pointing to
+ * without previously setting this pointer back to NULL.
+ */
+MonoDebuggerSymbolFileTable *mono_debugger_symbol_file_table = NULL;
+
+/* Caution: This function MUST be called before touching the symbol table! */
+static void release_symbol_file_table (void);
+
+MonoDebugHandle *mono_debug_handle = NULL;
+gboolean mono_debug_initialized = FALSE;
+
+static CRITICAL_SECTION debugger_lock_mutex;
+
+extern void (*mono_debugger_class_init_func) (MonoClass *klass);
+
+static void mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data);
+static void mono_debug_close_assembly (AssemblyDebugInfo* info);
+static AssemblyDebugInfo *mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image);
+
+static int running_in_the_mono_debugger = FALSE;
+void (*mono_debugger_event_handler) (MonoDebuggerEvent event, gpointer data, gpointer data2) = NULL;
+
+#ifndef PLATFORM_WIN32
+
+MonoDebuggerIOLayer mono_debugger_io_layer = {
+ InitializeCriticalSection, DeleteCriticalSection, TryEnterCriticalSection,
+ EnterCriticalSection, LeaveCriticalSection, WaitForSingleObject, SignalObjectAndWait,
+ WaitForMultipleObjects, CreateSemaphore, ReleaseSemaphore, CreateThread
+};
+
+#endif
+
+void
+mono_debugger_event (MonoDebuggerEvent event, gpointer data, gpointer data2)
+{
+ if (mono_debugger_event_handler)
+ (* mono_debugger_event_handler) (event, data, data2);
+}
+
+void
+mono_debug_init (int in_the_debugger)
+{
+ if (mono_debug_initialized)
+ return;
+
+ InitializeCriticalSection (&debugger_lock_mutex);
+ mono_debug_initialized = TRUE;
+ running_in_the_mono_debugger = in_the_debugger;
+}
+
+gpointer
+mono_debug_create_notification_function (gpointer *notification_address)
+{
+ guint8 *ptr, *buf;
+
+ ptr = buf = g_malloc0 (16);
+ mono_debug_codegen_breakpoint (&buf);
+ if (notification_address)
+ *notification_address = buf;
+ mono_debug_codegen_ret (&buf);
+
+ return ptr;
+}
+
+void
+mono_debug_lock (void)
+{
+ if (mono_debug_initialized)
+ EnterCriticalSection (&debugger_lock_mutex);
+}
+
+void
+mono_debug_unlock (void)
+{
+ if (mono_debug_initialized)
+ LeaveCriticalSection (&debugger_lock_mutex);
+}
static void
-free_method_info (DebugMethodInfo *minfo)
+free_method_info (MonoDebugMethodInfo *minfo)
{
- if (minfo->line_numbers)
- g_ptr_array_free (minfo->line_numbers, TRUE);
- g_free (minfo->method_info.params);
- g_free (minfo->method_info.locals);
+ DebugMethodInfo *priv = minfo->user_data;
+
+ if (priv) {
+ g_free (priv->name);
+ g_free (priv);
+ }
+
+ if (minfo->jit) {
+ g_array_free (minfo->jit->line_numbers, TRUE);
+ g_free (minfo->jit->this_var);
+ g_free (minfo->jit->params);
+ g_free (minfo->jit->locals);
+ g_free (minfo->jit);
+ }
+
+ g_free (minfo->il_offsets);
g_free (minfo);
}
+static void
+free_wrapper_info (DebugWrapperInfo *winfo)
+{
+ g_free (winfo);
+}
+
static void
debug_arg_warning (const char *message)
{
{
MonoDebugHandle *debug;
const char **ptr;
-
+
+ g_assert (!mono_debug_handle);
+
debug = g_new0 (MonoDebugHandle, 1);
debug->name = g_strdup (assembly->image->name);
debug->format = format;
+ debug->source_files = g_ptr_array_new ();
debug->producer_name = g_strdup_printf ("Mono JIT compiler version %s", VERSION);
debug->next_idx = 100;
debug->dirty = TRUE;
debug->type_hash = g_hash_table_new (NULL, NULL);
- debug->source_files = g_ptr_array_new ();
+
+ debug->images = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) mono_debug_close_assembly);
for (ptr = args; ptr && *ptr; ptr++) {
const char *arg = *ptr;
continue;
}
break;
- case MONO_DEBUG_FORMAT_DWARF2_PLUS:
- if (!strcmp (arg, "dont_fallback")) {
- debug->flags |= MONO_DEBUG_FLAGS_DONT_FALLBACK;
- continue;
- } else if (!strcmp (arg, "dont_precompile")) {
- debug->flags |= MONO_DEBUG_FLAGS_DONT_PRECOMPILE;
- continue;
- }
- debug->flags |= MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES |
- MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
- break;
case MONO_DEBUG_FORMAT_MONO:
debug->flags |= MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES |
MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
debug->flags |= MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES;
continue;
}
- } else {
- if (!strcmp (arg, "internal_mono_debugger")) {
- debug->flags |= MONO_DEBUG_FLAGS_MONO_DEBUGGER;
- continue;
- }
}
message = g_strdup_printf ("Unknown argument `%s'.", arg);
if (!debug->objfile)
debug->objfile = g_strdup_printf ("%s.o", g_basename (debug->name));
break;
- case MONO_DEBUG_FORMAT_DWARF2_PLUS:
- if (!mono_default_debug_handle && !(debug->flags & MONO_DEBUG_FLAGS_DONT_FALLBACK))
- mono_debug_open (assembly, MONO_DEBUG_FORMAT_DWARF2, NULL);
- break;
case MONO_DEBUG_FORMAT_MONO:
- if (!debug->filename)
- debug->filename = g_strdup_printf ("%s.dbg", g_basename (debug->name));
+ mono_debugger_class_init_func = mono_debug_add_type;
break;
default:
g_assert_not_reached ();
}
- debug->next = mono_debug_handles;
- mono_debug_handles = debug;
-
- if (!mono_default_debug_handle && (debug->format != MONO_DEBUG_FORMAT_DWARF2_PLUS))
- mono_default_debug_handle = debug;
+ mono_debug_lock ();
+ release_symbol_file_table ();
+
+ mono_debug_handle = debug;
+ mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
+
+ mono_debug_open_image (mono_debug_handle, assembly->image);
+ mono_debug_open_image (mono_debug_handle, mono_defaults.corlib);
+
+ mono_debug_add_type (mono_defaults.object_class);
+ mono_debug_add_type (mono_defaults.object_class);
+ mono_debug_add_type (mono_defaults.byte_class);
+ mono_debug_add_type (mono_defaults.void_class);
+ mono_debug_add_type (mono_defaults.boolean_class);
+ mono_debug_add_type (mono_defaults.sbyte_class);
+ mono_debug_add_type (mono_defaults.int16_class);
+ mono_debug_add_type (mono_defaults.uint16_class);
+ mono_debug_add_type (mono_defaults.int32_class);
+ mono_debug_add_type (mono_defaults.uint32_class);
+ mono_debug_add_type (mono_defaults.int_class);
+ mono_debug_add_type (mono_defaults.uint_class);
+ mono_debug_add_type (mono_defaults.int64_class);
+ mono_debug_add_type (mono_defaults.uint64_class);
+ mono_debug_add_type (mono_defaults.single_class);
+ mono_debug_add_type (mono_defaults.double_class);
+ mono_debug_add_type (mono_defaults.char_class);
+ mono_debug_add_type (mono_defaults.string_class);
+ mono_debug_add_type (mono_defaults.enum_class);
+ mono_debug_add_type (mono_defaults.array_class);
+ mono_debug_add_type (mono_defaults.multicastdelegate_class);
+ mono_debug_add_type (mono_defaults.asyncresult_class);
+ mono_debug_add_type (mono_defaults.waithandle_class);
+ mono_debug_add_type (mono_defaults.typehandle_class);
+ mono_debug_add_type (mono_defaults.fieldhandle_class);
+ mono_debug_add_type (mono_defaults.methodhandle_class);
+ mono_debug_add_type (mono_defaults.monotype_class);
+ mono_debug_add_type (mono_defaults.exception_class);
+ mono_debug_add_type (mono_defaults.threadabortexception_class);
+ mono_debug_add_type (mono_defaults.thread_class);
+ mono_debug_add_type (mono_defaults.transparent_proxy_class);
+ mono_debug_add_type (mono_defaults.real_proxy_class);
+ mono_debug_add_type (mono_defaults.mono_method_message_class);
+ mono_debug_add_type (mono_defaults.appdomain_class);
+ mono_debug_add_type (mono_defaults.field_info_class);
+ mono_debug_add_type (mono_defaults.stringbuilder_class);
+ mono_debug_add_type (mono_defaults.math_class);
+ mono_debug_add_type (mono_defaults.stack_frame_class);
+ mono_debug_add_type (mono_defaults.stack_trace_class);
+ mono_debug_add_type (mono_defaults.marshal_class);
+ mono_debug_add_type (mono_defaults.iserializeable_class);
+ mono_debug_add_type (mono_defaults.serializationinfo_class);
+ mono_debug_add_type (mono_defaults.streamingcontext_class);
+
+ mono_debug_update_symbol_file_table ();
+
+ mono_debug_unlock ();
return debug;
}
+static void
+mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
+{
+ if (!mono_debug_handle)
+ return;
+
+ mono_debug_lock ();
+ mono_debug_open_image (mono_debug_handle, assembly->image);
+ mono_debug_unlock ();
+}
+
+static void
+generate_il_offsets (AssemblyDebugInfo *info, MonoMethod *method)
+{
+ GPtrArray *il_offsets = g_ptr_array_new ();
+ MonoClass *klass = method->klass;
+ MonoDebugMethodInfo *minfo;
+ DebugMethodInfo *priv;
+ int i;
+
+ g_assert (klass->image == info->image);
+
+ /* FIXME: doesn't work yet. */
+ if (!strcmp (klass->name_space, "System.Runtime.Remoting.Proxies"))
+ return;
+
+ mono_class_init (klass);
+
+ minfo = g_new0 (MonoDebugMethodInfo, 1);
+ minfo->method = method;
+ minfo->user_data = priv = g_new0 (DebugMethodInfo, 1);
+
+ priv->name = g_strdup_printf ("%s%s%s.%s", klass->name_space, klass->name_space [0]? ".": "",
+ klass->name, method->name);
+ priv->source_file = info->source_file;
+ priv->info = info;
+
+ /*
+ * Find the method index in the image.
+ */
+ for (i = 0; klass->methods && i < klass->method.count; ++i) {
+ if (klass->methods [i] == minfo->method) {
+ priv->method_number = klass->method.first + i + 1;
+ priv->first_line = info->mlines [priv->method_number];
+ break;
+ }
+ }
+
+ g_assert (priv->method_number);
+
+ /* info->moffsets contains -1 "outside" of functions. */
+ for (i = priv->first_line; (i > 0) && (info->moffsets [i] == 0); i--)
+ ;
+ priv->start_line = i + 1;
+
+ for (i = priv->start_line; info->moffsets [i] != -1; i++) {
+ MonoSymbolFileLineNumberEntry *lne = g_new0 (MonoSymbolFileLineNumberEntry, 1);
+
+ if (!info->moffsets [i] && (i > priv->start_line))
+ continue;
+
+ lne->offset = info->moffsets [i];
+ lne->row = i;
+
+ g_ptr_array_add (il_offsets, lne);
+ }
+
+ priv->last_line = i;
+
+ minfo->start_line = priv->first_line;
+ minfo->end_line = priv->last_line;
+
+ minfo->num_il_offsets = il_offsets->len;
+ minfo->il_offsets = g_new0 (MonoSymbolFileLineNumberEntry, il_offsets->len);
+ for (i = 0; i < il_offsets->len; i++) {
+ MonoSymbolFileLineNumberEntry *il = g_ptr_array_index (il_offsets, i);
+
+ minfo->il_offsets [i] = *il;
+ }
+
+ g_ptr_array_free (il_offsets, TRUE);
+
+ g_hash_table_insert (info->methods, method, minfo);
+}
+
static void
debug_load_method_lines (AssemblyDebugInfo* info)
{
+ MonoTableInfo *table = &info->image->tables [MONO_TABLE_METHOD];
FILE *f;
char buf [1024];
- int i, mnum;
+ int i, mnum, idx;
int offset = -1;
- g_message (G_STRLOC ": %d - %s", info->always_create_il, info->filename);
-
if (info->always_create_il || !(info->handle->flags & MONO_DEBUG_FLAGS_DONT_UPDATE_IL_FILES)) {
char *command = g_strdup_printf ("monodis --output=%s %s",
info->ilfile, info->image->name);
/* If the stat() failed or the file is older. */
if (stat (info->ilfile, &statb)) {
- /* Don't create any new *.il files if the user told us not to do so. */
- if (!(info->handle->flags & MONO_DEBUG_FLAGS_DONT_CREATE_IL_FILES))
- need_update = TRUE;
+ need_update = TRUE;
} else if (statb.st_mtime < stata.st_mtime)
need_update = TRUE;
if (need_update) {
+#ifndef PLATFORM_WIN32
+ struct sigaction act, oldact;
+ sigset_t old_set;
+#endif
+ int ret;
+
+#ifndef PLATFORM_WIN32
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+ sigemptyset (&act.sa_mask);
+ sigaddset (&act.sa_mask, SIGCHLD);
+ sigprocmask (SIG_BLOCK, &act.sa_mask, &old_set);
+ sigaction (SIGCHLD, &act, &oldact);
+#endif
+
g_print ("Recreating %s from %s.\n", info->ilfile, info->image->name);
- if (system (command)) {
+
+ ret = system (command);
+
+#ifndef PLATFORM_WIN32
+ sigaction (SIGCHLD, &oldact, NULL);
+ sigprocmask (SIG_SETMASK, &old_set, NULL);
+#endif
+
+ if (ret) {
g_warning ("cannot create IL assembly file (%s): %s",
command, g_strerror (errno));
g_free (command);
info->mlines [mnum] = pos;
}
fclose (f);
-}
-
-static void
-record_line_number (DebugMethodInfo *minfo, gpointer address, guint32 line, int is_basic_block)
-{
- DebugLineNumberInfo *lni = g_new0 (DebugLineNumberInfo, 1);
- lni->address = address;
- lni->line = line;
- lni->is_basic_block = is_basic_block;
- lni->source_file = minfo->source_file;
+ for (idx = 1; idx <= table->rows; idx++) {
+ guint32 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
+ MonoMethod *method = mono_get_method (info->image, token, NULL);
- g_ptr_array_add (minfo->line_numbers, lni);
-}
-
-static void
-record_il_offset (GPtrArray *array, guint32 line, guint32 offset, guint32 address)
-{
- MonoDebugILOffsetInfo *info = g_new0 (MonoDebugILOffsetInfo, 1);
+ if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
+ (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
+ (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
+ continue;
- info->line = line;
- info->offset = offset;
- info->address = address;
+ if (method->wrapper_type != MONO_WRAPPER_NONE)
+ continue;
- g_ptr_array_add (array, info);
+ generate_il_offsets (info, method);
+ }
}
-static void
-debug_generate_method_lines (AssemblyDebugInfo *info, DebugMethodInfo *minfo, MonoFlowGraph* cfg)
+void
+_mono_debug_generate_line_number (MonoDebugMethodInfo *minfo, guint32 address, guint32 offset, int debug)
{
- guint32 st_address, st_line;
- GPtrArray *il_offsets;
int i;
- il_offsets = g_ptr_array_new ();
- minfo->line_numbers = g_ptr_array_new ();
-
- st_line = minfo->first_line;
- st_address = minfo->method_info.prologue_end;
-
- /* record_line_number takes absolute memory addresses. */
- record_line_number (minfo, minfo->method_info.code_start, minfo->start_line, FALSE);
- /* record_il_offsets uses offsets relative to minfo->method_info.code_start. */
- record_il_offset (il_offsets, minfo->start_line, 0, st_address);
-
- /* This is the first actual code line of the method. */
- record_line_number (minfo, minfo->method_info.code_start + st_address, st_line, TRUE);
-
- /* start lines of basic blocks */
- for (i = 0; i < cfg->block_count; ++i) {
- int j;
-
- for (j = 0; cfg->bblocks [i].forest && (j < cfg->bblocks [i].forest->len); ++j) {
- MBTree *t = (MBTree *) g_ptr_array_index (cfg->bblocks [i].forest, j);
- gint32 line_inc = 0, addr_inc;
-
- if (!i && !j) {
- st_line = minfo->first_line;
- st_address = t->addr;
-
- record_line_number (minfo, cfg->start + st_address, st_line, TRUE);
- }
+ if (debug)
+ g_message (G_STRLOC ": searching IL offset %x", offset);
- addr_inc = t->addr - st_address;
- st_address += addr_inc;
+ for (i = minfo->num_il_offsets - 1; i >= 0; i--) {
+ MonoDebugLineNumberEntry *lne;
- if (t->cli_addr != -1)
- record_il_offset (il_offsets, st_line, t->cli_addr, st_address);
-
- if (!info->moffsets)
- continue;
+ if (minfo->il_offsets [i].offset > offset)
+ continue;
+ if (debug)
+ g_message (G_STRLOC ": found entry %d: offset = %x, row = %d",
+ i, minfo->il_offsets [i].offset, minfo->il_offsets [i].row);
- if (t->cli_addr != -1) {
- int *lines = info->moffsets + st_line;
- int *k = lines;
+ if (minfo->jit->line_numbers->len) {
+ MonoDebugLineNumberEntry last = g_array_index (
+ minfo->jit->line_numbers, MonoDebugLineNumberEntry,
+ minfo->jit->line_numbers->len - 1);
- while ((*k != -1) && (*k < t->cli_addr))
- k++;
+ /* Avoid writing more than one entry for the same line. */
+ if (minfo->il_offsets [i].row == last.line) {
+ if (debug)
+ g_message (G_STRLOC ": skipping line: line = %d, last line = %d, "
+ "last address = %x, address = %x, "
+ "last offset = %x, offset = %x",
+ last.line, minfo->il_offsets [i].row,
+ last.address, address, last.offset, offset);
- line_inc = k - lines;
+ return;
}
-
- st_line += line_inc;
-
- record_line_number (minfo, minfo->method_info.code_start + st_address,
- st_line, j == 0);
}
- }
- minfo->method_info.num_il_offsets = il_offsets->len;
- minfo->method_info.il_offsets = g_new0 (MonoDebugILOffsetInfo, il_offsets->len);
- for (i = 0; i < il_offsets->len; i++) {
- MonoDebugILOffsetInfo *il = (MonoDebugILOffsetInfo *) g_ptr_array_index (il_offsets, i);
+ if (debug)
+ g_message (G_STRLOC ": writing entry: line = %d, offfset = %x, address = %x",
+ minfo->il_offsets [i].row, offset, address);
- minfo->method_info.il_offsets [i] = *il;
- }
+ lne = g_new0 (MonoDebugLineNumberEntry, 1);
+ lne->address = address;
+ lne->offset = offset;
+ lne->line = minfo->il_offsets [i].row;
- g_ptr_array_free (il_offsets, TRUE);
+ g_array_append_val (minfo->jit->line_numbers, *lne);
+ return;
+ }
}
-static AssemblyDebugInfo *
-mono_debug_get_image (MonoDebugHandle* debug, MonoImage *image)
+AssemblyDebugInfo *
+_mono_debug_get_image (MonoDebugHandle* debug, MonoImage *image)
{
- GList *tmp;
- AssemblyDebugInfo *info;
-
- if (debug->format == MONO_DEBUG_FORMAT_NONE)
- return NULL;
-
- for (tmp = debug->info; tmp; tmp = tmp->next) {
- info = (AssemblyDebugInfo*)tmp->data;
-
- if (info->image == image)
- return info;
- }
-
- return NULL;
+ return g_hash_table_lookup (debug->images, image);
}
static AssemblyDebugInfo *
mono_debug_open_image (MonoDebugHandle* debug, MonoImage *image)
{
AssemblyDebugInfo *info;
+ MonoAssembly **ptr;
- info = mono_debug_get_image (debug, image);
+ info = _mono_debug_get_image (debug, image);
if (info != NULL)
return info;
info->handle = debug;
info->methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) free_method_info);
+ info->wrapper_methods = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) free_wrapper_info);
- info->source_file = debug->source_files->len;
- g_ptr_array_add (debug->source_files, g_strdup_printf ("%s.il", image->assembly_name));
-
- debug->info = g_list_prepend (debug->info, info);
+ g_hash_table_insert (debug->images, image, info);
info->nmethods = image->tables [MONO_TABLE_METHOD].rows + 1;
info->mlines = g_new0 (int, info->nmethods);
+ for (ptr = image->references; ptr && *ptr; ptr++)
+ mono_debug_add_assembly (*ptr, NULL);
+
+ if (image->assembly->dynamic)
+ return info;
+
switch (info->format) {
case MONO_DEBUG_FORMAT_STABS:
case MONO_DEBUG_FORMAT_DWARF2:
g_free (dirname);
} else
info->ilfile = g_strdup_printf ("%s.il", info->name);
+ info->source_file = debug->source_files->len;
+ g_ptr_array_add (debug->source_files, info->ilfile);
break;
- case MONO_DEBUG_FORMAT_DWARF2_PLUS: {
- gchar *dirname = g_path_get_dirname (image->name);
- info->filename = g_strdup_printf ("%s/%s-debug.s", dirname, info->name);
- info->objfile = g_strdup_printf ("%s-debug.o", info->name);
- mono_debug_open_assembly_dwarf2_plus (info);
- g_free (dirname);
- break;
- }
-
case MONO_DEBUG_FORMAT_MONO:
- info->filename = g_strdup_printf ("%s.dbg", info->name);
- if (g_file_test (info->filename, G_FILE_TEST_EXISTS))
- info->mono_symfile = mono_debug_open_mono_symbol_file
- (info->image, info->filename, TRUE);
- else if (debug->flags & MONO_DEBUG_FLAGS_MONO_DEBUGGER) {
- g_message (G_STRLOC ": Creating symbol file: %s - %s", info->name,
- info->image->name);
- info->always_create_il = TRUE;
- if (debug->flags & MONO_DEBUG_FLAGS_INSTALL_IL_FILES) {
- gchar *dirname = g_path_get_dirname (image->name);
- info->ilfile = g_strdup_printf ("%s/%s.il", dirname, info->name);
- g_free (dirname);
- } else {
- info->ilfile = g_strdup_printf ("%s.il", info->name);
- }
- debug_load_method_lines (info);
- info->mono_symfile = mono_debug_create_mono_symbol_file (info->image, info->ilfile);
- }
- mono_debugger_internal_symbol_files_changed = TRUE;
+ info->symfile = mono_debug_open_mono_symbol_file (info->image, running_in_the_mono_debugger);
+ mono_debugger_symbol_file_table_generation++;
break;
default:
break;
}
- if ((debug->format != MONO_DEBUG_FORMAT_DWARF2_PLUS) &&
- (debug->format != MONO_DEBUG_FORMAT_MONO))
+ if (debug->format != MONO_DEBUG_FORMAT_MONO)
debug_load_method_lines (info);
return info;
}
-void
-mono_debug_add_image (MonoDebugHandle* debug, MonoImage *image)
-{
- mono_debug_open_image (debug, image);
-}
-
void
mono_debug_write_symbols (MonoDebugHandle *debug)
{
- GList *tmp;
-
if (!debug || !debug->dirty)
return;
+
+ release_symbol_file_table ();
+
switch (debug->format) {
case MONO_DEBUG_FORMAT_STABS:
mono_debug_write_stabs (debug);
case MONO_DEBUG_FORMAT_DWARF2:
mono_debug_write_dwarf2 (debug);
break;
- case MONO_DEBUG_FORMAT_DWARF2_PLUS:
- for (tmp = debug->info; tmp; tmp = tmp->next) {
- AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
-
- mono_debug_write_assembly_dwarf2_plus (info);
- }
- break;
case MONO_DEBUG_FORMAT_MONO:
- for (tmp = debug->info; tmp; tmp = tmp->next) {
- AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
-
- if (!info->mono_symfile)
- continue;
-
- mono_debug_update_mono_symbol_file (info->mono_symfile, info->methods);
- }
break;
default:
g_assert_not_reached ();
void
mono_debug_make_symbols (void)
{
- MonoDebugHandle *debug;
+ if (!mono_debug_handle || !mono_debug_handle->dirty)
+ return;
+
+ switch (mono_debug_handle->format) {
+ case MONO_DEBUG_FORMAT_STABS:
+ mono_debug_write_stabs (mono_debug_handle);
+ break;
+ case MONO_DEBUG_FORMAT_DWARF2:
+ mono_debug_write_dwarf2 (mono_debug_handle);
+ break;
+ case MONO_DEBUG_FORMAT_MONO:
+ mono_debug_update_symbol_file_table ();
+ break;
+ default:
+ g_assert_not_reached ();
+ }
- for (debug = mono_debug_handles; debug; debug = debug->next)
- mono_debug_write_symbols (debug);
+ mono_debug_handle->dirty = FALSE;
}
static void
mono_debug_close_assembly (AssemblyDebugInfo* info)
{
switch (info->format) {
- case MONO_DEBUG_FORMAT_DWARF2_PLUS:
- mono_debug_close_assembly_dwarf2_plus (info);
- break;
case MONO_DEBUG_FORMAT_MONO:
- if (info->mono_symfile != NULL)
- mono_debug_close_mono_symbol_file (info->mono_symfile);
+ if (info->symfile != NULL)
+ mono_debug_close_mono_symbol_file (info->symfile);
break;
default:
break;
}
g_hash_table_destroy (info->methods);
+ g_hash_table_destroy (info->wrapper_methods);
g_free (info->mlines);
g_free (info->moffsets);
g_free (info->name);
void
mono_debug_cleanup (void)
{
- MonoDebugHandle *debug, *temp;
-
- for (debug = mono_debug_handles; debug; debug = temp) {
- GList *tmp;
-
- if (debug->flags & MONO_DEBUG_FLAGS_UPDATE_ON_EXIT)
- mono_debug_write_symbols (debug);
-
+ release_symbol_file_table ();
- for (tmp = debug->info; tmp; tmp = tmp->next) {
- AssemblyDebugInfo* info = (AssemblyDebugInfo*)tmp->data;
+ if (!mono_debug_handle)
+ return;
- mono_debug_close_assembly (info);
- }
+ if (mono_debug_handle->flags & MONO_DEBUG_FLAGS_UPDATE_ON_EXIT)
+ mono_debug_write_symbols (mono_debug_handle);
- g_ptr_array_free (debug->source_files, TRUE);
- g_hash_table_destroy (debug->type_hash);
- g_free (debug->producer_name);
- g_free (debug->name);
+ g_hash_table_destroy (mono_debug_handle->images);
+ g_ptr_array_free (mono_debug_handle->source_files, FALSE);
+ g_hash_table_destroy (mono_debug_handle->type_hash);
+ g_free (mono_debug_handle->producer_name);
+ g_free (mono_debug_handle->name);
+ g_free (mono_debug_handle);
- temp = debug->next;
- g_free (debug);
- }
-
- mono_debug_handles = NULL;
- mono_default_debug_handle = NULL;
+ mono_debug_handle = NULL;
}
guint32
return index;
}
-MonoDebugHandle *
-mono_debug_handle_from_class (MonoClass *klass)
-{
- MonoDebugHandle *debug;
-
- mono_class_init (klass);
-
- for (debug = mono_debug_handles; debug; debug = debug->next) {
- GList *tmp;
-
- for (tmp = debug->info; tmp; tmp = tmp->next) {
- AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
-
- if (info->image == klass->image)
- return debug;
- }
- }
-
- return NULL;
-}
-
static gint32
-il_offset_from_address (DebugMethodInfo *minfo, guint32 address)
+il_offset_from_address (MonoDebugMethodInfo *minfo, guint32 address)
{
int i;
- for (i = 0; i < minfo->method_info.num_il_offsets; i++) {
- MonoDebugILOffsetInfo *ilo = &minfo->method_info.il_offsets [i];
-
- if (ilo->address > address)
- return ilo->offset;
- }
-
- return -1;
-}
-
-static gint32
-address_from_il_offset (DebugMethodInfo *minfo, guint32 il_offset)
-{
- int i;
+ if (!minfo->jit || !minfo->jit->line_numbers)
+ return -1;
- for (i = 0; i < minfo->method_info.num_il_offsets; i++) {
- MonoDebugILOffsetInfo *ilo = &minfo->method_info.il_offsets [i];
+ for (i = minfo->jit->line_numbers->len - 1; i >= 0; i--) {
+ MonoDebugLineNumberEntry lne = g_array_index (
+ minfo->jit->line_numbers, MonoDebugLineNumberEntry, i);
- if (ilo->offset > il_offset)
- return ilo->address;
+ if (lne.address <= address)
+ return lne.offset;
}
return -1;
void
mono_debug_add_type (MonoClass *klass)
{
- MonoDebugHandle *debug = mono_debug_handle_from_class (klass);
+ AssemblyDebugInfo* info;
+
+ if (!mono_debug_handle)
+ return;
- g_assert (debug != NULL);
+ info = _mono_debug_get_image (mono_debug_handle, klass->image);
+ g_assert (info);
- mono_debug_get_type (debug, klass);
+ if (mono_debug_handle->format != MONO_DEBUG_FORMAT_MONO)
+ return;
+
+ if (info->symfile) {
+ mono_debug_lock ();
+ mono_debug_symfile_add_type (info->symfile, klass);
+ mono_debugger_event (MONO_DEBUGGER_EVENT_TYPE_ADDED, info->symfile, klass);
+ mono_debug_unlock ();
+ }
}
-static gint32
-il_offset_from_position (MonoFlowGraph *cfg, MonoPosition *pos)
+struct LookupMethodData
{
- MonoBBlock *bblock;
- MBTree *tree;
+ MonoDebugMethodInfo *minfo;
+ MonoMethod *method;
+};
- if (pos->abs_pos == 0)
- return -1;
+static void
+lookup_method_func (gpointer key, gpointer value, gpointer user_data)
+{
+ AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
+ struct LookupMethodData *data = (struct LookupMethodData *) user_data;
- if (pos->pos.bid >= cfg->block_count)
- return -1;
+ if (data->minfo)
+ return;
- bblock = &cfg->bblocks [pos->pos.bid];
- if (pos->pos.tid >= bblock->forest->len)
- return -1;
+ if (info->symfile)
+ data->minfo = mono_debug_find_method (info->symfile, data->method);
+ else
+ data->minfo = g_hash_table_lookup (info->methods, data->method);
+}
- tree = (MBTree *) g_ptr_array_index (bblock->forest, pos->pos.tid);
+MonoDebugMethodInfo *
+_mono_debug_lookup_method (MonoMethod *method)
+{
+ struct LookupMethodData data = { NULL, method };
+
+ if (!mono_debug_handle)
+ return NULL;
- return tree->cli_addr;
+ g_hash_table_foreach (mono_debug_handle->images, lookup_method_func, &data);
+ return data.minfo;
}
void
-mono_debug_add_method (MonoFlowGraph *cfg)
+mono_debug_add_wrapper (MonoMethod *method, MonoMethod *wrapper_method)
{
- MonoMethod *method = cfg->method;
MonoClass *klass = method->klass;
- int method_number = 0, line = 0, start_line = 0, end_line = 0, i;
- MonoDebugHandle* debug;
AssemblyDebugInfo* info;
- DebugMethodInfo *minfo;
- char *name;
-
- mono_class_init (klass);
-
- debug = mono_debug_handle_from_class (klass);
- if (!debug) {
- if (mono_default_debug_handle)
- debug = mono_default_debug_handle;
- else
- return;
- }
+ MonoDebugMethodInfo *minfo;
+ DebugWrapperInfo *winfo;
+ MonoDebugMethodJitInfo *jit;
- info = mono_debug_open_image (debug, klass->image);
-
- /*
- * Find the method index in the image.
- */
- for (i = 0; klass->methods && i < klass->method.count; ++i) {
- if (klass->methods [i] == method) {
- method_number = klass->method.first + i + 1;
- line = info->mlines [method_number];
- break;
- }
- }
-
- if (g_hash_table_lookup (info->methods, method))
+ if (!mono_debug_handle)
return;
- debug->dirty = TRUE;
-
- if (info->moffsets) {
- /* info->moffsets contains -1 "outside" of functions. */
- for (i = line; (i > 0) && (info->moffsets [i] == 0); i--)
- ;
- start_line = i + 1;
-
- for (i = start_line; info->moffsets [i] != -1; i++)
- ;
- end_line = i;
- }
-
- name = g_strdup_printf ("%s%s%s.%s", klass->name_space, klass->name_space [0]? ".": "",
- klass->name, method->name);
-
- minfo = g_new0 (DebugMethodInfo, 1);
- minfo->name = name;
- minfo->start_line = start_line;
- minfo->first_line = line;
- minfo->last_line = end_line;
- minfo->source_file = info->source_file;
- minfo->info = info;
- minfo->method_info.code_start = cfg->start;
- minfo->method_info.code_size = cfg->epilogue_end;
- minfo->method_number = method_number;
- minfo->method_info.method = method;
- minfo->method_info.num_params = method->signature->param_count;
- minfo->method_info.params = g_new0 (MonoDebugVarInfo, minfo->method_info.num_params);
- minfo->method_info.prologue_end = cfg->prologue_end;
- minfo->method_info.epilogue_begin = cfg->epilog;
-
- if (method->signature->hasthis) {
- MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index;
-
- minfo->method_info.this_var = g_new0 (MonoDebugVarInfo, 1);
- minfo->method_info.this_var->offset = ptr->offset;
- }
-
- for (i = 0; i < minfo->method_info.num_params; i++) {
- MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->args_start_index +
- method->signature->hasthis;
+ if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL))
+ return;
- minfo->method_info.params [i].offset = ptr [i].offset;
- }
+ mono_class_init (klass);
- debug_generate_method_lines (info, minfo, cfg);
-
- if (!method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
- MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
- MonoVarInfo *ptr = ((MonoVarInfo *) cfg->varinfo->data) + cfg->locals_start_index;
- MonoDebugVarInfo *locals;
-
- locals = g_new0 (MonoDebugVarInfo, header->num_locals);
- for (i = 0; i < header->num_locals; i++) {
- gint32 begin_offset, end_offset;
- gint32 begin_scope, end_scope;
-
- if (ptr [i].reg >= 0) {
- locals [i].index = ptr [i].reg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER;
- locals [i].offset = 0;
- } else
- locals [i].offset = ptr [i].offset;
-
- begin_offset = il_offset_from_position (cfg, &ptr [i].range.first_use);
- end_offset = il_offset_from_position (cfg, &ptr [i].range.last_use);
- if (end_offset >= 0)
- end_offset++;
-
- begin_scope = address_from_il_offset (minfo, begin_offset);
- end_scope = address_from_il_offset (minfo, end_offset);
-
- if (begin_scope > 0)
- locals [i].begin_scope = begin_scope;
- else
- locals [i].begin_scope = minfo->method_info.prologue_end;
- if (end_scope > 0)
- locals [i].end_scope = end_scope;
- else
- locals [i].end_scope = minfo->method_info.epilogue_begin;
- }
+ info = _mono_debug_get_image (mono_debug_handle, klass->image);
+ g_assert (info);
- minfo->method_info.num_locals = header->num_locals;
- minfo->method_info.locals = locals;
- }
+ minfo = _mono_debug_lookup_method (method);
+ if (!minfo || minfo->jit)
+ return;
- g_hash_table_insert (info->methods, method, minfo);
-}
+ winfo = g_hash_table_lookup (info->wrapper_methods, wrapper_method);
+ g_assert (winfo);
-static DebugMethodInfo *
-lookup_method (MonoMethod *method)
-{
- MonoDebugHandle *debug;
+ mono_debug_lock ();
- for (debug = mono_debug_handles; debug; debug = debug->next) {
- GList *tmp;
+ mono_debug_handle->dirty = TRUE;
- for (tmp = debug->info; tmp; tmp = tmp->next) {
- AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
- DebugMethodInfo *minfo;
+ minfo->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1);
+ jit->code_start = winfo->code_start;
+ jit->code_size = winfo->code_size;
+ jit->prologue_end = 0;
+ jit->epilogue_begin = winfo->code_size;
+ jit->num_params = 0;
+ jit->wrapper_addr = method->addr;
- minfo = g_hash_table_lookup (info->methods, method);
- if (minfo)
- return minfo;
- }
+ if (info->symfile) {
+ mono_debug_symfile_add_method (info->symfile, method);
+ mono_debugger_event (MONO_DEBUGGER_EVENT_METHOD_ADDED, info->symfile, method);
}
- return NULL;
+ mono_debug_unlock ();
}
gchar *
mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number)
{
- DebugMethodInfo *minfo = lookup_method (method);
- MonoDebugHandle *debug;
- int i;
+ MonoDebugMethodInfo *minfo = _mono_debug_lookup_method (method);
if (!minfo)
return NULL;
- if (minfo->info->mono_symfile) {
+ if (minfo->symfile) {
gint32 offset = il_offset_from_address (minfo, address);
if (offset < 0)
return NULL;
- return mono_debug_find_source_location (minfo->info->mono_symfile, method, offset, line_number);
- }
-
- if (!minfo->line_numbers)
- return NULL;
-
- debug = minfo->info->handle;
-
- for (i = 0; i < minfo->line_numbers->len; i++) {
- DebugLineNumberInfo *lni = g_ptr_array_index (minfo->line_numbers, i);
-
- if ((gchar *)lni->address > minfo->method_info.code_start + address) {
- gchar *source_file = g_ptr_array_index (debug->source_files, lni->source_file);
-
- if (line_number) {
- *line_number = lni->line;
- return g_strdup (source_file);
- } else
- return g_strdup_printf ("%s:%d", source_file, lni->line);
- }
+ return mono_debug_find_source_location (minfo->symfile, method, offset, line_number);
}
return NULL;
gint32
mono_debug_il_offset_from_address (MonoMethod *method, gint32 address)
{
- DebugMethodInfo *minfo;
+ MonoDebugMethodInfo *minfo;
if (address < 0)
return -1;
- minfo = lookup_method (method);
- if (!minfo || !minfo->method_info.il_offsets)
+ minfo = _mono_debug_lookup_method (method);
+ if (!minfo || !minfo->il_offsets)
return -1;
return il_offset_from_address (minfo, address);
gint32
mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset)
{
- DebugMethodInfo *minfo;
+ MonoDebugMethodInfo *minfo;
if (il_offset < 0)
return -1;
- minfo = lookup_method (method);
- if (!minfo || !minfo->method_info.il_offsets)
+ minfo = _mono_debug_lookup_method (method);
+ if (!minfo || !minfo->il_offsets)
return -1;
- return address_from_il_offset (minfo, il_offset);
+ return _mono_debug_address_from_il_offset (minfo, il_offset);
}
-MonoSymbolFile *
-mono_debugger_internal_get_symbol_files (void)
+static void
+release_symbol_file_table ()
+{
+ MonoDebuggerSymbolFileTable *temp;
+
+ if (!mono_debugger_symbol_file_table)
+ return;
+
+ /*
+ * Caution: The debugger may access the memory pointed to by this variable
+ * at any time. It is very important to set the pointer to NULL
+ * before freeing the area.
+ */
+
+ temp = mono_debugger_symbol_file_table;
+ mono_debugger_symbol_file_table = NULL;
+ g_free (mono_debugger_symbol_file_table);
+}
+
+static void
+update_symbol_file_table_count_func (gpointer key, gpointer value, gpointer user_data)
+{
+ AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
+
+ if (!info->symfile)
+ return;
+ if (info->format != MONO_DEBUG_FORMAT_MONO)
+ return;
+
+ ++ (* (int *) user_data);
+}
+
+struct SymfileTableData
+{
+ MonoDebuggerSymbolFileTable *symfile_table;
+ int index;
+};
+
+static void
+update_symbol_file_table_func (gpointer key, gpointer value, gpointer user_data)
+{
+ AssemblyDebugInfo *info = (AssemblyDebugInfo *) value;
+ struct SymfileTableData *data = (struct SymfileTableData *) user_data;
+
+ if (!info->symfile)
+ return;
+ if (info->format != MONO_DEBUG_FORMAT_MONO)
+ return;
+
+ data->symfile_table->symfiles [data->index++] = info->symfile;
+}
+
+int
+mono_debug_update_symbol_file_table (void)
{
- MonoDebugHandle *debug;
- MonoSymbolFile *symfiles, *ptr;
int count = 0;
+ MonoDebuggerSymbolFileTable *symfile_table;
+ struct SymfileTableData data;
+ guint32 size;
- mono_debug_make_symbols ();
+ if (!mono_debug_handle)
+ return FALSE;
- for (debug = mono_debug_handles; debug; debug = debug->next) {
- GList *tmp;
+ mono_debug_lock ();
- if (debug->format != MONO_DEBUG_FORMAT_MONO)
- continue;
+ g_hash_table_foreach (mono_debug_handle->images, update_symbol_file_table_count_func, &count);
- for (tmp = debug->info; tmp; tmp = tmp->next) {
- AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
- MonoSymbolFile *symfile = info->mono_symfile;
+ release_symbol_file_table ();
- if (!symfile)
- continue;
+ size = sizeof (MonoDebuggerSymbolFileTable) + count * sizeof (MonoSymbolFile *);
+ symfile_table = g_malloc0 (size);
+ symfile_table->magic = MONO_SYMBOL_FILE_DYNAMIC_MAGIC;
+ symfile_table->version = MONO_SYMBOL_FILE_DYNAMIC_VERSION;
+ symfile_table->total_size = size;
+ symfile_table->count = count;
+ symfile_table->generation = mono_debugger_symbol_file_table_generation;
+ symfile_table->global_symfile = mono_debugger_global_symbol_file;
- count++;
- }
- }
+ data.symfile_table = symfile_table;
+ data.index = 0;
- symfiles = ptr = g_new0 (MonoSymbolFile, count+1);
+ g_hash_table_foreach (mono_debug_handle->images, update_symbol_file_table_func, &data);
- for (debug = mono_debug_handles; debug; debug = debug->next) {
- GList *tmp;
+ mono_debugger_symbol_file_table = symfile_table;
- if (debug->format != MONO_DEBUG_FORMAT_MONO)
- continue;
+ mono_debug_unlock ();
- for (tmp = debug->info; tmp; tmp = tmp->next) {
- AssemblyDebugInfo *info = (AssemblyDebugInfo*)tmp->data;
- MonoSymbolFile *symfile = info->mono_symfile;
+ return TRUE;
+}
- if (!symfile)
- continue;
+static GPtrArray *breakpoints = NULL;
- *ptr++ = *symfile;
- }
+int
+mono_insert_breakpoint_full (MonoMethodDesc *desc, gboolean use_trampoline)
+{
+ static int last_breakpoint_id = 0;
+ MonoDebuggerBreakpointInfo *info;
+
+ info = g_new0 (MonoDebuggerBreakpointInfo, 1);
+ info->desc = desc;
+ info->use_trampoline = use_trampoline;
+ info->index = ++last_breakpoint_id;
+
+ if (!breakpoints)
+ breakpoints = g_ptr_array_new ();
+
+ g_ptr_array_add (breakpoints, info);
+
+ return info->index;
+}
+
+int
+mono_remove_breakpoint (int breakpoint_id)
+{
+ int i;
+
+ if (!breakpoints)
+ return 0;
+
+ for (i = 0; i < breakpoints->len; i++) {
+ MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
+
+ if (info->index != breakpoint_id)
+ continue;
+
+ mono_method_desc_free (info->desc);
+ g_ptr_array_remove (breakpoints, info);
+ g_free (info);
+ return 1;
}
- mono_debugger_internal_symbol_files_changed = FALSE;
+ return 0;
+}
+
+int
+mono_insert_breakpoint (const gchar *method_name, gboolean include_namespace)
+{
+ MonoMethodDesc *desc;
- return symfiles;
+ desc = mono_method_desc_new (method_name, include_namespace);
+ if (!desc)
+ return 0;
+
+ return mono_insert_breakpoint_full (desc, running_in_the_mono_debugger);
}
-void
-mono_debugger_internal_free_symbol_files (gpointer data)
+int
+mono_method_has_breakpoint (MonoMethod* method, gboolean use_trampoline)
{
- g_free (data);
+ int i;
+
+ if (!breakpoints || (method->wrapper_type != MONO_WRAPPER_NONE))
+ return 0;
+
+ for (i = 0; i < breakpoints->len; i++) {
+ MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
+
+ if (info->use_trampoline != use_trampoline)
+ continue;
+
+ if (!mono_method_desc_full_match (info->desc, method))
+ continue;
+
+ return info->index;
+ }
+
+ return 0;
}
-/* This is intentionally a global variable and not a method. */
-int mono_debugger_internal_symbol_files_changed = FALSE;
+void
+mono_debugger_trampoline_breakpoint_callback (void)
+{
+ mono_debugger_event (MONO_DEBUGGER_EVENT_BREAKPOINT_TRAMPOLINE, NULL, NULL);
+}