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

    #endregion

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

    #region IDebugProgram3 Members

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

    public int ExecuteOnThread (IDebugThread2 pThread)
    {
      // 
      // Executes the debugger program. The thread is returned to give the debugger information on which thread the user is viewing when executing the program.
      // 

      LoggingUtils.PrintFunction ();

      try
      {
        uint threadId;

        CLangDebuggeeThread thread = pThread as CLangDebuggeeThread;

        LoggingUtils.RequireOk (thread.GetThreadId (out threadId));

        string command = "-thread-select " + threadId;

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

        MiResultRecord.RequireOk (resultRecord, command);

        CurrentThreadId = threadId;

        LoggingUtils.RequireOk (Execute ());

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

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

        public int Step(IDebugThread2 pThread, enum_STEPKIND sk, enum_STEPUNIT Step)
        {
            //
            // Performs a step.
            //

            LoggingUtils.PrintFunction();

            try
            {
                CLangDebuggeeThread thread = pThread as CLangDebuggeeThread;

                LoggingUtils.RequireOk(thread.GetThreadId(out uint threadId));

                GdbClient.StepType stepType = (GdbClient.StepType)Step;

                switch (sk)
                {
                case enum_STEPKIND.STEP_INTO:
                {
                    m_debugger.GdbClient.StepInto(threadId, stepType, false);

                    break;
                }

                case enum_STEPKIND.STEP_OVER:
                {
                    m_debugger.GdbClient.StepOver(threadId, stepType, false);

                    break;
                }

                case enum_STEPKIND.STEP_OUT:
                {
                    m_debugger.GdbClient.StepOut(threadId, stepType, false);

                    break;
                }

                case enum_STEPKIND.STEP_BACKWARDS:
                {
                    throw new NotImplementedException();
                }
                }

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

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

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

        public void RefreshThread(uint tid)
        {
            LoggingUtils.PrintFunction();

            try
            {
                m_debugger.RunInterruptOperation(delegate(CLangDebugger debugger)
                {
                    string command = string.Format("-thread-info {0}", (tid == 0) ? "" : tid.ToString());

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

                    MiResultRecord.RequireOk(resultRecord, command);

                    if (!resultRecord.HasField("threads"))
                    {
                        throw new InvalidOperationException("-thread-info result missing 'threads' field");
                    }

                    MiResultValueList threadsValueList = (MiResultValueList)resultRecord ["threads"] [0];

                    List <MiResultValue> threadsData = threadsValueList.List;

                    bool refreshedProcesses = false;

                    for (int i = threadsData.Count - 1; i >= 0; --i) // reported threads are in descending order.
                    {
                        uint id = threadsData [i] ["id"] [0].GetUnsignedInt();

                        CLangDebuggeeThread thread = GetThread(id) ?? AddThread(id);

                        if (thread.RequiresRefresh)
                        {
                            MiResultValue threadData = threadsData [i];

                            if (!refreshedProcesses)
                            {
                                AndroidDevice hostDevice = DebugProgram.DebugProcess.NativeProcess.HostDevice;

                                hostDevice.RefreshProcesses(DebugProgram.DebugProcess.NativeProcess.Pid);

                                refreshedProcesses = true;
                            }

                            thread.Refresh(ref threadData);
                        }
                    }

                    if (resultRecord.HasField("current-thread-id"))
                    {
                        CurrentThreadId = resultRecord ["current-thread-id"] [0].GetUnsignedInt();
                    }
                });
            }
            catch (Exception e)
            {
                LoggingUtils.HandleException(e);
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public CLangDebuggeeStackFrame(CLangDebugger debugger, CLangDebuggeeThread thread, MiResultValueTuple frameTuple, string frameName)
            : base(debugger.Engine, thread as DebuggeeThread, frameName)
        {
            m_debugger = debugger;

            m_queriedRegisters = false;

            m_queriedArgumentsAndLocals = false;

            GetInfoFromCurrentLevel(frameTuple);
        }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeStackFrame (CLangDebugger debugger, CLangDebuggeeThread thread, MiResultValueTuple frameTuple, string frameName)
      : base (debugger.Engine, thread as DebuggeeThread, frameName)
    {
      m_debugger = debugger;

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

      m_queriedRegisters = false;

      m_queriedArgumentsAndLocals = false;

      GetInfoFromCurrentLevel (frameTuple);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeThread AddThread (uint threadId)
    {
      LoggingUtils.PrintFunction ();

      DebuggeeThread thread = null;

      lock (m_debugThreads)
      {
        if (!m_debugThreads.TryGetValue (threadId, out thread))
        {
          thread = new CLangDebuggeeThread (m_debugger, this, threadId);

          m_debugThreads.Add (threadId, thread);
        }
      }

      if (thread != null)
      {
        m_debugger.Engine.Broadcast (new DebugEngineEvent.ThreadCreate (), DebugProgram, thread);
      }

      return (CLangDebuggeeThread) thread;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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