Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
5c58c90
[lldb] Update JSONTransport to use MainLoop for reading. (#152367)
ashgti Aug 12, 2025
77c25d6
[lldb] Disable JSONTransportTests on Windows. (#153453)
ashgti Aug 13, 2025
a0ccd95
Bump ProtocolServerMCPTest timeout to 200ms (#154182)
mysterymath Aug 18, 2025
dc3ad07
[lldb] Refactoring JSONTransport into an abstract RPC Message Handler…
ashgti Aug 19, 2025
f62d4a8
[lldb-dap] Add module symbol table viewer to VS Code extension #14062…
eronnen Aug 20, 2025
3c176e3
[lldb-dap] Re-land refactor of DebugCommunication. (#147787)
ashgti Aug 21, 2025
7ff6ac6
Revert "[lldb-dap] Re-land refactor of DebugCommunication. (#147787)"
rastogishubham Aug 21, 2025
d32d7fa
Reapply "[lldb-dap] Re-land refactor of DebugCommunication. (#147787)…
ashgti Aug 21, 2025
2097336
Revert "[lldb-dap] Add module symbol table viewer to VS Code extensio…
omjavaid Aug 22, 2025
76b380f
[lldb-dap] Migrating 'completions' to structured types. (#153317)
ashgti Aug 22, 2025
b76406f
Re-land LLDB dap module symbol tables (#155021)
eronnen Aug 23, 2025
9fe9578
[lldb] Adopt JSONTransport in the MCP Server (#155034)
JDevlieghere Aug 25, 2025
d54de4a
Revert "[lldb] Adopt JSONTransport in the MCP Server" (#155280)
JDevlieghere Aug 25, 2025
b667b39
[lldb-dap] improve symbol table style (#155097)
eronnen Aug 25, 2025
6f2dc0f
[lldb] Adopt JSONTransport in the MCP Server (Reland) (#155322)
JDevlieghere Aug 25, 2025
fa21865
[lldb] Fix a warning
kazutakahirata Aug 26, 2025
058839c
[lldb][lldb-dap] parse `pathFormat` as an optional (#155238)
da-viper Aug 26, 2025
bcbae12
[lldb] Adding structured types for existing MCP calls. (#155460)
ashgti Aug 26, 2025
0a0d8dd
[lldb][test] Disable some more failing lldb-dap tests on Windows
DavidSpickett Aug 27, 2025
a07901a
[lldb] NFC Moving mcp::Transport into its own file. (#155711)
ashgti Aug 27, 2025
4f86e78
[lldb] Add lldb-mcp scaffolding (#155708)
JDevlieghere Aug 27, 2025
039391d
[lldb] Correct a usage after a rename was merged. (#155720)
ashgti Aug 27, 2025
d07b520
Revert "[lldb] NFC Moving mcp::Transport into its own file. (#155711)"
sylvestre Aug 28, 2025
6cecb98
Revert "[lldb] Correct a usage after a rename was merged. (#155720)"
mstorsjo Aug 28, 2025
5aac02e
[lldb-mcp] Fix building for Windows
mstorsjo Aug 28, 2025
97b076c
[lldb] Add lldbHost dependency to lldbProtocolMCP (#155811)
nikic Aug 28, 2025
48aafae
[vscode-lldb] Support lldb-dap environment in debug configuration (#1…
royitaqi Aug 28, 2025
12a8679
[lldb][test] Disable TestDAP_startDebugging.py on Windows
DavidSpickett Aug 29, 2025
8e2425d
[lldb][test] Skip more of TestDAP_attach.py on Windows
DavidSpickett Aug 29, 2025
640fe8b
[lldb][test] Disable more of TestDAP_attach.py on Windows
DavidSpickett Sep 12, 2025
c3fe5d4
[lldb][test] Disable a test from TestDAP_cancel.py on Windows
DavidSpickett Sep 15, 2025
1677af5
[lldb][lldb-dap] Disable more DAP tests on Windows (#158906)
DavidSpickett Sep 16, 2025
98db3c1
[lldb][lldb-dap] Disable all lldb-dap tests on Windows on Arm (#159542)
DavidSpickett Sep 18, 2025
351fddd
[lldb-dap] Fix typescript issue in updated typescript code. (#156117)
cmtice Aug 29, 2025
da6cc56
[lldb-dap] Add `--no-lldbinit` as a CLI flag (#156131)
piyushjaiswal98 Sep 4, 2025
077192d
ensure that dap_symbol is always initialized (#156956)
lexi-nadia Sep 4, 2025
f6b1799
[lldb-dap] Destroy debugger when debug session terminates (#156231)
royitaqi Sep 4, 2025
23007f2
Default-initialize all fields of lldb_dap::protocol::Symbol. (#157150)
lexi-nadia Sep 5, 2025
e613b02
[lldb-dap] Add command line option `--connection-timeout` (#156803)
royitaqi Sep 10, 2025
facd42d
[lldb-dap] Fix test: TestDAP_server.py (#157924)
royitaqi Sep 10, 2025
7daa74e
[lldb-dap] Add invalidated event (#157530)
DrSergei Sep 11, 2025
cba6b4b
[lldb-dap] Add `debugAdapterEnv` for `attach` requests & improve rege…
royitaqi Sep 12, 2025
2c8223e
[lldb-dap] Add stdio redirection (#158609)
DrSergei Sep 16, 2025
d57bc54
[NFC][lldb-dap] Fix typo in invalidated event (#158338)
DrSergei Sep 16, 2025
77b81d2
[lldb-dap] Add memory event (#158437)
DrSergei Sep 17, 2025
236e094
[lldb-dap] Bump form-data from 4.0.1 to 4.0.4
JDevlieghere Sep 18, 2025
46e7068
[vscode-lldb] Restart server when lldb-dap binary has changed (#159797)
royitaqi Sep 23, 2025
78bbdaa
[lldb-dap] Bump the version to 0.2.17
JDevlieghere Sep 23, 2025
2ec7a75
[lldb-dap] bundle lldb-dap extension using esbuild (#160598)
matthewbastien Sep 24, 2025
50269cd
[lldb-dap] Bump the version to 0.2.18
JDevlieghere Sep 24, 2025
26278ec
[lldb-dap] DataBreakpointInfoArguments make frameId optional. (#162845)
da-viper Oct 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[lldb-dap] Add command line option --connection-timeout (llvm#156803)
# Usage

This is an optional new command line option to use with `--connection`.

```
--connection-timeout <timeout>    When using --connection, the number of seconds to
        wait for new connections after the server has started and after all clients
        have disconnected. Each new connection will reset the timeout. When the
        timeout is reached, the server will be closed and the process will exit.
        Not specifying this argument or specifying non-positive values will cause
        the server to wait for new connections indefinitely.
```

A corresponding extension setting `Connection Timeout` is added to the
`lldb-dap` VS Code extension.

# Benefits

Automatic release of resources when lldb-dap is no longer being used
(e.g. release memory used by module cache).

# Test

See PR.

(cherry picked from commit acb38c8)
  • Loading branch information
royitaqi authored and JDevlieghere committed Oct 14, 2025
commit e613b02e8867750086253e925437dbe78851d4b8
Original file line number Diff line number Diff line change
Expand Up @@ -1533,6 +1533,7 @@ def launch(
env: Optional[dict[str, str]] = None,
log_file: Optional[TextIO] = None,
connection: Optional[str] = None,
connection_timeout: Optional[int] = None,
additional_args: list[str] = [],
) -> tuple[subprocess.Popen, Optional[str]]:
adapter_env = os.environ.copy()
Expand All @@ -1550,6 +1551,10 @@ def launch(
args.append("--connection")
args.append(connection)

if connection_timeout is not None:
args.append("--connection-timeout")
args.append(str(connection_timeout))

process = subprocess.Popen(
args,
stdin=subprocess.PIPE,
Expand Down
59 changes: 56 additions & 3 deletions lldb/test/API/tools/lldb-dap/server/TestDAP_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os
import signal
import tempfile
import time

import dap_server
from lldbsuite.test.decorators import *
Expand All @@ -13,22 +14,28 @@


class TestDAP_server(lldbdap_testcase.DAPTestCaseBase):
def start_server(self, connection):
def start_server(
self, connection, connection_timeout=None, wait_seconds_for_termination=None
):
log_file_path = self.getBuildArtifact("dap.txt")
(process, connection) = dap_server.DebugAdapterServer.launch(
executable=self.lldbDAPExec,
connection=connection,
connection_timeout=connection_timeout,
log_file=log_file_path,
)

def cleanup():
process.terminate()
if wait_seconds_for_termination is not None:
process.wait(wait_seconds_for_termination)
else:
process.terminate()

self.addTearDownHook(cleanup)

return (process, connection)

def run_debug_session(self, connection, name):
def run_debug_session(self, connection, name, sleep_seconds_in_middle=None):
self.dap_server = dap_server.DebugAdapterServer(
connection=connection,
)
Expand All @@ -41,6 +48,8 @@ def run_debug_session(self, connection, name):
args=[name],
disconnectAutomatically=False,
)
if sleep_seconds_in_middle is not None:
time.sleep(sleep_seconds_in_middle)
self.set_source_breakpoints(source, [breakpoint_line])
self.continue_to_next_stop()
self.continue_to_exit()
Expand Down Expand Up @@ -108,3 +117,47 @@ def test_server_interrupt(self):
self.dap_server.exit_status,
"Process exited before interrupting lldb-dap server",
)

@skipIfWindows
def test_connection_timeout_at_server_start(self):
"""
Test launching lldb-dap in server mode with connection timeout and waiting for it to terminate automatically when no client connects.
"""
self.build()
self.start_server(
connection="listen://localhost:0",
connection_timeout=1,
wait_seconds_for_termination=2,
)

@skipIfWindows
def test_connection_timeout_long_debug_session(self):
"""
Test launching lldb-dap in server mode with connection timeout and terminating the server after the a long debug session.
"""
self.build()
(_, connection) = self.start_server(
connection="listen://localhost:0",
connection_timeout=1,
wait_seconds_for_termination=2,
)
# The connection timeout should not cut off the debug session
self.run_debug_session(connection, "Alice", 1.5)

@skipIfWindows
def test_connection_timeout_multiple_sessions(self):
"""
Test launching lldb-dap in server mode with connection timeout and terminating the server after the last debug session.
"""
self.build()
(_, connection) = self.start_server(
connection="listen://localhost:0",
connection_timeout=1,
wait_seconds_for_termination=2,
)
time.sleep(0.5)
# Should be able to connect to the server.
self.run_debug_session(connection, "Alice")
time.sleep(0.5)
# Should be able to connect to the server, because it's still within the connection timeout.
self.run_debug_session(connection, "Bob")
9 changes: 9 additions & 0 deletions lldb/tools/lldb-dap/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,12 @@ def no_lldbinit: F<"no-lldbinit">,
def: Flag<["-"], "x">,
Alias<no_lldbinit>,
HelpText<"Alias for --no-lldbinit">;

def connection_timeout: S<"connection-timeout">,
MetaVarName<"<timeout>">,
HelpText<"When using --connection, the number of seconds to wait for new "
"connections after the server has started and after all clients have "
"disconnected. Each new connection will reset the timeout. When the "
"timeout is reached, the server will be closed and the process will exit. "
"Not specifying this argument or specifying non-positive values will "
"cause the server to wait for new connections indefinitely.">;
19 changes: 16 additions & 3 deletions lldb/tools/lldb-dap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,9 @@ User settings can set the default value for the following supported
| **exitCommands** | [string] | `[]` |
| **terminateCommands** | [string] | `[]` |

To adjust your settings, open the Settings editor via the
`File > Preferences > Settings` menu or press `Ctrl+`, on Windows/Linux and
`Cmd+`, on Mac.
To adjust your settings, open the Settings editor
via the `File > Preferences > Settings` menu or press `Ctrl+,` on Windows/Linux,
and the `VS Code > Settings... > Settings` menu or press `Cmd+,` on Mac.

## Debug Console

Expand Down Expand Up @@ -372,6 +372,19 @@ for more details on Debug Adapter Protocol events and the VS Code
[debug.onDidReceiveDebugSessionCustomEvent](https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent)
API for handling a custom event from an extension.

## Server Mode

lldb-dap supports a server mode that can be enabled via the following user settings.

| Setting | Type | Default | |
| -------------------------- | -------- | :-----: | --------- |
| **Server Mode** | string | `False` | Run lldb-dap in server mode. When enabled, lldb-dap will start a background server that will be reused between debug sessions. This allows caching of debug symbols between sessions and improves launch performance.
| **Connection Timeout** | number | `0` | When running lldb-dap in server mode, the time in seconds to wait for new connections after the server has started and after all clients have disconnected. Each new connection will reset the timeout. When the timeout is reached, the server will be closed and the process will exit. Specifying non-positive values will cause the server to wait for new connections indefinitely.

To adjust your settings, open the Settings editor
via the `File > Preferences > Settings` menu or press `Ctrl+,` on Windows/Linux,
and the `VS Code > Settings... > Settings` menu or press `Cmd+,` on Mac.

## Contributing

`lldb-dap` and `lldb` are developed under the umbrella of the [LLVM project](https://llvm.org/).
Expand Down
7 changes: 7 additions & 0 deletions lldb/tools/lldb-dap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@
"markdownDescription": "Run lldb-dap in server mode.\n\nWhen enabled, lldb-dap will start a background server that will be reused between debug sessions. This allows caching of debug symbols between sessions and improves launch performance.",
"default": false
},
"lldb-dap.connectionTimeout": {
"order": 0,
"scope": "resource",
"type": "number",
"markdownDescription": "When running lldb-dap in server mode, the time in seconds to wait for new connections after the server has started and after all clients have disconnected. Each new connection will reset the timeout. When the timeout is reached, the server will be closed and the process will exit. Specifying non-positive values will cause the server to wait for new connections indefinitely.",
"default": 0
},
"lldb-dap.arguments": {
"scope": "resource",
"type": "array",
Expand Down
5 changes: 5 additions & 0 deletions lldb/tools/lldb-dap/src-ts/debug-configuration-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,15 @@ export class LLDBDapConfigurationProvider
config.get<boolean>("serverMode", false) &&
(await isServerModeSupported(executable.command))
) {
const connectionTimeoutSeconds = config.get<number | undefined>(
"connectionTimeout",
undefined,
);
const serverInfo = await this.server.start(
executable.command,
executable.args,
executable.options,
connectionTimeoutSeconds,
);
if (!serverInfo) {
return undefined;
Expand Down
13 changes: 12 additions & 1 deletion lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,19 @@ export class LLDBDapServer implements vscode.Disposable {
dapPath: string,
args: string[],
options?: child_process.SpawnOptionsWithoutStdio,
connectionTimeoutSeconds?: number,
): Promise<{ host: string; port: number } | undefined> {
const dapArgs = [...args, "--connection", "listen://localhost:0"];
// Both the --connection and --connection-timeout arguments are subject to the shouldContinueStartup() check.
const connectionTimeoutArgs =
connectionTimeoutSeconds && connectionTimeoutSeconds > 0
? ["--connection-timeout", `${connectionTimeoutSeconds}`]
: [];
const dapArgs = [
...args,
"--connection",
"listen://localhost:0",
...connectionTimeoutArgs,
];
if (!(await this.shouldContinueStartup(dapPath, dapArgs, options?.env))) {
return undefined;
}
Expand Down
84 changes: 78 additions & 6 deletions lldb/tools/lldb-dap/tool/lldb-dap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,35 @@ static int DuplicateFileDescriptor(int fd) {
#endif
}

static void
ResetConnectionTimeout(std::mutex &connection_timeout_mutex,
MainLoopBase::TimePoint &conncetion_timeout_time_point) {
std::scoped_lock<std::mutex> lock(connection_timeout_mutex);
conncetion_timeout_time_point = MainLoopBase::TimePoint();
}

static void
TrackConnectionTimeout(MainLoop &loop, std::mutex &connection_timeout_mutex,
MainLoopBase::TimePoint &conncetion_timeout_time_point,
std::chrono::seconds ttl_seconds) {
MainLoopBase::TimePoint next_checkpoint =
std::chrono::steady_clock::now() + std::chrono::seconds(ttl_seconds);
{
std::scoped_lock<std::mutex> lock(connection_timeout_mutex);
// We don't need to take the max of `ttl_time_point` and `next_checkpoint`,
// because `next_checkpoint` must be the latest.
conncetion_timeout_time_point = next_checkpoint;
}
loop.AddCallback(
[&connection_timeout_mutex, &conncetion_timeout_time_point,
next_checkpoint](MainLoopBase &loop) {
std::scoped_lock<std::mutex> lock(connection_timeout_mutex);
if (conncetion_timeout_time_point == next_checkpoint)
loop.RequestTermination();
},
next_checkpoint);
}

static llvm::Expected<std::pair<Socket::SocketProtocol, std::string>>
validateConnection(llvm::StringRef conn) {
auto uri = lldb_private::URI::Parse(conn);
Expand Down Expand Up @@ -255,11 +284,11 @@ validateConnection(llvm::StringRef conn) {
return make_error();
}

static llvm::Error
serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,
Log *log, const ReplMode default_repl_mode,
const std::vector<std::string> &pre_init_commands,
bool no_lldbinit) {
static llvm::Error serveConnection(
const Socket::SocketProtocol &protocol, const std::string &name, Log *log,
const ReplMode default_repl_mode,
const std::vector<std::string> &pre_init_commands, bool no_lldbinit,
std::optional<std::chrono::seconds> connection_timeout_seconds) {
Status status;
static std::unique_ptr<Socket> listener = Socket::Create(protocol, status);
if (status.Fail()) {
Expand All @@ -284,6 +313,12 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,
g_loop.AddPendingCallback(
[](MainLoopBase &loop) { loop.RequestTermination(); });
});
static MainLoopBase::TimePoint g_connection_timeout_time_point;
static std::mutex g_connection_timeout_mutex;
if (connection_timeout_seconds)
TrackConnectionTimeout(g_loop, g_connection_timeout_mutex,
g_connection_timeout_time_point,
connection_timeout_seconds.value());
std::condition_variable dap_sessions_condition;
std::mutex dap_sessions_mutex;
std::map<MainLoop *, DAP *> dap_sessions;
Expand All @@ -292,6 +327,11 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,
&dap_sessions_mutex, &dap_sessions,
&clientCount](
std::unique_ptr<Socket> sock) {
// Reset the keep alive timer, because we won't be killing the server
// while this connection is being served.
if (connection_timeout_seconds)
ResetConnectionTimeout(g_connection_timeout_mutex,
g_connection_timeout_time_point);
std::string client_name = llvm::formatv("client_{0}", clientCount++).str();
DAP_LOG(log, "({0}) client connected", client_name);

Expand Down Expand Up @@ -328,6 +368,12 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,
std::unique_lock<std::mutex> lock(dap_sessions_mutex);
dap_sessions.erase(&loop);
std::notify_all_at_thread_exit(dap_sessions_condition, std::move(lock));

// Start the countdown to kill the server at the end of each connection.
if (connection_timeout_seconds)
TrackConnectionTimeout(g_loop, g_connection_timeout_mutex,
g_connection_timeout_time_point,
connection_timeout_seconds.value());
});
client.detach();
});
Expand Down Expand Up @@ -457,6 +503,31 @@ int main(int argc, char *argv[]) {
connection.assign(path);
}

std::optional<std::chrono::seconds> connection_timeout_seconds;
if (llvm::opt::Arg *connection_timeout_arg =
input_args.getLastArg(OPT_connection_timeout)) {
if (!connection.empty()) {
llvm::StringRef connection_timeout_string_value =
connection_timeout_arg->getValue();
int connection_timeout_int_value;
if (connection_timeout_string_value.getAsInteger(
10, connection_timeout_int_value)) {
llvm::errs() << "'" << connection_timeout_string_value
<< "' is not a valid connection timeout value\n";
return EXIT_FAILURE;
}
// Ignore non-positive values.
if (connection_timeout_int_value > 0)
connection_timeout_seconds =
std::chrono::seconds(connection_timeout_int_value);
} else {
llvm::errs()
<< "\"--connection-timeout\" requires \"--connection\" to be "
"specified\n";
return EXIT_FAILURE;
}
}

#if !defined(_WIN32)
if (input_args.hasArg(OPT_wait_for_debugger)) {
printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid());
Expand Down Expand Up @@ -523,7 +594,8 @@ int main(int argc, char *argv[]) {
std::string name;
std::tie(protocol, name) = *maybeProtoclAndName;
if (auto Err = serveConnection(protocol, name, log.get(), default_repl_mode,
pre_init_commands, no_lldbinit)) {
pre_init_commands, no_lldbinit,
connection_timeout_seconds)) {
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(),
"Connection failed: ");
return EXIT_FAILURE;
Expand Down