X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fdebug-debugger.c;h=a103595c0bf72426da06cef43e283fb219b22e1a;hb=0d40321933ac575314ab51efa3c62e8cf535a9d2;hp=51ab06bdbde6618ddb4c49535782b73ea204cb2c;hpb=07ec1253c277856bdbb74213e2defc8ed23cf8e3;p=mono.git diff --git a/mono/mini/debug-debugger.c b/mono/mini/debug-debugger.c index 51ab06bdbde..a103595c0bf 100644 --- a/mono/mini/debug-debugger.c +++ b/mono/mini/debug-debugger.c @@ -1,3 +1,12 @@ +/* + * debug-debugger.c: Hard debugger support (mdb) + * + * Author: + * + * Copyright 2006-2010 Novell, Inc. + */ +#if MONO_DEBUGGER_SUPPORTED + #include #include #include @@ -6,6 +15,7 @@ #include #define _IN_THE_MONO_DEBUGGER #include "debug-debugger.h" +#include "debug-mini.h" #include #include "mini.h" #include @@ -19,43 +29,55 @@ * configure.in checks whether we're using the included libgc and disables the debugger if not. */ -#if !defined(MONO_DEBUGGER_SUPPORTED) -#error "Some clown tried to compile debug-debugger.c on an unsupported platform - fix Makefile.am!" -#elif !defined(USE_INCLUDED_LIBGC) -#error "Some clown #defined MONO_DEBUGGER_SUPPORTED without USE_INCLUDED_GC - fix configure.in!" +#if !defined(USE_INCLUDED_LIBGC) +#error "Inconsistency detected: #defined MONO_DEBUGGER_SUPPORTED without USE_INCLUDED_GC - fix configure.in!" #endif -static MonoCodeManager *debugger_codeman = NULL; - -static guint64 debugger_insert_breakpoint (guint64 method_argument, const gchar *string_argument); -static guint64 debugger_remove_breakpoint (guint64 breakpoint); static guint64 debugger_compile_method (guint64 method_arg); static guint64 debugger_get_virtual_method (guint64 class_arg, guint64 method_arg); static guint64 debugger_get_boxed_object (guint64 klass_arg, guint64 val_arg); -static guint64 debugger_create_string (guint64 dummy_argument, const gchar *string_argument); static guint64 debugger_class_get_static_field_data (guint64 klass); -static guint64 debugger_lookup_class (guint64 image_argument, guint64 token_arg); -static guint64 debugger_lookup_type (guint64 dummy_argument, const gchar *string_argument); -static guint64 debugger_lookup_assembly (guint64 dummy_argument, const gchar *string_argument); + static guint64 debugger_run_finally (guint64 argument1, guint64 argument2); -static guint64 debugger_get_current_thread (void); -static void debugger_attach (void); -static void debugger_detach (void); static void debugger_initialize (void); +static guint64 debugger_init_code_buffer (void); + +static void debugger_event_handler (MonoDebuggerEvent event, guint64 data, guint64 arg); + +static guint64 debugger_create_string (G_GNUC_UNUSED guint64 dummy, G_GNUC_UNUSED guint64 dummy2, + G_GNUC_UNUSED guint64 dummy3, const gchar *string_argument); +static gint64 debugger_lookup_class (guint64 image_argument, G_GNUC_UNUSED guint64 dummy, + G_GNUC_UNUSED guint64 dummy2, gchar *full_name); +static guint64 debugger_insert_method_breakpoint (guint64 method_argument, guint64 index); +static guint64 debugger_insert_source_breakpoint (guint64 image_argument, guint64 token, + guint64 index, const gchar *class_name); +static void debugger_remove_breakpoint (guint64 index, G_GNUC_UNUSED guint64 dummy); +static guint64 debugger_register_class_init_callback (guint64 image_argument, guint64 token, + guint64 index, const gchar *class_name); +static void debugger_remove_class_init_callback (guint64 index, G_GNUC_UNUSED guint64 dummy); +static guint64 debugger_get_method_signature (guint64 argument1, G_GNUC_UNUSED guint64 argument2); -static void (*mono_debugger_notification_function) (guint64 command, guint64 data, guint64 data2); +static guint64 debugger_abort_runtime_invoke (G_GNUC_UNUSED guint64 dummy1, G_GNUC_UNUSED guint64 dummy2); + +#define EXECUTABLE_CODE_BUFFER_SIZE 4096 +static guint8 *debugger_executable_code_buffer = NULL; + +static GCThreadFunctions debugger_thread_vtable; + +static guint32 debugger_thread_abort_signal = 0; static MonoDebuggerMetadataInfo debugger_metadata_info = { sizeof (MonoDebuggerMetadataInfo), sizeof (MonoDefaults), &mono_defaults, - sizeof (MonoType), + MONO_SIZEOF_TYPE, sizeof (MonoArrayType), sizeof (MonoClass), - sizeof (MonoThread), - G_STRUCT_OFFSET (MonoThread, tid), - G_STRUCT_OFFSET (MonoThread, stack_ptr), - G_STRUCT_OFFSET (MonoThread, end_stack), + sizeof (MonoInternalThread), + G_STRUCT_OFFSET (MonoInternalThread, tid), + G_STRUCT_OFFSET (MonoInternalThread, stack_ptr), + G_STRUCT_OFFSET (MonoInternalThread, end_stack), + G_STRUCT_OFFSET (MonoClass, image), G_STRUCT_OFFSET (MonoClass, instance_size), G_STRUCT_OFFSET (MonoClass, parent), G_STRUCT_OFFSET (MonoClass, type_token), @@ -66,7 +88,10 @@ static MonoDebuggerMetadataInfo debugger_metadata_info = { G_STRUCT_OFFSET (MonoClass, byval_arg), G_STRUCT_OFFSET (MonoClass, generic_class), G_STRUCT_OFFSET (MonoClass, generic_container), + G_STRUCT_OFFSET (MonoClass, vtable), sizeof (MonoClassField), + G_STRUCT_OFFSET (MonoClassField, type), + G_STRUCT_OFFSET (MonoClassField, offset), G_STRUCT_OFFSET (MonoDefaults, corlib), G_STRUCT_OFFSET (MonoDefaults, object_class), G_STRUCT_OFFSET (MonoDefaults, byte_class), @@ -88,79 +113,95 @@ static MonoDebuggerMetadataInfo debugger_metadata_info = { G_STRUCT_OFFSET (MonoDefaults, enum_class), G_STRUCT_OFFSET (MonoDefaults, array_class), G_STRUCT_OFFSET (MonoDefaults, delegate_class), - G_STRUCT_OFFSET (MonoDefaults, exception_class) + G_STRUCT_OFFSET (MonoDefaults, exception_class), + G_STRUCT_OFFSET (MonoMethod, klass), + G_STRUCT_OFFSET (MonoMethod, token), + G_STRUCT_OFFSET (MonoMethod, name) + sizeof (void *), + G_STRUCT_OFFSET (MonoMethodInflated, declaring), + G_STRUCT_OFFSET (MonoVTable, klass), + G_STRUCT_OFFSET (MonoVTable, vtable) }; +extern void MONO_DEBUGGER__notification_function (guint64 command, guint64 data, guint64 data2); + /* * This is a global data symbol which is read by the debugger. */ MonoDebuggerInfo MONO_DEBUGGER__debugger_info = { MONO_DEBUGGER_MAGIC, - MONO_DEBUGGER_VERSION, + MONO_DEBUGGER_MAJOR_VERSION, + MONO_DEBUGGER_MINOR_VERSION, + 0, /* runtime_flags */ sizeof (MonoDebuggerInfo), sizeof (MonoSymbolTable), - 0, - &mono_debugger_notification_function, + MONO_TRAMPOLINE_NUM, mono_trampoline_code, + &MONO_DEBUGGER__notification_function, &mono_symbol_table, &debugger_metadata_info, + &mono_debug_debugger_version, + &debugger_compile_method, &debugger_get_virtual_method, &debugger_get_boxed_object, - &debugger_insert_breakpoint, - &debugger_remove_breakpoint, &mono_debugger_runtime_invoke, - &debugger_create_string, &debugger_class_get_static_field_data, - &debugger_lookup_class, - &debugger_lookup_type, - &debugger_lookup_assembly, &debugger_run_finally, - &debugger_get_current_thread, - &debugger_attach, - &debugger_detach, - &debugger_initialize -}; + &debugger_initialize, -static guint64 -debugger_insert_breakpoint (guint64 method_argument, const gchar *string_argument) -{ - MonoMethodDesc *desc; + &debugger_create_string, + &debugger_lookup_class, - desc = mono_method_desc_new (string_argument, TRUE); - if (!desc) - return 0; + &debugger_insert_method_breakpoint, + &debugger_insert_source_breakpoint, + &debugger_remove_breakpoint, - return (guint64) mono_debugger_insert_breakpoint_full (desc); -} + &debugger_register_class_init_callback, + &debugger_remove_class_init_callback, -static guint64 -debugger_remove_breakpoint (guint64 breakpoint) -{ - return mono_debugger_remove_breakpoint (breakpoint); -} + &mono_debugger_thread_table, -static gpointer -debugger_compile_method_cb (MonoMethod *method) -{ - gpointer retval; + &debugger_executable_code_buffer, + mono_breakpoint_info, + mono_breakpoint_info_index, - mono_debugger_lock (); - retval = mono_compile_method (method); - mono_debugger_unlock (); + EXECUTABLE_CODE_BUFFER_SIZE, + MONO_BREAKPOINT_ARRAY_SIZE, + + debugger_get_method_signature, + debugger_init_code_buffer, + + &gc_thread_vtable, + &debugger_thread_vtable, + + &mono_debugger_event_handler, + debugger_event_handler, + + &_mono_debug_using_mono_debugger, + (gint32*)&_mono_debugger_interruption_request, - mono_debugger_notification_function ( - MONO_DEBUGGER_EVENT_METHOD_COMPILED, (guint64) (gsize) retval, 0); + &debugger_abort_runtime_invoke, - return retval; + &debugger_thread_abort_signal +}; + +static guint64 +debugger_abort_runtime_invoke (G_GNUC_UNUSED guint64 dummy1, G_GNUC_UNUSED guint64 dummy2) +{ + return mono_debugger_abort_runtime_invoke (); } static guint64 debugger_compile_method (guint64 method_arg) { MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg); + gpointer addr; - return (guint64) (gsize) debugger_compile_method_cb (method); + mono_debugger_lock (); + addr = mono_compile_method (method); + mono_debugger_unlock (); + + return (guint64) (gsize) addr; } static guint64 @@ -193,101 +234,212 @@ debugger_get_boxed_object (guint64 klass_arg, guint64 val_arg) } static guint64 -debugger_create_string (guint64 dummy_argument, const gchar *string_argument) +debugger_create_string (G_GNUC_UNUSED guint64 dummy, G_GNUC_UNUSED guint64 dummy2, + G_GNUC_UNUSED guint64 dummy3, const gchar *string_argument) { return (guint64) (gsize) mono_string_new_wrapper (string_argument); } -static guint64 -debugger_lookup_type (guint64 dummy_argument, const gchar *string_argument) +static gint64 +debugger_lookup_class (guint64 image_argument, G_GNUC_UNUSED guint64 dummy, + G_GNUC_UNUSED guint64 dummy2, gchar *full_name) { - guint64 retval; + MonoImage *image = (MonoImage *) GUINT_TO_POINTER ((gsize) image_argument); + gchar *name_space, *name, *pos; + MonoClass *klass; - mono_debugger_lock (); - // retval = mono_debugger_lookup_type (string_argument); - retval = -1; - mono_debugger_unlock (); - return retval; + pos = strrchr (full_name, '.'); + if (pos) { + name_space = full_name; + *pos = 0; + name = pos + 1; + } else { + name = full_name; + name_space = NULL; + } + + klass = mono_class_from_name (image, name_space ? name_space : "", name); + if (!klass) + return -1; + + mono_class_init (klass); + mono_class_setup_methods (klass); + return (gint64) (gssize) klass; } static guint64 -debugger_lookup_class (guint64 image_argument, guint64 token_argument) +debugger_run_finally (guint64 context_argument, G_GNUC_UNUSED guint64 dummy) { - MonoImage *image = (MonoImage *) GUINT_TO_POINTER ((gsize) image_argument); - guint32 token = (guint32) token_argument; - MonoClass *klass; - - klass = mono_class_get (image, token); - if (klass) - mono_class_init (klass); + mono_debugger_run_finally (GUINT_TO_POINTER ((gsize)context_argument)); + return 0; +} - return (guint64) (gsize) klass; +static guint64 +debugger_class_get_static_field_data (guint64 value) +{ + MonoClass *klass = GUINT_TO_POINTER ((gsize) value); + MonoVTable *vtable = mono_class_vtable (mono_domain_get (), klass); + return (guint64) (gsize) mono_vtable_get_static_field_data (vtable); } static guint64 -debugger_lookup_assembly (guint64 dummy_argument, const gchar *string_argument) +debugger_insert_method_breakpoint (guint64 method_argument, guint64 index) { - gint64 retval; + MonoMethod *method = GUINT_TO_POINTER ((gsize) method_argument); + MonoDebugMethodAddressList *info; mono_debugger_lock (); - retval = mono_debugger_lookup_assembly (string_argument); + + if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) { + const char *name = method->name; + MonoMethod *nm = NULL; + + if (method->klass->parent == mono_defaults.multicastdelegate_class) { + if (*name == 'I' && (strcmp (name, "Invoke") == 0)) + nm = mono_marshal_get_delegate_invoke (method, NULL); + else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) + nm = mono_marshal_get_delegate_begin_invoke (method); + else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) + nm = mono_marshal_get_delegate_end_invoke (method); + } + + if (!nm) { + mono_debugger_unlock (); + return 0; + } + + method = nm; + } + + info = mono_debugger_insert_method_breakpoint (method, index); + mono_debugger_unlock (); - return retval; + return (guint64) (gsize) info; } static guint64 -debugger_run_finally (guint64 context_argument, guint64 dummy) +debugger_insert_source_breakpoint (guint64 image_argument, guint64 token, guint64 index, + const gchar *class_name) { - mono_debugger_run_finally (GUINT_TO_POINTER (context_argument)); + MonoImage *image = GUINT_TO_POINTER ((gsize) image_argument); + MonoDebugMethodAddressList *info; + MonoClass *klass; + int i; + + mono_debugger_lock (); + + klass = mono_debugger_register_class_init_callback (image, class_name, token, index); + if (!klass || !klass->inited || !klass->methods) { + mono_debugger_unlock (); + return 0; + } + + for (i = 0; i < klass->method.count; i++) { + MonoMethod *method = klass->methods [i]; + + if (method->token != token) + continue; + + if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) { + const char *name = method->name; + MonoMethod *nm = NULL; + + if (method->klass->parent == mono_defaults.multicastdelegate_class) { + if (*name == 'I' && (strcmp (name, "Invoke") == 0)) + nm = mono_marshal_get_delegate_invoke (method, NULL); + else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) + nm = mono_marshal_get_delegate_begin_invoke (method); + else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) + nm = mono_marshal_get_delegate_end_invoke (method); + } + + if (!nm) { + mono_debugger_unlock (); + return 0; + } + + method = nm; + } + + info = mono_debug_lookup_method_addresses (method); + mono_debugger_unlock (); + return (guint64) (gsize) info; + } + + mono_debugger_unlock (); return 0; } +static void +debugger_remove_breakpoint (guint64 index, G_GNUC_UNUSED guint64 dummy) +{ + mono_debugger_lock (); + mono_debugger_remove_method_breakpoint (index); + mono_debugger_remove_class_init_callback (index); + mono_debugger_unlock (); +} + static guint64 -debugger_class_get_static_field_data (guint64 value) +debugger_register_class_init_callback (guint64 image_argument, guint64 token, guint64 index, + const gchar *class_name) { - MonoClass *klass = GUINT_TO_POINTER ((gsize) value); - MonoVTable *vtable = mono_class_vtable (mono_domain_get (), klass); - return (guint64) (gsize) mono_vtable_get_static_field_data (vtable); + MonoImage *image = GUINT_TO_POINTER ((gsize) image_argument); + MonoClass *klass; + + mono_debugger_lock (); + klass = mono_debugger_register_class_init_callback (image, class_name, token, index); + mono_debugger_unlock (); + return (guint64) (gsize) klass; } static void -debugger_event_handler (MonoDebuggerEvent event, guint64 data, guint64 arg) +debugger_remove_class_init_callback (guint64 index, G_GNUC_UNUSED guint64 dummy) { - mono_debugger_notification_function (event, data, arg); + mono_debugger_lock (); + mono_debugger_remove_class_init_callback (index); + mono_debugger_unlock (); } static guint64 -debugger_get_current_thread (void) +debugger_get_method_signature (guint64 method_arg, G_GNUC_UNUSED guint64 dummy) { - return (guint64) (gsize) mono_thread_current (); + MonoMethod *method = (MonoMethod *) GUINT_TO_POINTER ((gsize) method_arg); + MonoMethodSignature *sig; + + sig = mono_method_signature (method); + return (guint64) (gsize) sig; +} + +static void +debugger_event_handler (MonoDebuggerEvent event, guint64 data, guint64 arg) +{ + MONO_DEBUGGER__notification_function (event, data, arg); } static void debugger_gc_thread_created (pthread_t thread, void *stack_ptr) { - mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CREATED, + mono_debugger_event (MONO_DEBUGGER_EVENT_GC_THREAD_CREATED, (guint64) (gsize) stack_ptr, thread); } static void debugger_gc_thread_exited (pthread_t thread, void *stack_ptr) { - mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_EXITED, + mono_debugger_event (MONO_DEBUGGER_EVENT_GC_THREAD_EXITED, (guint64) (gsize) stack_ptr, thread); } static void debugger_gc_stop_world (void) { - mono_debugger_event ( - MONO_DEBUGGER_EVENT_ACQUIRE_GLOBAL_THREAD_LOCK, 0, 0); + mono_debugger_event (MONO_DEBUGGER_EVENT_ACQUIRE_GLOBAL_THREAD_LOCK, 0, 0); } static void debugger_gc_start_world (void) { - mono_debugger_event ( - MONO_DEBUGGER_EVENT_RELEASE_GLOBAL_THREAD_LOCK, 0, 0); + mono_debugger_event (MONO_DEBUGGER_EVENT_RELEASE_GLOBAL_THREAD_LOCK, 0, 0); } static GCThreadFunctions debugger_thread_vtable = { @@ -306,48 +458,68 @@ debugger_init_threads (void) gc_thread_vtable = &debugger_thread_vtable; } +#if 0 + static void debugger_finalize_threads (void) { gc_thread_vtable = NULL; } -static void -debugger_attach (void) -{ - mono_debugger_init (); - - mono_debugger_event_handler = debugger_event_handler; - mono_debugger_notification_function (MONO_DEBUGGER_EVENT_INITIALIZE_MANAGED_CODE, 0, 0); +#endif - debugger_init_threads (); - GC_mono_debugger_add_all_threads (); +static guint64 +debugger_init_code_buffer (void) +{ + if (!debugger_executable_code_buffer) + debugger_executable_code_buffer = mono_global_codeman_reserve (EXECUTABLE_CODE_BUFFER_SIZE); + return (guint64) (gsize) debugger_executable_code_buffer; } +extern MonoDebuggerInfo *MONO_DEBUGGER__debugger_info_ptr; +extern long MONO_DEBUGGER__using_debugger; + static void -debugger_detach (void) +debugger_initialize (void) { - mono_debugger_event_handler = NULL; - mono_debugger_notification_function = NULL; - debugger_finalize_threads (); } -static void -debugger_initialize (void) +/** + * Check whether we're running inside the debugger. + * + * There seems to be a bug in some versions of glibc which causes _dl_debug_state() being called with + * RT_CONSISTENT before relocations are done. + * + * If that happens, the debugger cannot read the `MONO_DEBUGGER__debugger_info' structure at the time + * the `libmono.so' library is loaded. + * + * As a workaround, the `mdb_debug_info' now also contains a global variable called + * `MONO_DEBUGGER__using_debugger' which may we set to 1 by the debugger to tell us that we're running + * inside the debugger. + * + * mini_init() checks this and calls mini_debugger_init() if necessary. + * + */ + +gboolean +mini_debug_running_inside_mdb (void) { + return MONO_DEBUGGER__using_debugger || mono_debug_using_mono_debugger (); } void -mono_debugger_init (void) +mini_debugger_init (void) { - /* - * Use mono_code_manager_new_dynamic() to create a new malloc()-based code manager - * and intentionally leak the memory on exit. - */ - debugger_codeman = mono_code_manager_new_dynamic (); - mono_debugger_notification_function = mono_debugger_create_notification_function (debugger_codeman); + if (mono_debugger_event_handler) { + g_warning (G_STRLOC ": duplicate call to mono_debugger_init()!"); + return; + } + + debugger_executable_code_buffer = mono_global_codeman_reserve (EXECUTABLE_CODE_BUFFER_SIZE); mono_debugger_event_handler = debugger_event_handler; + debugger_thread_abort_signal = mono_thread_get_abort_signal (); + /* * Use an indirect call so gcc can't optimize it away. */ @@ -357,10 +529,20 @@ mono_debugger_init (void) /* * Initialize the thread manager. + * + * NOTE: We only reference the `MONO_DEBUGGER__debugger_info_ptr' here to prevent the + * linker from removing the .mdb_debug_info section. */ - mono_debugger_notification_function (MONO_DEBUGGER_EVENT_INITIALIZE_THREAD_MANAGER, - GetCurrentThreadId (), 0); + mono_debugger_event (MONO_DEBUGGER_EVENT_INITIALIZE_THREAD_MANAGER, + (guint64) (gssize) MONO_DEBUGGER__debugger_info_ptr, 0); +} + +void +mini_debugger_set_attach_ok (void) +{ + debugger_thread_abort_signal = mono_thread_get_abort_signal (); + MONO_DEBUGGER__debugger_info.runtime_flags |= DEBUGGER_RUNTIME_FLAGS_ATTACH_OK; } typedef struct @@ -381,49 +563,36 @@ static guint32 main_thread_handler (gpointer user_data) { MainThreadArgs *main_args = (MainThreadArgs *) user_data; - gpointer function; - int retval; - - mono_debugger_notification_function (MONO_DEBUGGER_EVENT_REACHED_MAIN, - (guint64) (gsize) main_args->method, 0); - - retval = mono_runtime_run_main (main_args->method, main_args->argc, main_args->argv, NULL); - - /* - * This will never return. - */ - mono_debugger_notification_function (MONO_DEBUGGER_EVENT_MAIN_EXITED, 0, - (guint64) (gsize) retval); - return retval; + return mono_runtime_run_main (main_args->method, main_args->argc, main_args->argv, NULL); } int -mono_debugger_main (MonoDomain *domain, MonoAssembly *assembly, int argc, char **argv) +mini_debugger_main (MonoDomain *domain, MonoAssembly *assembly, int argc, char **argv) { MainThreadArgs main_args; MonoImage *image; - MonoMethod *main; + MonoMethod *main_method; /* * Get and compile the main function. */ image = mono_assembly_get_image (assembly); - main = mono_get_method (image, mono_image_get_entry_point (image), NULL); + main_method = mono_get_method (image, mono_image_get_entry_point (image), NULL); /* - * Reload symbol tables. + * Initialize managed code. */ - mono_debugger_notification_function (MONO_DEBUGGER_EVENT_INITIALIZE_MANAGED_CODE, 0, 0); - mono_debugger_unlock (); + mono_debugger_event (MONO_DEBUGGER_EVENT_INITIALIZE_MANAGED_CODE, + (guint64) (gssize) main_method, 0); /* * Start the main thread and wait until it's ready. */ main_args.domain = domain; - main_args.method = main; + main_args.method = main_method; main_args.argc = argc; main_args.argv = argv; @@ -438,7 +607,8 @@ mono_debugger_main (MonoDomain *domain, MonoAssembly *assembly, int argc, char * /* * This will never return. */ - mono_debugger_notification_function (MONO_DEBUGGER_EVENT_WRAPPER_MAIN, 0, 0); + mono_debugger_event (MONO_DEBUGGER_EVENT_WRAPPER_MAIN, 0, 0); return 0; } +#endif /* MONO_DEBUGGER_SUPPORTED */