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); }
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; }
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; }