Exemple #1
0
        void LoadSymbols(ILldbAttachedProgram program)
        {
            _taskContext.ThrowIfNotOnMainThread();

            foreach (string moduleName in ListSelectedModules())
            {
                foreach (var module in program.GetModulesByName(moduleName))
                {
                    module.LoadSymbols();
                }
            }
        }
        public async Task TestConnectRemoteNotCalledWithAttachToCoreAsync(
            [Values] bool stadiaPlatformAvailable)
        {
            var connectRemoteRecorder = new PlatformFactoryFakeConnectRecorder();
            var launcherFactory       =
                CreateLauncherFactory(stadiaPlatformAvailable, connectRemoteRecorder);
            var launcher = launcherFactory.Create(_debugEngine, LaunchOption.AttachToCore,
                                                  "some/core/path", "", "", _gameLaunch);
            ILldbAttachedProgram program = await LaunchAsync(launcher);

            Assert.That(connectRemoteRecorder.InvocationCount, Is.EqualTo(0));
            Assert.That(program, Is.Not.Null);
            program.Stop();
        }
        public async Task TestConnectRemoteCalledForLinuxWithCorrectUrlAsync(
            LaunchOption launchOption)
        {
            var connectRemoteRecorder = new PlatformFactoryFakeConnectRecorder();
            var launcherFactory       = CreateLauncherFactory(false, connectRemoteRecorder);
            var launcher = launcherFactory.Create(_debugEngine, launchOption, "", _gameBinary,
                                                  _gameBinary, _gameLaunch);
            ILldbAttachedProgram program = await LaunchAsync(launcher);

            Assert.That(connectRemoteRecorder.InvocationCount, Is.EqualTo(1));
            Assert.That(connectRemoteRecorder.InvocationOptions[0].GetUrl(),
                        Is.EqualTo("connect://localhost:10200"));
            Assert.That(program, Is.Not.Null);
            program.Stop();
        }
        public async Task TestConnectRemoteCalledForStadiaWithScpCommandAsExtraArgAsync(
            LaunchOption launchOption)
        {
            var connectRemoteRecorder = new PlatformFactoryFakeConnectRecorder();
            var launcherFactory       = CreateLauncherFactory(true, connectRemoteRecorder);
            var launcher = launcherFactory.Create(_debugEngine, launchOption, "", _gameBinary,
                                                  _gameBinary, _gameLaunch);
            ILldbAttachedProgram program = await LaunchAsync(launcher);

            Assert.That(connectRemoteRecorder.InvocationCount, Is.EqualTo(1));
            Assert.That(connectRemoteRecorder.InvocationOptions.Count, Is.EqualTo(1));

            string connectRemoteUrl = connectRemoteRecorder.InvocationOptions[0].GetUrl();

            // argument for ConnectRemote should start with a standard value, ending with ';'
            // used as a separator between it and scp command.
            Assert.That(connectRemoteUrl, Does.StartWith("connect://localhost:10200;"));
            // path to the scp.exe should be quoted, to check this we add \" to the assertion.
            Assert.That(connectRemoteUrl, Does.Contain("scp.exe\""));
            Assert.That(connectRemoteUrl,
                        Does.Contain("-oStrictHostKeyChecking=yes -oUserKnownHostsFile"));
            Assert.That(program, Is.Not.Null);
            program.Stop();
        }
        public async Task <ILldbAttachedProgram> LaunchAsync(
            ICancelable task, IDebugProcess2 process, Guid programId, uint?attachPid,
            DebuggerOptions.DebuggerOptions debuggerOptions, HashSet <string> libPaths,
            GrpcConnection grpcConnection, int localDebuggerPort, string targetIpAddress,
            int targetPort, IDebugEventCallback2 callback)
        {
            var       launchSucceeded = false;
            Stopwatch launchTimer     = Stopwatch.StartNew();


            // This should be the first request to the DebuggerGrpcServer.  Providing a retry wait
            // time allows us to connect to a DebuggerGrpcServer that is slow to start. Note that
            // we postpone sourcing .lldbinit until we are done with our initialization so that
            // the users can override our defaults.
            var lldbDebugger =
                _lldbDebuggerFactory.Create(grpcConnection, false, TimeSpan.FromSeconds(10));

            if (lldbDebugger == null)
            {
                throw new AttachException(VSConstants.E_ABORT, ErrorStrings.FailedToCreateDebugger);
            }

            if (debuggerOptions[DebuggerOption.CLIENT_LOGGING] == DebuggerOptionState.ENABLED)
            {
                lldbDebugger.EnableLog("lldb", new List <string> {
                    "default", "module"
                });

                // TODO: Disable 'dwarf' logs until we can determine why this
                // causes LLDB to hang.
                // lldbDebugger.EnableLog("dwarf", new List<string> { "default" });
            }

            if (_fastExpressionEvaluation)
            {
                lldbDebugger.EnableFastExpressionEvaluation();
            }

            lldbDebugger.SetDefaultLLDBSettings();

            // Apply .lldbinit after we set our settings so that the user can override our
            // defaults with a custom .lldbinit.
            LoadLocalLldbInit(lldbDebugger);

            // Add exec search paths, so that LLDB can find the executable and any dependent
            // libraries.  If LLDB is able to find the files locally, it won't try to download
            // them from the remote server, saving valuable time on attach.
            foreach (string path in libPaths)
            {
                lldbDebugger.SetLibrarySearchPath(path);
            }

            lldbDebugger.SetAsync(true);

            SbPlatform lldbPlatform;

            switch (_launchOption)
            {
            case LaunchOption.AttachToGame:
            // Fall through.
            case LaunchOption.LaunchGame:
                lldbPlatform = CreateRemotePlatform(grpcConnection, lldbDebugger);
                if (lldbPlatform == null)
                {
                    throw new AttachException(VSConstants.E_FAIL,
                                              ErrorStrings.FailedToCreateLldbPlatform);
                }
                task.ThrowIfCancellationRequested();
                Trace.WriteLine("Attempting to connect debugger");
                task.Progress.Report("Connecting to debugger");

                string connectRemoteUrl      = $"{_lldbConnectUrl}:{localDebuggerPort}";
                string connectRemoteArgument =
                    CreateConnectRemoteArgument(connectRemoteUrl, targetIpAddress, targetPort);

                SbPlatformConnectOptions lldbConnectOptions =
                    _lldbPlatformConnectOptionsFactory.Create(connectRemoteArgument);

                IAction debugerWaitAction =
                    _actionRecorder.CreateToolAction(ActionType.DebugWaitDebugger);

                bool TryConnectRemote()
                {
                    if (lldbPlatform.ConnectRemote(lldbConnectOptions).Success())
                    {
                        return(true);
                    }

                    VerifyGameIsReady(debugerWaitAction);
                    return(false);
                }

                try
                {
                    debugerWaitAction.Record(() => RetryWithTimeout(
                                                 task, TryConnectRemote, _launchRetryDelay,
                                                 _launchTimeout, launchTimer));
                }
                catch (TimeoutException e)
                {
                    throw new AttachException(
                              VSConstants.E_ABORT,
                              ErrorStrings.FailedToConnectDebugger(lldbConnectOptions.GetUrl()), e);
                }
                Trace.WriteLine("LLDB successfully connected");
                break;

            case LaunchOption.AttachToCore:
                lldbPlatform = _lldbPlatformFactory.Create(_localLldbPlatformName, grpcConnection);
                if (lldbPlatform == null)
                {
                    throw new AttachException(VSConstants.E_FAIL,
                                              ErrorStrings.FailedToCreateLldbPlatform);
                }
                break;

            default:
                throw new AttachException(VSConstants.E_ABORT, ErrorStrings.InvalidLaunchOption(
                                              _launchOption.ToString()));
            }

            lldbDebugger.SetSelectedPlatform(lldbPlatform);

            task.ThrowIfCancellationRequested();
            task.Progress.Report("Debugger is attaching (this can take a while)");

            RemoteTarget lldbTarget = null;

            if (_launchOption == LaunchOption.LaunchGame &&
                !string.IsNullOrEmpty(_executableFullPath))
            {
                var createExecutableTargetAction =
                    _actionRecorder.CreateToolAction(ActionType.DebugCreateExecutableTarget);
                createExecutableTargetAction.Record(
                    () => lldbTarget = CreateTarget(lldbDebugger, _executableFullPath));
            }
            else
            {
                lldbTarget = CreateTarget(lldbDebugger, "");
            }

            var lldbListener = CreateListener(grpcConnection);

            // This is required to catch breakpoint change events.
            lldbTarget.AddListener(lldbListener, EventType.STATE_CHANGED);
            var listenerSubscriber = new LldbListenerSubscriber(lldbListener);
            var eventHandler       = new EventHandler <FileUpdateReceivedEventArgs>(
                (s, e) => ListenerSubscriberOnFileUpdateReceived(task, e));

            listenerSubscriber.FileUpdateReceived += eventHandler;
            listenerSubscriber.Start();

            try
            {
                if (_launchOption == LaunchOption.AttachToCore)
                {
                    var       loadCoreAction      = _actionRecorder.CreateToolAction(ActionType.DebugLoadCore);
                    SbProcess lldbDebuggerProcess = null;
                    loadCoreAction.Record(() =>
                                          lldbDebuggerProcess = LoadCore(lldbTarget, loadCoreAction));

                    await _taskContext.Factory.SwitchToMainThreadAsync();

                    return(_attachedProgramFactory.Create(
                               process, programId, _debugEngine, callback, lldbDebugger, lldbTarget,
                               listenerSubscriber, lldbDebuggerProcess,
                               lldbDebugger.GetCommandInterpreter(), true, new NullExceptionManager(),
                               _moduleSearchLogHolder, remotePid: 0));
                }

                // Get process ID.
                uint processId = 0;
                switch (_launchOption)
                {
                case LaunchOption.AttachToGame:
                    if (!attachPid.HasValue)
                    {
                        throw new AttachException(VSConstants.E_ABORT,
                                                  ErrorStrings.FailedToRetrieveProcessId);
                    }

                    processId = attachPid.Value;
                    break;

                case LaunchOption.LaunchGame:
                    // Since we have no way of knowing when the remote process actually
                    // starts, try a few times to get the pid.

                    IAction debugWaitAction =
                        _actionRecorder.CreateToolAction(ActionType.DebugWaitProcess);

                    bool TryGetRemoteProcessId()
                    {
                        if (GetRemoteProcessId(_executableFileName, lldbPlatform, out processId))
                        {
                            return(true);
                        }

                        VerifyGameIsReady(debugWaitAction);
                        return(false);
                    }

                    try
                    {
                        debugWaitAction.Record(() => RetryWithTimeout(
                                                   task, TryGetRemoteProcessId, _launchRetryDelay,
                                                   _launchTimeout, launchTimer));
                    }
                    catch (TimeoutException e)
                    {
                        throw new AttachException(VSConstants.E_ABORT,
                                                  ErrorStrings.FailedToRetrieveProcessId, e);
                    }

                    break;
                }

                Trace.WriteLine("Attaching to pid " + processId);
                var debugAttachAction = _actionRecorder.CreateToolAction(ActionType.DebugAttach);

                SbProcess debuggerProcess = null;
                debugAttachAction.Record(() => {
                    var moduleFileLoadRecorder =
                        _moduleFileLoadRecorderFactory.Create(debugAttachAction);
                    moduleFileLoadRecorder.RecordBeforeLoad(Array.Empty <SbModule>());

                    debuggerProcess = lldbTarget.AttachToProcessWithID(lldbListener, processId,
                                                                       out SbError lldbError);
                    if (lldbError.Fail())
                    {
                        throw new AttachException(
                            VSConstants.E_ABORT,
                            GetLldbAttachErrorDetails(lldbError, lldbPlatform, processId));
                    }

                    RecordModules(lldbTarget, moduleFileLoadRecorder);
                });

                var exceptionManager = _exceptionManagerFactory.Create(debuggerProcess);

                await _taskContext.Factory.SwitchToMainThreadAsync();

                ILldbAttachedProgram attachedProgram = _attachedProgramFactory.Create(
                    process, programId, _debugEngine, callback, lldbDebugger, lldbTarget,
                    listenerSubscriber, debuggerProcess, lldbDebugger.GetCommandInterpreter(),
                    false, exceptionManager, _moduleSearchLogHolder, processId);
                launchSucceeded = true;
                return(attachedProgram);
            }
            finally
            {
                // clean up the SBListener subscriber
                listenerSubscriber.FileUpdateReceived -= eventHandler;
                // stop the SBListener subscriber completely if the game failed to launch
                if (!launchSucceeded)
                {
                    listenerSubscriber.Stop();
                }
            }
        }
 public SessionStoppedEventArgs(ILldbAttachedProgram program)
 {
     Program = program;
 }
 public SessionLaunchedEventArgs(DebugEngine.DebugEngine.LaunchOption mode,
                                 ILldbAttachedProgram program)
 {
     Mode    = mode;
     Program = program;
 }