src/vs/workbench/contrib/debug/node/debugAdapter.ts/ExecutableDebugAdapter/startSession
class ExecutableDebugAdapter:	async startSession(): Promise<void> {

		const command = this.adapterExecutable.command;
		const args = this.adapterExecutable.args;
		const options = this.adapterExecutable.options || {};

		try {
			// verify executables asynchronously
			if (command) {
				if (path.isAbsolute(command)) {
					const commandExists = await Promises.exists(command);
					if (!commandExists) {
						throw new Error(nls.localize('debugAdapterBinNotFound', "Debug adapter executable '{0}' does not exist.", command));
					}
				} else {
					// relative path
					if (command.indexOf('/') < 0 && command.indexOf('\\') < 0) {
						// no separators: command looks like a runtime name like 'node' or 'mono'
						// TODO: check that the runtime is available on PATH
					}
				}
			} else {
				throw new Error(nls.localize({ key: 'debugAdapterCannotDetermineExecutable', comment: ['Adapter executable file not found'] },
					"Cannot determine executable for debug adapter '{0}'.", this.debugType));
			}

			let env = process.env;
			if (options.env && Object.keys(options.env).length > 0) {
				env = objects.mixin(objects.deepClone(process.env), options.env);
			}

			if (command === 'node') {
				if (Array.isArray(args) && args.length > 0) {
					const isElectron = !!process.env['ELECTRON_RUN_AS_NODE'] || !!process.versions['electron'];
					const forkOptions: cp.ForkOptions = {
						env: env,
						execArgv: isElectron ? ['-e', 'delete process.env.ELECTRON_RUN_AS_NODE;require(process.argv[1])'] : [],
						silent: true
					};
					if (options.cwd) {
						forkOptions.cwd = options.cwd;
					}
					const child = cp.fork(args[0], args.slice(1), forkOptions);
					if (!child.pid) {
						throw new Error(nls.localize('unableToLaunchDebugAdapter', "Unable to launch debug adapter from '{0}'.", args[0]));
					}
					this.serverProcess = child;
				} else {
					throw new Error(nls.localize('unableToLaunchDebugAdapterNoArgs', "Unable to launch debug adapter."));
				}
			} else {
				const spawnOptions: cp.SpawnOptions = {
					env: env
				};
				if (options.cwd) {
					spawnOptions.cwd = options.cwd;
				}
				this.serverProcess = cp.spawn(command, args, spawnOptions);
			}

			this.serverProcess.on('error', err => {
				this._onError.fire(err);
			});
			this.serverProcess.on('exit', (code, signal) => {
				this._onExit.fire(code);
			});

			this.serverProcess.stdout!.on('close', () => {
				this._onError.fire(new Error('read error'));
			});
			this.serverProcess.stdout!.on('error', error => {
				this._onError.fire(error);
			});

			this.serverProcess.stdin!.on('error', error => {
				this._onError.fire(error);
			});

			const outputService = this.outputService;
			if (outputService) {
				const sanitize = (s: string) => s.toString().replace(/\r?\n$/mg, '');
				// this.serverProcess.stdout.on('data', (data: string) => {
				// 	console.log('%c' + sanitize(data), 'background: #ddd; font-style: italic;');
				// });
				this.serverProcess.stderr!.on('data', (data: string) => {
					const channel = outputService.getChannel(ExtensionsChannelId);
					if (channel) {
						channel.append(sanitize(data));
					}
				});
			} else {
				this.serverProcess.stderr!.resume();
			}

			// finally connect to the DA
			this.connect(this.serverProcess.stdout!, this.serverProcess.stdin!);

		} catch (err) {
			this._onError.fire(err);
		}
	}