X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fdebug-mini.c;h=29131f9c3c6f8741a0a31ba2ce37bcf32921864e;hb=f9467fdbd01a3bab5d2f2e0cf34567788303945a;hp=00babd5b2825a253e4225cf9d4bcea52ed50550f;hpb=4dd39f8376b10ee4f9e2bf707705b106c8345c5c;p=mono.git diff --git a/mono/mini/debug-mini.c b/mono/mini/debug-mini.c index 00babd5b282..29131f9c3c6 100644 --- a/mono/mini/debug-mini.c +++ b/mono/mini/debug-mini.c @@ -20,9 +20,7 @@ #include #include "debug-mini.h" -#ifdef HAVE_VALGRIND_H -#include -#endif +#include #ifdef MONO_DEBUGGER_SUPPORTED #include @@ -33,13 +31,6 @@ typedef struct { MonoMethodDesc *desc; } MiniDebugBreakpointInfo; -typedef struct -{ - guint64 index; - MonoMethod *method; - MonoDebugMethodAddressList *address_list; -} MiniDebugMethodBreakpointInfo; - typedef struct { MonoDebugMethodJitInfo *jit; @@ -48,6 +39,24 @@ typedef struct guint32 breakpoint_id; } MiniDebugMethodInfo; +typedef struct { + MonoObject *last_exception; + guint32 stopped_on_exception : 1; + guint32 stopped_on_unhandled : 1; +} MonoDebuggerExceptionState; + +typedef enum { + MONO_DEBUGGER_THREAD_FLAGS_NONE = 0, + MONO_DEBUGGER_THREAD_FLAGS_INTERNAL = 1, + MONO_DEBUGGER_THREAD_FLAGS_THREADPOOL = 2 +} MonoDebuggerThreadFlags; + +typedef enum { + MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_NONE = 0, + MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_IN_RUNTIME_INVOKE = 1, + MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_ABORT_REQUESTED = 2 +} MonoDebuggerInternalThreadFlags; + struct _MonoDebuggerThreadInfo { guint64 tid; guint64 lmf_addr; @@ -66,17 +75,27 @@ struct _MonoDebuggerThreadInfo { guint32 stack_size; guint32 signal_stack_size; + guint32 thread_flags; + /* * The debugger doesn't access anything beyond this point. */ + MonoDebuggerExceptionState exception_state; + + guint32 internal_flags; + MonoJitTlsData *jit_tls; - MonoThread *thread; + MonoInternalThread *thread; }; -MonoDebuggerThreadInfo *mono_debugger_thread_table = NULL; +typedef struct { + gpointer stack_pointer; + MonoObject *exception_obj; + guint32 stop; + guint32 stop_unhandled; +} MonoDebuggerExceptionInfo; -static void -mono_debugger_check_breakpoints (MonoMethod *method, MonoDebugMethodAddress *debug_info); +MonoDebuggerThreadInfo *mono_debugger_thread_table = NULL; static inline void record_line_number (MiniDebugMethodInfo *info, guint32 address, guint32 offset) @@ -89,16 +108,6 @@ record_line_number (MiniDebugMethodInfo *info, guint32 address, guint32 offset) g_array_append_val (info->line_numbers, lne); } -static void -mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit) -{ - g_free (jit->line_numbers); - g_free (jit->lexical_blocks); - g_free (jit->this_var); - g_free (jit->params); - g_free (jit->locals); - g_free (jit); -} void mono_debug_init_method (MonoCompile *cfg, MonoBasicBlock *start_block, guint32 breakpoint_id) @@ -127,7 +136,7 @@ mono_debug_open_method (MonoCompile *cfg) mono_class_init (cfg->method->klass); - header = mono_method_get_header (cfg->method); + header = cfg->header; g_assert (header); info->jit = jit = g_new0 (MonoDebugMethodJitInfo, 1); @@ -143,6 +152,8 @@ write_variable (MonoInst *inst, MonoDebugVarInfo *var) if (inst->opcode == OP_REGVAR) var->index = inst->dreg | MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER; + else if (inst->flags & MONO_INST_IS_DEAD) + var->index = MONO_DEBUG_VAR_ADDRESS_MODE_DEAD; else { /* the debug interface needs fixing to allow 0(%base) address */ var->index = inst->inst_basereg | MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET; @@ -248,6 +259,7 @@ mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit) g_free (addresses); g_free (lines); + mono_metadata_free_mh (header); #endif /* VALGRIND_ADD_LINE_INFO */ } @@ -270,7 +282,7 @@ mono_debug_close_method (MonoCompile *cfg) } method = cfg->method; - header = mono_method_get_header (method); + header = cfg->header; sig = mono_method_signature (method); jit = info->jit; @@ -278,21 +290,22 @@ mono_debug_close_method (MonoCompile *cfg) jit->epilogue_begin = cfg->epilog_begin; jit->code_size = cfg->code_len; - record_line_number (info, jit->epilogue_begin, header->code_size); + if (jit->epilogue_begin) + record_line_number (info, jit->epilogue_begin, header->code_size); jit->num_params = sig->param_count; jit->params = g_new0 (MonoDebugVarInfo, jit->num_params); for (i = 0; i < jit->num_locals; i++) - write_variable (cfg->varinfo [cfg->locals_start + i], &jit->locals [i]); + write_variable (cfg->locals [i], &jit->locals [i]); if (sig->hasthis) { jit->this_var = g_new0 (MonoDebugVarInfo, 1); - write_variable (cfg->varinfo [0], jit->this_var); + write_variable (cfg->args [0], jit->this_var); } for (i = 0; i < jit->num_params; i++) - write_variable (cfg->varinfo [i + sig->hasthis], &jit->params [i]); + write_variable (cfg->args [i + sig->hasthis], &jit->params [i]); jit->num_line_numbers = info->line_numbers->len; jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers); @@ -300,13 +313,10 @@ mono_debug_close_method (MonoCompile *cfg) for (i = 0; i < jit->num_line_numbers; i++) jit->line_numbers [i] = g_array_index (info->line_numbers, MonoDebugLineNumberEntry, i); - debug_info = mono_debug_add_method (method, jit, cfg->domain); + debug_info = mono_debug_add_method (cfg->method_to_register, jit, cfg->domain); mono_debug_add_vg_method (method, jit); - if (info->breakpoint_id) - mono_debugger_breakpoint_callback (method, info->breakpoint_id); - mono_debugger_check_breakpoints (method, debug_info); mono_debug_free_method_jit_info (jit); @@ -325,7 +335,7 @@ mono_debug_record_line_number (MonoCompile *cfg, MonoInst *ins, guint32 address) if (!info || !info->jit || !ins->cil_code) return; - header = mono_method_get_header (cfg->method); + header = cfg->header; g_assert (header); if ((ins->cil_code < header->code) || @@ -352,7 +362,7 @@ mono_debug_open_block (MonoCompile *cfg, MonoBasicBlock *bb, guint32 address) if (!info || !info->jit || !bb->cil_code) return; - header = mono_method_get_header (cfg->method); + header = cfg->header; g_assert (header); if ((bb->cil_code < header->code) || @@ -439,14 +449,16 @@ serialize_variable (MonoDebugVarInfo *var, guint8 *p, guint8 **endbuf) { guint32 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS; + encode_value (var->index, p, &p); + switch (flags) { case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER: - encode_value (var->index, p, &p); break; case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET: - encode_value (var->index, p, &p); encode_value (var->offset, p, &p); break; + case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD: + break; default: g_assert_not_reached (); } @@ -456,18 +468,17 @@ serialize_variable (MonoDebugVarInfo *var, guint8 *p, guint8 **endbuf) void mono_debug_serialize_debug_info (MonoCompile *cfg, guint8 **out_buf, guint32 *buf_len) { - MiniDebugMethodInfo *info; MonoDebugMethodJitInfo *jit; guint32 size, prev_offset, prev_native_offset; guint8 *buf, *p; int i; - info = (MiniDebugMethodInfo *) cfg->debug_info; - if (!info || !info->jit) { + /* Can't use cfg->debug_info as it is freed by close_method () */ + jit = mono_debug_find_method (cfg->method, mono_domain_get ()); + if (!jit) { *buf_len = 0; return; } - jit = info->jit; size = ((jit->num_params + jit->num_locals + 1) * 10) + (jit->num_line_numbers * 10) + 64; p = buf = g_malloc (size); @@ -518,6 +529,8 @@ deserialize_variable (MonoDebugVarInfo *var, guint8 *p, guint8 **endbuf) case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET: var->offset = decode_value (p, &p); break; + case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD: + break; default: g_assert_not_reached (); } @@ -577,6 +590,7 @@ deserialize_debug_info (MonoMethod *method, guint8 *code_start, guint8 *buf, gui prev_native_offset = native_offset; } + mono_metadata_free_mh (header); return jit; } @@ -674,81 +688,7 @@ mono_debug_print_vars (gpointer ip, gboolean only_arguments) print_var_info (&jit->locals [i], i, "", "Local"); } } -} - - -/* - * Debugger breakpoint interface. - * - * This interface is used to insert breakpoints on methods which are not yet JITed. - * The debugging code keeps a list of all such breakpoints and automatically inserts the - * breakpoint when the method is JITed. - */ - -static GPtrArray *method_breakpoints = NULL; - -MonoDebugMethodAddressList * -mono_debugger_insert_method_breakpoint (MonoMethod *method, guint64 index) -{ - MiniDebugMethodBreakpointInfo *info; - - info = g_new0 (MiniDebugMethodBreakpointInfo, 1); - info->method = method; - info->index = index; - - info->address_list = mono_debug_lookup_method_addresses (method); - - if (!method_breakpoints) - method_breakpoints = g_ptr_array_new (); - - g_ptr_array_add (method_breakpoints, info); - - return info->address_list; -} - -int -mono_debugger_remove_method_breakpoint (guint64 index) -{ - int i; - - if (!method_breakpoints) - return 0; - - for (i = 0; i < method_breakpoints->len; i++) { - MiniDebugMethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i); - - if (info->index != index) - continue; - - g_ptr_array_remove (method_breakpoints, info); - g_free (info->address_list); - g_free (info); - return 1; - } - - return 0; -} - -static void -mono_debugger_check_breakpoints (MonoMethod *method, MonoDebugMethodAddress *debug_info) -{ - int i; - - if (!method_breakpoints) - return; - - if (method->is_inflated) - method = ((MonoMethodInflated *) method)->declaring; - - for (i = 0; i < method_breakpoints->len; i++) { - MiniDebugMethodBreakpointInfo *info = g_ptr_array_index (method_breakpoints, i); - - if (method != info->method) - continue; - - mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT, - (guint64) (gsize) debug_info, info->index); - } + mono_debug_free_method_jit_info (jit); } /* @@ -819,7 +759,8 @@ mono_debugger_method_has_breakpoint (MonoMethod *method) { int i; - if (!breakpoints || (method->wrapper_type != MONO_WRAPPER_NONE)) + if (!breakpoints || ((method->wrapper_type != MONO_WRAPPER_NONE) && + (method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD))) return 0; for (i = 0; i < breakpoints->len; i++) { @@ -841,7 +782,7 @@ mono_debugger_breakpoint_callback (MonoMethod *method, guint32 index) } void -mono_debugger_thread_created (gsize tid, MonoThread *thread, MonoJitTlsData *jit_tls) +mono_debugger_thread_created (gsize tid, MonoThread *thread, MonoJitTlsData *jit_tls, gpointer func) { #ifdef MONO_DEBUGGER_SUPPORTED size_t stsize = 0; @@ -851,11 +792,13 @@ mono_debugger_thread_created (gsize tid, MonoThread *thread, MonoJitTlsData *jit if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) return; + mono_debugger_lock (); + mono_thread_get_stack_bounds (&staddr, &stsize); info = g_new0 (MonoDebuggerThreadInfo, 1); info->tid = tid; - info->thread = thread; + info->thread = thread->internal_thread; info->stack_start = (guint64) (gsize) staddr; info->signal_stack_start = (guint64) (gsize) jit_tls->signal_stack; info->stack_size = stsize; @@ -864,11 +807,18 @@ mono_debugger_thread_created (gsize tid, MonoThread *thread, MonoJitTlsData *jit info->lmf_addr = (guint64) (gsize) mono_get_lmf_addr (); info->jit_tls = jit_tls; + if (func) + info->thread_flags = MONO_DEBUGGER_THREAD_FLAGS_INTERNAL; + if (thread->internal_thread->threadpool_thread) + info->thread_flags |= MONO_DEBUGGER_THREAD_FLAGS_THREADPOOL; + info->next = mono_debugger_thread_table; mono_debugger_thread_table = info; mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CREATED, tid, (guint64) (gsize) info); + + mono_debugger_unlock (); #endif /* MONO_DEBUGGER_SUPPORTED */ } @@ -881,6 +831,8 @@ mono_debugger_thread_cleanup (MonoJitTlsData *jit_tls) if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) return; + mono_debugger_lock (); + for (ptr = &mono_debugger_thread_table; *ptr; ptr = &(*ptr)->next) { MonoDebuggerThreadInfo *info = *ptr; @@ -894,6 +846,8 @@ mono_debugger_thread_cleanup (MonoJitTlsData *jit_tls) g_free (info); break; } + + mono_debugger_unlock (); #endif } @@ -902,11 +856,13 @@ mono_debugger_extended_notification (MonoDebuggerEvent event, guint64 data, guin { #ifdef MONO_DEBUGGER_SUPPORTED MonoDebuggerThreadInfo **ptr; - MonoThread *thread = mono_thread_current (); + MonoInternalThread *thread = mono_thread_internal_current (); if (!mono_debug_using_mono_debugger ()) return; + mono_debugger_lock (); + for (ptr = &mono_debugger_thread_table; *ptr; ptr = &(*ptr)->next) { MonoDebuggerThreadInfo *info = *ptr; @@ -918,12 +874,341 @@ mono_debugger_extended_notification (MonoDebuggerEvent event, guint64 data, guin mono_debugger_event (event, data, arg); } + + mono_debugger_unlock (); #endif } void -mono_debugger_trampoline_compiled (MonoMethod *method, const guint8 *code) +mono_debugger_trampoline_compiled (const guint8 *trampoline, MonoMethod *method, const guint8 *code) { - mono_debugger_extended_notification (MONO_DEBUGGER_EVENT_TRAMPOLINE, +#ifdef MONO_DEBUGGER_SUPPORTED + struct { + const guint8 * trampoline; + MonoMethod *method; + const guint8 *code; + } info = { trampoline, method, code }; + + mono_debugger_extended_notification (MONO_DEBUGGER_EVENT_OLD_TRAMPOLINE, (guint64) (gsize) method, (guint64) (gsize) code); + mono_debugger_extended_notification (MONO_DEBUGGER_EVENT_TRAMPOLINE, + (guint64) (gsize) &info, 0); +#endif +} + +#if MONO_DEBUGGER_SUPPORTED +static MonoDebuggerThreadInfo * +find_debugger_thread_info (MonoInternalThread *thread) +{ + MonoDebuggerThreadInfo **ptr; + + for (ptr = &mono_debugger_thread_table; *ptr; ptr = &(*ptr)->next) { + MonoDebuggerThreadInfo *info = *ptr; + + if (info->thread == thread) + return info; + } + + return NULL; } +#endif + +MonoDebuggerExceptionAction +_mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc) +{ +#ifdef MONO_DEBUGGER_SUPPORTED + MonoDebuggerExceptionInfo exc_info; + MonoDebuggerThreadInfo *thread_info; + + if (!mono_debug_using_mono_debugger ()) + return MONO_DEBUGGER_EXCEPTION_ACTION_NONE; + + mono_debugger_lock (); + + thread_info = find_debugger_thread_info (mono_thread_internal_current ()); + if (!thread_info) { + mono_debugger_unlock (); + return MONO_DEBUGGER_EXCEPTION_ACTION_NONE; + } + + if ((thread_info->internal_flags & MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_ABORT_REQUESTED) != 0) { + mono_debugger_unlock (); + return MONO_DEBUGGER_EXCEPTION_ACTION_NONE; + } + + if (thread_info->exception_state.stopped_on_exception || + thread_info->exception_state.stopped_on_unhandled) { + thread_info->exception_state.stopped_on_exception = 0; + mono_debugger_unlock (); + return MONO_DEBUGGER_EXCEPTION_ACTION_NONE; + } + + /* Protect the exception object from being garbage collected. */ + + thread_info->exception_state.stopped_on_unhandled = 0; + thread_info->exception_state.stopped_on_exception = 1; + thread_info->exception_state.last_exception = exc; + + /* + * Backwards compatibility: + * + * Older debugger versions only know `exc_info.stop' and older runtime versions check + * `exc_info.stop != 0'. + * + * The debugger must check for `mono_debug_debugger_version >= 5' before accessing the + * `stop_unhandled' field. + */ + + exc_info.stack_pointer = stack; + exc_info.exception_obj = exc; + exc_info.stop = 0; + exc_info.stop_unhandled = 0; + + mono_debugger_event (MONO_DEBUGGER_EVENT_THROW_EXCEPTION, (guint64) (gsize) &exc_info, + (guint64) (gsize) addr); + + if (!exc_info.stop) { + thread_info->exception_state.stopped_on_exception = 0; + thread_info->exception_state.last_exception = NULL; + } + + mono_debugger_unlock (); + + if (exc_info.stop) + return MONO_DEBUGGER_EXCEPTION_ACTION_STOP; + else if (exc_info.stop_unhandled) + return MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED; +#endif + + return MONO_DEBUGGER_EXCEPTION_ACTION_NONE; +} + +gboolean +_mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc) +{ +#ifdef MONO_DEBUGGER_SUPPORTED + MonoDebuggerThreadInfo *thread_info; + + if (!mono_debug_using_mono_debugger ()) + return FALSE; + + if (exc) { + const gchar *name = mono_class_get_name (mono_object_get_class (exc)); + if (!strcmp (name, "ThreadAbortException")) + return FALSE; + } + + mono_debugger_lock (); + + thread_info = find_debugger_thread_info (mono_thread_internal_current ()); + if (!thread_info) { + mono_debugger_unlock (); + return FALSE; + } + + if ((thread_info->internal_flags & MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_ABORT_REQUESTED) != 0) { + mono_debugger_unlock (); + return FALSE; + } + + if (thread_info->exception_state.stopped_on_unhandled) { + thread_info->exception_state.stopped_on_unhandled = 0; + mono_debugger_unlock (); + return FALSE; + } + + thread_info->exception_state.stopped_on_unhandled = 1; + thread_info->exception_state.last_exception = exc; + + mono_debugger_event (MONO_DEBUGGER_EVENT_UNHANDLED_EXCEPTION, + (guint64) (gsize) exc, (guint64) (gsize) addr); + + return TRUE; +#else + return FALSE; +#endif +} + +/* + * mono_debugger_call_exception_handler: + * + * Called from mono_handle_exception_internal() to tell the debugger that we're about + * to invoke an exception handler. + * + * The debugger may choose to set a breakpoint at @addr. This is used if the user is + * single-stepping from a `try' into a `catch' block, for instance. + */ + +void +mono_debugger_call_exception_handler (gpointer addr, gpointer stack, MonoObject *exc) +{ +#ifdef MONO_DEBUGGER_SUPPORTED + MonoDebuggerThreadInfo *thread_info; + MonoDebuggerExceptionInfo exc_info; + + if (!mono_debug_using_mono_debugger ()) + return; + + mono_debugger_lock (); + + thread_info = find_debugger_thread_info (mono_thread_internal_current ()); + if (!thread_info) { + mono_debugger_unlock (); + return; + } + + if ((thread_info->internal_flags & MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_ABORT_REQUESTED) != 0) { + mono_debugger_unlock (); + return; + } + + // Prevent the object from being finalized. + thread_info->exception_state.last_exception = exc; + + exc_info.stack_pointer = stack; + exc_info.exception_obj = exc; + exc_info.stop = 0; + exc_info.stop_unhandled = 0; + + mono_debugger_event (MONO_DEBUGGER_EVENT_HANDLE_EXCEPTION, (guint64) (gsize) &exc_info, + (guint64) (gsize) addr); + + mono_debugger_unlock (); +#endif +} + +#ifdef MONO_DEBUGGER_SUPPORTED + +static gchar * +get_exception_message (MonoObject *exc) +{ + char *message = NULL; + MonoString *str; + MonoMethod *method; + MonoClass *klass; + gint i; + + if (mono_object_isinst (exc, mono_defaults.exception_class)) { + klass = exc->vtable->klass; + method = NULL; + while (klass && method == NULL) { + for (i = 0; i < klass->method.count; ++i) { + method = klass->methods [i]; + if (!strcmp ("ToString", method->name) && + mono_method_signature (method)->param_count == 0 && + method->flags & METHOD_ATTRIBUTE_VIRTUAL && + method->flags & METHOD_ATTRIBUTE_PUBLIC) { + break; + } + method = NULL; + } + + if (method == NULL) + klass = klass->parent; + } + + g_assert (method); + + str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL); + if (str) + message = mono_string_to_utf8 (str); + } + + return message; +} + +MonoObject * +mono_debugger_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc) +{ + MonoDebuggerThreadInfo *thread_info; + MonoDebuggerExceptionState saved_exception_state; + MonoObject *retval; + gchar *message; + + mono_debugger_lock (); + + thread_info = find_debugger_thread_info (mono_thread_internal_current ()); + if (!thread_info) { + mono_debugger_unlock (); + return NULL; + } + + saved_exception_state = thread_info->exception_state; + + thread_info->exception_state.last_exception = NULL; + thread_info->exception_state.stopped_on_unhandled = 0; + thread_info->exception_state.stopped_on_exception = 0; + + thread_info->internal_flags |= MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_IN_RUNTIME_INVOKE; + + mono_debugger_unlock (); + + if (!strcmp (method->name, ".ctor")) { + retval = obj = mono_object_new (mono_domain_get (), method->klass); + + mono_runtime_invoke (method, obj, params, exc); + } else + retval = mono_runtime_invoke (method, obj, params, exc); + + mono_debugger_lock (); + + thread_info->exception_state = saved_exception_state; + thread_info->internal_flags &= ~MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_IN_RUNTIME_INVOKE; + + if ((thread_info->internal_flags & MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_ABORT_REQUESTED) != 0) { + thread_info->internal_flags &= ~MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_ABORT_REQUESTED; + mono_thread_internal_reset_abort (thread_info->thread); + + mono_debugger_unlock (); + + *exc = NULL; + return NULL; + } + + mono_debugger_unlock (); + + if (!exc || (*exc == NULL)) + return retval; + + retval = *exc; + message = get_exception_message (*exc); + if (message) { + *exc = (MonoObject *) mono_string_new_wrapper (message); + g_free (message); + } + + return retval; +} + +gboolean +mono_debugger_abort_runtime_invoke () +{ + MonoInternalThread *thread = mono_thread_internal_current (); + MonoDebuggerThreadInfo *thread_info; + + mono_debugger_lock (); + + thread_info = find_debugger_thread_info (thread); + if (!thread_info) { + mono_debugger_unlock (); + return FALSE; + } + + if ((thread_info->internal_flags & MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_IN_RUNTIME_INVOKE) == 0) { + mono_debugger_unlock (); + return FALSE; + } + + if ((thread_info->internal_flags & MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_ABORT_REQUESTED) != 0) { + mono_debugger_unlock (); + return TRUE; + } + + thread_info->internal_flags |= MONO_DEBUGGER_INTERNAL_THREAD_FLAGS_ABORT_REQUESTED; + ves_icall_System_Threading_Thread_Abort (thread_info->thread, NULL); + + mono_debugger_unlock (); + return TRUE; +} + +#endif