X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fdebugger-agent.c;h=2c47fa815020437f13709f6fb4c3748bd5d7279a;hb=92d89b2b067df5ee75533d956b69d42a3dfac611;hp=4d07c8de11816a8c019c2fa43006c52d30609cad;hpb=a16815186f5f0b72a5d7391d49d3d7756b1d6d66;p=mono.git diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index 4d07c8de118..2c47fa81502 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -76,6 +76,7 @@ int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD, #include #include #include +#include #include "debugger-agent.h" #include "mini.h" @@ -87,10 +88,6 @@ int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD, #define DISABLE_DEBUGGER_AGENT 1 #endif -#if defined(__MACH__) -#include -#endif - #ifndef DISABLE_DEBUGGER_AGENT #include @@ -128,8 +125,14 @@ typedef struct * method. */ MonoMethod *actual_method; + /* + * This is the method which is visible to debugger clients. Same as method, + * except for native-to-managed wrappers. + */ + MonoMethod *api_method; MonoContext ctx; MonoDebugMethodJitInfo *jit; + MonoJitInfo *ji; int flags; mgreg_t *reg_locations [MONO_MAX_IREGS]; /* @@ -156,6 +159,7 @@ struct _InvokeData MonoMethod *method; gpointer *args; guint32 suspend_count; + int nmethods; InvokeData *last_invoke; }; @@ -163,7 +167,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; @@ -270,7 +273,7 @@ typedef struct { #define HEADER_LENGTH 11 #define MAJOR_VERSION 2 -#define MINOR_VERSION 17 +#define MINOR_VERSION 22 typedef enum { CMD_SET_VM = 1, @@ -353,7 +356,8 @@ typedef enum { typedef enum { STEP_FILTER_NONE = 0, - STEP_FILTER_STATIC_CTOR = 1 + STEP_FILTER_STATIC_CTOR = 1, + STEP_FILTER_DEBUGGER_HIDDEN = 2 } StepFilter; typedef enum { @@ -395,7 +399,8 @@ typedef enum { CMD_VM_ABORT_INVOKE = 9, CMD_VM_SET_KEEPALIVE = 10, CMD_VM_GET_TYPES_FOR_SOURCE_FILE = 11, - CMD_VM_GET_TYPES = 12 + CMD_VM_GET_TYPES = 12, + CMD_VM_INVOKE_METHODS = 13 } CmdVM; typedef enum { @@ -449,6 +454,7 @@ typedef enum { CMD_METHOD_GET_INFO = 6, CMD_METHOD_GET_BODY = 7, CMD_METHOD_RESOLVE_TOKEN = 8, + CMD_METHOD_GET_CATTRS = 9, } CmdMethod; typedef enum { @@ -739,6 +745,8 @@ static void finish_agent_init (gboolean on_startup); static void process_profiler_event (EventKind event, gpointer arg); +static void invalidate_frames (DebuggerTlsData *tls); + #ifndef DISABLE_SOCKET_TRANSPORT static void register_socket_transport (void); @@ -862,6 +870,8 @@ mono_debugger_agent_parse_options (char *options) } } + //agent_config.log_level = 0; + if (agent_config.transport == NULL) { fprintf (stderr, "debugger-agent: The 'transport' option is mandatory.\n"); exit (1); @@ -951,13 +961,16 @@ mono_debugger_agent_init (void) mono_disable_optimizations (MONO_OPT_LINEARS); #endif + /* + * The stack walk done from thread_interrupt () needs to be signal safe, but it + * isn't, since it can call into mono_aot_find_jit_info () which is not signal + * safe (#3411). So load AOT info eagerly when the debugger is running as a + * workaround. + */ + mini_get_debug_options ()->load_aot_jit_info_eagerly = TRUE; + if (!agent_config.onuncaught && !agent_config.onthrow) finish_agent_init (TRUE); - - /* FIXME: Is this still needed ? */ -#if defined(__MACH__) - mono_thread_info_disable_new_interrupt (TRUE); -#endif } /* @@ -1036,15 +1049,30 @@ socket_transport_recv (void *buf, int len) int total = 0; int fd = conn_fd; int flags = 0; + static gint32 last_keepalive; + gint32 msecs; do { again: res = recv (fd, (char *) buf + total, len - total, flags); if (res > 0) total += res; - if (agent_config.keepalive && res == -1 && get_last_sock_error () == MONO_EWOULDBLOCK) { - process_profiler_event (EVENT_KIND_KEEPALIVE, NULL); - goto again; + if (agent_config.keepalive) { + gboolean need_keepalive = FALSE; + if (res == -1 && get_last_sock_error () == MONO_EWOULDBLOCK) { + need_keepalive = TRUE; + } else if (res == -1) { + /* This could happen if recv () is interrupted repeatedly */ + msecs = mono_msec_ticks (); + if (msecs - last_keepalive >= agent_config.keepalive) { + need_keepalive = TRUE; + last_keepalive = msecs; + } + } + if (need_keepalive) { + process_profiler_event (EVENT_KIND_KEEPALIVE, NULL); + goto again; + } } } while ((res > 0 && total < len) || (res == -1 && get_last_sock_error () == MONO_EINTR)); return total; @@ -1060,7 +1088,7 @@ set_keepalive (void) struct timeval tv; int result; - if (!agent_config.keepalive) + if (!agent_config.keepalive || !conn_fd) return; tv.tv_sec = agent_config.keepalive / 1000; @@ -1175,7 +1203,7 @@ socket_transport_connect (const char *address) addrlen = sizeof (addr); memset (&addr, 0, sizeof (addr)); - res = getsockname (sfd, &addr, &addrlen); + res = getsockname (sfd, (struct sockaddr*)&addr, &addrlen); g_assert (res == 0); host = (char*)"127.0.0.1"; @@ -1288,8 +1316,7 @@ socket_transport_connect (const char *address) #endif } - disconnected = !transport_handshake (); - if (disconnected) + if (!transport_handshake ()) exit (1); } @@ -1418,6 +1445,8 @@ transport_handshake (void) guint8 buf [128]; int res; + disconnected = TRUE; + /* Write handshake message */ sprintf (handshake_msg, "DWP-Handshake"); do { @@ -1446,7 +1475,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, @@ -1459,6 +1488,7 @@ transport_handshake (void) set_keepalive (); #endif + disconnected = FALSE; return TRUE; } @@ -2280,7 +2310,6 @@ get_last_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data) /* Store the context/lmf for the frame above the last frame */ memcpy (&data->ctx, ctx, sizeof (MonoContext)); data->lmf = info->lmf; - return TRUE; } } @@ -2332,7 +2361,7 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, void *sigctx, Mono if (info) tid = mono_thread_info_get_tid (info); else - tid = GetCurrentThreadId (); + tid = (MonoNativeThreadId)GetCurrentThreadId (); // FIXME: Races when the thread leaves managed code before hitting a single step // event. @@ -2424,8 +2453,10 @@ mono_debugger_agent_thread_interrupt (void *sigctx, MonoJitInfo *ji) return FALSE; tls = mono_native_tls_get_value (debugger_tls_id); - if (!tls) - return FALSE; + if (!tls) { + DEBUG (1, fprintf (log_file, "[%p] Received interrupt with no TLS, continuing.\n", (gpointer)GetCurrentThreadId ())); + return FALSE; + } return thread_interrupt (tls, NULL, sigctx, ji); } @@ -2441,15 +2472,23 @@ static void CALLBACK notify_thread_apc (ULONG_PTR param) /* * reset_native_thread_suspend_state: * - * Reset the suspended flag on native threads + * Reset the suspended flag and state on native threads */ static void reset_native_thread_suspend_state (gpointer key, gpointer value, gpointer user_data) { DebuggerTlsData *tls = value; - if (!tls->really_suspended && tls->suspended) + if (!tls->really_suspended && tls->suspended) { tls->suspended = FALSE; + /* + * The thread might still be running if it was executing native code, so the state won't be invalided by + * suspend_current (). + */ + tls->context.valid = FALSE; + tls->async_state.valid = FALSE; + invalidate_frames (tls); + } } /* @@ -2506,11 +2545,13 @@ notify_thread (gpointer key, gpointer value, gpointer user_data) mono_thread_info_resume (mono_thread_info_get_tid (info)); } else { res = mono_thread_kill (thread, mono_thread_get_abort_signal ()); - if (res) + if (res) { + DEBUG(1, fprintf (log_file, "[%p] mono_thread_kill () failed for %p: %d...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid, res)); /* * Attached thread which died without detaching. */ tls->terminated = TRUE; + } } #endif } @@ -2608,7 +2649,7 @@ resume_vm (void) g_assert (suspend_count > 0); suspend_count --; - DEBUG(1, fprintf (log_file, "[%p] Resuming vm...\n", (gpointer)GetCurrentThreadId ())); + DEBUG(1, fprintf (log_file, "[%p] Resuming vm, suspend count=%d...\n", (gpointer)GetCurrentThreadId (), suspend_count)); if (suspend_count == 0) { // FIXME: Is it safe to call this inside the lock ? @@ -2758,7 +2799,7 @@ suspend_current (void) /* The frame info becomes invalid after a resume */ tls->context.valid = FALSE; tls->async_state.valid = FALSE; - invalidate_frames (NULL); + invalidate_frames (tls); } static void @@ -2938,7 +2979,7 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data) { ComputeFramesUserData *ud = user_data; StackFrame *frame; - MonoMethod *method, *actual_method; + MonoMethod *method, *actual_method, *api_method; SeqPoint *sp; int flags = 0; @@ -2956,11 +2997,12 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data) else method = info->method; actual_method = info->actual_method; + api_method = method; if (!method) return FALSE; - if (!method || !info->managed || (method->wrapper_type && method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && method->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)) + if (!method || (method->wrapper_type && method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && method->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)) return FALSE; if (info->il_offset == -1) { @@ -2980,16 +3022,23 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data) if (!CHECK_PROTOCOL_VERSION (2, 17)) /* Older clients can't handle this flag */ return FALSE; + api_method = mono_marshal_method_from_wrapper (method); + if (!api_method) + return FALSE; + actual_method = api_method; flags |= FRAME_FLAG_NATIVE_TRANSITION; } frame = g_new0 (StackFrame, 1); frame->method = method; frame->actual_method = actual_method; + frame->api_method = api_method; frame->il_offset = info->il_offset; frame->native_offset = info->native_offset; frame->flags = flags; - memcpy (frame->reg_locations, info->reg_locations, MONO_MAX_IREGS * sizeof (mgreg_t*)); + frame->ji = info->ji; + if (info->reg_locations) + memcpy (frame->reg_locations, info->reg_locations, MONO_MAX_IREGS * sizeof (mgreg_t*)); if (ctx) { frame->ctx = *ctx; frame->has_ctx = TRUE; @@ -3236,7 +3285,7 @@ create_event_list (EventKind event, GPtrArray *reqs, MonoJitInfo *ji, EventInfo MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method); if (minfo) { - mono_debug_symfile_get_line_numbers_full (minfo, &source_file, &source_file_list, NULL, NULL, NULL, NULL); + mono_debug_symfile_get_line_numbers_full (minfo, &source_file, &source_file_list, NULL, NULL, NULL, NULL, NULL); for (i = 0; i < source_file_list->len; ++i) { sinfo = g_ptr_array_index (source_file_list, i); /* @@ -3265,6 +3314,26 @@ create_event_list (EventKind event, GPtrArray *reqs, MonoJitInfo *ji, EventInfo (ji->method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && !strcmp (ji->method->name, ".cctor")) filtered = TRUE; + if ((mod->data.filter & STEP_FILTER_DEBUGGER_HIDDEN) && ji) { + MonoCustomAttrInfo *ainfo; + static MonoClass *klass; + + if (!klass) { + klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerHiddenAttribute"); + g_assert (klass); + } + if (!ji->dbg_hidden_inited) { + ainfo = mono_custom_attrs_from_method (ji->method); + if (ainfo) { + if (mono_custom_attrs_has_attr (ainfo, klass)) + ji->dbg_hidden = TRUE; + mono_custom_attrs_free (ainfo); + } + ji->dbg_hidden_inited = TRUE; + } + if (ji->dbg_hidden) + filtered = TRUE; + } } } @@ -3578,7 +3647,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); @@ -3608,13 +3676,15 @@ thread_end (MonoProfiler *prof, uintptr_t tid) mono_loader_lock (); thread = mono_g_hash_table_lookup (tid_to_thread, (gpointer)tid); if (thread) { - tls = mono_g_hash_table_lookup (thread_to_tls, thread); - /* FIXME: Maybe we need to free this instead, but some code can't handle that */ - tls->terminated = TRUE; mono_g_hash_table_remove (tid_to_thread_obj, (gpointer)tid); - /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */ - MONO_GC_UNREGISTER_ROOT (tls->thread); - tls->thread = NULL; + tls = mono_g_hash_table_lookup (thread_to_tls, thread); + if (tls) { + /* FIXME: Maybe we need to free this instead, but some code can't handle that */ + tls->terminated = TRUE; + /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */ + MONO_GC_UNREGISTER_ROOT (tls->thread); + tls->thread = NULL; + } } mono_loader_unlock (); @@ -3895,7 +3965,7 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo char *s = g_strdup_printf ("Unable to insert breakpoint at %s:%d, seq_points=%d\n", mono_method_full_name (ji->method, TRUE), bp->il_offset, seq_points->len); for (i = 0; i < seq_points->len; ++i) - printf ("%d\n", seq_points->seq_points [i].il_offset); + DEBUG (1, fprintf (log_file, "%d\n", seq_points->seq_points [i].il_offset)); if (error) { mono_error_set_error (error, MONO_ERROR_GENERIC, "%s", s); @@ -4262,8 +4332,6 @@ process_breakpoint_inner (DebuggerTlsData *tls) ss_reqs = g_ptr_array_new (); ss_reqs_orig = g_ptr_array_new (); - DEBUG(1, fprintf (log_file, "[%p] Breakpoint hit, method=%s, offset=0x%x.\n", (gpointer)GetCurrentThreadId (), ji->method->name, native_offset)); - mono_loader_lock (); /* @@ -4272,6 +4340,8 @@ process_breakpoint_inner (DebuggerTlsData *tls) */ sp = find_prev_seq_point_for_native_offset (mono_domain_get (), ji->method, native_offset, &info); + 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)); + bp = NULL; for (i = 0; i < breakpoints->len; ++i) { bp = g_ptr_array_index (breakpoints, i); @@ -4314,9 +4384,11 @@ process_breakpoint_inner (DebuggerTlsData *tls) 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)) + 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; @@ -4424,7 +4496,6 @@ mono_debugger_agent_breakpoint_hit (void *sigctx) * problems, like the original signal is disabled, libgc can't handle altstack, etc. * So set up the signal context to return to the real breakpoint handler function. */ - resume_from_signal_handler (sigctx, process_breakpoint); } @@ -4753,7 +4824,7 @@ ss_stop (SingleStepReq *ss_req) static void ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch) { - int i, frame_index; + int i, j, frame_index; SeqPoint *next_sp; MonoBreakpoint *bp; gboolean enable_global = FALSE; @@ -4770,7 +4841,7 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI } else { frame_index = 1; - if ((!sp || sp->next_len == 0 || ss_req->depth == STEP_DEPTH_OUT) && ctx) { + if ((!sp || sp->next_len == 0 || ss_req->depth == STEP_DEPTH_OUT || ss_req->depth == STEP_DEPTH_OVER) && ctx) { /* Need parent frames */ if (!tls->context.valid) mono_thread_state_init_from_monoctx (&tls->context, ctx); @@ -4792,6 +4863,8 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI if (sp && sp->next_len != 0) break; } + // 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) { sp = NULL; @@ -4814,6 +4887,27 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI } } + if (ss_req->depth == STEP_DEPTH_OVER) { + /* Need to stop in catch clauses as well */ + for (i = 0; i < tls->frame_count; ++i) { + StackFrame *frame = tls->frames [i]; + + if (frame->ji) { + MonoJitInfo *jinfo = frame->ji; + for (j = 0; j < jinfo->num_clauses; ++j) { + MonoJitExceptionInfo *ei = &jinfo->clauses [j]; + + sp = find_next_seq_point_for_native_offset (frame->domain, frame->method, (char*)ei->handler_start - (char*)jinfo->code_start, NULL); + if (sp) { + bp = set_breakpoint (frame->method, sp->il_offset, ss_req->req, NULL); + ss_req->bps = g_slist_append (ss_req->bps, bp); + } + } + } + } + } + + if (ss_req->depth == STEP_DEPTH_INTO) { /* Enable global stepping so we stop at method entry too */ enable_global = TRUE; @@ -5299,11 +5393,29 @@ buffer_add_value (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain) buffer_add_value_full (buf, t, addr, domain, FALSE); } +static gboolean +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) { + klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class; + if (mono_class_is_assignable_from (mono_class_from_mono_type (t), klass)) { + return TRUE; + } + } + return FALSE; + } + return TRUE; +} + static ErrorCode -decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit) +decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit); + +static ErrorCode +decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit) { int err; - int type = decode_byte (buf, &buf, limit); if (type != t->type && !MONO_TYPE_IS_REFERENCE (t) && !(t->type == MONO_TYPE_I && type == MONO_TYPE_VALUETYPE) && @@ -5416,8 +5528,12 @@ decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 if (err) return err; - if (obj && !mono_class_is_assignable_from (mono_class_from_mono_type (t), obj->vtable->klass)) - return ERR_INVALID_ARGUMENT; + if (obj) { + if (!obj_is_of_type (obj, t)) { + DEBUG (1, fprintf (log_file, "Expected type '%s', got '%s'\n", mono_type_full_name (t), obj->vtable->klass->name)); + return ERR_INVALID_ARGUMENT; + } + } if (obj && obj->vtable->domain != domain) return ERR_INVALID_ARGUMENT; @@ -5438,6 +5554,47 @@ decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 return 0; } +static ErrorCode +decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit) +{ + int err; + int type = decode_byte (buf, &buf, limit); + + if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) { + MonoType *targ = t->data.generic_class->context.class_inst->type_argv [0]; + guint8 *nullable_buf; + + /* + * First try decoding it as a Nullable`1 + */ + err = decode_value_internal (t, type, domain, addr, buf, endbuf, limit); + if (!err) + return err; + + /* + * Then try decoding as a primitive value or null. + */ + if (targ->type == type) { + nullable_buf = g_malloc (mono_class_instance_size (mono_class_from_mono_type (targ))); + err = decode_value_internal (targ, type, domain, nullable_buf, buf, endbuf, limit); + if (err) { + g_free (nullable_buf); + return err; + } + mono_nullable_init (addr, mono_value_box (domain, mono_class_from_mono_type (targ), nullable_buf), mono_class_from_mono_type (t)); + g_free (nullable_buf); + *endbuf = buf; + return ERR_NONE; + } else if (type == VALUE_TYPE_ID_NULL) { + mono_nullable_init (addr, NULL, mono_class_from_mono_type (t)); + *endbuf = buf; + return ERR_NONE; + } + } + + return decode_value_internal (t, type, domain, addr, buf, endbuf, limit); +} + static void add_var (Buffer *buf, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, gboolean as_vtype) { @@ -5512,6 +5669,9 @@ set_var (MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domai g_assert_not_reached (); } + if (t->byref) + NOT_IMPLEMENTED; + /* Set value on the stack or in the return ctx */ if (reg_locations [reg]) { /* Saved on the stack */ @@ -5537,8 +5697,15 @@ set_var (MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domai //printf ("[R%d+%d] = %p\n", reg, var->offset, addr); + if (t->byref) { + addr = *(guint8**)addr; + + if (!addr) + break; + } + // FIXME: Write barriers - memcpy (addr, val, size); + mono_gc_memmove (addr, val, size); break; case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD: NOT_IMPLEMENTED; @@ -5664,9 +5831,8 @@ add_thread (gpointer key, gpointer value, gpointer user_data) } static ErrorCode -do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke) +do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8 *p, guint8 **endp) { - guint8 *p = invoke->p; guint8 *end = invoke->endp; MonoMethod *m; int i, err, nargs; @@ -5733,7 +5899,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke) } } - if (this && !mono_class_is_assignable_from (m->klass, this->vtable->klass)) + if (this && !obj_is_of_type (this, &m->klass->byval_arg)) return ERR_INVALID_ARGUMENT; nargs = decode_int (p, &p, end); @@ -5841,12 +6007,14 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke) buffer_add_value (buf, &mono_defaults.void_class->byval_arg, NULL, domain); } else if (MONO_TYPE_IS_REFERENCE (sig->ret)) { buffer_add_value (buf, sig->ret, &res, domain); - } else if (mono_class_from_mono_type (sig->ret)->valuetype) { + } else if (mono_class_from_mono_type (sig->ret)->valuetype || sig->ret->type == MONO_TYPE_PTR || sig->ret->type == MONO_TYPE_FNPTR) { if (mono_class_is_nullable (mono_class_from_mono_type (sig->ret))) { - if (!res) - buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &res, domain); - else - buffer_add_value (buf, sig->ret, mono_object_unbox (res), domain); + MonoClass *k = mono_class_from_mono_type (sig->ret); + guint8 *nullable_buf = g_alloca (mono_class_value_size (k, NULL)); + + g_assert (nullable_buf); + mono_nullable_init (nullable_buf, res, k); + buffer_add_value (buf, sig->ret, nullable_buf, domain); } else { g_assert (res); buffer_add_value (buf, sig->ret, mono_object_unbox (res), domain); @@ -5863,6 +6031,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke) mono_set_lmf ((gpointer)(((gssize)ext.lmf.previous_lmf) & ~3)); #endif + *endp = p; // FIXME: byref arguments // FIXME: varargs return ERR_NONE; @@ -5879,10 +6048,11 @@ invoke_method (void) DebuggerTlsData *tls; InvokeData *invoke; int id; - int err; + int i, err, mindex; Buffer buf; static void (*restore_context) (void *); MonoContext restore_ctx; + guint8 *p; if (!restore_context) restore_context = mono_get_restore_context (); @@ -5910,17 +6080,29 @@ invoke_method (void) id = invoke->id; - buffer_init (&buf, 128); + p = invoke->p; + err = 0; + for (mindex = 0; mindex < invoke->nmethods; ++mindex) { + buffer_init (&buf, 128); - err = do_invoke_method (tls, &buf, invoke); + if (err) { + /* Fail the other invokes as well */ + } else { + err = do_invoke_method (tls, &buf, invoke, p, &p); + } - /* Start suspending before sending the reply */ - if (!(invoke->flags & INVOKE_FLAG_SINGLE_THREADED)) - suspend_vm (); + /* Start suspending before sending the reply */ + if (mindex == invoke->nmethods - 1) { + if (!(invoke->flags & INVOKE_FLAG_SINGLE_THREADED)) { + for (i = 0; i < invoke->suspend_count; ++i) + suspend_vm (); + } + } - send_reply_packet (id, err, &buf); + send_reply_packet (id, err, &buf); - buffer_free (&buf); + buffer_free (&buf); + } memcpy (&restore_ctx, &invoke->ctx, sizeof (MonoContext)); @@ -5990,7 +6172,7 @@ get_source_files_for_type (MonoClass *klass) GPtrArray *source_file_list; if (minfo) { - mono_debug_symfile_get_line_numbers_full (minfo, NULL, &source_file_list, NULL, NULL, NULL, NULL); + mono_debug_symfile_get_line_numbers_full (minfo, NULL, &source_file_list, NULL, NULL, NULL, NULL, NULL); for (j = 0; j < source_file_list->len; ++j) { sinfo = g_ptr_array_index (source_file_list, j); for (i = 0; i < files->len; ++i) @@ -6116,6 +6298,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) tls->pending_invoke = g_new0 (InvokeData, 1); tls->pending_invoke->method = exit_method; tls->pending_invoke->args = args; + tls->pending_invoke->nmethods = 1; while (suspend_count > 0) resume_vm (); @@ -6143,11 +6326,12 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) } break; } - case CMD_VM_INVOKE_METHOD: { + case CMD_VM_INVOKE_METHOD: + case CMD_VM_INVOKE_METHODS: { int objid = decode_objid (p, &p, end); MonoThread *thread; DebuggerTlsData *tls; - int err, flags; + int i, count, err, flags, nmethods; err = get_object (objid, (MonoObject**)&thread); if (err) @@ -6155,6 +6339,11 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) flags = decode_int (p, &p, end); + if (command == CMD_VM_INVOKE_METHODS) + nmethods = decode_int (p, &p, end); + else + nmethods = 1; + // Wait for suspending if it already started if (suspend_count) wait_for_suspend (); @@ -6175,7 +6364,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) * resumed. */ if (tls->pending_invoke) - NOT_IMPLEMENTED; + return ERR_NOT_SUSPENDED; tls->pending_invoke = g_new0 (InvokeData, 1); tls->pending_invoke->id = id; tls->pending_invoke->flags = flags; @@ -6183,11 +6372,16 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) memcpy (tls->pending_invoke->p, p, end - p); tls->pending_invoke->endp = tls->pending_invoke->p + (end - p); tls->pending_invoke->suspend_count = suspend_count; + tls->pending_invoke->nmethods = nmethods; - if (flags & INVOKE_FLAG_SINGLE_THREADED) + if (flags & INVOKE_FLAG_SINGLE_THREADED) { resume_thread (THREAD_TO_INTERNAL (thread)); - else - resume_vm (); + } + else { + count = suspend_count; + for (i = 0; i < count; ++i) + resume_vm (); + } break; } case CMD_VM_ABORT_INVOKE: { @@ -6757,7 +6951,7 @@ assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf) break; } case CMD_ASSEMBLY_GET_OBJECT: { - MonoObject *o = (MonoObject*)mono_assembly_get_object (mono_domain_get (), ass); + MonoObject *o = (MonoObject*)mono_assembly_get_object (domain, ass); buffer_add_objid (buf, o); break; } @@ -7241,7 +7435,7 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint break; } case CMD_TYPE_GET_OBJECT: { - MonoObject *o = (MonoObject*)mono_type_get_object (mono_domain_get (), &klass->byval_arg); + MonoObject *o = (MonoObject*)mono_type_get_object (domain, &klass->byval_arg); buffer_add_objid (buf, o); break; } @@ -7389,6 +7583,7 @@ static ErrorCode method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, guint8 *p, guint8 *end, Buffer *buf) { MonoMethodHeader *header; + int err; switch (command) { case CMD_METHOD_GET_NAME: { @@ -7405,6 +7600,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g int i, j, n_il_offsets; int *il_offsets; int *line_numbers; + int *column_numbers; int *source_files; GPtrArray *source_file_list; @@ -7425,7 +7621,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g break; } - mono_debug_symfile_get_line_numbers_full (minfo, &source_file, &source_file_list, &n_il_offsets, &il_offsets, &line_numbers, &source_files); + mono_debug_symfile_get_line_numbers_full (minfo, &source_file, &source_file_list, &n_il_offsets, &il_offsets, &line_numbers, &column_numbers, &source_files); buffer_add_int (buf, header->code_size); if (CHECK_PROTOCOL_VERSION (2, 13)) { buffer_add_int (buf, source_file_list->len); @@ -7441,7 +7637,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g buffer_add_string (buf, source_file); } buffer_add_int (buf, n_il_offsets); - DEBUG (10, printf ("Line number table for method %s:\n", mono_method_full_name (method, TRUE))); + DEBUG (10, fprintf (log_file, "Line number table for method %s:\n", mono_method_full_name (method, TRUE))); for (i = 0; i < n_il_offsets; ++i) { const char *srcfile = ""; @@ -7449,11 +7645,13 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g MonoDebugSourceInfo *sinfo = g_ptr_array_index (source_file_list, source_files [i]); srcfile = sinfo->source_file; } - DEBUG (10, printf ("IL%x -> %s:%d\n", il_offsets [i], srcfile, line_numbers [i])); + DEBUG (10, fprintf (log_file, "IL%x -> %s:%d %d\n", il_offsets [i], srcfile, line_numbers [i], column_numbers ? column_numbers [i] : -1)); buffer_add_int (buf, il_offsets [i]); buffer_add_int (buf, line_numbers [i]); if (CHECK_PROTOCOL_VERSION (2, 13)) buffer_add_int (buf, source_files [i]); + if (CHECK_PROTOCOL_VERSION (2, 19)) + buffer_add_int (buf, column_numbers ? column_numbers [i] : -1); } g_free (source_file); g_free (il_offsets); @@ -7494,7 +7692,8 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g MonoDebugLocalsInfo *locals; header = mono_method_get_header (method); - g_assert (header); + if (!header) + return ERR_INVALID_ARGUMENT; buffer_add_int (buf, header->num_locals); @@ -7610,12 +7809,34 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g header = mono_method_get_header (method); if (!header) { buffer_add_int (buf, 0); + + if (CHECK_PROTOCOL_VERSION (2, 18)) + buffer_add_int (buf, 0); } else { buffer_add_int (buf, header->code_size); for (i = 0; i < header->code_size; ++i) buffer_add_byte (buf, header->code [i]); + + if (CHECK_PROTOCOL_VERSION (2, 18)) { + buffer_add_int (buf, header->num_clauses); + for (i = 0; i < header->num_clauses; ++i) { + MonoExceptionClause *clause = &header->clauses [i]; + + buffer_add_int (buf, clause->flags); + buffer_add_int (buf, clause->try_offset); + buffer_add_int (buf, clause->try_len); + buffer_add_int (buf, clause->handler_offset); + buffer_add_int (buf, clause->handler_len); + if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) + buffer_add_typeid (buf, domain, clause->data.catch_class); + else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) + buffer_add_int (buf, clause->data.filter_offset); + } + } + + mono_metadata_free_mh (header); } - mono_metadata_free_mh (header); + break; } case CMD_METHOD_RESOLVE_TOKEN: { @@ -7682,6 +7903,20 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g } break; } + case CMD_METHOD_GET_CATTRS: { + MonoClass *attr_klass; + MonoCustomAttrInfo *cinfo; + + attr_klass = decode_typeid (p, &p, end, NULL, &err); + /* attr_klass can be NULL */ + if (err) + return err; + + cinfo = mono_custom_attrs_from_method (method); + + buffer_add_cattrs (buf, domain, method->klass->image, attr_klass, cinfo); + break; + } default: return ERR_NOT_IMPLEMENTED; } @@ -7855,14 +8090,14 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) return ERR_INVALID_FRAMEID; if (!frame->jit) { - frame->jit = mono_debug_find_method (frame->method, frame->domain); - if (!frame->jit && frame->method->is_inflated) - frame->jit = mono_debug_find_method (mono_method_get_declaring_generic_method (frame->method), frame->domain); + frame->jit = mono_debug_find_method (frame->api_method, frame->domain); + if (!frame->jit && frame->api_method->is_inflated) + frame->jit = mono_debug_find_method (mono_method_get_declaring_generic_method (frame->api_method), frame->domain); if (!frame->jit) { char *s; /* This could happen for aot images with no jit debug info */ - s = mono_method_full_name (frame->method, TRUE); + s = mono_method_full_name (frame->api_method, TRUE); DEBUG (1, fprintf (log_file, "[dbg] No debug information found for '%s'.\n", s)); g_free (s); return ERR_ABSENT_INFORMATION; @@ -7906,7 +8141,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) break; } case CMD_STACK_FRAME_GET_THIS: { - if (frame->method->klass->valuetype) { + if (frame->api_method->klass->valuetype) { if (!sig->hasthis) { MonoObject *p = NULL; buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &p, frame->domain); @@ -7918,7 +8153,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) MonoObject *p = NULL; buffer_add_value (buf, &frame->actual_method->klass->byval_arg, &p, frame->domain); } else { - add_var (buf, &frame->method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE); + add_var (buf, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE); } } break; @@ -8095,7 +8330,8 @@ object_commands (int command, guint8 *p, guint8 *end, Buffer *buf) switch (command) { case CMD_OBJECT_REF_GET_TYPE: - buffer_add_typeid (buf, obj->vtable->domain, obj->vtable->klass); + /* This handles transparent proxies too */ + buffer_add_typeid (buf, obj->vtable->domain, mono_class_from_mono_type (((MonoReflectionType*)obj->vtable->type)->type)); break; case CMD_OBJECT_REF_GET_VALUES: len = decode_int (p, &p, end); @@ -8185,7 +8421,7 @@ object_commands (int command, guint8 *p, guint8 *end, Buffer *buf) buffer_add_domainid (buf, obj->vtable->domain); break; case CMD_OBJECT_REF_GET_INFO: - buffer_add_typeid (buf, obj->vtable->domain, obj->vtable->klass); + buffer_add_typeid (buf, obj->vtable->domain, mono_class_from_mono_type (((MonoReflectionType*)obj->vtable->type)->type)); buffer_add_domainid (buf, obj->vtable->domain); break; default: @@ -8254,6 +8490,8 @@ cmd_to_string (CommandSet set, int command) return "SET_PROTOCOL_VERSION"; case CMD_VM_ABORT_INVOKE: return "ABORT_INVOKE"; + case CMD_VM_SET_KEEPALIVE: + return "SET_KEEPALIVE"; default: break; }