1616#include " lldb/API/SBStream.h"
1717#include " lldb/Host/Config.h"
1818#include " lldb/Host/File.h"
19+ #include " lldb/Host/FileSystem.h"
1920#include " lldb/Host/MainLoop.h"
2021#include " lldb/Host/MainLoopBase.h"
2122#include " lldb/Host/MemoryMonitor.h"
2425#include " lldb/Utility/UriParser.h"
2526#include " lldb/lldb-forward.h"
2627#include " llvm/ADT/ArrayRef.h"
28+ #include " llvm/ADT/DenseMap.h"
2729#include " llvm/ADT/ScopeExit.h"
30+ #include " llvm/ADT/SmallVector.h"
2831#include " llvm/ADT/StringExtras.h"
2932#include " llvm/ADT/StringRef.h"
3033#include " llvm/Option/Arg.h"
4245#include " llvm/Support/WithColor.h"
4346#include " llvm/Support/raw_ostream.h"
4447#include < condition_variable>
48+ #include < cstddef>
4549#include < cstdio>
4650#include < cstdlib>
51+ #include < exception>
4752#include < fcntl.h>
4853#include < map>
4954#include < memory>
@@ -143,6 +148,74 @@ static void PrintVersion() {
143148 llvm::outs () << " liblldb: " << lldb::SBDebugger::GetVersionString () << ' \n ' ;
144149}
145150
151+ #if not defined(_WIN32)
152+ struct FDGroup {
153+ int GetFlags () const {
154+ if (read && write)
155+ return O_NOCTTY | O_CREAT | O_RDWR;
156+ if (read)
157+ return O_NOCTTY | O_RDONLY;
158+ return O_NOCTTY | O_CREAT | O_WRONLY | O_TRUNC;
159+ }
160+
161+ std::vector<int > fds;
162+ bool read = false ;
163+ bool write = false ;
164+ };
165+
166+ static llvm::Error RedirectToFile (const FDGroup &fdg, llvm::StringRef file) {
167+ if (!fdg.read && !fdg.write )
168+ return llvm::Error::success ();
169+ int target_fd = lldb_private::FileSystem::Instance ().Open (
170+ file.str ().c_str (), fdg.GetFlags (), 0666 );
171+ if (target_fd == -1 )
172+ return llvm::errorCodeToError (
173+ std::error_code (errno, std::generic_category ()));
174+ for (int fd : fdg.fds ) {
175+ if (target_fd == fd)
176+ continue ;
177+ if (::dup2 (target_fd, fd) == -1 )
178+ return llvm::errorCodeToError (
179+ std::error_code (errno, std::generic_category ()));
180+ }
181+ ::close (target_fd);
182+ return llvm::Error::success ();
183+ }
184+
185+ static llvm::Error
186+ SetupIORedirection (const llvm::SmallVectorImpl<llvm::StringRef> &files) {
187+ llvm::SmallDenseMap<llvm::StringRef, FDGroup> groups;
188+ for (size_t i = 0 ; i < files.size (); i++) {
189+ if (files[i].empty ())
190+ continue ;
191+ auto group = groups.find (files[i]);
192+ if (group == groups.end ())
193+ group = groups.insert ({files[i], {{static_cast <int >(i)}}}).first ;
194+ else
195+ group->second .fds .push_back (i);
196+ switch (i) {
197+ case 0 :
198+ group->second .read = true ;
199+ break ;
200+ case 1 :
201+ case 2 :
202+ group->second .write = true ;
203+ break ;
204+ default :
205+ group->second .read = true ;
206+ group->second .write = true ;
207+ break ;
208+ }
209+ }
210+ for (const auto &[file, group] : groups) {
211+ if (llvm::Error err = RedirectToFile (group, file))
212+ return llvm::createStringError (
213+ llvm::formatv (" {0}: {1}" , file, llvm::toString (std::move (err))));
214+ }
215+ return llvm::Error::success ();
216+ }
217+ #endif
218+
146219// If --launch-target is provided, this instance of lldb-dap becomes a
147220// runInTerminal launcher. It will ultimately launch the program specified in
148221// the --launch-target argument, which is the original program the user wanted
@@ -165,6 +238,7 @@ static void PrintVersion() {
165238static llvm::Error LaunchRunInTerminalTarget (llvm::opt::Arg &target_arg,
166239 llvm::StringRef comm_file,
167240 lldb::pid_t debugger_pid,
241+ llvm::StringRef stdio,
168242 char *argv[]) {
169243#if defined(_WIN32)
170244 return llvm::createStringError (
@@ -179,6 +253,16 @@ static llvm::Error LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg,
179253 (void )prctl (PR_SET_PTRACER, debugger_pid, 0 , 0 , 0 );
180254#endif
181255
256+ lldb_private::FileSystem::Initialize ();
257+ if (!stdio.empty ()) {
258+ llvm::SmallVector<llvm::StringRef, 3 > files;
259+ stdio.split (files, ' :' );
260+ while (files.size () < 3 )
261+ files.push_back (files.back ());
262+ if (llvm::Error err = SetupIORedirection (files))
263+ return err;
264+ }
265+
182266 RunInTerminalLauncherCommChannel comm_channel (comm_file);
183267 if (llvm::Error err = comm_channel.NotifyPid ())
184268 return err;
@@ -484,9 +568,10 @@ int main(int argc, char *argv[]) {
484568 break ;
485569 }
486570 }
571+ llvm::StringRef stdio = input_args.getLastArgValue (OPT_stdio);
487572 if (llvm::Error err =
488573 LaunchRunInTerminalTarget (*target_arg, comm_file->getValue (), pid,
489- argv + target_args_pos)) {
574+ stdio, argv + target_args_pos)) {
490575 llvm::errs () << llvm::toString (std::move (err)) << ' \n ' ;
491576 return EXIT_FAILURE;
492577 }
0 commit comments