Inheritance: AsyncRedirectProcess.EventListener, IDisposable
Exemplo n.º 1
0
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public void Detach ()
    {
      LoggingUtils.PrintFunction ();

      try
      {
        string command = "-target-detach";

        SendCommand (command, delegate (MiResultRecord resultRecord)
        {
          MiResultRecord.RequireOk (resultRecord, command);
        });
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        throw;
      }
      finally
      {
        m_gdbServer = null;

        m_gdbSetup.ClearPortForwarding ();

        IsAttached = false;
      }
    }
Exemplo n.º 2
0
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    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 ();
    }
Exemplo n.º 3
0
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public void Attach (GdbServer gdbServer)
    {
      LoggingUtils.PrintFunction ();

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

      m_gdbServer = gdbServer;

      m_gdbSetup.ClearPortForwarding ();

      m_gdbSetup.SetupPortForwarding ();

      SetSetting ("auto-solib-add", "on", false);

      SetSetting ("stop-on-solib-events", "0", false);

      SetSetting ("breakpoint pending", "on", false); // an unrecognized breakpoint location should automatically result in a pending breakpoint being created.

      // 
      // Figure out the target executable and architecture to be debugged.
      // 
      //   AFAIK the most reliable way to evaluate this is to read the symbolic link 'exe' for the target process:
      //   - This should also support 64-bit (app_process64) processes.
      // 
      //   lrwxrwxrwx u0_a91   u0_a91            2015-02-09 14:13 exe -> /system/bin/app_process32
      //

      bool debugging64bitProcess = false;

      string targetAppProcess = m_gdbSetup.Process.HostDevice.Shell ("run-as", string.Format ("{0} readlink /proc/{1}/exe", m_gdbSetup.Process.Name, m_gdbSetup.Process.Pid)).Replace ("\r", "").Replace ("\n", "");

      string cachedAppProcess = Path.Combine (m_gdbSetup.CacheSysRoot, targetAppProcess.Substring (1));

      if (targetAppProcess.Contains ("app_process64"))
      {
        debugging64bitProcess = true;
      }

      // 
      // Pull required system and application binaries from the device.
      // TODO: Use 'ndk-depends' to figure out which system shared libraries are used and pull these.
      // 

      HashSet<string> sharedLibrarySearchPaths = new HashSet<string> ();

      HashSet<string> debugFileDirectoryPaths = new HashSet<string> ();

      string [] cachedSystemBinaries = m_gdbSetup.CacheSystemBinaries (debugging64bitProcess);

      string [] cachedSystemLibraries = m_gdbSetup.CacheSystemLibraries (debugging64bitProcess);

      sharedLibrarySearchPaths.Add (PathUtils.SantiseWindowsPath (m_gdbSetup.CacheSysRoot)); // prioritise sysroot parent.

      foreach (string systemBinary in cachedSystemLibraries)
      {
        string posixSystemBinaryDirectory = PathUtils.SantiseWindowsPath (Path.GetDirectoryName (systemBinary));

        if (!sharedLibrarySearchPaths.Contains (posixSystemBinaryDirectory))
        {
          sharedLibrarySearchPaths.Add (posixSystemBinaryDirectory);
        }
      }

      string [] cachedAppLibraries = m_gdbSetup.CacheApplicationLibraries ();

      foreach (string appBinary in cachedAppLibraries)
      {
        string posixAppBinaryDirectory = PathUtils.SantiseWindowsPath (Path.GetDirectoryName (appBinary));

        if (!sharedLibrarySearchPaths.Contains (posixAppBinaryDirectory))
        {
          sharedLibrarySearchPaths.Add (posixAppBinaryDirectory);
        }
      }

      foreach (string symbolDir in m_gdbSetup.SymbolDirectories)
      {
        string path = PathUtils.SantiseWindowsPath (symbolDir);

        if (!debugFileDirectoryPaths.Contains (path))
        {
          debugFileDirectoryPaths.Add (path);
        }
      }

      SetSetting ("sysroot", PathUtils.SantiseWindowsPath (m_gdbSetup.CacheSysRoot), false);

#if true
      {
        string [] array = new string [sharedLibrarySearchPaths.Count];

        sharedLibrarySearchPaths.CopyTo (array, 0);

        SetSetting ("solib-search-path", string.Join (";", array), true);
      }
#endif

#if true
      {
        string [] array = new string [debugFileDirectoryPaths.Count];

        debugFileDirectoryPaths.CopyTo (array, 0);

        SetSetting ("debug-file-directory", string.Join (";", array), true);
      }
#endif

      if (!File.Exists (cachedAppProcess))
      {
        string linker = (debugging64bitProcess) ? @"system\bin\linker64" : @"system\bin\linker";

        cachedAppProcess = Path.Combine (m_gdbSetup.CacheSysRoot, linker);
      }

      if (string.IsNullOrEmpty (cachedAppProcess) || !File.Exists (cachedAppProcess))
      {
        throw new InvalidOperationException (string.Format ("Could not locate target binary: {0}", cachedAppProcess));
      }

      try
      {
        string command = "-file-exec-and-symbols " + PathUtils.SantiseWindowsPath (cachedAppProcess);

        MiResultRecord resultRecord = SendSyncCommand (command);

        MiResultRecord.RequireOk (resultRecord, command);
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        throw;
      }

      // 
      // Connect to the remote target.
      // 

      try
      {
        int timeout = 60000; // 60 seconds

        string command = string.Format ("-target-select remote {0}:{1}", m_gdbSetup.Host, m_gdbSetup.Port);

        MiResultRecord resultRecord = SendSyncCommand (command, timeout);

        MiResultRecord.RequireOk (resultRecord, command);

        IsAttached = true;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        throw;
      }

      // 
      // Evaluate target's GDB/MI support and capabilities. 
      // 

      try
      {
        string command = "-list-target-features";

        MiResultRecord resultRecord = SendSyncCommand (command);

        MiResultRecord.RequireOk (resultRecord, command);

        if (resultRecord.HasField ("features"))
        {
          foreach (MiResultValue feature in resultRecord ["features"] [0].Values)
          {
            m_gdbSupportedTargetMiFeatures.Add (feature.GetString ());
          }
        }
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        throw;
      }

      // 
      // Evaluate target's registers (and their names).
      // 

      try
      {
        string command = "-data-list-register-names";

        MiResultRecord resultRecord = SendSyncCommand (command);

        MiResultRecord.RequireOk (resultRecord, command);

        if (resultRecord.HasField ("register-names"))
        {
          MiResultValue registerNames = resultRecord ["register-names"] [0];

          for (int i = 0; i < registerNames.Values.Count; ++i)
          {
            string register = registerNames [i].GetString ();

            m_registerIdMapping.Add ((uint) i, register);
          }
        }
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        throw;
      }
    }