X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fdebugger-agent.c;h=ebf7735578575cfda26e0b514b6960322c38e463;hb=7c89014866fd7d162336970a78a89c9f0ffd7a4d;hp=b5d3484cdeafcb1244cd7ff9ecc2662c7380efe1;hpb=fe8bdbcef723fc8c92afcc822aa4c12e34c21c0b;p=mono.git diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index b5d3484cdea..ebf77355785 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -72,6 +72,9 @@ int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD, #include #include #include +#include +#include +#include #include #include #include @@ -80,6 +83,15 @@ int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD, #include "debugger-agent.h" #include "mini.h" +/* +On iOS we can't use System.Environment.Exit () as it will do the wrong +shutdown sequence. +*/ +#if !defined (TARGET_IOS) +#define TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT +#endif + + #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED #define DISABLE_DEBUGGER_AGENT 1 #endif @@ -90,7 +102,7 @@ int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD, #ifndef DISABLE_DEBUGGER_AGENT -#include +#include /* Definitions to make backporting to 2.6 easier */ //#define MonoInternalThread MonoThread @@ -167,7 +179,6 @@ struct _InvokeData typedef struct { MonoThreadUnwindState context; - gpointer resume_event; /* This is computed on demand when it is requested using the wire protocol */ /* It is freed up when the thread is resumed */ int frame_count; @@ -246,9 +257,7 @@ typedef struct { * The context where single stepping should resume while the thread is suspended because * of an EXCEPTION event. */ - MonoContext catch_ctx; - - gboolean has_catch_ctx; + MonoThreadUnwindState catch_state; /* * The context which needs to be restored after handling a single step/breakpoint @@ -274,7 +283,7 @@ typedef struct { #define HEADER_LENGTH 11 #define MAJOR_VERSION 2 -#define MINOR_VERSION 22 +#define MINOR_VERSION 24 typedef enum { CMD_SET_VM = 1, @@ -456,6 +465,7 @@ typedef enum { CMD_METHOD_GET_BODY = 7, CMD_METHOD_RESOLVE_TOKEN = 8, CMD_METHOD_GET_CATTRS = 9, + CMD_METHOD_MAKE_GENERIC_METHOD = 10 } CmdMethod; typedef enum { @@ -476,6 +486,7 @@ typedef enum { CMD_TYPE_GET_METHODS_BY_NAME_FLAGS = 15, CMD_TYPE_GET_INTERFACES = 16, CMD_TYPE_GET_INTERFACE_MAP = 17, + CMD_TYPE_IS_INITIALIZED = 18 } CmdType; typedef enum { @@ -668,6 +679,9 @@ static gboolean protocol_version_set; /* A hash table containing all active domains */ static GHashTable *domains; +/* The number of times the runtime is suspended */ +static gint32 suspend_count; + static void transport_init (void); static void transport_connect (const char *address); static gboolean transport_handshake (void); @@ -905,7 +919,7 @@ mono_debugger_agent_init (void) event_requests = g_ptr_array_new (); - mono_mutex_init (&debugger_thread_exited_mutex, NULL); + mono_mutex_init (&debugger_thread_exited_mutex); mono_cond_init (&debugger_thread_exited_cond, NULL); mono_profiler_install ((MonoProfiler*)&debugger_profiler, runtime_shutdown); @@ -1317,8 +1331,7 @@ socket_transport_connect (const char *address) #endif } - disconnected = !transport_handshake (); - if (disconnected) + if (!transport_handshake ()) exit (1); } @@ -1378,6 +1391,15 @@ static DebuggerTransport *transport; static DebuggerTransport transports [MAX_TRANSPORTS]; static int ntransports; +void +mono_debugger_agent_register_transport (DebuggerTransport *trans); + +void +mono_debugger_agent_register_transport (DebuggerTransport *trans) +{ + register_transport (trans); +} + static void register_transport (DebuggerTransport *trans) { @@ -1440,6 +1462,12 @@ transport_recv (void *buf, int len) return transport->recv (buf, len); } +gboolean +mono_debugger_agent_transport_handshake (void) +{ + return transport_handshake (); +} + static gboolean transport_handshake (void) { @@ -1447,6 +1475,8 @@ transport_handshake (void) guint8 buf [128]; int res; + disconnected = TRUE; + /* Write handshake message */ sprintf (handshake_msg, "DWP-Handshake"); do { @@ -1475,7 +1505,7 @@ transport_handshake (void) * Set TCP_NODELAY on the socket so the client receives events/command * results immediately. */ - { + if (conn_fd) { int flag = 1; int result = setsockopt (conn_fd, IPPROTO_TCP, @@ -1488,6 +1518,7 @@ transport_handshake (void) set_keepalive (); #endif + disconnected = FALSE; return TRUE; } @@ -1788,6 +1819,7 @@ objrefs_cleanup (void) } static GHashTable *obj_to_objref; +static MonoGHashTable *suspended_objs; /* * Return an ObjRef for OBJ. @@ -1804,8 +1836,18 @@ get_objref (MonoObject *obj) mono_loader_lock (); - if (!obj_to_objref) + if (!obj_to_objref) { obj_to_objref = g_hash_table_new (NULL, NULL); + suspended_objs = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC); + MONO_GC_REGISTER_ROOT_FIXED (suspended_objs); + } + + if (suspend_count) { + /* + * Have to keep object refs created during suspensions alive for the duration of the suspension, so GCs during invokes don't collect them. + */ + mono_g_hash_table_insert (suspended_objs, obj, NULL); + } /* FIXME: The tables can grow indefinitely */ @@ -1852,6 +1894,20 @@ get_objref (MonoObject *obj) return ref; } +static gboolean +true_pred (gpointer key, gpointer value, gpointer user_data) +{ + return TRUE; +} + +static void +clear_suspended_objs (void) +{ + mono_loader_lock (); + mono_g_hash_table_foreach_remove (suspended_objs, true_pred, NULL); + mono_loader_unlock (); +} + static inline int get_objid (MonoObject *obj) { @@ -2151,7 +2207,17 @@ buffer_add_ptr_id (Buffer *buf, MonoDomain *domain, IdType type, gpointer val) static inline MonoClass* decode_typeid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, int *err) { - return decode_ptr_id (buf, endbuf, limit, ID_TYPE, domain, err); + MonoClass *klass; + + klass = decode_ptr_id (buf, endbuf, limit, ID_TYPE, domain, err); + if (G_UNLIKELY (log_level >= 2) && klass) { + char *s; + + s = mono_type_full_name (&klass->byval_arg); + DEBUG(2, fprintf (log_file, "[dbg] recv class [%s]\n", s)); + g_free (s); + } + return klass; } static inline MonoAssembly* @@ -2194,12 +2260,29 @@ static inline void buffer_add_typeid (Buffer *buf, MonoDomain *domain, MonoClass *klass) { buffer_add_ptr_id (buf, domain, ID_TYPE, klass); + if (G_UNLIKELY (log_level >= 2) && klass) { + char *s; + + s = mono_type_full_name (&klass->byval_arg); + if (GetCurrentThreadId () == debugger_thread_id) + DEBUG(2, fprintf (log_file, "[dbg] send class [%s]\n", s)); + else + DEBUG(2, fprintf (log_file, "[%p] send class [%s]\n", (gpointer)GetCurrentThreadId (), s)); + g_free (s); + } } static inline void buffer_add_methodid (Buffer *buf, MonoDomain *domain, MonoMethod *method) { buffer_add_ptr_id (buf, domain, ID_METHOD, method); + if (G_UNLIKELY (log_level >= 2) && method) { + char *s; + + s = mono_method_full_name (method, 1); + DEBUG(2, fprintf (log_file, "[dbg] send method [%s]\n", s)); + g_free (s); + } } static inline void @@ -2258,9 +2341,6 @@ save_thread_context (MonoContext *ctx) mono_thread_state_init_from_current (&tls->context); } -/* The number of times the runtime is suspended */ -static gint32 suspend_count; - /* Number of threads suspended */ /* * If this is equal to the size of thread_to_tls, the runtime is considered @@ -2279,7 +2359,7 @@ static MonoSemType suspend_sem; static void suspend_init (void) { - mono_mutex_init (&suspend_mutex, NULL); + mono_mutex_init (&suspend_mutex); mono_cond_init (&suspend_cond, NULL); MONO_SEM_INIT (&suspend_sem, 0); } @@ -2535,13 +2615,19 @@ notify_thread (gpointer key, gpointer value, gpointer user_data) MonoJitInfo *ji; info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE); - g_assert (info); - - ji = mono_jit_info_table_find (info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN], MONO_CONTEXT_GET_IP (&info->suspend_state.ctx)); + if (!info) { + DEBUG(1, fprintf (log_file, "[%p] mono_thread_info_suspend_sync () failed for %p...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid)); + /* + * Attached thread which died without detaching. + */ + tls->terminated = TRUE; + } else { + ji = mono_jit_info_table_find (info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN], MONO_CONTEXT_GET_IP (&info->suspend_state.ctx)); - thread_interrupt (tls, info, NULL, ji); + thread_interrupt (tls, info, NULL, ji); - mono_thread_info_resume (mono_thread_info_get_tid (info)); + mono_thread_info_resume (mono_thread_info_get_tid (info)); + } } else { res = mono_thread_kill (thread, mono_thread_get_abort_signal ()); if (res) { @@ -2625,6 +2711,12 @@ suspend_vm (void) mono_mutex_unlock (&suspend_mutex); + if (suspend_count == 1) + /* + * Suspend creation of new threadpool threads, since they cannot run + */ + mono_thread_pool_suspend (); + mono_loader_unlock (); } @@ -2663,6 +2755,9 @@ resume_vm (void) mono_mutex_unlock (&suspend_mutex); //g_assert (err == 0); + if (suspend_count == 0) + mono_thread_pool_resume (); + mono_loader_unlock (); } @@ -2883,16 +2978,13 @@ get_seq_points (MonoDomain *domain, MonoMethod *method) return seq_points; } -static MonoSeqPointInfo* -find_seq_points (MonoDomain *domain, MonoMethod *method) +static void +no_seq_points_found (MonoMethod *method) { - MonoSeqPointInfo *seq_points = get_seq_points (domain, method); - - if (!seq_points) - printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method, TRUE)); - g_assert (seq_points); - - return seq_points; + /* + * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space. + */ + printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method, TRUE)); } /* @@ -2906,7 +2998,13 @@ find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, g MonoSeqPointInfo *seq_points; int i; - seq_points = find_seq_points (domain, method); + seq_points = get_seq_points (domain, method); + if (!seq_points) { + if (info) + *info = NULL; + return NULL; + } + g_assert (seq_points); if (info) *info = seq_points; @@ -2929,9 +3027,11 @@ find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, g MonoSeqPointInfo *seq_points; int i; - seq_points = find_seq_points (domain, method); + seq_points = get_seq_points (domain, method); if (info) *info = seq_points; + if (!seq_points) + return NULL; for (i = seq_points->len - 1; i >= 0; --i) { if (seq_points->seq_points [i].native_offset <= native_offset) @@ -3294,6 +3394,15 @@ create_event_list (EventKind event, GPtrArray *reqs, MonoJitInfo *ji, EventInfo s = strdup_tolower (sinfo->source_file); if (g_hash_table_lookup (mod->data.source_files, s)) found = TRUE; + else { + char *s2 = g_path_get_basename (sinfo->source_file); + char *s3 = strdup_tolower (s2); + + if (g_hash_table_lookup (mod->data.source_files, s3)) + found = TRUE; + g_free (s2); + g_free (s3); + } g_free (s); } g_ptr_array_free (source_file_list, TRUE); @@ -3393,6 +3502,7 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx GSList *l; MonoDomain *domain = mono_domain_get (); MonoThread *thread = NULL; + MonoObject *keepalive_obj = NULL; gboolean send_success = FALSE; static int ecount; int nevents; @@ -3495,6 +3605,11 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx case EVENT_KIND_EXCEPTION: { EventInfo *ei = arg; buffer_add_objid (&buf, ei->exc); + /* + * We are not yet suspending, so get_objref () will not keep this object alive. So we need to do it + * later after the suspension. (#12494). + */ + keepalive_obj = ei->exc; break; } case EVENT_KIND_USER_BREAK: @@ -3536,6 +3651,10 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx */ save_thread_context (ctx); suspend_vm (); + + if (keepalive_obj) + /* This will keep this object alive */ + get_objref (keepalive_obj); } send_success = send_packet (CMD_SET_EVENT, CMD_COMPOSITE, &buf); @@ -3646,7 +3765,6 @@ thread_startup (MonoProfiler *prof, uintptr_t tid) g_assert (!tls); // FIXME: Free this somewhere tls = g_new0 (DebuggerTlsData, 1); - tls->resume_event = CreateEvent (NULL, FALSE, FALSE, NULL); MONO_GC_REGISTER_ROOT_SINGLE (tls->thread); tls->thread = thread; mono_native_tls_set_value (debugger_tls_id, tls); @@ -3969,11 +4087,13 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo if (error) { mono_error_set_error (error, MONO_ERROR_GENERIC, "%s", s); + g_warning ("%s", s); g_free (s); return; } else { - g_error ("%s", s); + g_warning ("%s", s); g_free (s); + return; } } @@ -3992,7 +4112,9 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo g_hash_table_insert (bp_locs, inst->ip, GINT_TO_POINTER (count + 1)); mono_loader_unlock (); - if (count == 0) { + if (sp->native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) { + DEBUG (1, fprintf (log_file, "[dbg] Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp->il_offset)); + } else if (count == 0) { #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED mono_arch_set_breakpoint (ji, inst->ip); #else @@ -4018,7 +4140,7 @@ remove_breakpoint (BreakpointInstance *inst) g_assert (count > 0); - if (count == 1) { + if (count == 1 && inst->native_offset != SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) { mono_arch_clear_breakpoint (ji, ip); } #else @@ -4288,6 +4410,42 @@ clear_breakpoints_for_domain (MonoDomain *domain) mono_loader_unlock (); } +/* + * ss_update: + * + * Return FALSE if single stepping needs to continue because we are at the same line. + */ +static gboolean +ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp) +{ + MonoDebugMethodInfo *minfo; + MonoDebugSourceLocation *loc = NULL; + gboolean hit = TRUE; + + if (req->size != STEP_SIZE_LINE) + return TRUE; + + /* Have to check whenever a different source line was reached */ + minfo = mono_debug_lookup_method (ji->method); + + if (minfo) + loc = mono_debug_symfile_lookup_location (minfo, sp->il_offset); + + if (!loc || (loc && ji->method == ss_req->last_method && loc->row == ss_req->last_line)) { + /* Have to continue single stepping */ + DEBUG(1, fprintf (log_file, "[%p] Same source line, continuing single stepping.\n", (gpointer)GetCurrentThreadId ())); + hit = FALSE; + } + + if (loc) { + ss_req->last_method = ji->method; + ss_req->last_line = loc->row; + mono_debug_free_source_location (loc); + } + + return hit; +} + static gboolean breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly) { @@ -4339,6 +4497,9 @@ process_breakpoint_inner (DebuggerTlsData *tls) * the offset recorded in the seq point map, so find the prev seq point before ip. */ sp = find_prev_seq_point_for_native_offset (mono_domain_get (), ji->method, native_offset, &info); + if (!sp) + no_seq_points_found (ji->method); + g_assert (sp); DEBUG(1, fprintf (log_file, "[%p] Breakpoint hit, method=%s, ip=%p, offset=0x%x, sp il offset=0x%x.\n", (gpointer)GetCurrentThreadId (), ji->method->name, ip, native_offset, sp ? sp->il_offset : -1)); @@ -4372,31 +4533,9 @@ process_breakpoint_inner (DebuggerTlsData *tls) for (i = 0; i < ss_reqs_orig->len; ++i) { EventRequest *req = g_ptr_array_index (ss_reqs_orig, i); SingleStepReq *ss_req = req->info; - gboolean hit = TRUE; - - if (ss_req->size == STEP_SIZE_LINE) { - /* Have to check whenever a different source line was reached */ - MonoDebugMethodInfo *minfo; - MonoDebugSourceLocation *loc = NULL; - - minfo = mono_debug_lookup_method (ji->method); - - if (minfo) - loc = mono_debug_symfile_lookup_location (minfo, sp->il_offset); - - if (!loc || (loc && ji->method == ss_req->last_method && loc->row == ss_req->last_line)) { - /* Have to continue single stepping */ - DEBUG(1, fprintf (log_file, "[%p] Same source line, continuing single stepping.\n", (gpointer)GetCurrentThreadId ())); - hit = FALSE; - } - - if (loc) { - ss_req->last_method = ji->method; - ss_req->last_line = loc->row; - mono_debug_free_source_location (loc); - } - } + gboolean hit; + hit = ss_update (ss_req, ji, sp); if (hit) g_ptr_array_add (ss_reqs, req); @@ -4468,6 +4607,8 @@ resume_from_signal_handler (void *sigctx, void *func) /* Save the original context in TLS */ // FIXME: This might not work on an altstack ? tls = mono_native_tls_get_value (debugger_tls_id); + if (!tls) + fprintf (stderr, "Thread %p is not attached to the JIT.\n", (gpointer)GetCurrentThreadId ()); g_assert (tls); // FIXME: MonoContext usually doesn't include the fp registers, so these are @@ -4613,41 +4754,8 @@ process_single_step_inner (DebuggerTlsData *tls) return; il_offset = sp->il_offset; - // FIXME: No tests fail if this is disabled -#if 0 - if (ss_req->size == STEP_SIZE_LINE) { - // FIXME: - NOT_IMPLEMENTED; - - /* Step until a different source line is reached */ - MonoDebugMethodInfo *minfo; - - minfo = mono_debug_lookup_method (ji->method); - - if (minfo) { - MonoDebugSourceLocation *loc = mono_debug_symfile_lookup_location (minfo, il_offset); - - if (loc && ji->method == ss_req->last_method && loc->row == ss_req->last_line) { - mono_debug_free_source_location (loc); - return; - } - if (!loc) - /* - * Step until we reach a location with line number info, - * otherwise the client can't show a location. - * This can happen for example with statics initialized inline - * outside of a cctor. - */ - return; - - if (loc) { - ss_req->last_method = ji->method; - ss_req->last_line = loc->row; - mono_debug_free_source_location (loc); - } - } - } -#endif + if (!ss_update (ss_req, ji, sp)) + return; /* Start single stepping again from the current sequence point */ ss_start (ss_req, ji->method, sp, info, ctx, tls, FALSE); @@ -4785,6 +4893,8 @@ stop_single_stepping (void) if (val == 0) mono_arch_stop_single_stepping (); + if (ss_req != NULL) + ss_invoke_addr = NULL; #else g_assert_not_reached (); #endif @@ -4866,13 +4976,16 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI // There could be method calls before the next seq point in the caller when using nested calls //enable_global = TRUE; } else { - while (sp && sp->next_len == 0) { + if (sp && sp->next_len == 0) { sp = NULL; - if (frame_index < tls->frame_count) { + while (frame_index < tls->frame_count) { StackFrame *frame = tls->frames [frame_index]; method = frame->method; sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info); + if (sp && sp->next_len != 0) + break; + sp = NULL; frame_index ++; } } @@ -4974,7 +5087,7 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ g_assert (tls->context.valid); ss_req->start_sp = ss_req->last_sp = MONO_CONTEXT_GET_SP (&tls->context.ctx); - if (tls->has_catch_ctx) { + if (tls->catch_state.valid) { gboolean res; StackFrameInfo frame; MonoContext new_ctx; @@ -4985,7 +5098,7 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ */ /* Find the the jit info for the catch context */ - res = mono_find_jit_info_ext (mono_domain_get (), thread->jit_data, NULL, &tls->catch_ctx, &new_ctx, NULL, &lmf, NULL, &frame); + res = mono_find_jit_info_ext (tls->catch_state.unwind_data [MONO_UNWIND_DATA_DOMAIN], thread->jit_data, NULL, &tls->catch_state.ctx, &new_ctx, NULL, &lmf, NULL, &frame); g_assert (res); g_assert (frame.type == FRAME_TYPE_MANAGED); @@ -4994,6 +5107,8 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ * point after ip. */ sp = find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info); + if (!sp) + no_seq_points_found (frame.method); g_assert (sp); method = frame.method; @@ -5038,6 +5153,8 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ if (!method && frame->il_offset != -1) { /* FIXME: Sort the table and use a binary search */ sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info); + if (!sp) + no_seq_points_found (frame->method); g_assert (sp); method = frame->method; } @@ -5095,13 +5212,35 @@ mono_debugger_agent_debug_log_is_enabled (void) return agent_config.enabled; } +#ifdef PLATFORM_ANDROID +void +mono_debugger_agent_unhandled_exception (MonoException *exc) +{ + int suspend_policy; + GSList *events; + EventInfo ei; + + if (!inited) + return; + + memset (&ei, 0, sizeof (EventInfo)); + ei.exc = (MonoObject*)exc; + + mono_loader_lock (); + events = create_event_list (EVENT_KIND_EXCEPTION, NULL, NULL, &ei, &suspend_policy); + mono_loader_unlock (); + + process_event (EVENT_KIND_EXCEPTION, &ei, 0, NULL, events, suspend_policy); +} +#endif + void mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch_ctx) { - int suspend_policy; + int i, j, suspend_policy; GSList *events; - MonoJitInfo *ji; + MonoJitInfo *ji, *catch_ji; EventInfo ei; DebuggerTlsData *tls = NULL; @@ -5164,23 +5303,55 @@ mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx return; ji = mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (throw_ctx), NULL); + if (catch_ctx) + catch_ji = mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (catch_ctx), NULL); + else + catch_ji = NULL; ei.exc = (MonoObject*)exc; ei.caught = catch_ctx != NULL; mono_loader_lock (); + + /* Treat exceptions which are caught in non-user code as unhandled */ + for (i = 0; i < event_requests->len; ++i) { + EventRequest *req = g_ptr_array_index (event_requests, i); + if (req->event_kind != EVENT_KIND_EXCEPTION) + continue; + + for (j = 0; j < req->nmodifiers; ++j) { + Modifier *mod = &req->modifiers [j]; + + if (mod->kind == MOD_KIND_ASSEMBLY_ONLY && catch_ji) { + int k; + gboolean found = FALSE; + MonoAssembly **assemblies = mod->data.assemblies; + + if (assemblies) { + for (k = 0; assemblies [k]; ++k) + if (assemblies [k] == catch_ji->method->klass->image->assembly) + found = TRUE; + } + if (!found) + ei.caught = FALSE; + } + } + } + events = create_event_list (EVENT_KIND_EXCEPTION, NULL, ji, &ei, &suspend_policy); mono_loader_unlock (); - if (tls && catch_ctx) { - tls->catch_ctx = *catch_ctx; - tls->has_catch_ctx = TRUE; + if (tls && ei.caught && catch_ctx) { + memset (&tls->catch_state, 0, sizeof (tls->catch_state)); + tls->catch_state.ctx = *catch_ctx; + tls->catch_state.unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get (); + tls->catch_state.valid = TRUE; } process_event (EVENT_KIND_EXCEPTION, &ei, 0, throw_ctx, events, suspend_policy); if (tls) - tls->has_catch_ctx = FALSE; + tls->catch_state.valid = FALSE; } void @@ -5251,6 +5422,12 @@ buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain, MonoObject *obj; if (t->byref) { + if (!(*(void**)addr)) { + /* This can happen with compiler generated locals */ + //printf ("%s\n", mono_type_full_name (t)); + buffer_add_byte (buf, VALUE_TYPE_ID_NULL); + return; + } g_assert (*(void**)addr); addr = *(void**)addr; } @@ -5398,7 +5575,7 @@ obj_is_of_type (MonoObject *obj, MonoType *t) { MonoClass *klass = obj->vtable->klass; if (!mono_class_is_assignable_from (mono_class_from_mono_type (t), klass)) { - if (klass == mono_defaults.transparent_proxy_class) { + if (mono_class_is_transparent_proxy (klass)) { klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class; if (mono_class_is_assignable_from (mono_class_from_mono_type (t), klass)) { return TRUE; @@ -5412,6 +5589,49 @@ obj_is_of_type (MonoObject *obj, MonoType *t) static ErrorCode decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit); +static ErrorCode +decode_vtype (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit) +{ + gboolean is_enum; + MonoClass *klass; + MonoClassField *f; + int nfields; + gpointer iter = NULL; + MonoDomain *d; + int err; + + is_enum = decode_byte (buf, &buf, limit); + /* Enums are sent as a normal vtype */ + if (is_enum) + return ERR_NOT_IMPLEMENTED; + klass = decode_typeid (buf, &buf, limit, &d, &err); + if (err) + return err; + + if (t && klass != mono_class_from_mono_type (t)) { + char *name = mono_type_full_name (t); + char *name2 = mono_type_full_name (&klass->byval_arg); + DEBUG(1, fprintf (log_file, "[%p] Expected value of type %s, got %s.\n", (gpointer)GetCurrentThreadId (), name, name2)); + g_free (name); + g_free (name2); + return ERR_INVALID_ARGUMENT; + } + + nfields = decode_int (buf, &buf, limit); + while ((f = mono_class_get_fields (klass, &iter))) { + if (f->type->attrs & FIELD_ATTRIBUTE_STATIC) + continue; + if (mono_field_is_deleted (f)) + continue; + err = decode_value (f->type, domain, (guint8*)addr + f->offset - sizeof (MonoObject), buf, &buf, limit); + if (err) + return err; + nfields --; + } + g_assert (nfields == 0); + return 0; +} + static ErrorCode decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit) { @@ -5484,38 +5704,11 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, g_assert (type == MONO_TYPE_VALUETYPE); /* Fall through */ handle_vtype: - case MONO_TYPE_VALUETYPE: { - gboolean is_enum = decode_byte (buf, &buf, limit); - MonoClass *klass; - MonoClassField *f; - int nfields; - gpointer iter = NULL; - MonoDomain *d; - - /* Enums are sent as a normal vtype */ - if (is_enum) - return ERR_NOT_IMPLEMENTED; - klass = decode_typeid (buf, &buf, limit, &d, &err); + case MONO_TYPE_VALUETYPE: + err = decode_vtype (t, domain, addr,buf, &buf, limit); if (err) return err; - - if (klass != mono_class_from_mono_type (t)) - return ERR_INVALID_ARGUMENT; - - nfields = decode_int (buf, &buf, limit); - while ((f = mono_class_get_fields (klass, &iter))) { - if (f->type->attrs & FIELD_ATTRIBUTE_STATIC) - continue; - if (mono_field_is_deleted (f)) - continue; - err = decode_value (f->type, domain, (guint8*)addr + f->offset - sizeof (MonoObject), buf, &buf, limit); - if (err) - return err; - nfields --; - } - g_assert (nfields == 0); break; - } handle_ref: default: if (MONO_TYPE_IS_REFERENCE (t)) { @@ -5540,7 +5733,44 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, mono_gc_wbarrier_generic_store (addr, obj); } else if (type == VALUE_TYPE_ID_NULL) { *(MonoObject**)addr = NULL; + } else if (type == MONO_TYPE_VALUETYPE) { + guint8 *buf2; + gboolean is_enum; + MonoClass *klass; + MonoDomain *d; + guint8 *vtype_buf; + int vtype_buf_size; + + /* This can happen when round-tripping boxed vtypes */ + /* + * Obtain vtype class. + * Same as the beginning of the handle_vtype case above. + */ + buf2 = buf; + is_enum = decode_byte (buf, &buf, limit); + if (is_enum) + return ERR_NOT_IMPLEMENTED; + klass = decode_typeid (buf, &buf, limit, &d, &err); + if (err) + return err; + + /* Decode the vtype into a temporary buffer, then box it. */ + vtype_buf_size = mono_class_value_size (klass, NULL); + vtype_buf = g_malloc0 (vtype_buf_size); + g_assert (vtype_buf); + + buf = buf2; + err = decode_vtype (NULL, domain, vtype_buf, buf, &buf, limit); + if (err) { + g_free (vtype_buf); + return err; + } + *(MonoObject**)addr = mono_value_box (d, klass, vtype_buf); + g_free (vtype_buf); } else { + char *name = mono_type_full_name (t); + DEBUG(1, fprintf (log_file, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer)GetCurrentThreadId (), name, type)); + g_free (name); return ERR_INVALID_ARGUMENT; } } else { @@ -5596,11 +5826,11 @@ decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 } static void -add_var (Buffer *buf, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, gboolean as_vtype) +add_var (Buffer *buf, MonoDebugMethodJitInfo *jit, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, gboolean as_vtype) { guint32 flags; int reg; - guint8 *addr; + guint8 *addr, *gaddr; mgreg_t reg_val; flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS; @@ -5623,6 +5853,59 @@ add_var (Buffer *buf, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, Mono case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD: NOT_IMPLEMENTED; break; + case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR: + /* Same as regoffset, but with an indirection */ + addr = (gpointer)mono_arch_context_get_int_reg (ctx, reg); + addr += (gint32)var->offset; + + gaddr = *(gpointer*)addr; + g_assert (gaddr); + buffer_add_value_full (buf, t, gaddr, domain, as_vtype); + break; + case MONO_DEBUG_VAR_ADDRESS_MODE_GSHAREDVT_LOCAL: { + MonoDebugVarInfo *info_var = jit->gsharedvt_info_var; + MonoDebugVarInfo *locals_var = jit->gsharedvt_locals_var; + MonoGSharedVtMethodRuntimeInfo *info; + guint8 *locals; + int idx; + + idx = reg; + + g_assert (info_var); + g_assert (locals_var); + + flags = info_var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS; + reg = info_var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS; + if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET) { + addr = (gpointer)mono_arch_context_get_int_reg (ctx, reg); + addr += (gint32)info_var->offset; + info = *(gpointer*)addr; + } else if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER) { + info = (gpointer)mono_arch_context_get_int_reg (ctx, reg); + } else { + g_assert_not_reached (); + } + g_assert (info); + + flags = locals_var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS; + reg = locals_var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS; + if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET) { + addr = (gpointer)mono_arch_context_get_int_reg (ctx, reg); + addr += (gint32)locals_var->offset; + locals = *(gpointer*)addr; + } else if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER) { + locals = (gpointer)mono_arch_context_get_int_reg (ctx, reg); + } else { + g_assert_not_reached (); + } + g_assert (locals); + + addr = locals + GPOINTER_TO_INT (info->entries [idx]); + + buffer_add_value_full (buf, t, addr, domain, as_vtype); + break; + } + default: g_assert_not_reached (); } @@ -5633,7 +5916,7 @@ set_var (MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domai { guint32 flags; int reg, size; - guint8 *addr; + guint8 *addr, *gaddr; flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS; reg = var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS; @@ -5707,6 +5990,16 @@ set_var (MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domai // FIXME: Write barriers mono_gc_memmove (addr, val, size); break; + case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR: + /* Same as regoffset, but with an indirection */ + addr = (gpointer)mono_arch_context_get_int_reg (ctx, reg); + addr += (gint32)var->offset; + + gaddr = *(gpointer*)addr; + g_assert (gaddr); + // FIXME: Write barriers + mono_gc_memmove (gaddr, val, size); + break; case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD: NOT_IMPLEMENTED; break; @@ -5869,8 +6162,10 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8 if (m->klass->valuetype && (m->flags & METHOD_ATTRIBUTE_STATIC)) { /* Should be null */ int type = decode_byte (p, &p, end); - if (type != VALUE_TYPE_ID_NULL) + if (type != VALUE_TYPE_ID_NULL) { + DEBUG (1, fprintf (log_file, "[%p] Error: Static vtype method invoked with this argument.\n", (gpointer)GetCurrentThreadId ())); return ERR_INVALID_ARGUMENT; + } memset (this_buf, 0, mono_class_instance_size (m->klass)); } else { err = decode_value (&m->klass->byval_arg, domain, this_buf, p, &p, end); @@ -6114,7 +6409,7 @@ invoke_method (void) tls->resume_count -= invoke->suspend_count; } - DEBUG (1, fprintf (log_file, "[%p] Invoke finished, resume_count = %d.\n", (gpointer)GetCurrentThreadId (), tls->resume_count)); + DEBUG (1, fprintf (log_file, "[%p] Invoke finished (%d), resume_count = %d.\n", (gpointer)GetCurrentThreadId (), err, tls->resume_count)); /* * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE: @@ -6228,6 +6523,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) if (suspend_count == 0) return ERR_NOT_SUSPENDED; resume_vm (); + clear_suspended_objs (); break; case CMD_VM_DISPOSE: /* Clear all event requests */ @@ -6247,7 +6543,9 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) case CMD_VM_EXIT: { MonoInternalThread *thread; DebuggerTlsData *tls; +#ifdef TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT MonoClass *env_class; +#endif MonoMethod *exit_method = NULL; gpointer *args; int exit_code; @@ -6278,9 +6576,11 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) suspend_vm (); wait_for_suspend (); +#ifdef TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT env_class = mono_class_from_name (mono_defaults.corlib, "System", "Environment"); if (env_class) exit_method = mono_class_get_method_from_name (env_class, "Exit", 1); +#endif mono_loader_lock (); thread = mono_g_hash_table_find (tid_to_thread, is_really_suspended, NULL); @@ -6310,9 +6610,8 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) while (suspend_count > 0) resume_vm (); - mono_runtime_set_shutting_down (); - - mono_threads_set_shutting_down (); + if (!mono_runtime_try_shutdown ()) + break; /* Suspend all managed threads since the runtime is going away */ DEBUG(1, fprintf (log_file, "Suspending all threads...\n")); @@ -7069,8 +7368,10 @@ buffer_add_cattrs (Buffer *buf, MonoDomain *domain, MonoImage *image, MonoClass MonoArray *typed_args, *named_args; MonoType *t; CattrNamedArg *arginfo; + MonoError error; - mono_reflection_create_custom_attr_data_args (image, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo); + mono_reflection_create_custom_attr_data_args (image, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo, &error); + g_assert (mono_error_ok (&error)); buffer_add_methodid (buf, domain, attr->ctor); @@ -7549,6 +7850,15 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint } break; } + case CMD_TYPE_IS_INITIALIZED: { + MonoVTable *vtable = mono_class_vtable (domain, klass); + + if (vtable) + buffer_add_int (buf, (vtable->initialized || vtable->init_failed) ? 1 : 0); + else + buffer_add_int (buf, 0); + break; + } default: return ERR_NOT_IMPLEMENTED; } @@ -7917,6 +8227,40 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g buffer_add_cattrs (buf, domain, method->klass->image, attr_klass, cinfo); break; } + case CMD_METHOD_MAKE_GENERIC_METHOD: { + MonoType **type_argv; + int i, type_argc; + MonoDomain *d; + MonoClass *klass; + MonoGenericInst *ginst; + MonoGenericContext tmp_context; + MonoMethod *inflated; + + type_argc = decode_int (p, &p, end); + type_argv = g_new0 (MonoType*, type_argc); + for (i = 0; i < type_argc; ++i) { + klass = decode_typeid (p, &p, end, &d, &err); + if (err) { + g_free (type_argv); + return err; + } + if (domain != d) { + g_free (type_argv); + return ERR_INVALID_ARGUMENT; + } + type_argv [i] = &klass->byval_arg; + } + ginst = mono_metadata_get_generic_inst (type_argc, type_argv); + g_free (type_argv); + tmp_context.class_inst = method->klass->generic_class ? method->klass->generic_class->context.class_inst : NULL; + tmp_context.method_inst = ginst; + + inflated = mono_class_inflate_generic_method (method, &tmp_context); + if (!mono_verifier_is_method_valid_generic_instantiation (inflated)) + return ERR_INVALID_ARGUMENT; + buffer_add_methodid (buf, domain, inflated); + break; + } default: return ERR_NOT_IMPLEMENTED; } @@ -8086,8 +8430,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) frame = tls->frames [frame_idx]; if (!frame->has_ctx) - // FIXME: - return ERR_INVALID_FRAMEID; + return ERR_ABSENT_INFORMATION; if (!frame->jit) { frame->jit = mono_debug_find_method (frame->api_method, frame->domain); @@ -8128,13 +8471,13 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) var = &jit->params [pos]; - add_var (buf, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE); + add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE); } else { g_assert (pos >= 0 && pos < jit->num_locals); var = &jit->locals [pos]; - add_var (buf, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE); + add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE); } } mono_metadata_free_mh (header); @@ -8146,14 +8489,14 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) MonoObject *p = NULL; buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &p, frame->domain); } else { - add_var (buf, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE); + add_var (buf, jit, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE); } } else { if (!sig->hasthis) { MonoObject *p = NULL; buffer_add_value (buf, &frame->actual_method->klass->byval_arg, &p, frame->domain); } else { - add_var (buf, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE); + add_var (buf, jit, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE); } } break; @@ -8466,41 +8809,188 @@ command_set_to_string (CommandSet command_set) } } +static const char* vm_cmds_str [] = { + "VERSION", + "ALL_THREADS", + "SUSPEND", + "RESUME", + "EXIT", + "DISPOSE", + "INVOKE_METHOD", + "SET_PROTOCOL_VERSION", + "ABORT_INVOKE", + "SET_KEEPALIVE" + "GET_TYPES_FOR_SOURCE_FILE", + "GET_TYPES", + "INVOKE_METHODS" +}; + +static const char* thread_cmds_str[] = { + "GET_FRAME_INFO", + "GET_NAME", + "GET_STATE", + "GET_INFO", + "GET_ID", + "GET_TID" +}; + +static const char* event_cmds_str[] = { + "REQUEST_SET", + "REQUEST_CLEAR", + "REQUEST_CLEAR_ALL_BREAKPOINTS" +}; + +static const char* appdomain_cmds_str[] = { + "GET_ROOT_DOMAIN", + "GET_FRIENDLY_NAME", + "GET_ASSEMBLIES", + "GET_ENTRY_ASSEMBLY", + "CREATE_STRING", + "GET_CORLIB", + "CREATE_BOXED_VALUE" +}; + +static const char* assembly_cmds_str[] = { + "GET_LOCATION", + "GET_ENTRY_POINT", + "GET_MANIFEST_MODULE", + "GET_OBJECT", + "GET_TYPE", + "GET_NAME" +}; + +static const char* module_cmds_str[] = { + "GET_INFO", +}; + +static const char* method_cmds_str[] = { + "GET_NAME", + "GET_DECLARING_TYPE", + "GET_DEBUG_INFO", + "GET_PARAM_INFO", + "GET_LOCALS_INFO", + "GET_INFO", + "GET_BODY", + "RESOLVE_TOKEN", + "GET_CATTRS ", + "MAKE_GENERIC_METHOD" +}; + +static const char* type_cmds_str[] = { + "GET_INFO", + "GET_METHODS", + "GET_FIELDS", + "GET_VALUES", + "GET_OBJECT", + "GET_SOURCE_FILES", + "SET_VALUES", + "IS_ASSIGNABLE_FROM", + "GET_PROPERTIES ", + "GET_CATTRS", + "GET_FIELD_CATTRS", + "GET_PROPERTY_CATTRS", + "GET_SOURCE_FILES_2", + "GET_VALUES_2", + "GET_METHODS_BY_NAME_FLAGS", + "GET_INTERFACES", + "GET_INTERFACE_MAP", + "IS_INITIALIZED" +}; + +static const char* stack_frame_cmds_str[] = { + "GET_VALUES", + "GET_THIS", + "SET_VALUES" +}; + +static const char* array_cmds_str[] = { + "GET_LENGTH", + "GET_VALUES", + "SET_VALUES", +}; + +static const char* string_cmds_str[] = { + "GET_VALUE", + "GET_LENGTH", + "GET_CHARS" +}; + +static const char* object_cmds_str[] = { + "GET_TYPE", + "GET_VALUES", + "IS_COLLECTED", + "GET_ADDRESS", + "GET_DOMAIN", + "SET_VALUES", + "GET_INFO", +}; + static const char* cmd_to_string (CommandSet set, int command) { + const char **cmds; + int cmds_len = 0; + switch (set) { - case CMD_SET_VM: { - switch (command) { - case CMD_VM_VERSION: - return "VERSION"; - case CMD_VM_ALL_THREADS: - return "ALL_THREADS"; - case CMD_VM_SUSPEND: - return "SUSPEND"; - case CMD_VM_RESUME: - return "RESUME"; - case CMD_VM_EXIT: - return "EXIT"; - case CMD_VM_DISPOSE: - return "DISPOSE"; - case CMD_VM_INVOKE_METHOD: - return "INVOKE_METHOD"; - case CMD_VM_SET_PROTOCOL_VERSION: - return "SET_PROTOCOL_VERSION"; - case CMD_VM_ABORT_INVOKE: - return "ABORT_INVOKE"; - case CMD_VM_SET_KEEPALIVE: - return "SET_KEEPALIVE"; - default: - break; - } + case CMD_SET_VM: + cmds = vm_cmds_str; + cmds_len = G_N_ELEMENTS (vm_cmds_str); + break; + case CMD_SET_OBJECT_REF: + cmds = object_cmds_str; + cmds_len = G_N_ELEMENTS (object_cmds_str); + break; + case CMD_SET_STRING_REF: + cmds = string_cmds_str; + cmds_len = G_N_ELEMENTS (string_cmds_str); + break; + case CMD_SET_THREAD: + cmds = thread_cmds_str; + cmds_len = G_N_ELEMENTS (thread_cmds_str); + break; + case CMD_SET_ARRAY_REF: + cmds = array_cmds_str; + cmds_len = G_N_ELEMENTS (array_cmds_str); + break; + case CMD_SET_EVENT_REQUEST: + cmds = event_cmds_str; + cmds_len = G_N_ELEMENTS (event_cmds_str); + break; + case CMD_SET_STACK_FRAME: + cmds = stack_frame_cmds_str; + cmds_len = G_N_ELEMENTS (stack_frame_cmds_str); + break; + case CMD_SET_APPDOMAIN: + cmds = appdomain_cmds_str; + cmds_len = G_N_ELEMENTS (appdomain_cmds_str); + break; + case CMD_SET_ASSEMBLY: + cmds = assembly_cmds_str; + cmds_len = G_N_ELEMENTS (assembly_cmds_str); + break; + case CMD_SET_METHOD: + cmds = method_cmds_str; + cmds_len = G_N_ELEMENTS (method_cmds_str); + break; + case CMD_SET_TYPE: + cmds = type_cmds_str; + cmds_len = G_N_ELEMENTS (type_cmds_str); + break; + case CMD_SET_MODULE: + cmds = module_cmds_str; + cmds_len = G_N_ELEMENTS (module_cmds_str); + break; + case CMD_SET_EVENT: + cmds = event_cmds_str; + cmds_len = G_N_ELEMENTS (event_cmds_str); break; - } default: break; } - return NULL; + if (command > 0 && command <= cmds_len) + return cmds [command - 1]; + else + return NULL; } static gboolean @@ -8574,8 +9064,10 @@ debugger_thread (void *arg) res = transport_recv (header, HEADER_LENGTH); /* This will break if the socket is closed during shutdown too */ - if (res != HEADER_LENGTH) + if (res != HEADER_LENGTH) { + DEBUG (1, fprintf (log_file, "[dbg] transport_recv () returned %d, expected %d.\n", res, HEADER_LENGTH)); break; + } p = header; end = header + HEADER_LENGTH; @@ -8598,15 +9090,17 @@ debugger_thread (void *arg) cmd_str = cmd_num; } - DEBUG (1, fprintf (log_file, "[dbg] Received command %s(%s), id=%d.\n", command_set_to_string (command_set), cmd_str, id)); + DEBUG (1, fprintf (log_file, "[dbg] Command %s(%s) [%d].\n", command_set_to_string (command_set), cmd_str, id)); } data = g_malloc (len - HEADER_LENGTH); if (len - HEADER_LENGTH > 0) { res = transport_recv (data, len - HEADER_LENGTH); - if (res != len - HEADER_LENGTH) + if (res != len - HEADER_LENGTH) { + DEBUG (1, fprintf (log_file, "[dbg] transport_recv () returned %d, expected %d.\n", res, len - HEADER_LENGTH)); break; + } } p = data; @@ -8668,7 +9162,7 @@ debugger_thread (void *arg) g_free (data); buffer_free (&buf); - if (command_set == CMD_SET_VM && command == CMD_VM_DISPOSE) + if (command_set == CMD_SET_VM && (command == CMD_VM_DISPOSE || command == CMD_VM_EXIT)) break; }