Author: Benjamin Kramer Date: 2025-01-08T15:49:46+01:00 New Revision: 81898ac00e04ed3f352534a810829bdf4e6e14b7
URL: https://github.com/llvm/llvm-project/commit/81898ac00e04ed3f352534a810829bdf4e6e14b7 DIFF: https://github.com/llvm/llvm-project/commit/81898ac00e04ed3f352534a810829bdf4e6e14b7.diff LOG: Revert "[lldb-dap] Ensure the IO forwarding threads are managed by the DAP object lifecycle. (#120457)" This reverts commit 0d9cf2671e06c9124a0b5fc753330c39c8b4a791. Breaks the lldb-aarch64-windows buildbot. Added: Modified: lldb/tools/lldb-dap/CMakeLists.txt lldb/tools/lldb-dap/DAP.cpp lldb/tools/lldb-dap/DAP.h lldb/tools/lldb-dap/IOStream.h lldb/tools/lldb-dap/OutputRedirector.cpp lldb/tools/lldb-dap/OutputRedirector.h lldb/tools/lldb-dap/lldb-dap.cpp Removed: ################################################################################ diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 43fc18873feb33..d68098bf7b3266 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -1,3 +1,7 @@ +if ( CMAKE_SYSTEM_NAME MATCHES "Windows" OR CMAKE_SYSTEM_NAME MATCHES "NetBSD" ) + list(APPEND extra_libs lldbHost) +endif () + if (HAVE_LIBPTHREAD) list(APPEND extra_libs pthread) endif () @@ -22,11 +26,9 @@ add_lldb_tool(lldb-dap lldb-dap.cpp Breakpoint.cpp BreakpointBase.cpp - DAP.cpp ExceptionBreakpoint.cpp FifoFiles.cpp FunctionBreakpoint.cpp - InstructionBreakpoint.cpp IOStream.cpp JSONUtils.cpp LLDBUtils.cpp @@ -34,11 +36,12 @@ add_lldb_tool(lldb-dap ProgressEvent.cpp RunInTerminal.cpp SourceBreakpoint.cpp + DAP.cpp Watchpoint.cpp + InstructionBreakpoint.cpp LINK_LIBS liblldb - lldbHost ${extra_libs} LINK_COMPONENTS diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index a67abe582abd40..35250d9eef608a 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -6,62 +6,34 @@ // //===----------------------------------------------------------------------===// +#include <chrono> +#include <cstdarg> +#include <fstream> +#include <mutex> + #include "DAP.h" #include "JSONUtils.h" #include "LLDBUtils.h" -#include "OutputRedirector.h" -#include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBCommandInterpreter.h" -#include "lldb/API/SBCommandReturnObject.h" #include "lldb/API/SBLanguageRuntime.h" #include "lldb/API/SBListener.h" -#include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Utility/Status.h" -#include "lldb/lldb-defines.h" -#include "lldb/lldb-enumerations.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cassert> -#include <chrono> -#include <cstdarg> -#include <cstdio> -#include <fstream> -#include <mutex> -#include <utility> #if defined(_WIN32) #define NOMINMAX #include <fcntl.h> #include <io.h> #include <windows.h> -#else -#include <unistd.h> #endif using namespace lldb_dap; -namespace { -#ifdef _WIN32 -const char DEV_NULL[] = "nul"; -#else -const char DEV_NULL[] = "/dev/null"; -#endif -} // namespace - namespace lldb_dap { -DAP::DAP(llvm::StringRef path, std::ofstream *log, ReplMode repl_mode, - StreamDescriptor input, StreamDescriptor output) - : debug_adaptor_path(path), log(log), input(std::move(input)), - output(std::move(output)), broadcaster("lldb-dap"), +DAP::DAP(llvm::StringRef path, ReplMode repl_mode) + : debug_adaptor_path(path), broadcaster("lldb-dap"), exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), enable_auto_variable_summaries(false), @@ -71,7 +43,21 @@ DAP::DAP(llvm::StringRef path, std::ofstream *log, ReplMode repl_mode, configuration_done_sent(false), waiting_for_run_in_terminal(false), progress_event_reporter( [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }), - reverse_request_seq(0), repl_mode(repl_mode) {} + reverse_request_seq(0), repl_mode(repl_mode) { + const char *log_file_path = getenv("LLDBDAP_LOG"); +#if defined(_WIN32) + // Windows opens stdout and stdin in text mode which converts \n to 13,10 + // while the value is just 10 on Darwin/Linux. Setting the file mode to binary + // fixes this. + int result = _setmode(fileno(stdout), _O_BINARY); + assert(result); + result = _setmode(fileno(stdin), _O_BINARY); + UNUSED_IF_ASSERT_DISABLED(result); + assert(result); +#endif + if (log_file_path) + log.reset(new std::ofstream(log_file_path)); +} DAP::~DAP() = default; @@ -187,45 +173,6 @@ ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const lldb::break_id_t bp_id) { return nullptr; } -llvm::Error DAP::ConfigureIO(std::FILE *overrideOut, std::FILE *overrideErr) { - in = lldb::SBFile(std::fopen(DEV_NULL, "r"), /*transfer_ownership=*/true); - - if (auto Error = out.RedirectTo([this](llvm::StringRef output) { - SendOutput(OutputType::Stdout, output); - })) - return Error; - - if (overrideOut) { - auto fd = out.GetWriteFileDescriptor(); - if (auto Error = fd.takeError()) - return Error; - - if (dup2(*fd, fileno(overrideOut)) == -1) - return llvm::errorCodeToError(llvm::errnoAsErrorCode()); - } - - if (auto Error = err.RedirectTo([this](llvm::StringRef output) { - SendOutput(OutputType::Stderr, output); - })) - return Error; - - if (overrideErr) { - auto fd = err.GetWriteFileDescriptor(); - if (auto Error = fd.takeError()) - return Error; - - if (dup2(*fd, fileno(overrideErr)) == -1) - return llvm::errorCodeToError(llvm::errnoAsErrorCode()); - } - - return llvm::Error::success(); -} - -void DAP::StopIO() { - out.Stop(); - err.Stop(); -} - // Send the JSON in "json_str" to the "out" stream. Correctly send the // "Content-Length:" field followed by the length, followed by the raw // JSON bytes. @@ -261,19 +208,19 @@ std::string DAP::ReadJSON() { std::string json_str; int length; - if (!input.read_expected(log, "Content-Length: ")) + if (!input.read_expected(log.get(), "Content-Length: ")) return json_str; - if (!input.read_line(log, length_str)) + if (!input.read_line(log.get(), length_str)) return json_str; if (!llvm::to_integer(length_str, length)) return json_str; - if (!input.read_expected(log, "\r\n")) + if (!input.read_expected(log.get(), "\r\n")) return json_str; - if (!input.read_full(log, length, json_str)) + if (!input.read_full(log.get(), length, json_str)) return json_str; if (log) { diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 846300cb945b0d..ae496236f13369 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -9,38 +9,36 @@ #ifndef LLDB_TOOLS_LLDB_DAP_DAP_H #define LLDB_TOOLS_LLDB_DAP_DAP_H -#include "DAPForward.h" -#include "ExceptionBreakpoint.h" -#include "FunctionBreakpoint.h" -#include "IOStream.h" -#include "InstructionBreakpoint.h" -#include "OutputRedirector.h" -#include "ProgressEvent.h" -#include "SourceBreakpoint.h" -#include "lldb/API/SBBroadcaster.h" -#include "lldb/API/SBCommandInterpreter.h" -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBError.h" -#include "lldb/API/SBFile.h" -#include "lldb/API/SBFormat.h" -#include "lldb/API/SBFrame.h" -#include "lldb/API/SBTarget.h" -#include "lldb/API/SBThread.h" -#include "lldb/API/SBValue.h" -#include "lldb/API/SBValueList.h" -#include "lldb/lldb-types.h" +#include <cstdio> +#include <iosfwd> +#include <map> +#include <optional> +#include <thread> + #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" #include "llvm/Support/Threading.h" -#include <map> -#include <mutex> -#include <optional> -#include <thread> -#include <vector> +#include "llvm/Support/raw_ostream.h" + +#include "lldb/API/SBAttachInfo.h" +#include "lldb/API/SBCommandInterpreter.h" +#include "lldb/API/SBCommandReturnObject.h" +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBEvent.h" +#include "lldb/API/SBFormat.h" +#include "lldb/API/SBLaunchInfo.h" +#include "lldb/API/SBTarget.h" +#include "lldb/API/SBThread.h" + +#include "ExceptionBreakpoint.h" +#include "FunctionBreakpoint.h" +#include "IOStream.h" +#include "InstructionBreakpoint.h" +#include "ProgressEvent.h" +#include "SourceBreakpoint.h" #define VARREF_LOCALS (int64_t)1 #define VARREF_GLOBALS (int64_t)2 @@ -140,18 +138,15 @@ struct SendEventRequestHandler : public lldb::SBCommandPluginInterface { struct DAP { llvm::StringRef debug_adaptor_path; - std::ofstream *log; InputStream input; OutputStream output; - lldb::SBFile in; - OutputRedirector out; - OutputRedirector err; lldb::SBDebugger debugger; lldb::SBTarget target; Variables variables; lldb::SBBroadcaster broadcaster; std::thread event_thread; std::thread progress_event_thread; + std::unique_ptr<std::ofstream> log; llvm::StringMap<SourceBreakpointMap> source_breakpoints; FunctionBreakpointMap function_breakpoints; InstructionBreakpointMap instruction_breakpoints; @@ -203,23 +198,13 @@ struct DAP { // will contain that expression. std::string last_nonempty_var_expression; - DAP(llvm::StringRef path, std::ofstream *log, ReplMode repl_mode, - StreamDescriptor input, StreamDescriptor output); + DAP(llvm::StringRef path, ReplMode repl_mode); ~DAP(); DAP(const DAP &rhs) = delete; void operator=(const DAP &rhs) = delete; ExceptionBreakpoint *GetExceptionBreakpoint(const std::string &filter); ExceptionBreakpoint *GetExceptionBreakpoint(const lldb::break_id_t bp_id); - /// Redirect stdout and stderr fo the IDE's console output. - /// - /// Errors in this operation will be printed to the log file and the IDE's - /// console output as well. - llvm::Error ConfigureIO(std::FILE *overrideOut, std::FILE *overrideErr); - - /// Stop the redirected IO threads and associated pipes. - void StopIO(); - // Serialize the JSON value into a string and send the JSON packet to // the "out" stream. void SendJSON(const llvm::json::Value &json); diff --git a/lldb/tools/lldb-dap/IOStream.h b/lldb/tools/lldb-dap/IOStream.h index 74889eb2e5a866..57d5fd458b7165 100644 --- a/lldb/tools/lldb-dap/IOStream.h +++ b/lldb/tools/lldb-dap/IOStream.h @@ -52,9 +52,6 @@ struct StreamDescriptor { struct InputStream { StreamDescriptor descriptor; - explicit InputStream(StreamDescriptor descriptor) - : descriptor(std::move(descriptor)) {} - bool read_full(std::ofstream *log, size_t length, std::string &text); bool read_line(std::ofstream *log, std::string &line); @@ -65,9 +62,6 @@ struct InputStream { struct OutputStream { StreamDescriptor descriptor; - explicit OutputStream(StreamDescriptor descriptor) - : descriptor(std::move(descriptor)) {} - bool write_full(llvm::StringRef str); }; } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/OutputRedirector.cpp b/lldb/tools/lldb-dap/OutputRedirector.cpp index 8fcbcfec99c443..2c2f49569869b4 100644 --- a/lldb/tools/lldb-dap/OutputRedirector.cpp +++ b/lldb/tools/lldb-dap/OutputRedirector.cpp @@ -6,8 +6,6 @@ // //===----------------------------------------------------------------------===/ -#include "llvm/Support/Error.h" -#include <system_error> #if defined(_WIN32) #include <fcntl.h> #include <io.h> @@ -19,59 +17,47 @@ #include "OutputRedirector.h" #include "llvm/ADT/StringRef.h" -using lldb_private::Pipe; -using lldb_private::Status; -using llvm::createStringError; -using llvm::Error; -using llvm::Expected; -using llvm::StringRef; +using namespace llvm; namespace lldb_dap { -Expected<int> OutputRedirector::GetWriteFileDescriptor() { - if (!m_pipe.CanWrite()) - return createStringError(std::errc::bad_file_descriptor, - "write handle is not open for writing"); - return m_pipe.GetWriteFileDescriptor(); -} +Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback) { + int new_fd[2]; +#if defined(_WIN32) + if (_pipe(new_fd, 4096, O_TEXT) == -1) { +#else + if (pipe(new_fd) == -1) { +#endif + int error = errno; + return createStringError(inconvertibleErrorCode(), + "Couldn't create new pipe for fd %d. %s", fd, + strerror(error)); + } -Error OutputRedirector::RedirectTo(std::function<void(StringRef)> callback) { - Status status = m_pipe.CreateNew(/*child_process_inherit=*/false); - if (status.Fail()) - return status.takeError(); + if (dup2(new_fd[1], fd) == -1) { + int error = errno; + return createStringError(inconvertibleErrorCode(), + "Couldn't override the fd %d. %s", fd, + strerror(error)); + } - m_forwarder = std::thread([this, callback]() { + int read_fd = new_fd[0]; + std::thread t([read_fd, callback]() { char buffer[OutputBufferSize]; - while (m_pipe.CanRead() && !m_stopped) { - size_t bytes_read; - Status status = m_pipe.Read(&buffer, sizeof(buffer), bytes_read); - if (status.Fail()) - continue; - - // EOF detected - if (bytes_read == 0 || m_stopped) + while (true) { + ssize_t bytes_count = read(read_fd, &buffer, sizeof(buffer)); + if (bytes_count == 0) + return; + if (bytes_count == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; break; - - callback(StringRef(buffer, bytes_read)); + } + callback(StringRef(buffer, bytes_count)); } }); - + t.detach(); return Error::success(); } -void OutputRedirector::Stop() { - m_stopped = true; - - if (m_pipe.CanWrite()) { - // Closing the pipe may not be sufficient to wake up the thread in case the - // write descriptor is duplicated (to stdout/err or to another process). - // Write a null byte to ensure the read call returns. - char buf[] = "\0"; - size_t bytes_written; - m_pipe.Write(buf, sizeof(buf), bytes_written); - m_pipe.CloseWriteFileDescriptor(); - m_forwarder.join(); - } -} - } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/OutputRedirector.h b/lldb/tools/lldb-dap/OutputRedirector.h index 41ea05c22c6919..e26d1648b104f9 100644 --- a/lldb/tools/lldb-dap/OutputRedirector.h +++ b/lldb/tools/lldb-dap/OutputRedirector.h @@ -9,39 +9,17 @@ #ifndef LLDB_TOOLS_LLDB_DAP_OUTPUT_REDIRECTOR_H #define LLDB_TOOLS_LLDB_DAP_OUTPUT_REDIRECTOR_H -#include "lldb/Host/Pipe.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" -#include <atomic> -#include <functional> -#include <thread> namespace lldb_dap { -class OutputRedirector { -public: - /// Creates writable file descriptor that will invoke the given callback on - /// each write in a background thread. - /// - /// \return - /// \a Error::success if the redirection was set up correctly, or an error - /// otherwise. - llvm::Error RedirectTo(std::function<void(llvm::StringRef)> callback); - - llvm::Expected<int> GetWriteFileDescriptor(); - void Stop(); - - ~OutputRedirector() { Stop(); } - - OutputRedirector() = default; - OutputRedirector(const OutputRedirector &) = delete; - OutputRedirector &operator=(const OutputRedirector &) = delete; - -private: - std::atomic<bool> m_stopped = false; - lldb_private::Pipe m_pipe; - std::thread m_forwarder; -}; +/// Redirects the output of a given file descriptor to a callback. +/// +/// \return +/// \a Error::success if the redirection was set up correctly, or an error +/// otherwise. +llvm::Error RedirectFd(int fd, std::function<void(llvm::StringRef)> callback); } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index 6c524081c493eb..7e8f7b5f6df679 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -10,10 +10,10 @@ #include "FifoFiles.h" #include "JSONUtils.h" #include "LLDBUtils.h" +#include "OutputRedirector.h" #include "RunInTerminal.h" #include "Watchpoint.h" #include "lldb/API/SBDeclaration.h" -#include "lldb/API/SBEvent.h" #include "lldb/API/SBInstruction.h" #include "lldb/API/SBListener.h" #include "lldb/API/SBMemoryRegionInfo.h" @@ -41,11 +41,9 @@ #include <cassert> #include <climits> #include <cstdarg> -#include <cstdint> #include <cstdio> #include <cstdlib> #include <cstring> -#include <fcntl.h> #include <map> #include <memory> #include <optional> @@ -142,14 +140,15 @@ lldb::SBValueList *GetTopLevelScope(DAP &dap, int64_t variablesReference) { } } -SOCKET AcceptConnection(std::ofstream *log, int portno) { +SOCKET AcceptConnection(DAP &dap, int portno) { // Accept a socket connection from any host on "portno". SOCKET newsockfd = -1; struct sockaddr_in serv_addr, cli_addr; SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { - if (log) - *log << "error: opening socket (" << strerror(errno) << ")" << std::endl; + if (dap.log) + *dap.log << "error: opening socket (" << strerror(errno) << ")" + << std::endl; } else { memset((char *)&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; @@ -157,9 +156,9 @@ SOCKET AcceptConnection(std::ofstream *log, int portno) { serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); serv_addr.sin_port = htons(portno); if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { - if (log) - *log << "error: binding socket (" << strerror(errno) << ")" - << std::endl; + if (dap.log) + *dap.log << "error: binding socket (" << strerror(errno) << ")" + << std::endl; } else { listen(sockfd, 5); socklen_t clilen = sizeof(cli_addr); @@ -167,8 +166,8 @@ SOCKET AcceptConnection(std::ofstream *log, int portno) { llvm::sys::RetryAfterSignal(static_cast<SOCKET>(-1), accept, sockfd, (struct sockaddr *)&cli_addr, &clilen); if (newsockfd < 0) - if (log) - *log << "error: accept (" << strerror(errno) << ")" << std::endl; + if (dap.log) + *dap.log << "error: accept (" << strerror(errno) << ")" << std::endl; } #if defined(_WIN32) closesocket(sockfd); @@ -1103,7 +1102,6 @@ void request_disconnect(DAP &dap, const llvm::json::Object &request) { dap.broadcaster.BroadcastEventByType(eBroadcastBitStopProgressThread); dap.progress_event_thread.join(); } - dap.StopIO(); dap.disconnecting = true; } @@ -1873,36 +1871,7 @@ void request_initialize(DAP &dap, const llvm::json::Object &request) { // which may affect the outcome of tests. bool source_init_file = GetBoolean(arguments, "sourceInitFile", true); - // Do not source init files until in/out/err are configured. - dap.debugger = lldb::SBDebugger::Create(false); - dap.debugger.SetInputFile(dap.in); - auto out_fd = dap.out.GetWriteFileDescriptor(); - if (llvm::Error err = out_fd.takeError()) { - response["success"] = false; - EmplaceSafeString(response, "message", llvm::toString(std::move(err))); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - dap.debugger.SetOutputFile(lldb::SBFile(*out_fd, "w", false)); - auto err_fd = dap.err.GetWriteFileDescriptor(); - if (llvm::Error err = err_fd.takeError()) { - response["success"] = false; - EmplaceSafeString(response, "message", llvm::toString(std::move(err))); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - dap.debugger.SetErrorFile(lldb::SBFile(*err_fd, "w", false)); - - auto interp = dap.debugger.GetCommandInterpreter(); - - if (source_init_file) { - dap.debugger.SkipLLDBInitFiles(false); - dap.debugger.SkipAppInitFiles(false); - lldb::SBCommandReturnObject init; - interp.SourceInitFileInGlobalDirectory(init); - interp.SourceInitFileInHomeDirectory(init); - } - + dap.debugger = lldb::SBDebugger::Create(source_init_file); if (llvm::Error err = dap.RunPreInitCommands()) { response["success"] = false; EmplaceSafeString(response, "message", llvm::toString(std::move(err))); @@ -4941,14 +4910,36 @@ static void redirection_test() { fflush(stderr); } -/// Duplicates a file descriptor, setting FD_CLOEXEC if applicable. -static int DuplicateFileDescriptor(int fd) { -#if defined(F_DUPFD_CLOEXEC) - // Ensure FD_CLOEXEC is set. - return ::fcntl(fd, F_DUPFD_CLOEXEC, 0); -#else - return ::dup(fd); -#endif +/// Redirect stdout and stderr fo the IDE's console output. +/// +/// Errors in this operation will be printed to the log file and the IDE's +/// console output as well. +/// +/// \return +/// A fd pointing to the original stdout. +static int SetupStdoutStderrRedirection(DAP &dap) { + int stdoutfd = fileno(stdout); + int new_stdout_fd = dup(stdoutfd); + auto output_callback_stderr = [&dap](llvm::StringRef data) { + dap.SendOutput(OutputType::Stderr, data); + }; + auto output_callback_stdout = [&dap](llvm::StringRef data) { + dap.SendOutput(OutputType::Stdout, data); + }; + if (llvm::Error err = RedirectFd(stdoutfd, output_callback_stdout)) { + std::string error_message = llvm::toString(std::move(err)); + if (dap.log) + *dap.log << error_message << std::endl; + output_callback_stderr(error_message); + } + if (llvm::Error err = RedirectFd(fileno(stderr), output_callback_stderr)) { + std::string error_message = llvm::toString(std::move(err)); + if (dap.log) + *dap.log << error_message << std::endl; + output_callback_stderr(error_message); + } + + return new_stdout_fd; } int main(int argc, char *argv[]) { @@ -5039,88 +5030,47 @@ int main(int argc, char *argv[]) { } #endif - std::unique_ptr<std::ofstream> log = nullptr; - const char *log_file_path = getenv("LLDBDAP_LOG"); - if (log_file_path) - log = std::make_unique<std::ofstream>(log_file_path); - // Initialize LLDB first before we do anything. - lldb::SBError error = lldb::SBDebugger::InitializeWithErrorHandling(); - if (error.Fail()) { - lldb::SBStream os; - error.GetDescription(os); - llvm::errs() << "lldb initialize failed: " << os.GetData() << "\n"; - return EXIT_FAILURE; - } + lldb::SBDebugger::Initialize(); // Terminate the debugger before the C++ destructor chain kicks in. auto terminate_debugger = llvm::make_scope_exit([] { lldb::SBDebugger::Terminate(); }); - StreamDescriptor input; - StreamDescriptor output; - std::FILE *redirectOut = nullptr; - std::FILE *redirectErr = nullptr; - if (portno != -1) { - printf("Listening on port %i...\n", portno); - SOCKET socket_fd = AcceptConnection(log.get(), portno); - if (socket_fd < 0) - return EXIT_FAILURE; + DAP dap = DAP(program_path.str(), default_repl_mode); - input = StreamDescriptor::from_socket(socket_fd, true); - output = StreamDescriptor::from_socket(socket_fd, false); - } else { -#if defined(_WIN32) - // Windows opens stdout and stdin in text mode which converts \n to 13,10 - // while the value is just 10 on Darwin/Linux. Setting the file mode to - // binary fixes this. - int result = _setmode(fileno(stdout), _O_BINARY); - assert(result); - result = _setmode(fileno(stdin), _O_BINARY); - UNUSED_IF_ASSERT_DISABLED(result); - assert(result); -#endif + RegisterRequestCallbacks(dap); - int stdout_fd = DuplicateFileDescriptor(fileno(stdout)); - if (stdout_fd == -1) { - llvm::logAllUnhandledErrors( - llvm::errorCodeToError(llvm::errnoAsErrorCode()), llvm::errs(), - "Failed to configure stdout redirect: "); + // stdout/stderr redirection to the IDE's console + int new_stdout_fd = SetupStdoutStderrRedirection(dap); + + if (portno != -1) { + printf("Listening on port %i...\n", portno); + SOCKET socket_fd = AcceptConnection(dap, portno); + if (socket_fd >= 0) { + dap.input.descriptor = StreamDescriptor::from_socket(socket_fd, true); + dap.output.descriptor = StreamDescriptor::from_socket(socket_fd, false); + } else { return EXIT_FAILURE; } + } else { + dap.input.descriptor = StreamDescriptor::from_file(fileno(stdin), false); + dap.output.descriptor = StreamDescriptor::from_file(new_stdout_fd, false); - redirectOut = stdout; - redirectErr = stderr; - - input = StreamDescriptor::from_file(fileno(stdin), false); - output = StreamDescriptor::from_file(stdout_fd, false); - } - - DAP dap = DAP(program_path.str(), log.get(), default_repl_mode, - std::move(input), std::move(output)); - - // stdout/stderr redirection to the IDE's console - if (auto Err = dap.ConfigureIO(redirectOut, redirectErr)) { - llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), - "Failed to configure lldb-dap IO operations: "); - return EXIT_FAILURE; + /// used only by TestVSCode_redirection_to_console.py + if (getenv("LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION") != nullptr) + redirection_test(); } - RegisterRequestCallbacks(dap); - for (const std::string &arg : input_args.getAllArgValues(OPT_pre_init_command)) { dap.pre_init_commands.push_back(arg); } - // used only by TestVSCode_redirection_to_console.py - if (getenv("LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION") != nullptr) - redirection_test(); - bool CleanExit = true; if (auto Err = dap.Loop()) { - if (log) - *log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n"; + if (dap.log) + *dap.log << "Transport Error: " << llvm::toString(std::move(Err)) << "\n"; CleanExit = false; } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits