////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public CLangDebuggeeProperty(CLangDebugger debugger, CLangDebuggeeStackFrame stackFrame, string expression, string value)
            : base(debugger.Engine, stackFrame, expression, value)
        {
            m_debugger = debugger;

            m_gdbVariable = null;
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public CLangDebuggeeProperty(CLangDebugger debugger, CLangDebuggeeStackFrame stackFrame, MiVariable gdbVariable)
            : base(debugger.Engine, stackFrame, gdbVariable.Expression, string.Empty)
        {
            m_debugger = debugger;

            m_gdbVariable = gdbVariable;
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public int EvaluateSync(enum_EVALFLAGS evaluateFlags, uint timeout, IDebugEventCallback2 eventCallback, out IDebugProperty2 result)
        {
            //
            // Evaluate the expression synchronously.
            //

            LoggingUtils.PrintFunction();

            try
            {
                CLangDebuggeeStackFrame stackFrame = m_stackFrame as CLangDebuggeeStackFrame;

                result = stackFrame.EvaluateCustomExpression(evaluateFlags, m_expression, m_radix);

                if (result == null)
                {
                    return(Constants.E_FAIL);
                }

                return(Constants.S_OK);
            }
            catch (Exception e)
            {
                LoggingUtils.HandleException(e);

                result = null;

                return(Constants.E_FAIL);
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public CLangDebuggeeProperty CreatePropertyFromVariable(CLangDebuggeeStackFrame stackFrame, MiVariable variable)
        {
            LoggingUtils.PrintFunction();

            try
            {
                if (stackFrame == null)
                {
                    throw new ArgumentNullException("stackFrame");
                }

                if (variable == null)
                {
                    throw new ArgumentNullException("variable");
                }

                /*CLangDebuggeeProperty [] childProperties = GetChildProperties (stackFrame, parentProperty);
                 *
                 * parentProperty.AddChildren (childProperties);*/

                return(new CLangDebuggeeProperty(m_debugger, stackFrame, variable));;
            }
            catch (Exception e)
            {
                LoggingUtils.HandleException(e);

                return(null);
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public MiVariable CreateVariableFromExpression(CLangDebuggeeStackFrame stackFrame, string expression)
        {
            LoggingUtils.PrintFunction();

            try
            {
                LoggingUtils.RequireOk(stackFrame.GetThread(out IDebugThread2 stackThread));

                LoggingUtils.RequireOk(stackThread.GetThreadId(out uint stackThreadId));

                string command = string.Format("-var-create --thread {0} --frame {1} - * \"{2}\"", stackThreadId, stackFrame.StackLevel, expression);

                MiResultRecord resultRecord = m_debugger.GdbClient.SendSyncCommand(command);

                MiResultRecord.RequireOk(resultRecord, command);

                return(new MiVariable(expression, resultRecord.Results));
            }
            catch (Exception e)
            {
                LoggingUtils.HandleException(e);

                return(null);
            }
        }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeProperty (CLangDebugger debugger, CLangDebuggeeStackFrame stackFrame, MiVariable gdbVariable)
      : base (debugger.Engine, stackFrame, gdbVariable.Expression, string.Empty)
    {
      m_debugger = debugger;

      m_gdbVariable = gdbVariable;
    }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public CLangDebuggeeProperty [] GetChildProperties(CLangDebuggeeStackFrame stackFrame, CLangDebuggeeProperty parentProperty)
        {
            LoggingUtils.PrintFunction();

            MiVariable parentVariable = parentProperty.GdbVariable;

            List <CLangDebuggeeProperty> childProperties = new List <CLangDebuggeeProperty> ();

            if (parentVariable.HasChildren && (parentVariable.Children.Count > 0))
            {
                foreach (MiVariable childVariable in parentVariable.Children.Values)
                {
                    CLangDebuggeeProperty childProperty = new CLangDebuggeeProperty(m_debugger, stackFrame, childVariable);

                    if (childVariable.IsPseudoChild)
                    {
                        CLangDebuggeeProperty [] childSubProperties = GetChildProperties(stackFrame, childProperty);

                        childProperties.AddRange(childSubProperties);
                    }
                    else
                    {
                        childProperties.Add(childProperty);
                    }
                }
            }

            return(childProperties.ToArray());
        }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeProperty (CLangDebugger debugger, CLangDebuggeeStackFrame stackFrame, string expression, string value)
      : base (debugger.Engine, stackFrame, expression, value)
    {
      m_debugger = debugger;

      m_gdbVariable = null;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeProperty [] GetChildProperties (CLangDebuggeeStackFrame stackFrame, CLangDebuggeeProperty parentProperty)
    {
      LoggingUtils.PrintFunction ();

      MiVariable parentVariable = parentProperty.GdbVariable;

      List<CLangDebuggeeProperty> childProperties = new List<CLangDebuggeeProperty> ();

      if (parentVariable.HasChildren && (parentVariable.Children.Count > 0))
      {
        foreach (MiVariable childVariable in parentVariable.Children.Values)
        {
          CLangDebuggeeProperty childProperty = new CLangDebuggeeProperty (m_debugger, stackFrame, childVariable);

          if (childVariable.IsPseudoChild)
          {
            CLangDebuggeeProperty [] childSubProperties = GetChildProperties (stackFrame, childProperty);

            childProperties.AddRange (childSubProperties);
          }
          else
          {
            childProperties.Add (childProperty);
          }
        }
      }

      return childProperties.ToArray ();
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeProperty CreatePropertyFromVariable (CLangDebuggeeStackFrame stackFrame, MiVariable variable)
    {
      LoggingUtils.PrintFunction ();

      try
      {
        if (stackFrame == null)
        {
          throw new ArgumentNullException ("stackFrame");
        }

        if (variable == null)
        {
          throw new ArgumentNullException ("variable");
        }

        /*CLangDebuggeeProperty [] childProperties = GetChildProperties (stackFrame, parentProperty);

        parentProperty.AddChildren (childProperties);*/

        return new CLangDebuggeeProperty (m_debugger, stackFrame, variable);;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        return null;
      }
    }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public void Refresh(ref MiResultValue threadData)
        {
            LoggingUtils.PrintFunction();

            if (threadData.HasField("name"))
            {
                m_threadDisplayName = threadData ["name"] [0].GetString(); // user-specified name
            }
            else if (threadData.HasField("target-id"))
            {
                uint threadPid;

                m_threadDisplayName = threadData ["target-id"] [0].GetString(); // usually the raw name, i.e. 'Thread 18771'

                if (m_threadDisplayName.StartsWith("Thread ") && uint.TryParse(m_threadDisplayName.Substring("Thread ".Length), out threadPid))
                {
                    AndroidDevice hostDevice = NativeProgram.DebugProgram.DebugProcess.NativeProcess.HostDevice;

                    AndroidProcess threadProcess = hostDevice.GetProcessFromPid(threadPid);

                    if (threadProcess != null)
                    {
                        m_threadDisplayName = threadProcess.Name;
                    }
                }
            }

            if (threadData.HasField("frame"))
            {
                MiResultValueTuple frameTuple = threadData ["frame"] [0] as MiResultValueTuple;

                uint stackLevel = frameTuple ["level"] [0].GetUnsignedInt();

                string stackFrameId = m_threadName + "#" + stackLevel;

                CLangDebuggeeStackFrame stackFrame = new CLangDebuggeeStackFrame(m_debugger, this, frameTuple, stackFrameId);

                lock (m_threadStackFrames)
                {
                    m_threadStackFrames.Add(stackFrame);
                }
            }

            RequiresRefresh = false;
        }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public override List<DebuggeeStackFrame> StackTrace (uint depth)
    {
      // 
      // Each thread maintains an internal cache of the last reported stack-trace. This is only cleared when threads are resumed via 'SetRunning(true)'.
      // 

      LoggingUtils.PrintFunction ();

      try
      {
        if (m_threadStackFrames.Count < depth)
        {
          uint threadId;

          LoggingUtils.RequireOk (GetThreadId (out threadId));

          m_debugProgram.AttachedEngine.NativeDebugger.RunInterruptOperation (delegate (CLangDebugger debugger)
          {
            // 
            // Determine the maximum available stack depth.
            // 

            string command;

            MiResultRecord resultRecord;

            if (depth == uint.MaxValue)
            {
              command = string.Format ("-stack-info-depth --thread {0}", threadId);

              resultRecord = debugger.GdbClient.SendSyncCommand (command);

              MiResultRecord.RequireOk (resultRecord, command);

              depth = resultRecord ["depth"] [0].GetUnsignedInt ();
            }

            // 
            // Acquire stack frame information for any levels which we're missing.
            // 

            if (m_threadStackFrames.Count < depth)
            {
              command = string.Format ("-stack-list-frames --thread {0} {1} {2}", threadId, m_threadStackFrames.Count, depth - 1);

              resultRecord = debugger.GdbClient.SendSyncCommand (command);

              MiResultRecord.RequireOk (resultRecord, command);

              if (resultRecord.HasField ("stack"))
              {
                MiResultValueList stackRecord = resultRecord ["stack"] [0] as MiResultValueList;

                for (int i = 0; i < stackRecord.Values.Count; ++i)
                {
                  MiResultValueTuple frameTuple = stackRecord [i] as MiResultValueTuple;

                  uint stackLevel = frameTuple ["level"] [0].GetUnsignedInt ();

                  string stackFrameId = m_threadName + "#" + stackLevel;

                  CLangDebuggeeStackFrame stackFrame = new CLangDebuggeeStackFrame (debugger, this, frameTuple, stackFrameId);

                  lock (m_threadStackFrames)
                  {
                    m_threadStackFrames.Add (stackFrame);
                  }
                }
              }
            }
          });
        }

        return m_threadStackFrames;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        throw;
      }
    }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public CLangDebuggeeProperty CreatePropertyFromVariable(CLangDebuggeeStackFrame stackFrame, MiVariable variable)
        {
            return(new CLangDebuggeeProperty(m_debugger, stackFrame, variable));
        }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public int EnumCodePaths (string pszHint, IDebugCodeContext2 pStart, IDebugStackFrame2 pFrame, int fSource, out IEnumCodePaths2 ppEnum, out IDebugCodeContext2 ppSafety)
    {
      // 
      // Enumerates the code paths of this program.
      // 

      LoggingUtils.PrintFunction ();

      try
      {
        // 
        // Get the entire call-stack for the current thread, and enumerate.
        // 

        CLangDebuggeeStackFrame stackFrame = pFrame as CLangDebuggeeStackFrame;

        IDebugThread2 thread;

        LoggingUtils.RequireOk (stackFrame.GetThread (out thread));

        CLangDebuggeeThread stackFrameThread = thread as CLangDebuggeeThread;

        List<DebuggeeStackFrame> threadCallStack = stackFrameThread.StackTrace (uint.MaxValue);

        List <CODE_PATH> threadCodePaths = new List <CODE_PATH> ();

        for (int i = 0; i < threadCallStack.Count; ++i)
        {
          string frameName;

          IDebugCodeContext2 codeContext;

          DebuggeeStackFrame frame = threadCallStack [i] as DebuggeeStackFrame;

          LoggingUtils.RequireOk (frame.GetName (out frameName));

          LoggingUtils.RequireOk (frame.GetCodeContext (out codeContext));

          if (codeContext != null)
          {
            CODE_PATH codePath = new CODE_PATH ();

            codePath.bstrName = frameName;

            codePath.pCode = codeContext;

            threadCodePaths.Add (codePath);
          }
        }

        ppEnum = new DebuggeeProgram.EnumeratorCodePaths (threadCodePaths);

        ppSafety = null;

        return Constants.S_OK;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        ppEnum = null;

        ppSafety = null;

        return Constants.E_FAIL;
      }
    }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public override List <DebuggeeStackFrame> StackTrace(uint depth)
        {
            //
            // Each thread maintains an internal cache of the last reported stack-trace. This is only cleared when threads are resumed via 'SetRunning(true)'.
            //

            LoggingUtils.PrintFunction();

            try
            {
                if (m_threadStackFrames.Count < depth)
                {
                    LoggingUtils.RequireOk(GetThreadId(out uint threadId));

                    m_debugProgram.AttachedEngine.NativeDebugger.RunInterruptOperation(delegate(CLangDebugger debugger)
                    {
                        //
                        // Determine the maximum available stack depth.
                        //

                        string command;

                        MiResultRecord resultRecord;

                        if (depth == uint.MaxValue)
                        {
                            command = string.Format("-stack-info-depth --thread {0}", threadId);

                            resultRecord = debugger.GdbClient.SendSyncCommand(command);

                            MiResultRecord.RequireOk(resultRecord, command);

                            depth = resultRecord ["depth"] [0].GetUnsignedInt();
                        }

                        //
                        // Acquire stack frame information for any levels which we're missing.
                        //

                        if (m_threadStackFrames.Count < depth)
                        {
                            command = string.Format("-stack-list-frames --thread {0} {1} {2}", threadId, m_threadStackFrames.Count, depth - 1);

                            resultRecord = debugger.GdbClient.SendSyncCommand(command);

                            MiResultRecord.RequireOk(resultRecord, command);

                            if (resultRecord.HasField("stack"))
                            {
                                MiResultValueList stackRecord = resultRecord ["stack"] [0] as MiResultValueList;

                                for (int i = 0; i < stackRecord.Values.Count; ++i)
                                {
                                    MiResultValueTuple frameTuple = stackRecord [i] as MiResultValueTuple;

                                    uint stackLevel = frameTuple ["level"] [0].GetUnsignedInt();

                                    string stackFrameId = m_threadName + "#" + stackLevel;

                                    CLangDebuggeeStackFrame stackFrame = new CLangDebuggeeStackFrame(debugger, this, frameTuple, stackFrameId);

                                    lock (m_threadStackFrames)
                                    {
                                        m_threadStackFrames.Add(stackFrame);
                                    }
                                }
                            }
                        }
                    });
                }

                return(m_threadStackFrames);
            }
            catch (Exception e)
            {
                LoggingUtils.HandleException(e);

                throw;
            }
        }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public void Refresh (ref MiResultValue threadData)
    {
      LoggingUtils.PrintFunction ();

      if (threadData.HasField ("name"))
      {
        m_threadDisplayName = threadData ["name"] [0].GetString (); // user-specified name
      }
      else if (threadData.HasField ("target-id"))
      {
        uint threadPid;

        m_threadDisplayName = threadData ["target-id"] [0].GetString (); // usually the raw name, i.e. 'Thread 18771'

        if (m_threadDisplayName.StartsWith ("Thread ") && uint.TryParse (m_threadDisplayName.Substring ("Thread ".Length), out threadPid))
        {
          AndroidDevice hostDevice = NativeProgram.DebugProgram.DebugProcess.NativeProcess.HostDevice;

          AndroidProcess threadProcess = hostDevice.GetProcessFromPid (threadPid);

          if (threadProcess != null)
          {
            m_threadDisplayName = threadProcess.Name;
          }
        }
      }

      if (threadData.HasField ("frame"))
      {
        MiResultValueTuple frameTuple = threadData ["frame"] [0] as MiResultValueTuple;

        uint stackLevel = frameTuple ["level"] [0].GetUnsignedInt ();

        string stackFrameId = m_threadName + "#" + stackLevel;

        CLangDebuggeeStackFrame stackFrame = new CLangDebuggeeStackFrame (m_debugger, this, frameTuple, stackFrameId);

        lock (m_threadStackFrames)
        {
          m_threadStackFrames.Add (stackFrame);
        }
      }

      RequiresRefresh = false;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public MiVariable CreateVariableFromExpression (CLangDebuggeeStackFrame stackFrame, string expression)
    {
      LoggingUtils.PrintFunction ();

      try
      {
        IDebugThread2 stackThread;

        uint stackThreadId;

        LoggingUtils.RequireOk (stackFrame.GetThread (out stackThread));

        LoggingUtils.RequireOk (stackThread.GetThreadId (out stackThreadId));

        string command = string.Format ("-var-create --thread {0} --frame {1} - * \"{2}\"", stackThreadId, stackFrame.StackLevel, expression);

        MiResultRecord resultRecord = m_debugger.GdbClient.SendSyncCommand (command);

        MiResultRecord.RequireOk (resultRecord, command);

        return new MiVariable (expression, resultRecord.Results);
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        return null;
      }
    }