private string event_TypeResolverHandler(string identifier, SourceLocation location) { if (_alreadyResolving.Contains(identifier)) { return(null); } if (identifier == "__EXCEPTION_OBJECT__") { return(null); } foreach (var loc in ActiveFrame.GetAllLocals()) { if (loc.Name == identifier) { return(null); } } //TODO: HACK _alreadyResolving.Add(identifier); ObjectValue resolvedValue = ActiveFrame.GetExpressionValue(identifier, EvaluationOptions.DefaultOptions); _alreadyResolving.Remove(identifier); if (resolvedValue != null && !resolvedValue.IsUnknown && !resolvedValue.IsError && !(resolvedValue.HasFlag(ObjectValueFlags.Namespace) && resolvedValue.HasFlag(ObjectValueFlags.Object))) { return(null); } return(identifier); }
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 (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) => { _showResumeMessage = true; _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)); 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)); 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 { var code = e.ExitCode != null?string.Format(" with code '{0}'", e.ExitCode) : string.Empty; Log.Notice("Inferior process '{0}' ('{1}') exited{2}", ActiveProcess.Id, StringizeTarget(), code); } // Make sure we clean everything up on a normal exit. Kill(); _debuggeeKilled = true; _kind = SessionKind.Disconnected; 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); 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); CommandLine.ResumeEvent.Set(); }; _session.TargetThreadStarted += (sender, e) => { Log.Notice("Inferior thread '{0}' ('{1}') started", e.Thread.Id, e.Thread.Name); }; _session.TargetThreadStopped += (sender, e) => { Log.Notice("Inferior thread '{0}' ('{1}') exited", e.Thread.Id, e.Thread.Name); }; } }