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;
        }
        void remove_temporary_breakpoint()
        {
            if (temp_breakpoint != null) {
                Report.Debug (DebugFlags.SSE, "{0} removing temp breakpoint {1}",
                          this, temp_breakpoint);

                inferior.RemoveBreakpoint (temp_breakpoint.ID);
                temp_breakpoint = null;
            }
        }
        void remove_lmf_breakpoint()
        {
            if (lmf_breakpoint == null)
                return;

            /*
             * We reused an already existing single-stepping breakpoint at the requested location.
             */
            if (lmf_breakpoint.Breakpoint == lmf_breakpoint.StolenBreakpoint)
                return;

            inferior.RemoveBreakpoint (lmf_breakpoint.Breakpoint.ID);

            /*
             * We stole the single-stepping breakpoint -> restore it here.
             */

            if (lmf_breakpoint.StolenBreakpoint != null) {
                int dr_index;
                TargetAddress address = lmf_breakpoint.StolenBreakpoint.Address;
                int id = inferior.InsertHardwareBreakpoint (address, true, out dr_index);

                temp_breakpoint = new TemporaryBreakpointData (id, address);

                Report.Debug (DebugFlags.SSE, "{0} restored stolen breakpoint: {1}", this, temp_breakpoint);
            }

            lmf_breakpoint = null;
        }
        void insert_temporary_breakpoint(TargetAddress address)
        {
            check_inferior ();

            if (temp_breakpoint != null)
                throw new InternalError ("temp_breakpoint_id != 0");

            int dr_index;
            int id = inferior.InsertHardwareBreakpoint (address, true, out dr_index);
            temp_breakpoint = new TemporaryBreakpointData (id, address);

            Report.Debug (DebugFlags.SSE, "{0} inserted temp breakpoint {1}:{2} at {3}",
                      this, id, dr_index, address);
        }
        void insert_lmf_breakpoint(TargetAddress lmf_address)
        {
            lmf_breakpoint = new LMFBreakpointData (lmf_address);

            /*
             * Insert a breakpoint on the last managed frame (LMF).  We use a hardware breakpoint for this
             * since the JIT might inspect / modify the callsite and we don't know whether we're at a safe
             * spot right now.
             *
             * If we already have a single-stepping breakpoint, we "steal" it here, so we only use one single
             * hardware register internally in the SSE.
             *
             */

            if (temp_breakpoint != null) {
                Report.Debug (DebugFlags.SSE, "{0} stealing temporary breakpoint {1} at {2} -> lmf breakpoint at {2}.",
                          temp_breakpoint.ID, temp_breakpoint.Address, lmf_address);

                lmf_breakpoint.StolenBreakpoint = temp_breakpoint;
                temp_breakpoint = null;

                /*
                 * The breakpoint is already at the requested location -> keep and reuse it.
                 */

                if (lmf_address == temp_breakpoint.Address) {
                    lmf_breakpoint.Breakpoint = lmf_breakpoint.StolenBreakpoint;
                    return;
                }

                inferior.RemoveBreakpoint (lmf_breakpoint.StolenBreakpoint.ID);
            }

            /*
             * The SSE's internal hardware breakpoint register is now free.
             */

            int dr_index;
            int id = inferior.InsertHardwareBreakpoint (lmf_address, true, out dr_index);

            Report.Debug (DebugFlags.SSE, "{0} inserted lmf breakpoint: {1} {2} {3}", this, lmf_address, id, dr_index);

            lmf_breakpoint.Breakpoint = new TemporaryBreakpointData (id, lmf_address);
        }
        internal void OnThreadExited(Inferior.ChildEvent cevent)
        {
            TargetEventArgs result;
            int arg = (int) cevent.Argument;
            if (killed)
                result = new TargetEventArgs (TargetEventType.TargetExited, 0);
            else if (cevent.Type == Inferior.ChildEventType.CHILD_SIGNALED)
                result = new TargetEventArgs (TargetEventType.TargetSignaled, arg);
            else
                result = new TargetEventArgs (TargetEventType.TargetExited, arg);
            temp_breakpoint = null;
            dead = true;

            if (current_operation != null)
                OperationCompleted (result);
            else
                process.Debugger.OnTargetEvent (thread, result);

            process.OnThreadExitedEvent (this);
            Dispose ();
        }