public void SetUp()
        {
            _lldbShell         = Substitute.For <ILLDBShell>();
            _breakpointManager = Substitute.For <IBreakpointManager>();
            _moduleFileLoader  = Substitute.For <IModuleFileLoader>();

            _debugger           = Substitute.For <SbDebugger>();
            _target             = Substitute.For <RemoteTarget>();
            _listenerSubscriber = Substitute.For <ILldbListenerSubscriber>();
            _process            = Substitute.For <SbProcess>();

            _debugEngineHandler = Substitute.For <IDebugEngineHandler>();
            _taskExecutor       = Substitute.For <ITaskExecutor>();
            _eventManager       = Substitute.For <IEventManager>();

            var exceptionManagerFactory =
                new LldbExceptionManager.Factory(new Dictionary <int, YetiCommon.Signal>());
            var exceptionManager = exceptionManagerFactory.Create(_process);

            _debugModuleCache = Substitute.For <IDebugModuleCache>();
            _debugProgram     = Substitute.For <IGgpDebugProgram>();

            _attachedProgram = new LldbAttachedProgram(
                _breakpointManager, _eventManager, _lldbShell, _moduleFileLoader,
                _debugEngineHandler, _taskExecutor, _debugProgram, _debugger, _target, _process,
                exceptionManager, _debugModuleCache, _listenerSubscriber, _remotePid);
        }
        public void SetUp()
        {
            var taskContext = new JoinableTaskContext();

            remoteThread = Substitute.For <RemoteThread>();
            mockThread   = Substitute.For <IDebugThread>();
            mockThread.GetRemoteThread().Returns(remoteThread);
            mockDebugEngineHandler            = Substitute.For <IDebugEngineHandler>();
            mockDebugThreadCreator            = Substitute.For <DebugProgram.ThreadCreator>();
            mockDebugDisassemblyStreamFactory = Substitute.For <DebugDisassemblyStream.Factory>();
            mockProcess = Substitute.For <IDebugProcess2>();
            var guid = new Guid();

            mockSbProcess              = Substitute.For <SbProcess>();
            mockRemoteTarget           = Substitute.For <RemoteTarget>();
            mockDocumentContextFactory = Substitute.For <DebugDocumentContext.Factory>();
            mockCodeContextFactory     = Substitute.For <DebugCodeContext.Factory>();
            threadEnumFactory          = new ThreadEnumFactory();
            moduleEnumFactory          = new ModuleEnumFactory();
            codeContextEnumFactory     = new CodeContextEnumFactory();

            mockDebugModuleCache = Substitute.For <IDebugModuleCache>();
            program = new DebugProgram.Factory(taskContext, mockDebugDisassemblyStreamFactory,
                                               mockDocumentContextFactory, mockCodeContextFactory, threadEnumFactory,
                                               moduleEnumFactory, codeContextEnumFactory)
                      .Create(mockDebugEngineHandler, mockDebugThreadCreator, mockProcess, guid,
                              mockSbProcess, mockRemoteTarget, mockDebugModuleCache, false);
        }
Exemple #3
0
 DebugProgram(
     JoinableTaskContext taskContext,
     ThreadCreator threadCreator,
     DebugDisassemblyStream.Factory debugDisassemblyStreamFactory,
     DebugDocumentContext.Factory documentContextFactory,
     DebugCodeContext.Factory codeContextFactory,
     ThreadEnumFactory threadEnumFactory,
     ModuleEnumFactory moduleEnumFactory,
     CodeContextEnumFactory codeContextEnumFactory,
     IDebugEngineHandler debugEngineHandler,
     IDebugProcess2 process,
     Guid programId,
     SbProcess lldbProcess,
     RemoteTarget lldbTarget,
     IDebugModuleCache debugModuleCache,
     bool isCoreAttach)
 {
     _id                            = programId;
     _process                       = process;
     _lldbProcess                   = lldbProcess;
     _lldbTarget                    = lldbTarget;
     _threadCache                   = new Dictionary <uint, IDebugThread>();
     _isCoreAttach                  = isCoreAttach;
     _debugEngineHandler            = debugEngineHandler;
     _taskContext                   = taskContext;
     _threadCreator                 = threadCreator;
     _debugDisassemblyStreamFactory = debugDisassemblyStreamFactory;
     _documentContextFactory        = documentContextFactory;
     _codeContextFactory            = codeContextFactory;
     _threadEnumFactory             = threadEnumFactory;
     _moduleEnumFactory             = moduleEnumFactory;
     _codeContextEnumFactory        = codeContextEnumFactory;
     _debugModuleCache              = debugModuleCache;
 }
 public virtual IEventManager Create(IDebugEngineHandler debugEngineHandler,
                                     IBreakpointManager breakpointManager,
                                     IGgpDebugProgram program, SbProcess process,
                                     LldbListenerSubscriber listenerSubscriber)
 {
     return(new LldbEventManager(debugEngineHandler, breakpointManager,
                                 _boundBreakpointEnumFactory, program, process,
                                 listenerSubscriber, _taskContext));
 }
        // Get the total number of threads in the thread list.
        public override Task <GetNumThreadsResponse> GetNumThreads(GetNumThreadsRequest request,
                                                                   ServerCallContext context)
        {
            SbProcess sbProcess     = GrpcLookupUtils.GetProcess(request.Process, processStore);
            int       numberThreads = sbProcess.GetNumThreads();

            return(Task.FromResult(new GetNumThreadsResponse {
                NumberThreads = numberThreads
            }));
        }
Exemple #6
0
 public IGgpDebugProgram Create(IDebugEngineHandler debugEngineHandler,
                                ThreadCreator threadCreator,
                                IDebugProcess2 process, Guid programId, SbProcess lldbProcess,
                                RemoteTarget lldbTarget,
                                IDebugModuleCache debugModuleCache, bool isCoreAttach)
 {
     return(new DebugProgram(_taskContext, threadCreator,
                             _debugDisassemblyStreamFactory,
                             _documentContextFactory, _codeContextFactory, _threadsEnumFactory,
                             _moduleEnumFactory, _codeContextEnumFactory, debugEngineHandler, process,
                             programId, lldbProcess, lldbTarget, debugModuleCache, isCoreAttach));
 }
        internal static SbProcess GetProcess(GrpcSbProcess grpcProcess,
                                             ConcurrentDictionary <int, SbProcess> processStore)
        {
            SbProcess sbProcess = null;

            if (!processStore.TryGetValue(grpcProcess.Id, out sbProcess))
            {
                ErrorUtils.ThrowError(StatusCode.Internal, "Could not find process in store: "
                                      + grpcProcess.Id);
            }
            return(sbProcess);
        }
        public override Task <GetTargetResponse> GetTarget(GetTargetRequest request,
                                                           ServerCallContext context)
        {
            SbProcess sbProcess    = GrpcLookupUtils.GetProcess(request.Process, processStore);
            var       target       = sbProcess.GetTarget();
            var       grpcSbThread = new GrpcSbTarget
            {
                Id = target.GetId()
            };

            return(Task.FromResult(new GetTargetResponse {
                Target = grpcSbThread
            }));
        }
 LldbEventManager(IDebugEngineHandler debugEngineHandler,
                  IBreakpointManager breakpointManager,
                  BoundBreakpointEnumFactory boundBreakpointEnumFactory,
                  IGgpDebugProgram program, SbProcess process,
                  LldbListenerSubscriber listenerSubscriber, JoinableTaskContext taskContext)
 {
     _debugEngineHandler         = debugEngineHandler;
     _lldbBreakpointManager      = breakpointManager;
     _boundBreakpointEnumFactory = boundBreakpointEnumFactory;
     _program                = program;
     _lldbProcess            = process;
     _lldbListenerSubscriber = listenerSubscriber;
     _taskContext            = taskContext;
 }
        public void SetUp()
        {
            mockTarget   = Substitute.For <SbTarget>();
            remoteTarget = new RemoteTargetFactory(new RemoteBreakpointFactory())
                           .Create(mockTarget);
            mockAddress      = Substitute.For <SbAddress>();
            mockProcess      = Substitute.For <SbProcess>();
            mockMemoryRegion = Substitute.For <SbMemoryRegionInfo>();
            mockError        = Substitute.For <SbError>();
            mockBreakpoint   = Substitute.For <SbBreakpoint>();
            remoteBreakpoint = new RemoteBreakpointFactory().Create(mockBreakpoint);
            mockFunction     = Substitute.For <SbFunction>();

            mockTarget.GetProcess().Returns(mockProcess);
        }
        public override Task <LoadCoreResponse> LoadCore(LoadCoreRequest request,
                                                         ServerCallContext context)
        {
            RemoteTarget target   = GrpcLookupUtils.GetTarget(request.Target, _targetStore);
            SbProcess    process  = target.LoadCore(request.CorePath);
            var          response = new LoadCoreResponse();

            if (process != null)
            {
                if (!_processStore.TryAdd(process.GetUniqueId(), process))
                {
                    ErrorUtils.ThrowError(StatusCode.Internal, "Could not add process to store: " +
                                          process.GetUniqueId());
                }
                response.Process = new GrpcSbProcess {
                    Id = process.GetUniqueId()
                };
            }
            return(Task.FromResult(response));
        }
        public void SetUp()
        {
            _mockSbListener         = Substitute.For <SbListener>();
            _mockSbProcess          = Substitute.For <SbProcess>();
            _mockSbEvent            = Substitute.For <SbEvent>();
            _mockRemoteThread       = Substitute.For <RemoteThread>();
            _mockBreakpointManager  = Substitute.For <IBreakpointManager>();
            _mockDebugEngineHandler = Substitute.For <IDebugEngineHandler>();

            _mockPendingBreakpoint1 = Substitute.For <IPendingBreakpoint>();
            _mockPendingBreakpoint2 = Substitute.For <IPendingBreakpoint>();
            _mockBoundBreakpoint1   = Substitute.For <IBoundBreakpoint>();
            _mockBoundBreakpoint2   = Substitute.For <IBoundBreakpoint>();
            _mockBoundBreakpoint3   = Substitute.For <IBoundBreakpoint>();
            _mockWatchpoint         = Substitute.For <IWatchpoint>();
            _mockProgram            = Substitute.For <IGgpDebugProgram>();

            MockEvent(EventType.STATE_CHANGED, StateType.STOPPED, false);
            MockListener(_mockSbEvent, true);
            MockThread(_mockRemoteThread, StopReason.BREAKPOINT, _breakpointStopData);
            MockProcess(new List <RemoteThread> {
                _mockRemoteThread
            });
            MockBreakpointManager();

            _mockListenerSubscriber = Substitute.For <LldbListenerSubscriber>(_mockSbListener);

            var threadContext = new FakeMainThreadContext();

            _eventManager =
                new LldbEventManager
                .Factory(new BoundBreakpointEnumFactory(), threadContext.JoinableTaskContext)
                .Create(_mockDebugEngineHandler, _mockBreakpointManager, _mockProgram,
                        _mockSbProcess, _mockListenerSubscriber);

            var lldbEventManager = _eventManager as LldbEventManager;

            lldbEventManager?.SubscribeToChanges();
        }
        public override Task <AttachToProcessWithIDResponse> AttachToProcessWithID(
            AttachToProcessWithIDRequest request, ServerCallContext context)
        {
            if (!_targetStore.TryGetValue(request.Target.Id, out RemoteTarget target))
            {
                ErrorUtils.ThrowError(StatusCode.Internal,
                                      "Could not find target in store: " + request.Target.Id);
            }

            if (!_listenerStore.TryGetValue(request.Listener.Id, out SbListener listener))
            {
                ErrorUtils.ThrowError(StatusCode.Internal,
                                      "Could not find listener in store: " + request.Listener.Id);
            }

            SbProcess process =
                target.AttachToProcessWithID(listener, request.Pid, out SbError error);

            var response =
                new AttachToProcessWithIDResponse {
                Error = new GrpcSbError {
                    Success = error.Success(),
                    Error   = error.GetCString(),
                }
            };

            if (process != null)
            {
                if (!_processStore.TryAdd(process.GetUniqueId(), process))
                {
                    ErrorUtils.ThrowError(StatusCode.Internal, "Could not add process to store: " +
                                          process.GetUniqueId());
                }
                response.Process = new GrpcSbProcess {
                    Id = process.GetUniqueId()
                };
            }
            return(Task.FromResult(response));
        }
 public LldbAttachedProgram(IBreakpointManager breakpointManager, IEventManager eventManager,
                            ILLDBShell lldbShell, IModuleFileLoader moduleFileLoader,
                            IDebugEngineHandler debugEngineHandler,
                            ITaskExecutor taskExecutor, IGgpDebugProgram debugProgram,
                            SbDebugger debugger, RemoteTarget target, SbProcess process,
                            IExceptionManager exceptionManager,
                            IDebugModuleCache debugModuleCache,
                            ILldbListenerSubscriber listenerSubscriber, uint remotePid)
 {
     _debugProgram       = debugProgram;
     _breakpointManager  = breakpointManager;
     _eventManager       = eventManager;
     _lldbShell          = lldbShell;
     _moduleFileLoader   = moduleFileLoader;
     _debugEngineHandler = debugEngineHandler;
     _taskExecutor       = taskExecutor;
     _debugger           = debugger;
     _target             = target;
     _process            = process;
     _exceptionManager   = exceptionManager;
     _debugModuleCache   = debugModuleCache;
     _listenerSubscriber = listenerSubscriber;
     RemotePid           = remotePid;
 }
 public LldbExceptionManager(SbProcess lldbProcess, IReadOnlyDictionary <int, Signal> defaultSignals)
 {
     this.lldbProcess    = lldbProcess;
     this.defaultSignals = defaultSignals;
     ResetToDefaults();
 }
        public List <InstructionInfo> ReadInstructionInfos(SbAddress address, uint count,
                                                           string flavor)
        {
            SbProcess process      = _sbTarget.GetProcess();
            var       instructions = new List <InstructionInfo>();

            while (instructions.Count < count)
            {
                SbMemoryRegionInfo memoryRegion = null;
                SbError            error        = process.GetMemoryRegionInfo(address.GetLoadAddress(_sbTarget),
                                                                              out memoryRegion);

                if (error.Fail())
                {
                    Trace.WriteLine("Unable to retrieve memory region info.");
                    return(new List <InstructionInfo>());
                }

                // If the address we are given is not mapped we should not try to disassemble it.
                if (!memoryRegion.IsMapped())
                {
                    uint instructionsLeft = count - (uint)instructions.Count;

                    ulong nextAddress = AddUnmappedInstructions(address, instructionsLeft,
                                                                memoryRegion, instructions);

                    address = _sbTarget.ResolveLoadAddress(nextAddress);

                    // Continue in case we still need more instructions
                    continue;
                }

                List <SbInstruction> sbInstructions =
                    _sbTarget.ReadInstructions(address, count - (uint)instructions.Count, flavor);
                foreach (SbInstruction sbInstruction in sbInstructions)
                {
                    SbAddress sbAddress = sbInstruction.GetAddress();
                    if (sbAddress == null)
                    {
                        // It should never happen that we cannot get an address for an instruction
                        Trace.WriteLine("Unable to retrieve address.");
                        return(new List <InstructionInfo>());
                    }

                    ulong instructionAddress = sbAddress.GetLoadAddress(_sbTarget);

                    SbSymbol symbol = sbAddress.GetSymbol();

                    string symbolName = null;
                    // Only set symbolName if it is the start of a function
                    SbAddress startAddress = symbol?.GetStartAddress();
                    if (startAddress != null &&
                        startAddress.GetLoadAddress(_sbTarget) == instructionAddress)
                    {
                        symbolName = symbol.GetName();
                    }

                    SbLineEntry   lineEntry     = sbAddress.GetLineEntry();
                    LineEntryInfo lineEntryInfo = null;
                    if (lineEntry != null)
                    {
                        lineEntryInfo = new LineEntryInfo {
                            FileName  = lineEntry.GetFileName(),
                            Directory = lineEntry.GetDirectory(),
                            Line      = lineEntry.GetLine(),
                            Column    = lineEntry.GetColumn(),
                        };
                    }

                    // Create a new instruction and fill in the values
                    var instruction = new InstructionInfo {
                        Address    = instructionAddress,
                        Operands   = sbInstruction.GetOperands(_sbTarget),
                        Comment    = sbInstruction.GetComment(_sbTarget),
                        Mnemonic   = sbInstruction.GetMnemonic(_sbTarget),
                        SymbolName = symbolName,
                        LineEntry  = lineEntryInfo,
                    };
                    instructions.Add(instruction);
                }

                // If we haven't managed to retrieve all the instructions we wanted, add
                // an invalid instruction and keep going from the next address.
                if (instructions.Count < count)
                {
                    ulong nextAddress =
                        AddInvalidInstruction(address, sbInstructions, instructions);

                    // Set the address to the next address after the invalid instruction
                    address = _sbTarget.ResolveLoadAddress(nextAddress);
                }
            }
            return(instructions);
        }
            public ILldbAttachedProgram Create(
                IDebugProcess2 debugProcess, Guid programId, IDebugEngine2 debugEngine,
                IDebugEventCallback2 callback, SbDebugger debugger, RemoteTarget target,
                LldbListenerSubscriber listenerSubscriber, SbProcess process,
                SbCommandInterpreter commandInterpreter, bool isCoreAttach,
                IExceptionManager exceptionManager, IModuleSearchLogHolder moduleSearchLogHolder,
                uint remotePid)
            {
                // Required due to an issue triggered by the proxy used to wrap debugProgramFactory.
                // TODO: Remove assertion once the issue with Castle.DynamicProxy is
                // fixed.
                _taskContext.ThrowIfNotOnMainThread();

                var debugEngineHandler = _debugEngineHandlerFactory.Create(debugEngine, callback);

                var binaryLoader     = _binaryLoaderFactory.Create(target);
                var symbolLoader     = _symbolLoaderFactory.Create(commandInterpreter);
                var moduleFileLoader = _moduleFileLoaderFactory.Create(symbolLoader, binaryLoader,
                                                                       moduleSearchLogHolder);

                var debugModuleCache = _debugModuleCacheFactory.Create(
                    (lldbModule, loadOrder, ggpProgram) => _debugModuleFactory.Create(
                        moduleFileLoader, moduleSearchLogHolder, lldbModule, loadOrder,
                        debugEngineHandler, ggpProgram));
                var ad7FrameInfoCreator = new AD7FrameInfoCreator(debugModuleCache);

                var stackFrameCreator = new StackFramesProvider.StackFrameCreator(
                    (frame, thread, program) => _debugStackFrameCreator(
                        ad7FrameInfoCreator, frame, thread, debugEngineHandler, program));
                var threadCreator = new DebugProgram.ThreadCreator(
                    (thread, program) => _debugThreadCreatorDelegate(
                        ad7FrameInfoCreator, stackFrameCreator, thread, program));
                var debugProgram = _debugProgramFactory.Create(
                    debugEngineHandler, threadCreator, debugProcess, programId, process, target,
                    debugModuleCache, isCoreAttach);

                _taskExecutor.StartAsyncTasks(
                    ex => debugEngineHandler.Abort(debugProgram, ExitInfo.Error(ex)));

                var breakpointManager =
                    _breakpointManagerFactory.Create(debugEngineHandler, debugProgram);
                var eventManager =
                    _eventManagerFactory.Create(debugEngineHandler, breakpointManager, debugProgram,
                                                process, listenerSubscriber);

                // TODO: Listen for module load/unload events from LLDB
                binaryLoader.LldbModuleReplaced += (o, args) =>
                {
                    debugModuleCache.GetOrCreate(args.AddedModule, debugProgram);
                    debugModuleCache.Remove(args.RemovedModule);
                };
                debugModuleCache.ModuleAdded += (o, args) =>
                                                debugEngineHandler.OnModuleLoad(args.Module, debugProgram);
                debugModuleCache.ModuleRemoved += (o, args) =>
                                                  debugEngineHandler.OnModuleUnload(args.Module, debugProgram);

                return(new LldbAttachedProgram(breakpointManager, eventManager, _lldbShell,
                                               moduleFileLoader, debugEngineHandler, _taskExecutor,
                                               debugProgram, debugger, target, process,
                                               exceptionManager, debugModuleCache,
                                               listenerSubscriber, remotePid));
            }
 public virtual IExceptionManager Create(SbProcess lldbProcess)
 {
     return(new LldbExceptionManager(lldbProcess, defaultSignals));
 }
        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();
                }
            }
        }
        SbProcess LoadCore(RemoteTarget lldbTarget, IAction loadCoreAction)
        {
            var moduleFileLoadRecorder = _moduleFileLoadRecorderFactory.Create(loadCoreAction);

            moduleFileLoadRecorder.RecordBeforeLoad(Array.Empty <SbModule>());

            bool isFullDump = _coreFilePath.EndsWith(".core");

            if (isFullDump)
            {
                string combinedPath = _taskContext.Factory.Run(async() =>
                {
                    await _taskContext.Factory.SwitchToMainThreadAsync();
                    _symbolSettingsProvider.GetStorePaths(out string paths, out string cache);
                    return(SymbolUtils.GetCombinedLookupPaths(paths, cache));
                });

                _moduleFileFinder.SetSearchPaths(combinedPath);

                TextWriter     searchLog = new StringWriter();
                DumpReadResult dump      = _dumpModulesProvider.GetModules(_coreFilePath);

                DumpModule[] executableModules =
                    dump.Modules.Where(module => module.IsExecutable).ToArray();
                DumpModule[] nonExecutableModules =
                    dump.Modules.Where(module => !module.IsExecutable).ToArray();

                // We should not pre-load non executable modules if there wasn't any successfully
                // loaded executable modules. Otherwise lldb will not upgrade image list during the
                // attachment to the core dump and will try to resolve the executable on the
                // developer machine. See (internal)
                if (executableModules.Any() &&
                    executableModules.All(module =>
                                          TryPreloadModule(lldbTarget, searchLog, module)))
                {
                    foreach (DumpModule module in nonExecutableModules)
                    {
                        TryPreloadModule(lldbTarget, searchLog, module);
                    }
                }

                if (dump.Warning == DumpReadWarning.None && !executableModules.Any())
                {
                    dump.Warning = DumpReadWarning.ExecutableBuildIdMissing;
                }
                if (dump.Warning != DumpReadWarning.None)
                {
                    var shouldAttach = _taskContext.Factory.Run(
                        async() => await _warningDialog.ShouldAttachToIncosistentCoreFileAsync(
                            dump.Warning));
                    if (!shouldAttach)
                    {
                        throw new CoreAttachStoppedException();
                    }
                }
            }

            SbProcess lldbDebuggerProcess = lldbTarget.LoadCore(_coreFilePath);

            if (lldbDebuggerProcess == null)
            {
                throw new AttachException(VSConstants.E_ABORT,
                                          ErrorStrings.FailedToLoadCore(_coreFilePath));
            }

            RecordModules(lldbTarget, moduleFileLoadRecorder);
            return(lldbDebuggerProcess);
        }