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

        public CLangDebuggeeThread(CLangDebugger debugger, CLangDebuggeeProgram program, uint id)
            : base(program.DebugProgram, id, string.Format("[Native-{0}]", id))
        {
            m_debugger = debugger;

            NativeProgram = program;

            RequiresRefresh = true;
        }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeThread (CLangDebugger debugger, CLangDebuggeeProgram program, uint id)
      : base (program.DebugProgram, id, string.Format ("[Native-{0}]", id))
    {
      m_debugger = debugger;

      NativeProgram = program;

      RequiresRefresh = true;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebugger (DebugEngine debugEngine, LaunchConfiguration launchConfiguration, DebuggeeProgram debugProgram)
    {
      Engine = debugEngine;

      m_launchConfiguration = launchConfiguration;

      NativeProgram = new CLangDebuggeeProgram (this, debugProgram);

      NativeMemoryBytes = new CLangDebuggeeMemoryBytes (this);

      VariableManager = new CLangDebuggerVariableManager (this);

      // 
      // Evaluate target device's architecture triple.
      // 

      string preferedGdbAbiToolPrefix = string.Empty;

      bool allow64BitAbis = true;

      switch (debugProgram.DebugProcess.NativeProcess.PrimaryCpuAbi)
      {
        case "armeabi":
        case "armeabi-v7a":
        {
          preferedGdbAbiToolPrefix = "arm-linux-androideabi";

          break;
        }

        case "arm64-v8a":
        {
          if (allow64BitAbis)
          {
            preferedGdbAbiToolPrefix = "aarch64-linux-android";
          }
          else
          {
            preferedGdbAbiToolPrefix = "arm-linux-androideabi";
          }

          break;
        }

        case "x86":
        {
          preferedGdbAbiToolPrefix = "i686-linux-android";

          break;
        }

        case "x86_64":
        {
          if (allow64BitAbis)
          {
            preferedGdbAbiToolPrefix = "x86_64-linux-android";
          }
          else
          {
            preferedGdbAbiToolPrefix = "i686-linux-android";
          }

          break;
        }

        case "mips":
        {
          preferedGdbAbiToolPrefix = "mipsel-linux-android";

          break;
        }

        case "mips64":
        {
          if (allow64BitAbis)
          {
            preferedGdbAbiToolPrefix = "mips64el-linux-android";
          }
          else
          {
            preferedGdbAbiToolPrefix = "mipsel-linux-android";
          }

          break;
        }
      }

      if (string.IsNullOrEmpty (preferedGdbAbiToolPrefix))
      {
        throw new InvalidOperationException (string.Format ("Unrecognised target primary CPU ABI: {0}", debugProgram.DebugProcess.NativeProcess.PrimaryCpuAbi));
      }

      bool preferedGdbAbiIs64Bit = preferedGdbAbiToolPrefix.Contains ("64");

      Engine.Broadcast (new DebugEngineEvent.DebuggerConnectionEvent (DebugEngineEvent.DebuggerConnectionEvent.EventType.LogStatus, string.Format ("Configuring GDB for '{0}' target...", preferedGdbAbiToolPrefix)), null, null);

      // 
      // Android++ bundles its own copies of GDB to get round various NDK issues. Search for these.
      // 

      string androidPlusPlusRoot = Environment.GetEnvironmentVariable ("ANDROID_PLUS_PLUS");

      // 
      // Build GDB version permutations.
      // 

      List<string> gdbToolPermutations = new List<string> ();

      string [] availableHostArchitectures = new string [] { "x86", "x86_64" };

      foreach (string arch in availableHostArchitectures)
      {
        if (arch.Contains ("64") && !Environment.Is64BitOperatingSystem)
        {
          continue;
        }

        string gdbToolFilePattern = string.Format ("{0}-gdb.cmd", preferedGdbAbiToolPrefix);

        string [] availableVersionPaths = Directory.GetDirectories (Path.Combine (androidPlusPlusRoot, "contrib", "gdb", "bin", arch), "*.*.*", SearchOption.TopDirectoryOnly);

        foreach (string versionPath in availableVersionPaths)
        {
          string [] gdbToolMatches = Directory.GetFiles (versionPath, gdbToolFilePattern, SearchOption.TopDirectoryOnly);

          foreach (string tool in gdbToolMatches)
          {
            gdbToolPermutations.Add (tool);
          }
        }
      }

      if (gdbToolPermutations.Count == 0)
      {
        throw new InvalidOperationException ("Could not locate required 32/64-bit GDB deployments.");
      }
      else
      {
        // 
        // Pick the oldest GDB version available if running 'Jelly Bean' or below.
        // 

        bool forceNdkR9dClient = (debugProgram.DebugProcess.NativeProcess.HostDevice.SdkVersion <= AndroidSettings.VersionCode.JELLY_BEAN);

        if (forceNdkR9dClient)
        {
          m_gdbSetup = new GdbSetup (debugProgram.DebugProcess.NativeProcess, gdbToolPermutations [0]);
        }
        else
        {
          m_gdbSetup = new GdbSetup (debugProgram.DebugProcess.NativeProcess, gdbToolPermutations [gdbToolPermutations.Count - 1]);
        }

        // 
        // A symbolic link to 'share' is placed in the architecture directory, provide GDB with that location.
        // 

        string architecturePath = Path.GetDirectoryName (Path.GetDirectoryName (m_gdbSetup.GdbToolPath));

        string pythonGdbScriptsPath = Path.Combine (architecturePath, "share", "gdb");

        m_gdbSetup.GdbToolArguments += " --data-directory " + PathUtils.SantiseWindowsPath (pythonGdbScriptsPath);
      }

      if (m_gdbSetup == null)
      {
        throw new InvalidOperationException ("Could not evaluate a suitable GDB instance. Ensure you have the correct NDK deployment for your system's architecture.");
      }

      if (m_launchConfiguration != null)
      {
        string launchDirectory;

        if (m_launchConfiguration.TryGetValue ("LaunchSuspendedDir", out launchDirectory))
        {
          m_gdbSetup.SymbolDirectories.Add (launchDirectory);
        }
      }

      GdbServer = new GdbServer (m_gdbSetup);

      GdbClient = new GdbClient (m_gdbSetup);

      GdbClient.OnResultRecord = OnClientResultRecord;

      GdbClient.OnAsyncRecord = OnClientAsyncRecord;

      GdbClient.OnStreamRecord = OnClientStreamRecord;

      GdbClient.Start ();
    }