Ejemplo n.º 1
0
        //////////////////////////////////////////////////////////////////////////////////
        //
        // Private implementation
        //
        //////////////////////////////////////////////////////////////////////////////////

        /* // NOT USED by O2MDbg
         * private int RunInputLoop()
         * {
         *  // Run the event loop
         *  string input;
         *  IMDbgCommand cmd = null;
         *  string cmdArgs = null;
         *
         *  int stopCount = -1;
         *
         *  while (true)
         *  {
         *      Thread.Sleep(1000);
         *      Debug.WriteLine("MSdn Shell, waiting for commands");
         *  }
         *
         *  while (m_run && IO.ReadCommand(out input))
         *  {
         *      try
         *      {
         *          if (Debugger.Processes.HaveActive)
         *          {
         *              stopCount = Debugger.Processes.Active.StopCounter;
         *          }
         *
         *          if (input.Length == 0)
         *          {
         *              if (cmd == null || !cmd.IsRepeatable)
         *              {
         *                  continue;
         *              }
         *          }
         *          else
         *          {
         *              Commands.ParseCommand(input, out cmd, out cmdArgs);
         *          }
         *          cmd.Execute(cmdArgs);
         *
         *          int newStopCount = Debugger.Processes.HaveActive
         *                                 ? Debugger.Processes.Active.StopCounter
         *                                 : Int32.MaxValue;
         *          bool movementCommand = newStopCount > stopCount;
         *          stopCount = newStopCount;
         *
         *          if (OnCommandExecuted != null)
         *          {
         *              OnCommandExecuted(this, new CommandExecutedEventArgs(this, cmd, cmdArgs, movementCommand));
         *          }
         *
         *          newStopCount = Debugger.Processes.HaveActive
         *                             ? Debugger.Processes.Active.StopCounter
         *                             : Int32.MaxValue;
         *          movementCommand = newStopCount > stopCount;
         *
         *          while (newStopCount > stopCount)
         *          {
         *              stopCount = newStopCount;
         *
         *              if (OnCommandExecuted != null)
         *              {
         *                  OnCommandExecuted(this, new CommandExecutedEventArgs(this, null, null, movementCommand));
         *              }
         *
         *              newStopCount = Debugger.Processes.HaveActive
         *                                 ? Debugger.Processes.Active.StopCounter
         *                                 : Int32.MaxValue;
         *              movementCommand = newStopCount > stopCount;
         *          }
         *          stopCount = newStopCount;
         *      }
         *      catch (Exception e)
         *      {
         *          ReportException(e);
         *      }
         *  } // end while
         *  return m_exitCode;
         * }
         */


        private void PrintCurrentException()
        {
            MDbgValue ex = Debugger.Processes.Active.Threads.Active.CurrentException;

            CommandBase.WriteOutput("Exception=" + ex.GetStringValue(0));
            foreach (MDbgValue f in ex.GetFields())
            {
                string outputType;
                string outputValue;

                if (f.Name == "_xptrs" || f.Name == "_xcode" || f.Name == "_stackTrace" ||
                    f.Name == "_remoteStackTraceString" || f.Name == "_remoteStackIndex" ||
                    f.Name == "_exceptionMethodString")
                {
                    outputType = MDbgOutputConstants.Ignore;
                }
                else
                {
                    outputType = MDbgOutputConstants.StdOutput;
                }

                outputValue = f.GetStringValue(0);
                // remove new line characters in string
                if (outputValue != null && (f.Name == "_exceptionMethodString" || f.Name == "_remoteStackTraceString"))
                {
                    outputValue = outputValue.Replace('\n', '#');
                }

                CommandBase.WriteOutput(outputType, "\t" + f.Name + "=" + outputValue);
            }
        }
Ejemplo n.º 2
0
        string SerializeException(CorValue exception)
        {
            var       result = new StringBuilder();
            MDbgValue ex     = new MDbgValue(shell.Debugger.Processes.Active, exception);

            result.Append(ex.GetStringValue(0) + ": ");
            foreach (MDbgValue f in ex.GetFields())
            {
                string outputValue = f.GetStringValue(0);

                if (f.Name == "_message")
                {
                    result.AppendLine(outputValue);
                    break;
                }

                //if (f.Name == "_xptrs" || f.Name == "_xcode" || f.Name == "_stackTrace" ||
                //    f.Name == "_remoteStackTraceString" || f.Name == "_remoteStackIndex" ||
                //    f.Name == "_exceptionMethodString")
                //{
                //    continue;
                //}

                //// remove new line characters in string
                //if (outputValue != "<null>" && outputValue != null && (f.Name == "_exceptionMethodString" || f.Name == "_remoteStackTraceString"))
                //{
                //    outputValue = outputValue.Replace('\n', '#');
                //}

                //string name = f.Name.Substring(1,1).ToUpper()+f.Name.Substring(2);
                //result.AppendLine("\t" + name + "=" + outputValue);
            }
            return(result.ToString());
        }
        /// <summary>
        /// Initialize a ManagedProcessUnhandledExceptionOccurredEventArgs object and raise the
        /// UnhandledExceptionOccurred event.
        /// </summary>
        private void HandleException()
        {
            CancelEventArgs e = new CancelEventArgs();

            this.OnStartHandleException(e);
            if (e.Cancel)
            {
                return;
            }

            MDbgValue ex = this.MDbgProcess.Threads.Active.CurrentException;

            if (ex.IsNull)
            {
                // No current exception is available.  Perhaps the user switched to a different
                // thread which was not throwing an exception.
                return;
            }

            IntPtr exceptionPointers = IntPtr.Zero;

            foreach (MDbgValue f in ex.GetFields())
            {
                if (f.Name == "_xptrs")
                {
                    string outputValue = f.GetStringValue(0);
                    exceptionPointers = (IntPtr)int.Parse(outputValue);
                }
            }

            if (exceptionPointers == IntPtr.Zero)
            {
                // Get the Exception Pointer in the target process
                MDbgValue value = FunctionEval(
                    "System.Runtime.InteropServices.Marshal.GetExceptionPointers");
                if (value != null)
                {
                    exceptionPointers = (IntPtr)int.Parse(value.GetStringValue(1));
                }
            }

            this.OnUnhandledExceptionOccurred(
                new ManagedProcessUnhandledExceptionOccurredEventArgs
            {
                ProcessID         = this.MDbgProcess.CorProcess.Id,
                ThreadID          = this.MDbgProcess.Threads.Active.Id,
                ExceptionPointers = exceptionPointers
            });
        }
Ejemplo n.º 4
0
 public O2MDbgVariable(MDbgValue mdbgValue, string _parentType, string _assemblyName)
 {
     IsProperty   = false;
     parentType   = _parentType;
     assemblyName = _assemblyName;
     name         = mdbgValue.Name;
     try
     {
         value = mdbgValue.GetStringValue(false);
     }
     catch (Exception ex)
     {
         DI.log.ex(ex, "in O2MDbgVariable(MDbgValue mdbgValue), while trying to get value for: " + mdbgValue.Name);
     }
     type        = mdbgValue.TypeName;
     complexType = mdbgValue.IsComplexType;
 }
Ejemplo n.º 5
0
        private void PrintCurrentException()
        {
            MDbgValue ex = Debugger.Processes.Active.Threads.Active.CurrentException;

            if (ex.IsNull)
            {
                // No current exception is available.  Perhaps the user switched to a different
                // thread which was not throwing an exception.
                return;
            }

            CommandBase.WriteOutput("Exception=" + ex.GetStringValue(0));
            foreach (MDbgValue f in ex.GetFields())
            {
                string outputType;
                string outputValue;

                if (f.Name == "_xptrs" || f.Name == "_xcode" || f.Name == "_stackTrace" ||
                    f.Name == "_remoteStackTraceString" || f.Name == "_remoteStackIndex" ||
                    f.Name == "_exceptionMethodString")
                {
                    outputType = MDbgOutputConstants.Ignore;
                }
                else
                {
                    outputType = MDbgOutputConstants.StdOutput;
                }

                outputValue = f.GetStringValue(0);
                // remove new line characters in string
                if (outputValue != null && (f.Name == "_exceptionMethodString" || f.Name == "_remoteStackTraceString"))
                {
                    outputValue = outputValue.Replace('\n', '#');
                }

                CommandBase.WriteOutput(outputType, "\t" + f.Name + "=" + outputValue);
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Acts on the current callback, based on the current debugger behavior for this stop
        /// option policy.
        /// </summary>
        /// <param name="currentProcess">Current MDbgProcess.</param>
        /// <param name="args">Callback arguments.</param>
        public override void ActOnCallback(MDbgProcess currentProcess, CustomPostCallbackEventArgs args)
        {
            CorEventArgs eventArgs = args.CallbackArgs as CorEventArgs;

            switch (m_behavior)
            {
            case DebuggerBehavior.Stop:
                args.Controller.Stop(eventArgs.Thread, MDbgUtil.CreateStopReasonFromEventArgs(eventArgs, currentProcess));
                break;

            case DebuggerBehavior.Log:
                CommandBase.WriteOutput(eventArgs.ToString() + "\n");
                break;

            case DebuggerBehavior.Notify:
                CommandBase.WriteOutput(eventArgs.ToString() + "\n");
                MDbgThread currentThread = currentProcess.Threads.GetThreadFromThreadId((args.CallbackArgs as CorThreadEventArgs).Thread.Id);

                try
                {
                    // Getting the current notification may not be implemented.
                    MDbgValue notification = currentThread.CurrentNotification;
                    if (notification != null)
                    {
                        CommandBase.WriteOutput(notification.GetStringValue(true, "-", null));
                    }
                    else
                    {
                        CommandBase.WriteOutput("custom notification is null\n");
                    }
                }
                catch (NotImplementedException)
                {
                    Trace.WriteLine("Custom Notifications Not Implemented");
                }
                break;
            }
        }
Ejemplo n.º 7
0
        //-----------------------------------------------------------------------------
        // Recursive helper to populate tree view.
        // val - value to print
        // c - node collection to add to.
        // Called on UI thread.
        //-----------------------------------------------------------------------------
        static public void PrintInternal(MainForm parent, MDbgValue val, TreeNodeCollection c)
        {
            string name = val.Name;

            try
            {
                TreeNode node = null;
                string st = null;
                parent.ExecuteOnWorkerThreadIfStoppedAndBlock(delegate(MDbgProcess proc)
                {
                    Debug.Assert(proc != null);
                    Debug.Assert(!proc.IsRunning);
                    Debug.Assert(proc == val.Process);

                    if (val.IsArrayType)
                    {         
                        // It would be nice to display array length here too.
                        // Add a "dummy" sub-node to signify that this node is expandable. We then trap
                        // the BeforeExpand event to add the real children.
                        node = new TreeNode(name + " (type='" + val.TypeName + "') array:",
                            new TreeNode[1] { new TreeNode("dummy") });                        
                    }
                    else if (val.IsComplexType)
                    {
                        // This will include both instance and static fields
                        // It will also include all base class fields.
                        node = new TreeNode(name + " (type='" + val.TypeName + "') fields:",
                            new TreeNode[1] { new TreeNode("dummy") });
                    }
                    else
                    {
                        // This is a catch-all for primitives.
                        string stValue = val.GetStringValue(false, "-", null);
                        st = (name + " (type='" + val.TypeName + "') value=" + stValue);

                    }

                });

                // Now add the node.
                if (node != null)
                {
                    node.Tag = val;
                    c.Add(node);
                }
                else if (st != null)
                {
                    c.Add(st);
                }
                else
                {
                    Debug.Assert(false, "No data set.");
                }
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                // Inspecting the vars may fail at the ICorDebug level.
                c.Add(name + "= <unavailable>");
            }

        }
Ejemplo n.º 8
0
        XElement XmlSerialize(MDbgValue val, int valueId, string displayName = null, string substituteValue = null)
        {
            if (val == null)
            {
                return(new XElement("value",
                                    new XAttribute("name", displayName ?? "<unknown>"),
                                    new XAttribute("id", valueId),
                                    new XAttribute("isProperty", false),
                                    new XAttribute("isStatic", false),
                                    new XAttribute("isFake", false),
                                    new XAttribute("isComplex", false),
                                    new XAttribute("isArray", false),
                                    new XAttribute("value", substituteValue ?? "<N/A>"),
                                    new XAttribute("typeName", "<N/A>")));
            }

            string name = val.Name;

            XElement result = new XElement("value",
                                           new XAttribute("name", displayName ?? name),
                                           new XAttribute("id", valueId),
                                           new XAttribute("isProperty", val.IsProperty),
                                           new XAttribute("isFake", val.IsFake),
                                           new XAttribute("rawDisplayValue", substituteValue ?? val.DisplayValue ?? ""),
                                           new XAttribute("isPublic", !val.IsPrivate),
                                           new XAttribute("isStatic", val.IsStatic),
                                           new XAttribute("typeName", val.TypeName));

            try
            {
                if (val.IsArrayType)
                {
                    // It would be nice to display array length here too.
                    // Add a "dummy" sub-node to signify that this node is expandable. We then trap
                    // the BeforeExpand event to add the real children.
                    result.Add(new XAttribute("isComplex", true),
                               new XAttribute("isArray", true));
                }
                else if (val.IsListType)
                {
                    result.Add(new XAttribute("isComplex", true),
                               new XAttribute("isList", true));
                }
                else if (val.IsDictionaryType)
                {
                    result.Add(new XAttribute("isComplex", true),
                               new XAttribute("isDictionary", true));
                }
                else if (val.IsComplexType)
                {
                    if (IsPrimitiveType(val)) //boxed primitive types will appear a ComplexTypes
                    {
                        string stValue = val.DisplayValue.Trim('{', '}');
                        result.Add(new XAttribute("isComplex", false),
                                   new XAttribute("value", substituteValue ?? stValue));
                    }
                    else
                    {
                        // This will include both instance and static fields
                        // It will also include all base class fields.
                        //string stValue = val.InvokeToString();
                        result.Add(new XAttribute("isComplex", true),
                                   //         new XAttribute("value", stValue),
                                   new XAttribute("isArray", false));
                    }
                }
                else
                {
                    // This is a catch-all for primitives.
                    string stValue = val.GetStringValue(false);
                    result.Add(new XAttribute("isComplex", false),
                               //new XAttribute("isArray", false),
                               new XAttribute("value", substituteValue ?? stValue));
                }
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                result.Add(new XAttribute("isComplex", false),
                           new XAttribute("isArray", false),
                           new XAttribute("value", "<unavailable>"));
            }

            return(result);
        }
Ejemplo n.º 9
0
        public void ProcessInvoke(string command)
        {
            //<invokeId>:<action>:<args>
            string[] parts  = command.Split(new[] { ':' }, 3);
            string   id     = parts[0];
            string   action = parts[1];
            string   args   = parts[2];
            string   result = "";

            blockNotifications = true;
            try
            {
                if (IsInBreakMode)
                {
                    if (action == "locals")
                    {
                        if (reportedValues.ContainsKey(args))
                        {
                            MDbgValue value = reportedValues[args];
                            result = SerializeValue(value);
                        }
                    }
                    else if (action == "resolve_primitive") //UI request for short info for tooltips
                    {
                        try
                        {
                            MDbgValue value = ResolveVariable(args);

                            if (value != null)
                            {
                                if (value.IsArrayType || value.IsListType || value.IsDictionaryType)
                                {
                                    result = SerializeValue(value, itemsOnly: true, itemsMaxCount: maxCollectionItemsInPrimitiveResolve);
                                }
                                else
                                {
                                    if (value.IsComplexType)
                                    {
                                        //Complex types have no 'value' attribute set as they are expandable
                                        //but for the tooltips we need to show some value. So invoke 'object.ToString'
                                        //and inject the result as 'value' attribute
                                        string stValue = value.GetStringValue(false);

                                        var xml = XmlSerialize(value, -1, args);
                                        xml.Add(new XAttribute("value", stValue));
                                        result = xml.ToString();
                                    }
                                    else
                                    {
                                        result = Serialize(value, args);
                                    }
                                }
                            }
                        }
                        catch
                        {
                            result = null;
                        }
                    }
                    else if (action == "resolve")
                    {
                        try
                        {
                            MDbgValue value = ResolveExpression(args);

                            string itemName = args;
                            //args can be variable (t.Index), method call (t.Test()) or set command (t.Index=7)
                            //set command may also be "watched" in IDE as the var name (t.Index)
                            bool isSetter = args.IsSetExpression();
                            if (isSetter)
                            {
                                itemName = args.Split('=').First();
                            }

                            if (isSetter)
                            {
                                //vale may be boxed so resolve the expression to ensure it is not
                                MDbgValue latestValue = value;

                                if (shell.Debugger.Processes.Active.IsEvalSafe())
                                {
                                    try
                                    {
                                        latestValue = ResolveExpression(itemName);
                                    }
                                    catch { }
                                }

                                result = "<items>" + Serialize(latestValue, itemName) + "</items>";

                                ThreadPool.QueueUserWorkItem(x =>
                                {
                                    Thread.Sleep(100);
                                    MessageQueue.AddNotification(NppCategory.Watch + result);
                                });
                            }
                            else
                            {
                                //return the invocation result as it is without boxing/unboxing considerations
                                if (value != null)
                                {
                                    result = "<items>" + Serialize(value, itemName) + "</items>";
                                }
                            }
                        }
                        catch
                        {
                            result = "<items/>";
                        }
                    }
                    else if (action == "inspect")
                    {
                        //not enabled yet
                        //try
                        //{
                        //    MDbgValue value = Inspect(args);

                        //    if (value != null)
                        //        result = "<items>" + Serialize(value, args) + "</items>";
                        //}
                        //catch
                        //{
                        //    result = "<items/>";
                        //}
                    }
                }
            }
            catch (Exception e)
            {
                result = "Error: " + e.Message;
            }
            blockNotifications = false;
            MessageQueue.AddNotification(NppCategory.Invoke + id + ":" + result);
        }
Ejemplo n.º 10
0
 private static string DumpValue(MDbgValue value)
 {
     return(string.Format("{0} = {1}", value.Name, value.GetStringValue(false)));
 }
Ejemplo n.º 11
0
        public static void PrintCmd(string arguments, O2Thread.FuncVoidT1 <string> o2Callback)
        {
            const string debuggerVarsOpt = "d";
            const string noFuncevalOpt   = "nf";
            const string expandDepthOpt  = "r";

            var  ap            = new ArgParser(arguments, debuggerVarsOpt + ";" + noFuncevalOpt + ";" + expandDepthOpt + ":1");
            bool canDoFunceval = !ap.OptionPassed(noFuncevalOpt);

            int?expandDepth = null;  // we use optional here because

            // different codes bellow has different
            // default values.
            if (ap.OptionPassed(expandDepthOpt))
            {
                expandDepth = ap.GetOption(expandDepthOpt).AsInt;
                if (expandDepth < 0)
                {
                    throw new MDbgShellException("Depth cannot be negative.");
                }
            }

            MDbgFrame frame = CommandBase.Debugger.Processes.Active.Threads.Active.CurrentFrame;

            if (ap.OptionPassed(debuggerVarsOpt))
            {
                // let's print all debugger variables
                MDbgProcess p = CommandBase.Debugger.Processes.Active;
                foreach (MDbgDebuggerVar dv in p.DebuggerVars)
                {
                    var v = new MDbgValue(p, dv.CorValue);
                    CommandBase.WriteOutput(dv.Name + "=" + v.GetStringValue(expandDepth == null ? 0 : (int)expandDepth,
                                                                             canDoFunceval));
                }
            }
            else
            {
                if (ap.Count == 0)
                {
                    // get all active variables
                    MDbgFunction f = frame.Function;

                    var         vars = new ArrayList();
                    MDbgValue[] vals = f.GetActiveLocalVars(frame);
                    if (vals != null)
                    {
                        vars.AddRange(vals);
                    }

                    vals = f.GetArguments(frame);
                    if (vals != null)
                    {
                        vars.AddRange(vals);
                    }
                    foreach (MDbgValue v in vars)
                    {
                        CommandBase.WriteOutput(v.Name + "=" + v.GetStringValue(expandDepth == null ? 0 : (int)expandDepth,
                                                                                canDoFunceval));
                    }
                }
                else
                {
                    // user requested printing of specific variables
                    for (int j = 0; j < ap.Count; ++j)
                    {
                        MDbgValue var = CommandBase.Debugger.Processes.Active.ResolveVariable(ap.AsString(j), frame);
                        if (var != null)
                        {
                            CommandBase.WriteOutput(ap.AsString(j) + "=" + var.GetStringValue(expandDepth == null
                                                                                      ? 1
                                                                                      : (int)expandDepth, canDoFunceval));
                        }
                        else
                        {
                            throw new MDbgShellException("Variable not found");
                        }
                    }
                }
            }
        }
Ejemplo n.º 12
0
        public static void FuncEvalCmd(string arguments, IMDbgShell Shell, O2Thread.FuncVoidT1 <string> execOnEval)
        {
            try
            {
                var          activeProcess   = DI.o2MDbg.ActiveProcess; //Debugger.Processes.Active
                const string appDomainOption = "ad";
                var          ap = new ArgParser(arguments, appDomainOption + ":1");
                if (!(ap.Count >= 1))
                {
                    throw new MDbgShellException("Not Enough arguments");
                }


                // Currently debugger picks first function -- we have not implementing resolving overloaded functions.
                // Good example is Console.WriteLine -- there is 18 different types:
                // 1) [06000575] Void WriteLine()
                // 2) [06000576] Void WriteLine(Boolean)
                // 3) [06000577] Void WriteLine(Char)
                // 4) [06000578] Void WriteLine(Char[])
                // 5) [06000579] Void WriteLine(Char[], Int32, Int32)
                // 6) [0600057a] Void WriteLine(Decimal)
                // 7) [0600057b] Void WriteLine(Double)
                // 8) [0600057c] Void WriteLine(Single)
                // 9) [0600057d] Void WriteLine(Int32)
                // 10) [0600057e] Void WriteLine(UInt32)
                // 11) [0600057f] Void WriteLine(Int64)
                // 12) [06000580] Void WriteLine(UInt64)
                // 13) [06000581] Void WriteLine(Object)
                // 14) [06000582] Void WriteLine(String)
                // 15) [06000583] Void WriteLine(String, Object)
                // 16) [06000584] Void WriteLine(String, Object, Object)
                // 17) [06000585] Void WriteLine(String, Object, Object, Object)
                // 18) [06000586] Void WriteLine(String, Object, Object, Object, Object, ...)
                // 19) [06000587] Void WriteLine(String, Object[])
                //
                CorAppDomain appDomain;
                if (ap.OptionPassed(appDomainOption))
                {
                    MDbgAppDomain ad = activeProcess.AppDomains[ap.GetOption(appDomainOption).AsInt];
                    if (ad == null)
                    {
                        throw new ArgumentException("Invalid Appdomain Number");
                    }
                    appDomain = ad.CorAppDomain;
                }
                else
                {
                    appDomain = activeProcess.Threads.Active.CorThread.AppDomain;
                }

                MDbgFunction func = activeProcess.ResolveFunctionNameFromScope(ap.AsString(0), appDomain);
                if (null == func)
                {
                    throw new MDbgShellException(String.Format(CultureInfo.InvariantCulture, "Could not resolve {0}",
                                                               new Object[] { ap.AsString(0) }));
                }

                CorEval eval = activeProcess.Threads.Active.CorThread.CreateEval();

                // Get Variables
                var    vars = new ArrayList();
                String arg;
                for (int i = 1; i < ap.Count; i++)
                {
                    arg = ap.AsString(i);

                    CorValue v = Shell.ExpressionParser.ParseExpression2(arg, activeProcess,
                                                                         activeProcess.Threads.Active.
                                                                         CurrentFrame);

                    if (v == null)
                    {
                        throw new MDbgShellException("Cannot resolve expression or variable " + ap.AsString(i));
                    }

                    if (v is CorGenericValue)
                    {
                        vars.Add(v);
                    }

                    else
                    {
                        CorHeapValue hv = v.CastToHeapValue();
                        if (hv != null)
                        {
                            // we cannot pass directly heap values, we need to pass reference to heap valus
                            CorReferenceValue myref =
                                eval.CreateValue(CorElementType.ELEMENT_TYPE_CLASS, null).CastToReferenceValue();
                            myref.Value = hv.Address;
                            vars.Add(myref);
                        }
                        else
                        {
                            vars.Add(v);
                        }
                    }
                }

                eval.CallFunction(func.CorFunction, (CorValue[])vars.ToArray(typeof(CorValue)));
                activeProcess.Go().WaitOne();

                // now display result of the funceval
                if (!(activeProcess.StopReason is EvalCompleteStopReason))
                {
                    // we could have received also EvalExceptionStopReason but it's derived from EvalCompleteStopReason
                    Shell.IO.WriteOutput(MDbgOutputConstants.StdOutput,
                                         "Func-eval not fully completed and debuggee has stopped");
                    Shell.IO.WriteOutput(MDbgOutputConstants.StdOutput,
                                         "Result of funceval won't be printed when finished.");
                }
                else
                {
                    eval = (activeProcess.StopReason as EvalCompleteStopReason).Eval;
                    Debug.Assert(eval != null);

                    CorValue cv = eval.Result;
                    if (cv != null)
                    {
                        var mv = new MDbgValue(activeProcess, cv);
                        if (execOnEval != null) // if this callback is set then execute
                        {
                            execOnEval(mv.GetStringValue(1));
                            return;
                        }
                        Shell.IO.WriteOutput(MDbgOutputConstants.StdOutput, "result = " + mv.GetStringValue(1));
                        if (cv.CastToReferenceValue() != null)
                        {
                            if (activeProcess.DebuggerVars.SetEvalResult(cv))
                            {
                                Shell.IO.WriteOutput(MDbgOutputConstants.StdOutput, "results saved to $result");
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                DI.log.ex(ex, "in FuncEvalCmd");
            }
            if (execOnEval != null)                         // need to call this here so that the sync AutoResetEvent is set
            {
                execOnEval(null);
            }
        }