[Lldb-commits] [lldb] [vscode-lldb] Restart server when lldb-dap binary has changed (PR #159797)
Roy Shi via lldb-commits
lldb-commits at lists.llvm.org
Tue Sep 23 07:16:57 PDT 2025
https://github.com/royitaqi updated https://github.com/llvm/llvm-project/pull/159797
>From e4d4d1c8d38ae929081778b47859c47a5a5665c8 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Fri, 19 Sep 2025 07:57:06 -0700
Subject: [PATCH 1/4] [vscode-lldb] Restart server when the lldb-dap binary has
changed
---
lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts | 77 +++++++++++++++----
1 file changed, 64 insertions(+), 13 deletions(-)
diff --git a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
index 774be50053a17..7a1754f4bce6a 100644
--- a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
+++ b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
@@ -1,4 +1,5 @@
import * as child_process from "node:child_process";
+import * as path from "path";
import { isDeepStrictEqual } from "util";
import * as vscode from "vscode";
@@ -12,6 +13,10 @@ export class LLDBDapServer implements vscode.Disposable {
private serverProcess?: child_process.ChildProcessWithoutNullStreams;
private serverInfo?: Promise<{ host: string; port: number }>;
private serverSpawnInfo?: string[];
+ // Detects changes to the lldb-dap executable file since the server's startup.
+ private serverFileWatcher?: vscode.FileSystemWatcher;
+ // Indicates whether the lldb-dap executable file has changed since the server's startup.
+ private serverFileChanged?: boolean;
constructor() {
vscode.commands.registerCommand(
@@ -83,6 +88,18 @@ export class LLDBDapServer implements vscode.Disposable {
});
this.serverProcess = process;
this.serverSpawnInfo = this.getSpawnInfo(dapPath, dapArgs, options?.env);
+ this.serverFileChanged = false;
+ // Cannot do `createFileSystemWatcher(dapPath)` for a single file. Have to use `RelativePattern`.
+ // See https://github.com/microsoft/vscode/issues/141011#issuecomment-1016772527
+ this.serverFileWatcher = vscode.workspace.createFileSystemWatcher(
+ new vscode.RelativePattern(
+ vscode.Uri.file(path.dirname(dapPath)),
+ path.basename(dapPath),
+ ),
+ );
+ this.serverFileWatcher.onDidChange(() => {
+ this.serverFileChanged = true;
+ });
});
return this.serverInfo;
}
@@ -100,20 +117,34 @@ export class LLDBDapServer implements vscode.Disposable {
args: string[],
env: NodeJS.ProcessEnv | { [key: string]: string } | undefined,
): Promise<boolean> {
- if (!this.serverProcess || !this.serverInfo || !this.serverSpawnInfo) {
+ if (
+ !this.serverProcess ||
+ !this.serverInfo ||
+ !this.serverSpawnInfo ||
+ !this.serverFileWatcher ||
+ this.serverFileChanged === undefined
+ ) {
return true;
}
- const newSpawnInfo = this.getSpawnInfo(dapPath, args, env);
- if (isDeepStrictEqual(this.serverSpawnInfo, newSpawnInfo)) {
- return true;
- }
+ // Check if the server has changed. If so, generate message and detail for user prompt.
+ const messageAndDetail = (() => {
+ if (this.serverFileChanged) {
+ return {
+ message:
+ "The lldb-dap binary has changed. Would you like to restart the server?",
+ detail: `An existing lldb-dap server (${this.serverProcess.pid}) is running with an old binary.
- const userInput = await vscode.window.showInformationMessage(
- "The arguments to lldb-dap have changed. Would you like to restart the server?",
- {
- modal: true,
- detail: `An existing lldb-dap server (${this.serverProcess.pid}) is running with different arguments.
+Restarting the server will interrupt any existing debug sessions and start a new server.`,
+ };
+ }
+
+ const newSpawnInfo = this.getSpawnInfo(dapPath, args, env);
+ if (!isDeepStrictEqual(this.serverSpawnInfo, newSpawnInfo)) {
+ return {
+ message:
+ "The arguments to lldb-dap have changed. Would you like to restart the server?",
+ detail: `An existing lldb-dap server (${this.serverProcess.pid}) is running with different arguments.
The previous lldb-dap server was started with:
@@ -124,15 +155,31 @@ The new lldb-dap server will be started with:
${newSpawnInfo.join(" ")}
Restarting the server will interrupt any existing debug sessions and start a new server.`,
+ };
+ }
+
+ return null;
+ })();
+
+ // If the server hasn't changed, continue startup without killing it.
+ if (messageAndDetail === null) {
+ return true;
+ }
+
+ // The server has changed. Prompt the user to restart it.
+ const { message, detail } = messageAndDetail;
+ const userInput = await vscode.window.showInformationMessage(
+ message,
+ {
+ modal: true,
+ detail,
},
"Restart",
"Use Existing",
);
switch (userInput) {
case "Restart":
- this.serverProcess.kill();
- this.serverProcess = undefined;
- this.serverInfo = undefined;
+ this.dispose();
return true;
case "Use Existing":
return true;
@@ -156,6 +203,10 @@ Restarting the server will interrupt any existing debug sessions and start a new
if (this.serverProcess === process) {
this.serverProcess = undefined;
this.serverInfo = undefined;
+ this.serverSpawnInfo = undefined;
+ this.serverFileWatcher?.dispose();
+ this.serverFileWatcher = undefined;
+ this.serverFileChanged = undefined;
}
}
>From eeae07535707f5dae0518f66b4f24382fa608874 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Fri, 19 Sep 2025 15:00:41 -0700
Subject: [PATCH 2/4] Use chokidar instead
---
lldb/tools/lldb-dap/package-lock.json | 31 +++++++++++++++++++
lldb/tools/lldb-dap/package.json | 3 ++
lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts | 18 +++++------
3 files changed, 41 insertions(+), 11 deletions(-)
diff --git a/lldb/tools/lldb-dap/package-lock.json b/lldb/tools/lldb-dap/package-lock.json
index 26db1ce6df2fd..3d8907f3115f6 100644
--- a/lldb/tools/lldb-dap/package-lock.json
+++ b/lldb/tools/lldb-dap/package-lock.json
@@ -8,6 +8,9 @@
"name": "lldb-dap",
"version": "0.2.16",
"license": "Apache 2.0 License with LLVM exceptions",
+ "dependencies": {
+ "chokidar": "^4.0.3"
+ },
"devDependencies": {
"@types/node": "^18.19.41",
"@types/tabulator-tables": "^6.2.10",
@@ -1301,6 +1304,21 @@
"url": "https://github.com/sponsors/fb55"
}
},
+ "node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
@@ -2712,6 +2730,19 @@
"node": ">= 6"
}
},
+ "node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json
index 6566ba3bdee13..3892535853f56 100644
--- a/lldb/tools/lldb-dap/package.json
+++ b/lldb/tools/lldb-dap/package.json
@@ -27,6 +27,9 @@
"categories": [
"Debuggers"
],
+ "dependencies": {
+ "chokidar": "^4.0.3"
+ },
"devDependencies": {
"@types/node": "^18.19.41",
"@types/tabulator-tables": "^6.2.10",
diff --git a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
index 7a1754f4bce6a..f38093e935a42 100644
--- a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
+++ b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
@@ -1,3 +1,4 @@
+import { FSWatcher, watch as chokidarWatch } from 'chokidar';
import * as child_process from "node:child_process";
import * as path from "path";
import { isDeepStrictEqual } from "util";
@@ -14,7 +15,7 @@ export class LLDBDapServer implements vscode.Disposable {
private serverInfo?: Promise<{ host: string; port: number }>;
private serverSpawnInfo?: string[];
// Detects changes to the lldb-dap executable file since the server's startup.
- private serverFileWatcher?: vscode.FileSystemWatcher;
+ private serverFileWatcher?: FSWatcher;
// Indicates whether the lldb-dap executable file has changed since the server's startup.
private serverFileChanged?: boolean;
@@ -91,15 +92,10 @@ export class LLDBDapServer implements vscode.Disposable {
this.serverFileChanged = false;
// Cannot do `createFileSystemWatcher(dapPath)` for a single file. Have to use `RelativePattern`.
// See https://github.com/microsoft/vscode/issues/141011#issuecomment-1016772527
- this.serverFileWatcher = vscode.workspace.createFileSystemWatcher(
- new vscode.RelativePattern(
- vscode.Uri.file(path.dirname(dapPath)),
- path.basename(dapPath),
- ),
- );
- this.serverFileWatcher.onDidChange(() => {
- this.serverFileChanged = true;
- });
+ this.serverFileWatcher = chokidarWatch(dapPath);
+ this.serverFileWatcher
+ .on('change', () => this.serverFileChanged = true)
+ .on('unlink', () => this.serverFileChanged = true);
});
return this.serverInfo;
}
@@ -204,7 +200,7 @@ Restarting the server will interrupt any existing debug sessions and start a new
this.serverProcess = undefined;
this.serverInfo = undefined;
this.serverSpawnInfo = undefined;
- this.serverFileWatcher?.dispose();
+ this.serverFileWatcher?.close();
this.serverFileWatcher = undefined;
this.serverFileChanged = undefined;
}
>From 2b6e28817043a33c284f394b26d48885735ac9d3 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Fri, 19 Sep 2025 15:28:21 -0700
Subject: [PATCH 3/4] Show both the binary change and the arguments change in
the same dialog box
---
lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts | 45 +++++++------------
1 file changed, 17 insertions(+), 28 deletions(-)
diff --git a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
index f38093e935a42..b8b5bb628a787 100644
--- a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
+++ b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
@@ -123,25 +123,17 @@ export class LLDBDapServer implements vscode.Disposable {
return true;
}
- // Check if the server has changed. If so, generate message and detail for user prompt.
- const messageAndDetail = (() => {
- if (this.serverFileChanged) {
- return {
- message:
- "The lldb-dap binary has changed. Would you like to restart the server?",
- detail: `An existing lldb-dap server (${this.serverProcess.pid}) is running with an old binary.
+ const changeTLDR = [];
+ const changeDetails = [];
-Restarting the server will interrupt any existing debug sessions and start a new server.`,
- };
- }
-
- const newSpawnInfo = this.getSpawnInfo(dapPath, args, env);
- if (!isDeepStrictEqual(this.serverSpawnInfo, newSpawnInfo)) {
- return {
- message:
- "The arguments to lldb-dap have changed. Would you like to restart the server?",
- detail: `An existing lldb-dap server (${this.serverProcess.pid}) is running with different arguments.
+ if (this.serverFileChanged) {
+ changeTLDR.push("an old binary");
+ }
+ const newSpawnInfo = this.getSpawnInfo(dapPath, args, env);
+ if (!isDeepStrictEqual(this.serverSpawnInfo, newSpawnInfo)) {
+ changeTLDR.push("different arguments");
+ changeDetails.push(`
The previous lldb-dap server was started with:
${this.serverSpawnInfo.join(" ")}
@@ -149,26 +141,23 @@ ${this.serverSpawnInfo.join(" ")}
The new lldb-dap server will be started with:
${newSpawnInfo.join(" ")}
-
-Restarting the server will interrupt any existing debug sessions and start a new server.`,
- };
- }
-
- return null;
- })();
+`
+ );
+ }
// If the server hasn't changed, continue startup without killing it.
- if (messageAndDetail === null) {
+ if (changeTLDR.length === 0) {
return true;
}
// The server has changed. Prompt the user to restart it.
- const { message, detail } = messageAndDetail;
const userInput = await vscode.window.showInformationMessage(
- message,
+ "The lldb-dap server has changed. Would you like to restart the server?",
{
modal: true,
- detail,
+ detail: `An existing lldb-dap server (${this.serverProcess.pid}) is running with ${changeTLDR.map(s => `*${s}*`).join(" and ")}.
+${changeDetails.join("\n")}
+Restarting the server will interrupt any existing debug sessions and start a new server.`,
},
"Restart",
"Use Existing",
>From de3c385d557b4a3ffc916438c8f91a73755b0604 Mon Sep 17 00:00:00 2001
From: Roy Shi <royshi at meta.com>
Date: Tue, 23 Sep 2025 07:14:20 -0700
Subject: [PATCH 4/4] Remove out-dated inline comments
---
lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
index c6ae3b3ef73a3..4e348965930d9 100644
--- a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
+++ b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
@@ -90,8 +90,6 @@ export class LLDBDapServer implements vscode.Disposable {
this.serverProcess = process;
this.serverSpawnInfo = this.getSpawnInfo(dapPath, dapArgs, options?.env);
this.serverFileChanged = false;
- // Cannot do `createFileSystemWatcher(dapPath)` for a single file. Have to use `RelativePattern`.
- // See https://github.com/microsoft/vscode/issues/141011#issuecomment-1016772527
this.serverFileWatcher = chokidarWatch(dapPath);
this.serverFileWatcher
.on('change', () => this.serverFileChanged = true)
More information about the lldb-commits
mailing list