public void TestAttachToGameFail_AnotherTracer()
        {
            string parentPid  = "1234";
            string tracerPid  = "9876";
            string tracerName = "gdb";

            var launcherFactory = CreateLauncherFactory(false);
            var launcher        = launcherFactory.Create(_debugEngine, LaunchOption.AttachToGame, "",
                                                         _gameBinary, _gameBinary, _gameLaunch);

            _debuggerFactory.SetTargetAttachError("Operation not permitted");
            _platformFactory.AddCommandOutput($"cat /proc/{_pid}/status",
                                              "Name:\tgame\n" + $"Pid:\t{_pid}\n" +
                                              $"PPid:\t{parentPid}\n" +
                                              $"TracerPid:\t{tracerPid}\n" + "FDSize:\t256\n");
            _platformFactory.AddCommandOutput($"cat /proc/{tracerPid}/comm", tracerName);

            AttachException e =
                Assert.ThrowsAsync <AttachException>(async() => await LaunchAsync(launcher));

            Assert.That(e.Message,
                        Is.EqualTo(
                            ErrorStrings
                            .FailedToAttachToProcessOtherTracer(tracerName, tracerPid)));
            CheckLldbListenerStops();
        }
        /// <summary>
        /// Get a more detailed error message if attaching to the remote process failed.
        ///
        /// At the moment, we handle specially only the case when another tracer is attached.
        /// In that case, we detect and show which process is the tracer.
        /// </summary>
        /// <param name="lldbError">Error object from Lldb attach.</param>
        /// <param name="platform">Lldb platform, used to run shell commands.</param>
        /// <param name="processId">Process Id of the debuggee.</param>
        /// <returns>Returns the error string.</returns>
        string GetLldbAttachErrorDetails(SbError lldbError, SbPlatform platform, uint processId)
        {
            string lldbMessageWhenAlreadyTraced = "Operation not permitted";

            // Compute the fallback error message.
            string errorString = ErrorStrings.FailedToAttachToProcess(lldbError.GetCString());

            // If the error does not need special handling, just return the default message.
            if (platform == null || lldbError.GetCString() != lldbMessageWhenAlreadyTraced)
            {
                return(errorString);
            }

            // Let us detect if there is a debugger already attached and provide a better error
            // message there.
            string output = RunShellCommand($"cat /proc/{processId}/status", platform);

            if (string.IsNullOrEmpty(output))
            {
                return(errorString);
            }

            Regex tracerRE    = new Regex("[\\r\\n]TracerPid:\\W*([0-9]+)[\\r\\n]");
            Regex parentRE    = new Regex("[\\r\\n]PPid:\\W*([0-9]+)[\\r\\n]");
            Regex firstLineRE = new Regex("^([^\\r\\n]*)([\\r\\n]|$)");

            // Find the line with tracer pid in the proc-status file.
            Match tracerMatch = tracerRE.Match(output);
            Match parentMatch = parentRE.Match(output);

            if (!tracerMatch.Success || !parentMatch.Success)
            {
                return(errorString);
            }
            string parentPid = parentMatch.Groups[1].Value;
            string tracerPid = tracerMatch.Groups[1].Value;

            // If there was no tracer, just show the default message.
            if (tracerPid == "0")
            {
                return(errorString);
            }

            // If the tracer is the parent process, then the debuggee is tracing itself.
            if (tracerPid == parentPid)
            {
                return(ErrorStrings.FailedToAttachToProcessSelfTrace);
            }

            // Try to find the tracer in the list of processes and report it in the error message.
            string commOutput = RunShellCommand($"cat /proc/{tracerPid}/comm", platform);

            if (string.IsNullOrEmpty(output))
            {
                return(errorString);
            }

            // Get the first line as the process name.
            Match  commMatch  = firstLineRE.Match(commOutput);
            string tracerName = commMatch.Success ? commMatch.Groups[1].Value : "<unkown>";

            return(ErrorStrings.FailedToAttachToProcessOtherTracer(tracerName, tracerPid));
        }