aboutsummaryrefslogtreecommitdiff
path: root/lldb/tools/lldb-dap
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/tools/lldb-dap')
-rw-r--r--lldb/tools/lldb-dap/Handler/RequestHandler.cpp4
-rw-r--r--lldb/tools/lldb-dap/JSONUtils.cpp15
-rw-r--r--lldb/tools/lldb-dap/JSONUtils.h7
-rw-r--r--lldb/tools/lldb-dap/Options.td6
-rw-r--r--lldb/tools/lldb-dap/Protocol/ProtocolRequests.h1
-rw-r--r--lldb/tools/lldb-dap/ProtocolUtils.cpp8
-rw-r--r--lldb/tools/lldb-dap/package.json5
-rw-r--r--lldb/tools/lldb-dap/tool/lldb-dap.cpp87
8 files changed, 127 insertions, 6 deletions
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index 7738913..e7d9b89 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -57,7 +57,7 @@ SetupIORedirection(const std::vector<std::optional<std::string>> &stdio,
size_t n = std::max(stdio.size(), static_cast<size_t>(3));
for (size_t i = 0; i < n; i++) {
std::optional<std::string> path;
- if (stdio.size() < i)
+ if (stdio.size() <= i)
path = stdio.back();
else
path = stdio[i];
@@ -107,7 +107,7 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
arguments.configuration.program, arguments.args, arguments.env,
- arguments.cwd, comm_file.m_path, debugger_pid,
+ arguments.cwd, comm_file.m_path, debugger_pid, arguments.stdio,
arguments.console == protocol::eConsoleExternalTerminal);
dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal",
std::move(reverse_request));
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 4f26599..71e91f8 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -866,7 +866,8 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit) {
llvm::json::Object CreateRunInTerminalReverseRequest(
llvm::StringRef program, const std::vector<std::string> &args,
const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
- llvm::StringRef comm_file, lldb::pid_t debugger_pid, bool external) {
+ llvm::StringRef comm_file, lldb::pid_t debugger_pid,
+ const std::vector<std::optional<std::string>> &stdio, bool external) {
llvm::json::Object run_in_terminal_args;
if (external) {
// This indicates the IDE to open an external terminal window.
@@ -885,6 +886,18 @@ llvm::json::Object CreateRunInTerminalReverseRequest(
}
req_args.push_back("--launch-target");
req_args.push_back(program.str());
+ if (!stdio.empty()) {
+ req_args.push_back("--stdio");
+ std::stringstream ss;
+ for (const std::optional<std::string> &file : stdio) {
+ if (file)
+ ss << *file;
+ ss << ":";
+ }
+ std::string files = ss.str();
+ files.pop_back();
+ req_args.push_back(std::move(files));
+ }
req_args.insert(req_args.end(), args.begin(), args.end());
run_in_terminal_args.try_emplace("args", req_args);
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index e9094f6..0c865a3 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -388,6 +388,10 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit);
/// launcher uses it on Linux tell the kernel that it should allow the
/// debugger process to attach.
///
+/// \param[in] stdio
+/// An array of file paths for redirecting the program's standard IO
+/// streams.
+///
/// \param[in] external
/// If set to true, the program will run in an external terminal window
/// instead of IDE's integrated terminal.
@@ -398,7 +402,8 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit);
llvm::json::Object CreateRunInTerminalReverseRequest(
llvm::StringRef program, const std::vector<std::string> &args,
const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
- llvm::StringRef comm_file, lldb::pid_t debugger_pid, bool external);
+ llvm::StringRef comm_file, lldb::pid_t debugger_pid,
+ const std::vector<std::optional<std::string>> &stdio, bool external);
/// Create a "Terminated" JSON object that contains statistics
///
diff --git a/lldb/tools/lldb-dap/Options.td b/lldb/tools/lldb-dap/Options.td
index c8492c6..5e9dd7a 100644
--- a/lldb/tools/lldb-dap/Options.td
+++ b/lldb/tools/lldb-dap/Options.td
@@ -47,6 +47,12 @@ def debugger_pid: S<"debugger-pid">,
HelpText<"The PID of the lldb-dap instance that sent the launchInTerminal "
"request when using --launch-target.">;
+def stdio: S<"stdio">,
+ MetaVarName<"<stdin:stdout:stderr:...>">,
+ HelpText<"An array of file paths for redirecting the program's standard IO "
+ "streams. A colon-separated list of entries. Empty value means no "
+ "redirection.">;
+
def repl_mode
: S<"repl-mode">,
MetaVarName<"<mode>">,
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index 92dada2..a85a68b 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -300,6 +300,7 @@ struct LaunchRequestArguments {
/// terminal or external terminal.
Console console = eConsoleInternal;
+ /// An array of file paths for redirecting the program's standard IO streams.
std::vector<std::optional<std::string>> stdio;
/// @}
diff --git a/lldb/tools/lldb-dap/ProtocolUtils.cpp b/lldb/tools/lldb-dap/ProtocolUtils.cpp
index 775c82f..868c67c 100644
--- a/lldb/tools/lldb-dap/ProtocolUtils.cpp
+++ b/lldb/tools/lldb-dap/ProtocolUtils.cpp
@@ -301,6 +301,14 @@ Variable CreateVariable(lldb::SBValue v, int64_t var_ref, bool format_hex,
if (lldb::addr_t addr = v.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS)
var.memoryReference = addr;
+ bool is_readonly = v.GetType().IsAggregateType() ||
+ v.GetValueType() == lldb::eValueTypeRegisterSet;
+ if (is_readonly) {
+ if (!var.presentationHint)
+ var.presentationHint = {VariablePresentationHint()};
+ var.presentationHint->attributes.push_back("readOnly");
+ }
+
return var;
}
diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json
index e961c2e..3f0f150 100644
--- a/lldb/tools/lldb-dap/package.json
+++ b/lldb/tools/lldb-dap/package.json
@@ -626,7 +626,10 @@
"stdio": {
"type": "array",
"items": {
- "type": "string"
+ "type": [
+ "string",
+ "null"
+ ]
},
"description": "The stdio property specifies the redirection targets for the debuggee's stdio streams. A null value redirects a stream to the default debug terminal. String can be a path to file, named pipe or TTY device. If less than three values are provided, the list will be padded with the last value. Specifying more than three values will create additional file descriptors (4, 5, etc.).",
"default": []
diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
index 93446c0..e59cef9 100644
--- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
@@ -16,6 +16,7 @@
#include "lldb/API/SBStream.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/File.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/MainLoop.h"
#include "lldb/Host/MainLoopBase.h"
#include "lldb/Host/MemoryMonitor.h"
@@ -24,7 +25,9 @@
#include "lldb/Utility/UriParser.h"
#include "lldb/lldb-forward.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/Arg.h"
@@ -42,8 +45,10 @@
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <condition_variable>
+#include <cstddef>
#include <cstdio>
#include <cstdlib>
+#include <exception>
#include <fcntl.h>
#include <map>
#include <memory>
@@ -143,6 +148,74 @@ static void PrintVersion() {
llvm::outs() << "liblldb: " << lldb::SBDebugger::GetVersionString() << '\n';
}
+#if not defined(_WIN32)
+struct FDGroup {
+ int GetFlags() const {
+ if (read && write)
+ return O_NOCTTY | O_CREAT | O_RDWR;
+ if (read)
+ return O_NOCTTY | O_RDONLY;
+ return O_NOCTTY | O_CREAT | O_WRONLY | O_TRUNC;
+ }
+
+ std::vector<int> fds;
+ bool read = false;
+ bool write = false;
+};
+
+static llvm::Error RedirectToFile(const FDGroup &fdg, llvm::StringRef file) {
+ if (!fdg.read && !fdg.write)
+ return llvm::Error::success();
+ int target_fd = lldb_private::FileSystem::Instance().Open(
+ file.str().c_str(), fdg.GetFlags(), 0666);
+ if (target_fd == -1)
+ return llvm::errorCodeToError(
+ std::error_code(errno, std::generic_category()));
+ for (int fd : fdg.fds) {
+ if (target_fd == fd)
+ continue;
+ if (::dup2(target_fd, fd) == -1)
+ return llvm::errorCodeToError(
+ std::error_code(errno, std::generic_category()));
+ }
+ ::close(target_fd);
+ return llvm::Error::success();
+}
+
+static llvm::Error
+SetupIORedirection(const llvm::SmallVectorImpl<llvm::StringRef> &files) {
+ llvm::SmallDenseMap<llvm::StringRef, FDGroup> groups;
+ for (size_t i = 0; i < files.size(); i++) {
+ if (files[i].empty())
+ continue;
+ auto group = groups.find(files[i]);
+ if (group == groups.end())
+ group = groups.insert({files[i], {{static_cast<int>(i)}}}).first;
+ else
+ group->second.fds.push_back(i);
+ switch (i) {
+ case 0:
+ group->second.read = true;
+ break;
+ case 1:
+ case 2:
+ group->second.write = true;
+ break;
+ default:
+ group->second.read = true;
+ group->second.write = true;
+ break;
+ }
+ }
+ for (const auto &[file, group] : groups) {
+ if (llvm::Error err = RedirectToFile(group, file))
+ return llvm::createStringError(
+ llvm::formatv("{0}: {1}", file, llvm::toString(std::move(err))));
+ }
+ return llvm::Error::success();
+}
+#endif
+
// If --launch-target is provided, this instance of lldb-dap becomes a
// runInTerminal launcher. It will ultimately launch the program specified in
// the --launch-target argument, which is the original program the user wanted
@@ -165,6 +238,7 @@ static void PrintVersion() {
static llvm::Error LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg,
llvm::StringRef comm_file,
lldb::pid_t debugger_pid,
+ llvm::StringRef stdio,
char *argv[]) {
#if defined(_WIN32)
return llvm::createStringError(
@@ -179,6 +253,16 @@ static llvm::Error LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg,
(void)prctl(PR_SET_PTRACER, debugger_pid, 0, 0, 0);
#endif
+ lldb_private::FileSystem::Initialize();
+ if (!stdio.empty()) {
+ llvm::SmallVector<llvm::StringRef, 3> files;
+ stdio.split(files, ':');
+ while (files.size() < 3)
+ files.push_back(files.back());
+ if (llvm::Error err = SetupIORedirection(files))
+ return err;
+ }
+
RunInTerminalLauncherCommChannel comm_channel(comm_file);
if (llvm::Error err = comm_channel.NotifyPid())
return err;
@@ -484,9 +568,10 @@ int main(int argc, char *argv[]) {
break;
}
}
+ llvm::StringRef stdio = input_args.getLastArgValue(OPT_stdio);
if (llvm::Error err =
LaunchRunInTerminalTarget(*target_arg, comm_file->getValue(), pid,
- argv + target_args_pos)) {
+ stdio, argv + target_args_pos)) {
llvm::errs() << llvm::toString(std::move(err)) << '\n';
return EXIT_FAILURE;
}