2010-01-16 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / debugger-agent.c
index ad4e4d401c5520102f26a7087cc3c3ff73908893..3d544f8b1c15d8f7bc33fb5581feffcf053563d4 100644 (file)
@@ -439,7 +439,11 @@ typedef struct {
        gpointer start_sp;
        MonoMethod *last_method;
        int last_line;
-} MonoSingleStepReq;
+       /* Whenever single stepping is performed using start/stop_single_stepping () */
+       gboolean global;
+       /* The list of breakpoints used to implement step-over */
+       GSList *bps;
+} SingleStepReq;
 
 /* Dummy structure used for the profiler callbacks */
 typedef struct {
@@ -514,7 +518,7 @@ static mono_mutex_t debugger_thread_exited_mutex;
 static DebuggerProfiler debugger_profiler;
 
 /* The single step request instance */
-static MonoSingleStepReq *ss_req = NULL;
+static SingleStepReq *ss_req = NULL;
 static gpointer ss_invoke_addr = NULL;
 
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
@@ -568,8 +572,9 @@ static void ids_cleanup (void);
 
 static void suspend_init (void);
 
-static ErrorCode ss_start (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req);
-static void ss_stop (EventRequest *req);
+static void ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls);
+static ErrorCode ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req);
+static void ss_destroy (SingleStepReq *req);
 
 static void start_debugger_thread (void);
 
@@ -657,6 +662,8 @@ mono_debugger_agent_parse_options (char *options)
                } else if (strncmp (arg, "onthrow=", 8) == 0) {
                        /* We support multiple onthrow= options */
                        agent_config.onthrow = g_slist_append (agent_config.onthrow, g_strdup (arg + 8));
+               } else if (strncmp (arg, "onthrow", 7) == 0) {
+                       agent_config.onthrow = g_slist_append (agent_config.onthrow, g_strdup (""));
                } else if (strncmp (arg, "help", 4) == 0) {
                        print_usage ();
                        exit (0);
@@ -834,8 +841,17 @@ mono_debugger_agent_cleanup (void)
        //WaitForSingleObject (debugger_thread_handle, INFINITE);
        if (GetCurrentThreadId () != debugger_thread_id) {
                mono_mutex_lock (&debugger_thread_exited_mutex);
-               if (!debugger_thread_exited)
+               if (!debugger_thread_exited) {
+#ifdef HOST_WIN32
+                       if (WAIT_TIMEOUT == WaitForSingleObject(debugger_thread_exited_cond, 0)) {
+                               mono_mutex_unlock (&debugger_thread_exited_mutex);
+                               Sleep(0);
+                               mono_mutex_lock (&debugger_thread_exited_mutex);
+                       }
+#else
                        mono_cond_wait (&debugger_thread_exited_cond, &debugger_thread_exited_mutex);
+#endif
+               }
                mono_mutex_unlock (&debugger_thread_exited_mutex);
        }
 
@@ -936,7 +952,15 @@ transport_connect (const char *host, int port)
                                break;
                        }
 
+#ifndef PLATFORM_WIN32
+                       /*
+                        * this function is not present on win2000 which we still support, and the
+                        * workaround described here:
+                        * http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx
+                        * only works with MSVC.
+                        */
                        freeaddrinfo (result);
+#endif
                }
 
                DEBUG (1, fprintf (log_file, "Listening on %s:%d (timeout=%d ms)...\n", host, port, agent_config.timeout));
@@ -980,7 +1004,10 @@ transport_connect (const char *host, int port)
 
                conn_fd = sfd;
 
+#ifndef PLATFORM_WIN32
+               /* See the comment above */
                freeaddrinfo (result);
+#endif
 
                if (rp == 0) {
                        fprintf (stderr, "debugger-agent: Unable to connect to %s:%d\n", host, port);
@@ -1787,7 +1814,6 @@ mono_debugger_agent_thread_interrupt (void *sigctx, MonoJitInfo *ji)
                        MonoContext ctx;
                        GetLastFrameUserData data;
 
-                       mono_arch_sigctx_to_monoctx (sigctx, &ctx);
                        // FIXME: printf is not signal safe, but this is only used during
                        // debugger debugging
                        DEBUG (1, printf ("[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer)GetCurrentThreadId (), mono_arch_ip_from_context (sigctx)));
@@ -1808,7 +1834,10 @@ mono_debugger_agent_thread_interrupt (void *sigctx, MonoJitInfo *ji)
                         * remain valid.
                         */
                        data.last_frame_set = FALSE;
-                       mono_jit_walk_stack_from_ctx_in_thread (get_last_frame, mono_domain_get (), &ctx, FALSE, tls->thread, mono_get_lmf (), &data);
+                       if (sigctx) {
+                               mono_arch_sigctx_to_monoctx (sigctx, &ctx);
+                               mono_jit_walk_stack_from_ctx_in_thread (get_last_frame, mono_domain_get (), &ctx, FALSE, tls->thread, mono_get_lmf (), &data);
+                       }
                        if (data.last_frame_set) {
                                memcpy (&tls->async_last_frame, &data.last_frame, sizeof (StackFrameInfo));
                                memcpy (&tls->async_ctx, &data.ctx, sizeof (MonoContext));
@@ -2192,6 +2221,60 @@ is_suspended (void)
        return count_threads_to_wait_for () == 0;
 }
 
+/*
+ * find_seq_point_for_native_offset:
+ *
+ *   Find the sequence point corresponding to the native offset NATIVE_OFFSET, which
+ * should be the location of a sequence point.
+ */
+static SeqPoint*
+find_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
+{
+       MonoSeqPointInfo *seq_points;
+       int i;
+
+       mono_domain_lock (domain);
+       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
+       mono_domain_unlock (domain);
+       g_assert (seq_points);
+
+       *info = seq_points;
+
+       for (i = 0; i < seq_points->len; ++i) {
+               if (seq_points->seq_points [i].native_offset == native_offset)
+                       return &seq_points->seq_points [i];
+       }
+
+       return NULL;
+}
+
+/*
+ * find_seq_point:
+ *
+ *   Find the sequence point corresponding to the IL offset IL_OFFSET, which
+ * should be the location of a sequence point.
+ */
+static SeqPoint*
+find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info)
+{
+       MonoSeqPointInfo *seq_points;
+       int i;
+
+       mono_domain_lock (domain);
+       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
+       mono_domain_unlock (domain);
+       g_assert (seq_points);
+
+       *info = seq_points;
+
+       for (i = 0; i < seq_points->len; ++i) {
+               if (seq_points->seq_points [i].il_offset == il_offset)
+                       return &seq_points->seq_points [i];
+       }
+
+       return NULL;
+}
+
 /*
  * compute_il_offset:
  *
@@ -2203,7 +2286,7 @@ is_suspended (void)
 static gint32
 compute_il_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
 {
-       GPtrArray *seq_points;
+       MonoSeqPointInfo *seq_points;
        int i, last_il_offset, seq_il_offset, seq_native_offset;
 
        mono_domain_lock (domain);
@@ -2214,9 +2297,9 @@ compute_il_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
        last_il_offset = -1;
 
        /* Find the sequence point */
-       for (i = 0; i < seq_points->len; i += 2) {
-               seq_il_offset = GPOINTER_TO_UINT (g_ptr_array_index (seq_points, i));
-               seq_native_offset = GPOINTER_TO_UINT (g_ptr_array_index (seq_points, i + 1));
+       for (i = 0; i < seq_points->len; ++i) {
+               seq_il_offset = seq_points->seq_points [i].il_offset;
+               seq_native_offset = seq_points->seq_points [i].native_offset;
 
                if (seq_native_offset > native_offset)
                        break;
@@ -2754,7 +2837,9 @@ start_runtime_invoke (MonoProfiler *prof, MonoMethod *method)
        mono_loader_lock ();
        
        tls = mono_g_hash_table_lookup (thread_to_tls, thread);
-       tls->invoke_addr = stackptr;
+       /* Could be the debugger thread with assembly/type load hooks */
+       if (tls)
+               tls->invoke_addr = stackptr;
 
        mono_loader_unlock ();
 }
@@ -2783,9 +2868,9 @@ end_runtime_invoke (MonoProfiler *prof, MonoMethod *method)
                EventRequest *req = g_ptr_array_index (event_requests, i);
 
                if (req->event_kind == EVENT_KIND_STEP) {
-                       ss_stop (req);
-                        g_ptr_array_remove_index_fast (event_requests, i);
-                        g_free (req);
+                       ss_destroy (req->info);
+                       g_ptr_array_remove_index_fast (event_requests, i);
+                       g_free (req);
                        break;
                }
        }
@@ -2904,16 +2989,16 @@ breakpoints_cleanup (void)
  * JI.
  */
 static void
-insert_breakpoint (GPtrArray *seq_points, MonoJitInfo *ji, MonoBreakpoint *bp)
+insert_breakpoint (MonoSeqPointInfo *seq_points, MonoJitInfo *ji, MonoBreakpoint *bp)
 {
        int i, count;
        gint32 il_offset, native_offset;
        BreakpointInstance *inst;
 
        native_offset = 0;
-       for (i = 0; i < seq_points->len; i += 2) {
-               il_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i));
-               native_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i + 1));
+       for (i = 0; i < seq_points->len; ++i) {
+               il_offset = seq_points->seq_points [i].il_offset;
+               native_offset = seq_points->seq_points [i].native_offset;
 
                if (il_offset == bp->il_offset)
                        break;
@@ -2977,7 +3062,7 @@ static void
 add_pending_breakpoints (MonoMethod *method, MonoJitInfo *ji)
 {
        int i;
-       GPtrArray *seq_points;
+       MonoSeqPointInfo *seq_points;
        MonoDomain *domain;
 
        if (!breakpoints)
@@ -3007,7 +3092,7 @@ add_pending_breakpoints (MonoMethod *method, MonoJitInfo *ji)
 }
 
 static void
-set_bp_in_method (MonoDomain *domain, MonoMethod *method, GPtrArray *seq_points, MonoBreakpoint *bp)
+set_bp_in_method (MonoDomain *domain, MonoMethod *method, MonoSeqPointInfo *seq_points, MonoBreakpoint *bp)
 {
        gpointer code;
        MonoJitInfo *ji;
@@ -3029,7 +3114,7 @@ static void
 set_bp_in_method_cb (gpointer key, gpointer value, gpointer user_data)
 {
        MonoMethod *method = key;
-       GPtrArray *seq_points = value;
+       MonoSeqPointInfo *seq_points = value;
        MonoBreakpoint *bp = user_data;
        MonoDomain *domain = mono_domain_get ();
 
@@ -3055,7 +3140,7 @@ set_bp_in_method_cb (gpointer key, gpointer value, gpointer user_data)
 static MonoBreakpoint*
 set_breakpoint (MonoMethod *method, long il_offset, EventRequest *req)
 {
-       GPtrArray *seq_points;
+       MonoSeqPointInfo *seq_points;
        MonoDomain *domain;
        MonoBreakpoint *bp;
 
@@ -3072,7 +3157,7 @@ set_breakpoint (MonoMethod *method, long il_offset, EventRequest *req)
        bp->req = req;
        bp->children = g_ptr_array_new ();
 
-       DEBUG(1, fprintf (log_file, "[dbg] Setting breakpoint at %s:0x%x.\n", method ? mono_method_full_name (method, TRUE) : "<all>", (int)il_offset));
+       DEBUG(1, fprintf (log_file, "[dbg] Setting %sbreakpoint at %s:0x%x.\n", (req->event_kind == EVENT_KIND_STEP) ? "single step " : "", method ? mono_method_full_name (method, TRUE) : "<all>", (int)il_offset));
 
        domain = mono_domain_get ();
        mono_domain_lock (domain);
@@ -3132,8 +3217,8 @@ process_breakpoint_inner (DebuggerTlsData *tls, MonoContext *ctx)
        guint32 native_offset;
        MonoBreakpoint *bp;
        BreakpointInstance *inst;
-       GPtrArray *reqs;
-       GSList *events = NULL;
+       GPtrArray *bp_reqs, *ss_reqs_orig, *ss_reqs;
+       GSList *bp_events = NULL, *ss_events = NULL, *enter_leave_events = NULL;
        EventKind kind = EVENT_KIND_BREAKPOINT;
 
        // FIXME: Speed this up
@@ -3159,7 +3244,9 @@ process_breakpoint_inner (DebuggerTlsData *tls, MonoContext *ctx)
        if (ji->method->wrapper_type || tls->disable_breakpoints)
                return;
 
-       reqs = g_ptr_array_new ();
+       bp_reqs = g_ptr_array_new ();
+       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));
 
@@ -3174,12 +3261,17 @@ process_breakpoint_inner (DebuggerTlsData *tls, MonoContext *ctx)
 
                for (j = 0; j < bp->children->len; ++j) {
                        inst = g_ptr_array_index (bp->children, j);
-                       if (inst->ji == ji && inst->native_offset == native_offset)
-                               g_ptr_array_add (reqs, bp->req);
+                       if (inst->ji == ji && inst->native_offset == native_offset) {
+                               if (bp->req->event_kind == EVENT_KIND_STEP) {
+                                       g_ptr_array_add (ss_reqs_orig, bp->req);
+                               } else {
+                                       g_ptr_array_add (bp_reqs, bp->req);
+                               }
+                       }
                }
        }
-       if (reqs->len == 0) {
-               GPtrArray *seq_points;
+       if (bp_reqs->len == 0 && ss_reqs_orig->len == 0) {
+               MonoSeqPointInfo *seq_points;
                int seq_il_offset, seq_native_offset;
                MonoDomain *domain = mono_domain_get ();
 
@@ -3194,9 +3286,9 @@ process_breakpoint_inner (DebuggerTlsData *tls, MonoContext *ctx)
                }
                g_assert (seq_points);
 
-               for (i = 0; i < seq_points->len; i += 2) {
-                       seq_il_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i));
-                       seq_native_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i + 1));
+               for (i = 0; i < seq_points->len; ++i) {
+                       seq_il_offset = seq_points->seq_points [i].il_offset;
+                       seq_native_offset = seq_points->seq_points [i].native_offset;
 
                        if (native_offset == seq_native_offset) {
                                if (seq_il_offset == METHOD_ENTRY_IL_OFFSET)
@@ -3207,18 +3299,68 @@ process_breakpoint_inner (DebuggerTlsData *tls, MonoContext *ctx)
                        }
                }
        }
-       
-       if (reqs->len > 0)
-               events = create_event_list (EVENT_KIND_BREAKPOINT, reqs, ji, NULL, &suspend_policy);
-       else if (kind != EVENT_KIND_BREAKPOINT)
-               events = create_event_list (kind, NULL, ji, NULL, &suspend_policy);
 
-       g_ptr_array_free (reqs, TRUE);
+       /* Process single step requests */
+       for (i = 0; i < ss_reqs_orig->len; ++i) {
+               EventRequest *req = g_ptr_array_index (ss_reqs_orig, i);
+               SingleStepReq *ss_req = bp->req->info;
+               gboolean hit = TRUE;
+               MonoSeqPointInfo *info;
+               SeqPoint *sp;
+
+               sp = find_seq_point_for_native_offset (mono_domain_get (), ji->method, native_offset, &info);
+               g_assert (sp);
+
+               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 */
+                               hit = FALSE;
+                               
+                       if (loc) {
+                               ss_req->last_method = ji->method;
+                               ss_req->last_line = loc->row;
+                               mono_debug_free_source_location (loc);
+                       }
+               }
+
+               if (hit)
+                       g_ptr_array_add (ss_reqs, req);
+
+               /* Start single stepping again from the current sequence point */
+               ss_start (ss_req, ji->method, sp, info, ctx, NULL);
+       }
+       
+       if (ss_reqs->len > 0)
+               ss_events = create_event_list (EVENT_KIND_STEP, ss_reqs, ji, NULL, &suspend_policy);
+       if (bp_reqs->len > 0)
+               bp_events = create_event_list (EVENT_KIND_BREAKPOINT, bp_reqs, ji, NULL, &suspend_policy);
+       if (kind != EVENT_KIND_BREAKPOINT)
+               enter_leave_events = create_event_list (kind, NULL, ji, NULL, &suspend_policy);
 
        mono_loader_unlock ();
 
-       if (events)
-               process_event (kind, ji->method, 0, ctx, events, suspend_policy);
+       g_ptr_array_free (bp_reqs, TRUE);
+       g_ptr_array_free (ss_reqs, TRUE);
+
+       /* 
+        * FIXME: The first event will suspend, so the second will only be sent after the
+        * resume.
+        */
+       if (ss_events)
+               process_event (EVENT_KIND_STEP, ji->method, 0, ctx, ss_events, suspend_policy);
+       if (bp_events)
+               process_event (kind, ji->method, 0, ctx, bp_events, suspend_policy);
+       if (enter_leave_events)
+               process_event (kind, ji->method, 0, ctx, enter_leave_events, suspend_policy);
 }
 
 static void
@@ -3259,8 +3401,11 @@ resume_from_signal_handler (void *sigctx, void *func)
        mono_arch_sigctx_to_monoctx (sigctx, &ctx);
        memcpy (&tls->handler_ctx, &ctx, sizeof (MonoContext));
        MONO_CONTEXT_SET_IP (&ctx, func);
-
        mono_arch_monoctx_to_sigctx (&ctx, sigctx);
+
+#ifdef PPC_USES_FUNCTION_DESCRIPTOR
+       mono_ppc_set_func_into_sigctx (sigctx, func);
+#endif
 }
 
 void
@@ -3519,13 +3664,101 @@ stop_single_stepping (void)
 #endif
 }
 
+/*
+ * ss_stop:
+ *
+ *   Stop the single stepping operation given by SS_REQ.
+ */
+static void
+ss_stop (SingleStepReq *ss_req)
+{
+       gboolean use_bps = FALSE;
+
+       if (ss_req->bps) {
+               GSList *l;
+
+               use_bps = TRUE;
+
+               for (l = ss_req->bps; l; l = l->next) {
+                       clear_breakpoint (l->data);
+               }
+               g_slist_free (ss_req->bps);
+               ss_req->bps = NULL;
+       }
+
+       if (ss_req->global) {
+               stop_single_stepping ();
+               ss_req->global = FALSE;
+       }
+}
+
+/*
+ * ss_start:
+ *
+ *   Start the single stepping operation given by SS_REQ from the sequence point SP.
+ */
+static void
+ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls)
+{
+       gboolean use_bp = FALSE;
+       int i, frame_index;
+       SeqPoint *next_sp;
+       MonoBreakpoint *bp;
+
+       /* Stop the previous operation */
+       ss_stop (ss_req);
+
+       /*
+        * Implement single stepping using breakpoints if possible.
+        */
+       if (ss_req->depth == STEP_DEPTH_OVER) {
+               frame_index = 1;
+               /*
+                * Find the first sequence point in the current or in a previous frame which
+                * is not the last in its method.
+                */
+               while (sp && sp->next_len == 0) {
+                       sp = NULL;
+                       if (tls && frame_index < tls->frame_count) {
+                               StackFrame *frame = tls->frames [frame_index];
+
+                               method = frame->method;
+                               if (frame->il_offset != -1) {
+                                       sp = find_seq_point (frame->domain, frame->method, frame->il_offset, &info);
+                               }
+                               frame_index ++;
+                       }
+               }
+
+               if (sp && sp->next_len > 0) {
+                       use_bp = TRUE;
+                       for (i = 0; i < sp->next_len; ++i) {
+                               next_sp = &info->seq_points [sp->next [i]];
+
+                               bp = set_breakpoint (method, next_sp->il_offset, ss_req->req);
+                               ss_req->bps = g_slist_append (ss_req->bps, bp);
+                       }
+               }
+       }
+
+       if (!ss_req->bps) {
+               ss_req->global = TRUE;
+               start_single_stepping ();
+       } else {
+               ss_req->global = FALSE;
+       }
+}
+
 /*
  * Start single stepping of thread THREAD
  */
 static ErrorCode
-ss_start (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req)
+ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req)
 {
        DebuggerTlsData *tls;
+       MonoSeqPointInfo *info;
+       SeqPoint *sp = NULL;
+       MonoMethod *method = NULL;
 
        if (suspend_count == 0)
                return ERR_NOT_SUSPENDED;
@@ -3538,7 +3771,7 @@ ss_start (MonoInternalThread *thread, StepSize size, StepDepth depth, EventReque
                return ERR_NOT_IMPLEMENTED;
        }
 
-       ss_req = g_new0 (MonoSingleStepReq, 1);
+       ss_req = g_new0 (SingleStepReq, 1);
        ss_req->req = req;
        ss_req->thread = thread;
        ss_req->size = size;
@@ -3576,22 +3809,37 @@ ss_start (MonoInternalThread *thread, StepSize size, StepDepth depth, EventReque
                }
        }
 
-       start_single_stepping ();
+       if (ss_req->depth == STEP_DEPTH_OVER) {
+               StackFrame *frame;
+
+               compute_frame_info (thread, tls);
+
+               g_assert (tls->frame_count);
+               frame = tls->frames [0];
+
+               if (frame->il_offset != -1) {
+                       /* FIXME: Sort the table and use a binary search */
+                       sp = find_seq_point (frame->domain, frame->method, frame->il_offset, &info);
+                       g_assert (sp);
+                       method = frame->method;
+               }
+       }
+
+       ss_start (ss_req, method, sp, info, NULL, tls);
 
        return 0;
 }
 
 static void
-ss_stop (EventRequest *req)
+ss_destroy (SingleStepReq *req)
 {
        // FIXME: Locking
-       g_assert (ss_req);
-       g_assert (ss_req->req == req);
+       g_assert (ss_req == req);
+
+       ss_stop (ss_req);
 
        g_free (ss_req);
        ss_req = NULL;
-
-       stop_single_stepping ();
 }
 
 void
@@ -3610,7 +3858,7 @@ mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *ctx)
                        char *ex_type = l->data;
                        char *f = mono_type_full_name (&exc->object.vtable->klass->byval_arg);
 
-                       if (!strcmp (ex_type, f))
+                       if (!strcmp (ex_type, "") || !strcmp (ex_type, f))
                                found = TRUE;
 
                        g_free (f);
@@ -3658,12 +3906,15 @@ mono_debugger_agent_handle_unhandled_exception (MonoException *exc, MonoContext
 }
 
 /*
- * buffer_add_value:
+ * buffer_add_value_full:
  *
  *   Add the encoding of the value at ADDR described by T to the buffer.
+ * AS_VTYPE determines whenever to treat primitive types as primitive types or
+ * vtypes.
  */
 static void
-buffer_add_value (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain)
+buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain,
+                                          gboolean as_vtype)
 {
        MonoObject *obj;
 
@@ -3672,6 +3923,30 @@ buffer_add_value (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain)
                addr = *(void**)addr;
        }
 
+       if (as_vtype) {
+               switch (t->type) {
+               case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
+               case MONO_TYPE_CHAR:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+               case MONO_TYPE_R4:
+               case MONO_TYPE_I8:
+               case MONO_TYPE_U8:
+               case MONO_TYPE_R8:
+               case MONO_TYPE_I:
+               case MONO_TYPE_U:
+               case MONO_TYPE_PTR:
+                       goto handle_vtype;
+                       break;
+               default:
+                       break;
+               }
+       }
+
        switch (t->type) {
        case MONO_TYPE_VOID:
                buffer_add_byte (buf, t->type);
@@ -3764,7 +4039,7 @@ buffer_add_value (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain)
                                continue;
                        if (mono_field_is_deleted (f))
                                continue;
-                       buffer_add_value (buf, f->type, (guint8*)addr + f->offset - sizeof (MonoObject), domain);
+                       buffer_add_value_full (buf, f->type, (guint8*)addr + f->offset - sizeof (MonoObject), domain, FALSE);
                }
                break;
        }
@@ -3780,14 +4055,23 @@ buffer_add_value (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain)
        }
 }
 
+static void
+buffer_add_value (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain)
+{
+       buffer_add_value_full (buf, t, addr, domain, FALSE);
+}
+
 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 (type != t->type && !MONO_TYPE_IS_REFERENCE (t)) {
-               DEBUG(1, fprintf (log_file, "Expected value of type %d, got %d.\n", t->type, type));
+       if (type != t->type && !MONO_TYPE_IS_REFERENCE (t) &&
+               !(t->type == MONO_TYPE_I && type == MONO_TYPE_VALUETYPE) &&
+               !(t->type == MONO_TYPE_U && type == MONO_TYPE_VALUETYPE) &&
+               !(t->type == MONO_TYPE_PTR && type == MONO_TYPE_I8)) {
+               DEBUG(1, fprintf (log_file, "[%p] Expected value of type 0x%0x, got 0x%0x.\n", (gpointer)GetCurrentThreadId (), t->type, type));
                return ERR_INVALID_ARGUMENT;
        }
 
@@ -3828,6 +4112,16 @@ decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8
        case MONO_TYPE_R8:
                *(guint64*)addr = decode_long (buf, &buf, limit);
                break;
+       case MONO_TYPE_PTR:
+               /* We send these as I8, so we get them back as such */
+               g_assert (type == MONO_TYPE_I8);
+               *(gssize*)addr = decode_long (buf, &buf, limit);
+               break;
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+               /* We send these as vtypes, so we get them back as such */
+               g_assert (type == MONO_TYPE_VALUETYPE);
+               /* Fall through */
        case MONO_TYPE_VALUETYPE: {
                gboolean is_enum = decode_byte (buf, &buf, limit);
                MonoClass *klass;
@@ -3894,7 +4188,7 @@ 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)
+add_var (Buffer *buf, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, gboolean as_vtype)
 {
        guint32 flags;
        int reg;
@@ -3908,7 +4202,7 @@ add_var (Buffer *buf, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, Mono
        case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
                reg_val = mono_arch_context_get_int_reg (ctx, reg);
 
-               buffer_add_value (buf, t, &reg_val, domain);
+               buffer_add_value_full (buf, t, &reg_val, domain, as_vtype);
                break;
        case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
                addr = mono_arch_context_get_int_reg (ctx, reg);
@@ -3916,7 +4210,7 @@ add_var (Buffer *buf, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, Mono
 
                //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
 
-               buffer_add_value (buf, t, addr, domain);
+               buffer_add_value_full (buf, t, addr, domain, as_vtype);
                break;
        case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD:
                NOT_IMPLEMENTED;
@@ -3976,7 +4270,7 @@ clear_event_request (int req_id, int etype)
                        if (req->event_kind == EVENT_KIND_BREAKPOINT)
                                clear_breakpoint (req->info);
                        if (req->event_kind == EVENT_KIND_STEP)
-                               ss_stop (req);
+                               ss_destroy (req->info);
                        if (req->event_kind == EVENT_KIND_METHOD_ENTRY)
                                clear_breakpoint (req->info);
                        if (req->event_kind == EVENT_KIND_METHOD_EXIT)
@@ -4121,6 +4415,11 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke)
                /* Mark that this is a MonoLMFExt */
                ext.lmf.previous_lmf = (gpointer)(((gssize)ext.lmf.previous_lmf) | 2);
                ext.lmf.ebp = (gssize)&ext;
+#elif defined(TARGET_POWERPC)
+               ext.lmf.previous_lmf = *(lmf_addr);
+               /* Mark that this is a MonoLMFExt */
+               ext.lmf.previous_lmf = (gpointer)(((gssize)ext.lmf.previous_lmf) | 2);
+               ext.lmf.ebp = (gssize)&ext;
 #else
                g_assert_not_reached ();
 #endif
@@ -4526,7 +4825,7 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                                return err;
                        }
 
-                       err = ss_start (THREAD_TO_INTERNAL (step_thread), size, depth, req);
+                       err = ss_create (THREAD_TO_INTERNAL (step_thread), size, depth, req);
                        if (err) {
                                g_free (req);
                                return err;
@@ -5511,13 +5810,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);
+                               add_var (buf, 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);
+                               add_var (buf, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
                        }
                }
                break;
@@ -5528,14 +5827,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->method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain);
+                               add_var (buf, &frame->method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
                        }
                } else {
                        if (!sig->hasthis) {
                                MonoObject *p = NULL;
                                buffer_add_value (buf, &frame->method->klass->byval_arg, &p, frame->domain);
                        } else {
-                               add_var (buf, &frame->method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain);
+                               add_var (buf, &frame->method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
                        }
                }
                break;