Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@ def request_launch(
disableSTDIO=False,
shellExpandArguments=False,
console: Optional[str] = None,
stdio: Optional[list[str]] = None,
enableAutoVariableSummaries=False,
displayExtendedBacktrace=False,
enableSyntheticChildDebugging=False,
Expand Down Expand Up @@ -1090,6 +1091,8 @@ def request_launch(
args_dict["sourceMap"] = sourceMap
if console:
args_dict["console"] = console
if stdio:
args_dict["stdio"] = stdio
if postRunCommands:
args_dict["postRunCommands"] = postRunCommands
if customFrameFormat:
Expand Down
21 changes: 21 additions & 0 deletions lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from lldbsuite.test.lldbtest import *
import lldbdap_testcase
import os
import pathlib
import re
import tempfile

Expand Down Expand Up @@ -624,3 +625,23 @@ def test_no_lldbinit_flag(self):

# Verify the initCommands were executed
self.verify_commands("initCommands", output, initCommands)

def test_stdio_redirection(self):
"""
Test stdio redirection.
"""
temp_file = tempfile.NamedTemporaryFile().name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use this pattern

with tempfile.TemporaryFile() as fp:
  ...

that way you don't need to unlink the file manually

self.build_and_create_debug_adapter()
program = self.getBuildArtifact("a.out")

self.launch(program, stdio=[None, temp_file, None])
self.continue_to_exit()

try:
with open(temp_file, "r") as f:
lines = f.readlines()
self.assertIn(
program, lines[0], "make sure program path is in first argument"
)
finally:
pathlib.Path(temp_file).unlink(missing_ok=True)
25 changes: 25 additions & 0 deletions lldb/tools/lldb-dap/Handler/RequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,31 @@ llvm::Error BaseRequestHandler::LaunchProcess(
launch_info.SetEnvironment(env, true);
}

if (!arguments.stdio.empty() && !arguments.disableSTDIO) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to a helper function because this function is already very big

size_t n = std::max(arguments.stdio.size(), static_cast<size_t>(3));
for (size_t i = 0; i < n; i++) {
std::optional<std::string> path;
if (arguments.stdio.size() < i)
path = arguments.stdio.back();
else
path = arguments.stdio[i];
if (!path)
continue;
switch (i) {
case 0:
launch_info.AddOpenFileAction(i, path->c_str(), true, false);
break;
case 1:
case 2:
launch_info.AddOpenFileAction(i, path->c_str(), false, true);
break;
default:
launch_info.AddOpenFileAction(i, path->c_str(), true, true);
break;
}
}
}

launch_info.SetDetachOnError(arguments.detachOnError);
launch_info.SetShellExpandArguments(arguments.shellExpandArguments);

Expand Down
3 changes: 2 additions & 1 deletion lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@ bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
O.mapOptional("disableSTDIO", LRA.disableSTDIO) &&
O.mapOptional("shellExpandArguments", LRA.shellExpandArguments) &&
O.mapOptional("runInTerminal", LRA.console) &&
O.mapOptional("console", LRA.console) && parseEnv(Params, LRA.env, P);
O.mapOptional("console", LRA.console) &&
O.mapOptional("stdio", LRA.stdio) && parseEnv(Params, LRA.env, P);
}

bool fromJSON(const json::Value &Params, AttachRequestArguments &ARA,
Expand Down
2 changes: 2 additions & 0 deletions lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ struct LaunchRequestArguments {
/// terminal or external terminal.
Console console = eConsoleInternal;

std::vector<std::optional<std::string>> stdio;

/// @}
};
bool fromJSON(const llvm::json::Value &, LaunchRequestArguments &,
Expand Down
1 change: 1 addition & 0 deletions lldb/tools/lldb-dap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ contain the following key/value pairs:
| **stopOnEntry** | boolean | | Whether to stop program immediately after launching.
| **runInTerminal** (deprecated) | boolean | | Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs.
| **console** | string | | Specify where to launch the program: internal console (`internalConsole`), integrated terminal (`integratedTerminal`) or external terminal (`externalTerminal`). Supported from lldb-dap 21.0 version.
| **stdio** | [string] | | Destination for program stdio streams (0 - stdin, 1 - stdout, 2 - stderr, ...). Using `null` value means no redirection. Supported from lldb-dap 22.0 version.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you pretty much include all the contents from here

The stdio property is a list of redirection targets for each of the debuggee's stdio streams:

null value will cause redirect to the default debug session terminal (as specified by the terminal launch property),
"/some/path" will cause the stream to be redirected to the specified file, pipe or a TTY device*,
if you provide less than 3 values, the list will be padded to 3 entries using the last provided value,
you may specify more than three values, in which case additional file descriptors will be created (4, 5, etc.)
Examples:

"stdio": [null, "log.txt", null] - connect stdin and stderr to the default terminal, while sending stdout to "log.txt",
"stdio": ["input.txt", "log.txt"] - connect stdin to "input.txt", while sending both stdout and stderr to "log.txt",
"stdio": null - connect all three streams to the default terminal.

? That will be very clear

| **launchCommands** | [string] | | LLDB commands executed to launch the program.

For JSON configurations of `"type": "attach"`, the JSON configuration can contain
Expand Down
8 changes: 8 additions & 0 deletions lldb/tools/lldb-dap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,14 @@
"description": "Specify where to launch the program: internal console, integrated terminal or external terminal.",
"default": "internalConsole"
},
"stdio": {
"type": "array",
"items": {
"type": "string"
},
"description": "Destination for program stdio streams (0 - stdin, 1 - stdout, 2 - stderr, ...). Using null value means no redirection.",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here about

The stdio property is a list of redirection targets for each of the debuggee's stdio streams:

null value will cause redirect to the default debug session terminal (as specified by the terminal launch property),
"/some/path" will cause the stream to be redirected to the specified file, pipe or a TTY device*,
if you provide less than 3 values, the list will be padded to 3 entries using the last provided value,
you may specify more than three values, in which case additional file descriptors will be created (4, 5, etc.)
Examples:

"stdio": [null, "log.txt", null] - connect stdin and stderr to the default terminal, while sending stdout to "log.txt",
"stdio": ["input.txt", "log.txt"] - connect stdin to "input.txt", while sending both stdout and stderr to "log.txt",
"stdio": null - connect all three streams to the default terminal.

"default": []
},
"timeout": {
"type": "number",
"description": "The time in seconds to wait for a program to stop at entry point when launching with \"launchCommands\". Defaults to 30 seconds."
Expand Down
Loading