예제 #1
0
        protected void DoProcessEvent(Inferior.ChildEvent cevent)
        {
            Inferior.ChildEventType message = cevent.Type;
            int arg = (int) cevent.Argument;

            if (message == Inferior.ChildEventType.THROW_EXCEPTION) {
                TargetAddress info = new TargetAddress (inferior.AddressDomain, cevent.Data1);
                TargetAddress ip = new TargetAddress (manager.AddressDomain, cevent.Data2);

                Report.Debug (DebugFlags.EventLoop,
                          "{0} received exception: {1} {2} {3}", this, message, info, ip);

                TargetAddress stack = inferior.ReadAddress (info);
                TargetAddress exc = inferior.ReadAddress (info + inferior.TargetAddressSize);

                ExceptionAction action = throw_exception (stack, exc, ip);

                Report.Debug (DebugFlags.SSE,
                          "{0} throw exception ({1}:{2}:{3}) - {4} - {5} - {6}",
                          this, stack, exc, ip, action, current_operation, temp_breakpoint);

                switch (action) {
                case ExceptionAction.None:
                    do_continue ();
                    return;

                case ExceptionAction.Stop:
                    inferior.WriteInteger (info + 2 * inferior.TargetAddressSize, 1);
                    PushOperation (new OperationException (this, ip, exc, false));
                    return;

                case ExceptionAction.StopUnhandled:
                    if (!check_runtime_version (81, 1) && !check_runtime_version (80, 1))
                        goto case ExceptionAction.Stop;
                    inferior.WriteInteger (info + 4 + 2 * inferior.TargetAddressSize, 1);
                    do_continue ();
                    return;
                }
            }

            if (message == Inferior.ChildEventType.HANDLE_EXCEPTION) {
                TargetAddress info = new TargetAddress (inferior.AddressDomain, cevent.Data1);
                TargetAddress ip = new TargetAddress (manager.AddressDomain, cevent.Data2);

                Report.Debug (DebugFlags.EventLoop,
                          "{0} received exception: {1} {2} {3}", this, message, info, ip);

                TargetAddress stack = inferior.ReadAddress (info);
                TargetAddress exc = inferior.ReadAddress (info + inferior.TargetAddressSize);

                bool stop = handle_exception (stack, exc, ip);

                Report.Debug (DebugFlags.SSE,
                          "{0} {1}stopping at exception handler ({2}:{3}:{4}) - {4} - {5}",
                          this, stop ? "" : "not ", stack, exc, ip, current_operation, temp_breakpoint);

                if (stop) {
                    inferior.WriteInteger (info + 2 * inferior.TargetAddressSize, 1);
                    PushOperation (new OperationException (this, ip, exc, false));
                    return;
                }

                do_continue ();
                return;
            }

            if (lmf_breakpoint != null) {
                if ((message == Inferior.ChildEventType.CHILD_HIT_BREAKPOINT) &&
                    (arg == lmf_breakpoint.Breakpoint.ID)) {
                    remove_lmf_breakpoint ();

                    Report.Debug (DebugFlags.SSE, "{0} back in managed land: {1}",
                              this, inferior.CurrentFrame);

                    Method method = Lookup (inferior.CurrentFrame);

                    bool is_managed = (method != null) && method.Module.Language.IsManaged;
                    Report.Debug (DebugFlags.SSE, "{0} back in managed land #1: {1}", this, is_managed);

                    Queue<ManagedCallbackData> queue = process.MonoManager.ClearManagedCallbacks (inferior);
                    if (!OnManagedCallback (queue))
                        do_continue ();
                    return;
                }
            }

            // To step over a method call, the sse inserts a temporary
            // breakpoint immediately after the call instruction and then
            // resumes the target.
            //
            // If the target stops and we have such a temporary breakpoint, we
            // need to distinguish a few cases:
            //
            // a) we may have received a signal
            // b) we may have hit another breakpoint
            // c) we actually hit the temporary breakpoint
            //
            // In either case, we need to remove the temporary breakpoint if
            // the target is to remain stopped.  Note that this piece of code
            // here only deals with the temporary breakpoint, the handling of
            // a signal or another breakpoint is done later.
            if ((temp_breakpoint != null) &&
                (message == Inferior.ChildEventType.CHILD_HIT_BREAKPOINT) && (arg == temp_breakpoint.ID)) {
                // we hit the temporary breakpoint; this'll always
                // happen in the `correct' thread since the
                // `temp_breakpoint_id' is only set in this
                // SingleSteppingEngine and not in any other thread's.

                remove_temporary_breakpoint ();

                //
                // Lookup again using the current address since `arg' points to the hardware breakpoint,
                // but there may be a user breakpoint on the current instruction as well.
                //

                int idx;
                bool is_enabled;
                BreakpointHandle handle = process.BreakpointManager.LookupBreakpoint (
                    inferior.CurrentFrame, out idx, out is_enabled);

                Report.Debug (DebugFlags.SSE,
                          "{0} hit temporary breakpoint {1} at {2}: {3} {4} {5}",
                          this, arg, inferior.CurrentFrame, handle, idx, is_enabled);

                if ((handle == null) || !is_enabled || !handle.Breakpoint.Breaks (thread.ID) ||
                    handle.Breakpoint.HideFromUser) {
                    message = Inferior.ChildEventType.CHILD_STOPPED;
                    arg = 0;
                    cevent = new Inferior.ChildEvent (Inferior.ChildEventType.CHILD_STOPPED, 0, 0, 0);
                } else {
                    cevent = new Inferior.ChildEvent (Inferior.ChildEventType.CHILD_HIT_BREAKPOINT, idx, 0, 0);
                    ProcessOperationEvent (cevent);
                    return;
                }
            }

            if (message == Inferior.ChildEventType.UNHANDLED_EXCEPTION) {
                TargetAddress exc = new TargetAddress (manager.AddressDomain, cevent.Data1);
                TargetAddress ip = new TargetAddress (manager.AddressDomain, cevent.Data2);
                PushOperation (new OperationException (this, ip, exc, true));
                return;
            } else if (message == Inferior.ChildEventType.CHILD_HIT_BREAKPOINT) {
                // Ok, the next thing we need to check is whether this is actually "our"
                // breakpoint or whether it belongs to another thread.  In this case,
                // `step_over_breakpoint' does everything for us and we can just continue
                // execution.
                Breakpoint bpt;
                bool remain_stopped = child_breakpoint (cevent, arg, out bpt);
                if (!remain_stopped) {
                    do_continue ();
                    return;
                }
            }

            ProcessOperationEvent (cevent);
        }
예제 #2
0
        public bool ProcessEvent(Inferior.ChildEvent cevent)
        {
            Report.Debug (DebugFlags.EventLoop, "{0} received event {1}",
                      this, cevent);

            if (killed) {
                if (cevent.Type == Inferior.ChildEventType.CHILD_INTERRUPTED) {
                    inferior.Continue ();
                    return true;
                } else if (cevent.Type != Inferior.ChildEventType.CHILD_EXITED) {
                    Report.Debug (DebugFlags.EventLoop,
                              "{0} received event {1} when already killed",
                              this, cevent);
                    return true;
                }
            }

            if ((cevent.Type == Inferior.ChildEventType.CHILD_EXITED) ||
                (cevent.Type == Inferior.ChildEventType.CHILD_SIGNALED)) {
                Report.Debug (DebugFlags.EventLoop, "{0} received {1} while running {2}",
                          this, cevent, current_operation);
                // we can't remove the breakpoint anymore after
                // the target exited, but we need to clear this id.
                temp_breakpoint = null;
                dead = true;
            } else {
                string frame_text = "";
                Inferior.StackFrame iframe = inferior.GetCurrentFrame (true);
                if (iframe != null)
                    frame_text = " at " + iframe.Address.ToString ();

                string running_text;
                if (HasThreadLock)
                    running_text = String.Format ("being thread-locked ({0})", thread_lock);
                else
                    running_text = String.Format ("running {0}", current_operation);

                string event_text;
                if (cevent.Type == Inferior.ChildEventType.CHILD_NOTIFICATION)
                    event_text = String.Format ("notification {0} ({1})", cevent, (NotificationType) cevent.Argument);
                else
                    event_text = "event " + cevent.ToString ();

                Report.Debug (DebugFlags.EventLoop, "{0} received {1}{2} while {3}",
                          this, event_text, frame_text, running_text);

                if (HasThreadLock) {
                    thread_lock.SetStopEvent (cevent);
                    return false;
                }
            }

            if (Process.IsAttached && !attach_initialized) {
                attach_initialized = true;

                if (cevent.Type == Inferior.ChildEventType.CHILD_INTERRUPTED)
                    cevent = new Inferior.ChildEvent (Inferior.ChildEventType.CHILD_STOPPED, 0, 0, 0);
            }

            bool resume_target;
            if (manager.HandleChildEvent (this, inferior, ref cevent, out resume_target)) {
                Report.Debug (DebugFlags.EventLoop,
                          "{0} done handling event: {1}{2}{3}{4}",
                          this, cevent, resume_target ? " resume-target" : "" ,
                          stop_requested ? " stop-requested" : "",
                          HasThreadLock ? " thread-lock" : "");
                if (stop_requested) {
                    OperationInterrupted ();
                } else if (resume_target) {
                    if (!current_operation.ResumeOperation ())
                        inferior.Continue ();
                }
                return true;
            }

            Inferior.ChildEventType message = cevent.Type;
            int arg = (int) cevent.Argument;

            switch (message) {
            case Inferior.ChildEventType.CHILD_INTERRUPTED:
                if (current_operation != null)
                    OperationInterrupted ();
                return true;
            case Inferior.ChildEventType.CHILD_SIGNALED:
                if (killed)
                    OperationCompleted (new TargetEventArgs (TargetEventType.TargetExited, 0));
                else
                    OperationCompleted (new TargetEventArgs (TargetEventType.TargetSignaled, arg));
                return true;

            case Inferior.ChildEventType.INTERNAL_ERROR:
                frame_changed (inferior.CurrentFrame, null);
                Report.Error ("{0} got {1} at {2} while executing {3}", this, message,
                          inferior.CurrentFrame, current_operation);
                OperationCompleted (new TargetEventArgs (TargetEventType.TargetSignaled, -1));
                return true;

            case Inferior.ChildEventType.CHILD_EXITED:
                OperationCompleted (new TargetEventArgs (TargetEventType.TargetExited, arg));
                return true;

            case Inferior.ChildEventType.CHILD_CALLBACK_COMPLETED:
                frame_changed (inferior.CurrentFrame, null);
                OperationCompleted (new TargetEventArgs (TargetEventType.TargetStopped, 0, current_frame));
                return true;

            case Inferior.ChildEventType.RUNTIME_INVOKE_DONE:
                OperationRuntimeInvoke rti = rti_stack.Pop ();
                if (rti.ID != cevent.Argument)
                    throw new InternalError ("{0} got unknown RUNTIME_INVOKE_DONE: {1} {2}", this, rti.ID, cevent);

                frame_changed (inferior.CurrentFrame, null);
                rti.Completed (cevent.Data1, cevent.Data2);

                if (rti.IsSuspended) {
                    InterruptibleOperation io = nested_break_stack.Pop ();
                    if (io != rti)
                        throw new InternalError ("{0} unexpected item on nested break state stack: {1}", this, io);
                    process.Debugger.OnLeaveNestedBreakState (thread);
                }

                if (current_operation != rti) {
                    OperationCommandResult result = current_operation.Result as OperationCommandResult;
                    if (result != null)
                        result.Completed (this, null);
                    current_operation.Result.Completed ();
                }
                current_operation = rti;

                TargetEventArgs args = rti.OperationCompleted (current_frame, false);
                OperationCompleted (args);
                return true;
            }

            if (stop_requested) {
                switch (message) {
                case Inferior.ChildEventType.CHILD_STOPPED:
                case Inferior.ChildEventType.CHILD_CALLBACK:
                case Inferior.ChildEventType.CHILD_HIT_BREAKPOINT:
                    OperationInterrupted ();
                    return true;

                case Inferior.ChildEventType.UNHANDLED_EXCEPTION:
                case Inferior.ChildEventType.THROW_EXCEPTION:
                case Inferior.ChildEventType.HANDLE_EXCEPTION:
                case Inferior.ChildEventType.CHILD_NOTIFICATION:
                    inferior.RestartNotification ();
                    OperationInterrupted ();
                    return true;

                default:
                    OperationInterrupted ();
                    return false;
                }
            }

            DoProcessEvent (cevent);
            return true;
        }
예제 #3
0
        internal bool HandleChildEvent(SingleSteppingEngine engine, Inferior inferior,
						ref Inferior.ChildEvent cevent, out bool resume_target)
        {
            if (cevent.Type == Inferior.ChildEventType.NONE) {
                resume_target = true;
                return true;
            }

            if (cevent.Type == Inferior.ChildEventType.CHILD_CREATED_THREAD) {
                int pid = (int) cevent.Argument;
                inferior.Process.ThreadCreated (inferior, pid, false, true);
                if (pending_sigstops.ContainsKey (pid))
                    pending_sigstops.Remove (pid);
                resume_target = true;
                return true;
            }

            if (cevent.Type == Inferior.ChildEventType.CHILD_FORKED) {
                inferior.Process.ChildForked (inferior, (int) cevent.Argument);
                resume_target = true;
                return true;
            }

            if (cevent.Type == Inferior.ChildEventType.CHILD_EXECD) {
                thread_hash.Remove (engine.PID);
                engine_hash.Remove (engine.ID);
                inferior.Process.ChildExecd (engine, inferior);
                resume_target = false;
                return true;
            }

            if (cevent.Type == Inferior.ChildEventType.CHILD_STOPPED) {
                if (cevent.Argument == inferior.SIGCHLD) {
                    cevent = new Inferior.ChildEvent (
                        Inferior.ChildEventType.CHILD_STOPPED, 0, 0, 0);
                    resume_target = true;
                    return true;
                } else if (inferior.Has_SIGWINCH && (cevent.Argument == inferior.SIGWINCH)) {
                    resume_target = true;
                    return true;
                } else if (inferior.HasSignals && (cevent.Argument == inferior.Kernel_SIGRTMIN+1)) {
                    // __SIGRTMIN and __SIGRTMIN+1 are used internally by the threading library
                    resume_target = true;
                    return true;
                }
            }

            if (inferior.Process.OperatingSystem.CheckForPendingMonoInit (inferior)) {
                resume_target = true;
                return true;
            }

            bool retval = false;
            resume_target = false;
            if (inferior.Process.MonoManager != null)
                retval = inferior.Process.MonoManager.HandleChildEvent (
                    engine, inferior, ref cevent, out resume_target);

            if ((cevent.Type == Inferior.ChildEventType.CHILD_EXITED) ||
                (cevent.Type == Inferior.ChildEventType.CHILD_SIGNALED)) {
                thread_hash.Remove (engine.PID);
                engine_hash.Remove (engine.ID);
                engine.OnThreadExited (cevent);
                resume_target = false;
                return true;
            }

            return retval;
        }