static void EnsureCreated() { lock (_lock) { if (_session != null) { return; } _session = new SoftDebuggerSession(); _session.Breakpoints = BreakEvents; _session.ExceptionHandler = ex => { if (Configuration.Current.LogInternalErrors) { Log.Error("Internal debugger error:", ex.GetType()); Log.Error(ex.ToString()); } return(true); }; _session.LogWriter = (isStdErr, text) => { if (Configuration.Current.LogRuntimeSpew) { Log.NoticeSameLine("[Mono] {0}", text); // The string already has a line feed. } }; _session.OutputWriter = (isStdErr, text) => { //lock (Log.Lock) //{ if (Callback != null) { Callback.Invoke(isStdErr ? "ErrorOutput" : "Output", null, text); } else { if (isStdErr) { Console.Error.Write(text); } else { Console.Write(text); } } //} }; _session.TypeResolverHandler += (identifier, location) => { // I honestly have no idea how correct this is. I suspect you // could probably break it in some corner cases. It does make // something like `p Android.Runtime.JNIEnv.Handle` work, // though, which would otherwise have required `global::` to // be explicitly prepended. if (identifier == "__EXCEPTION_OBJECT__") { return(null); } foreach (var loc in ActiveFrame.GetAllLocals()) { if (loc.Name == identifier) { return(null); } } return(identifier); }; _session.TargetEvent += (sender, e) => { Log.Debug("Event: '{0}'", e.Type); }; _session.TargetStarted += (sender, e) => { _activeFrame = null; /* * if (_showResumeMessage) * Log.Notice("Inferior process '{0}' ('{1}') resumed", * ActiveProcess.Id, StringizeTarget()); */ }; _session.TargetReady += (sender, e) => { _activeProcess = _session.GetProcesses().SingleOrDefault(); // The inferior process has launched, so we can safely // set our `SIGINT` handler without it interfering with // the inferior. CommandLine.SetControlCHandler(); /* * Log.Notice("Inferior process '{0}' ('{1}') started", * ActiveProcess.Id, StringizeTarget()); */ }; _session.TargetStopped += (sender, e) => { //Log.Notice("Inferior process '{0}' ('{1}') suspended", // ActiveProcess.Id, StringizeTarget()); //Log.Emphasis(Utilities.StringizeFrame(ActiveFrame, true)); if (Callback != null) { Callback.Invoke("TargetStopped", e.Thread, null); } CommandLine.ResumeEvent.Set(); }; _session.TargetInterrupted += (sender, e) => { Log.Notice("Inferior process '{0}' ('{1}') interrupted", ActiveProcess.Id, StringizeTarget()); Log.Emphasis(Utilities.StringizeFrame(ActiveFrame, true)); CommandLine.ResumeEvent.Set(); }; _session.TargetHitBreakpoint += (sender, e) => { // var bp = e.BreakEvent as Breakpoint; // var fbp = e.BreakEvent as FunctionBreakpoint; /* * if (fbp != null) * Log.Notice("Hit method breakpoint on '{0}'", fbp.FunctionName); * else * { * var cond = bp.ConditionExpression != null ? * string.Format(" (condition '{0}' met)", bp.ConditionExpression) : * string.Empty; * * Log.Notice("Hit breakpoint at '{0}:{1}'{2}", bp.FileName, bp.Line, cond); * } * * Log.Emphasis(Utilities.StringizeFrame(ActiveFrame, true)); */ if (Callback != null) { Callback.Invoke("TargetHitBreakpoint", e.Thread, null); } CommandLine.ResumeEvent.Set(); }; _session.TargetExited += (sender, e) => { var p = ActiveProcess; /* * // Can happen when a remote connection attempt fails. * if (p == null) * { * if (_kind == SessionKind.Listening) * Log.Notice("Listening socket closed"); * else if (_kind == SessionKind.Connected) * Log.Notice("Connection attempt terminated"); * else * Log.Notice("Failed to connect to '{0}'", StringizeTarget()); * } * else * Log.Notice("Inferior process '{0}' ('{1}') exited", ActiveProcess.Id, StringizeTarget()); */ // Make sure we clean everything up on a normal exit. Kill(); _debuggeeKilled = true; _kind = SessionKind.Disconnected; if (Callback != null) { Callback.Invoke("TargetExited", null, null); } CommandLine.ResumeEvent.Set(); }; _session.TargetExceptionThrown += (sender, e) => { var ex = ActiveException; //Log.Notice("Trapped first-chance exception of type '{0}'", ex.Type); //Log.Emphasis(Utilities.StringizeFrame(ActiveFrame, true)); PrintException(ex); if (Callback != null) { Callback.Invoke("TargetExceptionThrown", e.Thread, null); } CommandLine.ResumeEvent.Set(); }; _session.TargetUnhandledException += (sender, e) => { var ex = ActiveException; //Log.Notice("Trapped unhandled exception of type '{0}'", ex.Type); //Log.Emphasis(Utilities.StringizeFrame(ActiveFrame, true)); PrintException(ex); if (Callback != null) { Callback.Invoke("TargetUnhandledException", e.Thread, null); } CommandLine.ResumeEvent.Set(); }; _session.TargetThreadStarted += (sender, e) => { //Log.Notice("Inferior thread '{0}' ('{1}') started", // e.Thread.Id, e.Thread.Name); if (Callback != null) { Callback.Invoke("TargetThreadStarted", e.Thread, null); } }; _session.TargetThreadStopped += (sender, e) => { //Log.Notice("Inferior thread '{0}' ('{1}') exited", // e.Thread.Id, e.Thread.Name); if (Callback != null) { Callback.Invoke("TargetThreadStopped", e.Thread, null); } }; } }