Merge pull request #1412 from esdrubal/stackframe
[mono.git] / mono / mini / debugger-agent.c
index e2467da18f04e8e16a433d2134aca0c926838597..240f8419a4532cb81c55751c5b4f9965a4f7ac98 100644 (file)
@@ -84,6 +84,7 @@ int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD,
 #include <mono/utils/mono-threads.h>
 #include "debugger-agent.h"
 #include "mini.h"
+#include "seq-points.h"
 
 /*
 On iOS we can't use System.Environment.Exit () as it will do the wrong
@@ -1030,7 +1031,7 @@ mono_debugger_agent_init (void)
        breakpoints_init ();
        suspend_init ();
 
-       mini_get_debug_options ()->gen_seq_points = TRUE;
+       mini_get_debug_options ()->gen_seq_points_debug_data = TRUE;
        /* 
         * This is needed because currently we don't handle liveness info.
         */
@@ -3145,24 +3146,6 @@ is_suspended (void)
        return count_threads_to_wait_for () == 0;
 }
 
-static MonoSeqPointInfo*
-get_seq_points (MonoDomain *domain, MonoMethod *method)
-{
-       MonoSeqPointInfo *seq_points;
-
-       mono_domain_lock (domain);
-       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
-       if (!seq_points && method->is_inflated) {
-               /* generic sharing + aot */
-               seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mono_method_get_declaring_generic_method (method));
-               if (!seq_points)
-                       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mini_get_shared_method (method));
-       }
-       mono_domain_unlock (domain);
-
-       return seq_points;
-}
-
 static void
 no_seq_points_found (MonoMethod *method)
 {
@@ -3172,87 +3155,6 @@ no_seq_points_found (MonoMethod *method)
        printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method, TRUE));
 }
 
-/*
- * find_next_seq_point_for_native_offset:
- *
- *   Find the first sequence point after NATIVE_OFFSET.
- */
-static SeqPoint*
-find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
-{
-       MonoSeqPointInfo *seq_points;
-       int i;
-
-       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;
-
-       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_prev_seq_point_for_native_offset:
- *
- *   Find the first sequence point before NATIVE_OFFSET.
- */
-static SeqPoint*
-find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
-{
-       MonoSeqPointInfo *seq_points;
-       int i;
-
-       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)
-                       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 G_GNUC_UNUSED SeqPoint*
-find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info)
-{
-       MonoSeqPointInfo *seq_points;
-       int i;
-
-       *info = NULL;
-
-       seq_points = get_seq_points (domain, method);
-       if (!seq_points)
-               return NULL;
-       *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;
-}
-
 typedef struct {
        DebuggerTlsData *tls;
        GSList *frames;
@@ -3264,7 +3166,7 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
        ComputeFramesUserData *ud = user_data;
        StackFrame *frame;
        MonoMethod *method, *actual_method, *api_method;
-       SeqPoint *sp;
+       SeqPoint sp;
        int flags = 0;
 
        if (info->type != FRAME_TYPE_MANAGED) {
@@ -3292,9 +3194,8 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
        if (info->il_offset == -1) {
                /* mono_debug_il_offset_from_address () doesn't seem to be precise enough (#2092) */
                if (ud->frames == NULL) {
-                       sp = find_prev_seq_point_for_native_offset (info->domain, method, info->native_offset, NULL);
-                       if (sp)
-                               info->il_offset = sp->il_offset;
+                       if (find_prev_seq_point_for_native_offset (info->domain, method, info->native_offset, NULL, &sp))
+                               info->il_offset = sp.il_offset;
                }
                if (info->il_offset == -1)
                        info->il_offset = mono_debug_il_offset_from_address (method, info->domain, info->native_offset);
@@ -4286,7 +4187,6 @@ typedef struct {
        guint8 *ip;
        MonoJitInfo *ji;
        MonoDomain *domain;
-       SeqPoint *sp;
 } BreakpointInstance;
 
 /*
@@ -4331,38 +4231,44 @@ breakpoints_init (void)
 static void
 insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo *ji, MonoBreakpoint *bp, MonoError *error)
 {
-       int i, count;
+       int count;
        BreakpointInstance *inst;
-       SeqPoint *sp = NULL;
+       SeqPointIterator it;
+       gboolean it_has_sp = FALSE;
 
        if (error)
                mono_error_init (error);
 
-       for (i = 0; i < seq_points->len; ++i) {
-               sp = &seq_points->seq_points [i];
-
-               if (sp->il_offset == bp->il_offset)
+       seq_point_iterator_init (&it, seq_points);
+       while (seq_point_iterator_next (&it)) {
+               if (it.seq_point.il_offset == bp->il_offset) {
+                       it_has_sp = TRUE;
                        break;
+               }
        }
 
-       if (i == seq_points->len) {
+       if (!it_has_sp) {
                /*
                 * The set of IL offsets with seq points doesn't completely match the
                 * info returned by CMD_METHOD_GET_DEBUG_INFO (#407).
                 */
-               for (i = 0; i < seq_points->len; ++i) {
-                       sp = &seq_points->seq_points [i];
-
-                       if (sp->il_offset != METHOD_ENTRY_IL_OFFSET && sp->il_offset != METHOD_EXIT_IL_OFFSET && sp->il_offset + 1 == bp->il_offset)
+               seq_point_iterator_init (&it, seq_points);
+               while (seq_point_iterator_next (&it)) {
+                       if (it.seq_point.il_offset != METHOD_ENTRY_IL_OFFSET &&
+                               it.seq_point.il_offset != METHOD_EXIT_IL_OFFSET &&
+                               it.seq_point.il_offset + 1 == bp->il_offset) {
+                               it_has_sp = TRUE;
                                break;
+                       }
                }
        }
 
-       if (i == seq_points->len) {
-               char *s = g_strdup_printf ("Unable to insert breakpoint at %s:%d, seq_points=%d\n", mono_method_full_name (jinfo_get_method (ji), TRUE), bp->il_offset, seq_points->len);
+       if (!it_has_sp) {
+               char *s = g_strdup_printf ("Unable to insert breakpoint at %s:%d", mono_method_full_name (jinfo_get_method (ji), TRUE), bp->il_offset);
 
-               for (i = 0; i < seq_points->len; ++i)
-                       DEBUG (1, fprintf (log_file, "%d\n", seq_points->seq_points [i].il_offset));
+               seq_point_iterator_init (&it, seq_points);
+               while (seq_point_iterator_next (&it))
+                       DEBUG (1, fprintf (log_file, "%d\n", it.seq_point.il_offset));
 
                if (error) {
                        mono_error_set_error (error, MONO_ERROR_GENERIC, "%s", s);
@@ -4377,9 +4283,9 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
        }
 
        inst = g_new0 (BreakpointInstance, 1);
-       inst->sp = sp;
-       inst->native_offset = sp->native_offset;
-       inst->ip = (guint8*)ji->code_start + sp->native_offset;
+       inst->il_offset = it.seq_point.il_offset;
+       inst->native_offset = it.seq_point.native_offset;
+       inst->ip = (guint8*)ji->code_start + it.seq_point.native_offset;
        inst->ji = ji;
        inst->domain = domain;
 
@@ -4394,7 +4300,7 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
        g_hash_table_insert (bp_locs, inst->ip, GINT_TO_POINTER (count + 1));
        dbg_unlock ();
 
-       if (sp->native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
+       if (it.seq_point.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
@@ -4404,7 +4310,7 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
 #endif
        }
 
-       DEBUG(1, fprintf (log_file, "[dbg] Inserted breakpoint at %s:0x%x [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)sp->il_offset, inst->ip, count));
+       DEBUG(1, fprintf (log_file, "[dbg] Inserted breakpoint at %s:0x%x [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)it.seq_point.il_offset, inst->ip, count));
 }
 
 static void
@@ -4776,7 +4682,8 @@ process_breakpoint_inner (DebuggerTlsData *tls)
        MonoContext *ctx = &tls->restore_ctx;
        MonoMethod *method;
        MonoSeqPointInfo *info;
-       SeqPoint *sp;
+       SeqPoint sp;
+       gboolean found_sp;
 
        // FIXME: Speed this up
 
@@ -4806,12 +4713,14 @@ process_breakpoint_inner (DebuggerTlsData *tls)
         * The ip points to the instruction causing the breakpoint event, which is after
         * 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 (), method, native_offset, &info);
-       if (!sp)
+       found_sp = find_prev_seq_point_for_native_offset (mono_domain_get (), method, native_offset, &info, &sp);
+
+       if (!found_sp)
                no_seq_points_found (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 (), method->name, ip, native_offset, sp ? sp->il_offset : -1));
+       g_assert (found_sp);
+
+       DEBUG(1, fprintf (log_file, "[%p] Breakpoint hit, method=%s, ip=%p, offset=0x%x, sp il offset=0x%x.\n", (gpointer)GetCurrentThreadId (), method->name, ip, native_offset, sp.il_offset));
 
        bp = NULL;
        for (i = 0; i < breakpoints->len; ++i) {
@@ -4822,7 +4731,7 @@ process_breakpoint_inner (DebuggerTlsData *tls)
 
                for (j = 0; j < bp->children->len; ++j) {
                        inst = g_ptr_array_index (bp->children, j);
-                       if (inst->ji == ji && inst->sp == sp) {
+                       if (inst->ji == ji && inst->il_offset == sp.il_offset && inst->native_offset == sp.native_offset) {
                                if (bp->req->event_kind == EVENT_KIND_STEP) {
                                        g_ptr_array_add (ss_reqs_orig, bp->req);
                                } else {
@@ -4833,9 +4742,9 @@ process_breakpoint_inner (DebuggerTlsData *tls)
        }
        if (bp_reqs->len == 0 && ss_reqs_orig->len == 0) {
                /* Maybe a method entry/exit event */
-               if (sp->il_offset == METHOD_ENTRY_IL_OFFSET)
+               if (sp.il_offset == METHOD_ENTRY_IL_OFFSET)
                        kind = EVENT_KIND_METHOD_ENTRY;
-               else if (sp->il_offset == METHOD_EXIT_IL_OFFSET)
+               else if (sp.il_offset == METHOD_EXIT_IL_OFFSET)
                        kind = EVENT_KIND_METHOD_EXIT;
        }
 
@@ -4848,12 +4757,12 @@ process_breakpoint_inner (DebuggerTlsData *tls)
                if (mono_thread_internal_current () != ss_req->thread)
                        continue;
 
-               hit = ss_update (ss_req, ji, sp, tls, ctx);
+               hit = ss_update (ss_req, ji, &sp, tls, ctx);
                if (hit)
                        g_ptr_array_add (ss_reqs, req);
 
                /* Start single stepping again from the current sequence point */
-               ss_start (ss_req, method, sp, info, ctx, tls, FALSE);
+               ss_start (ss_req, method, &sp, info, ctx, tls, FALSE);
        }
        
        if (ss_reqs->len > 0)
@@ -5014,7 +4923,7 @@ process_single_step_inner (DebuggerTlsData *tls)
        GSList *events;
        MonoContext *ctx = &tls->restore_ctx;
        MonoMethod *method;
-       SeqPoint *sp;
+       SeqPoint sp;
        MonoSeqPointInfo *info;
 
        ip = MONO_CONTEXT_GET_IP (ctx);
@@ -5060,16 +4969,16 @@ process_single_step_inner (DebuggerTlsData *tls)
         * The ip points to the instruction causing the single step event, which is before
         * the offset recorded in the seq point map, so find the next seq point after ip.
         */
-       sp = find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info);
-       if (!sp)
+       if (!find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp))
                return;
-       il_offset = sp->il_offset;
 
-       if (!ss_update (ss_req, ji, sp, tls, ctx))
+       il_offset = sp.il_offset;
+
+       if (!ss_update (ss_req, ji, &sp, tls, ctx))
                return;
 
        /* Start single stepping again from the current sequence point */
-       ss_start (ss_req, method, sp, info, ctx, tls, FALSE);
+       ss_start (ss_req, method, &sp, info, ctx, tls, FALSE);
 
        if ((ss_req->filter & STEP_FILTER_STATIC_CTOR) &&
                (method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
@@ -5243,10 +5152,12 @@ ss_stop (SingleStepReq *ss_req)
  * belong to the same thread as CTX.
  */
 static void
-ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch)
+ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPointsp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch)
 {
        int i, j, frame_index;
        SeqPoint *next_sp;
+       SeqPoint local_sp;
+       gboolean found_sp;
        MonoBreakpoint *bp;
        gboolean enable_global = FALSE;
 
@@ -5279,7 +5190,8 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                                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);
+                               found_sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info, &local_sp);
+                               sp = (found_sp)? &local_sp : NULL;
                                frame_index ++;
                                if (sp && sp->next_len != 0)
                                        break;
@@ -5293,7 +5205,8 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                                        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);
+                                       found_sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info, &local_sp);
+                                       sp = (found_sp)? &local_sp : NULL;
                                        if (sp && sp->next_len != 0)
                                                break;
                                        sp = NULL;
@@ -5303,12 +5216,16 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                }
 
                if (sp && sp->next_len > 0) {
-                       for (i = 0; i < sp->next_len; ++i) {
-                               next_sp = &info->seq_points [sp->next [i]];
+                       SeqPoint* next = g_new(SeqPoint, sp->next_len);
+
+                       seq_point_init_next (info, *sp, next);
+                       for (i = 0; i < sp->next_len; i++) {
+                               next_sp = &next[i];
 
                                bp = set_breakpoint (method, next_sp->il_offset, ss_req->req, NULL);
                                ss_req->bps = g_slist_append (ss_req->bps, bp);
                        }
+                       g_free (next);
                }
 
                if (ss_req->depth == STEP_DEPTH_OVER) {
@@ -5323,7 +5240,8 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                                        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);
+                                               found_sp = find_next_seq_point_for_native_offset (frame->domain, frame->method, (char*)ei->handler_start - (char*)jinfo->code_start, NULL, &local_sp);
+                                               sp = (found_sp)? &local_sp : 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);
@@ -5369,6 +5287,8 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ
        DebuggerTlsData *tls;
        MonoSeqPointInfo *info = NULL;
        SeqPoint *sp = NULL;
+       SeqPoint local_sp;
+       gboolean found_sp;
        MonoMethod *method = NULL;
        MonoDebugMethodInfo *minfo;
        gboolean step_to_catch = FALSE;
@@ -5419,7 +5339,8 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ
                 * Find the seq point corresponding to the landing site ip, which is the first seq
                 * point after ip.
                 */
-               sp = find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info);
+               found_sp = find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info, &local_sp);
+               sp = (found_sp)? &local_sp : NULL;
                if (!sp)
                        no_seq_points_found (frame.method);
                g_assert (sp);
@@ -5465,7 +5386,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);
+                               found_sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info, &local_sp);
+                               sp = (found_sp)? &local_sp : NULL;
                                if (!sp)
                                        no_seq_points_found (frame->method);
                                g_assert (sp);
@@ -8856,9 +8778,9 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                MonoMethod *method;
                MonoDomain *domain;
                MonoSeqPointInfo *seq_points;
-               SeqPoint *sp = NULL;
+               SeqPoint sp;
+               gboolean found_sp;
                gint64 il_offset;
-               int i;
 
                method = decode_methodid (p, &p, end, &domain, &err);
                if (err)
@@ -8879,22 +8801,17 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                if (tls->frame_count == 0 || tls->frames [0]->actual_method != method)
                        return ERR_INVALID_ARGUMENT;
 
-               seq_points = get_seq_points (domain, method);
-               g_assert (seq_points);
+               found_sp = find_seq_point (domain, method, il_offset, &seq_points, &sp);
 
-               for (i = 0; i < seq_points->len; ++i) {
-                       sp = &seq_points->seq_points [i];
+               g_assert (seq_points);
 
-                       if (sp->il_offset == il_offset)
-                               break;
-               }
-               if (i == seq_points->len)
+               if (!found_sp)
                        return ERR_INVALID_ARGUMENT;
 
                // FIXME: Check that the ip change is safe
 
-               DEBUG (1, fprintf (log_file, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp->il_offset, (int)sp->native_offset));
-               MONO_CONTEXT_SET_IP (&tls->restore_ctx, (guint8*)tls->frames [0]->ji->code_start + sp->native_offset);
+               DEBUG (1, fprintf (log_file, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp.il_offset, (int)sp.native_offset));
+               MONO_CONTEXT_SET_IP (&tls->restore_ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
                break;
        }
        default:
@@ -9807,4 +9724,3 @@ mono_debugger_agent_unhandled_exception (MonoException *exc)
 }
 
 #endif
-