[lldb-dap] Refactoring IOStream into Transport handler. (#130026)

Instead of having two discrete InputStream and OutputStream helpers,
this merges the two into a unifed 'Transport' handler.

This handler is responsible for reading the DAP message headers, parsing
the resulting JSON and converting the messages into
`lldb_dap::protocol::Message`s for both input and output.

---------

Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
This commit is contained in:
John Harrison 2025-03-12 12:29:05 -07:00 committed by GitHub
parent 4d79e9892c
commit 7790d69cce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 288 additions and 248 deletions

View File

@ -337,7 +337,7 @@ class DebugCommunication(object):
self.send_packet(
{
"type": "response",
"seq": -1,
"seq": 0,
"request_seq": response_or_request["seq"],
"success": True,
"command": "runInTerminal",
@ -349,7 +349,7 @@ class DebugCommunication(object):
self.send_packet(
{
"type": "response",
"seq": -1,
"seq": 0,
"request_seq": response_or_request["seq"],
"success": True,
"command": "startDebugging",

View File

@ -2,6 +2,8 @@
Test lldb-dap IO handling.
"""
import sys
from lldbsuite.test.decorators import *
import lldbdap_testcase
import dap_server
@ -19,18 +21,18 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
if process.poll() is None:
process.terminate()
process.wait()
stdout_data = process.stdout.read()
stderr_data = process.stderr.read()
print("========= STDOUT =========")
print(stdout_data)
print("========= END =========")
print("========= STDERR =========")
print(stderr_data)
print("========= END =========")
print("========= DEBUG ADAPTER PROTOCOL LOGS =========")
stdout_data = process.stdout.read().decode()
stderr_data = process.stderr.read().decode()
print("========= STDOUT =========", file=sys.stderr)
print(stdout_data, file=sys.stderr)
print("========= END =========", file=sys.stderr)
print("========= STDERR =========", file=sys.stderr)
print(stderr_data, file=sys.stderr)
print("========= END =========", file=sys.stderr)
print("========= DEBUG ADAPTER PROTOCOL LOGS =========", file=sys.stderr)
with open(log_file_path, "r") as file:
print(file.read())
print("========= END =========")
print(file.read(), file=sys.stderr)
print("========= END =========", file=sys.stderr)
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
@ -45,6 +47,15 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
process.stdin.close()
self.assertEqual(process.wait(timeout=5.0), 0)
def test_invalid_header(self):
"""
lldb-dap handles invalid message headers.
"""
process = self.launch()
process.stdin.write(b"not the corret message header")
process.stdin.close()
self.assertEqual(process.wait(timeout=5.0), 1)
def test_partial_header(self):
"""
lldb-dap handles parital message headers.
@ -52,7 +63,7 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
process = self.launch()
process.stdin.write(b"Content-Length: ")
process.stdin.close()
self.assertEqual(process.wait(timeout=5.0), 0)
self.assertEqual(process.wait(timeout=5.0), 1)
def test_incorrect_content_length(self):
"""
@ -61,13 +72,13 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
process = self.launch()
process.stdin.write(b"Content-Length: abc")
process.stdin.close()
self.assertEqual(process.wait(timeout=5.0), 0)
self.assertEqual(process.wait(timeout=5.0), 1)
def test_partial_content_length(self):
"""
lldb-dap handles partial messages.
"""
process = self.launch()
process.stdin.write(b"Content-Length: 10{")
process.stdin.write(b"Content-Length: 10\r\n\r\n{")
process.stdin.close()
self.assertEqual(process.wait(timeout=5.0), 0)
self.assertEqual(process.wait(timeout=5.0), 1)

View File

@ -28,14 +28,14 @@ add_lldb_tool(lldb-dap
FifoFiles.cpp
FunctionBreakpoint.cpp
InstructionBreakpoint.cpp
IOStream.cpp
JSONUtils.cpp
LLDBUtils.cpp
OutputRedirector.cpp
ProgressEvent.cpp
Protocol.cpp
RunInTerminal.cpp
SourceBreakpoint.cpp
Protocol.cpp
Transport.cpp
Watchpoint.cpp
Handler/ResponseHandler.cpp

View File

@ -12,6 +12,7 @@
#include "JSONUtils.h"
#include "LLDBUtils.h"
#include "OutputRedirector.h"
#include "Transport.h"
#include "lldb/API/SBBreakpoint.h"
#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBCommandReturnObject.h"
@ -63,11 +64,10 @@ const char DEV_NULL[] = "/dev/null";
namespace lldb_dap {
DAP::DAP(llvm::StringRef client_name, llvm::StringRef path, std::ofstream *log,
lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode,
std::vector<std::string> pre_init_commands)
: client_name(client_name), debug_adapter_path(path), log(log),
input(std::move(input)), output(std::move(output)),
DAP::DAP(llvm::StringRef path, std::ofstream *log,
const ReplMode default_repl_mode,
std::vector<std::string> pre_init_commands, Transport &transport)
: debug_adapter_path(path), log(log), transport(transport),
broadcaster("lldb-dap"), exception_breakpoints(),
pre_init_commands(std::move(pre_init_commands)),
focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false),
@ -78,7 +78,7 @@ DAP::DAP(llvm::StringRef client_name, llvm::StringRef path, std::ofstream *log,
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(default_repl_mode) {}
DAP::~DAP() = default;
@ -221,52 +221,21 @@ void DAP::StopEventHandlers() {
}
}
// 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.
void DAP::SendJSON(const std::string &json_str) {
output.write_full("Content-Length: ");
output.write_full(llvm::utostr(json_str.size()));
output.write_full("\r\n\r\n");
output.write_full(json_str);
}
// Serialize the JSON value into a string and send the JSON packet to
// the "out" stream.
void DAP::SendJSON(const llvm::json::Value &json) {
std::string json_str;
llvm::raw_string_ostream strm(json_str);
strm << json;
static std::mutex mutex;
std::lock_guard<std::mutex> locker(mutex);
SendJSON(json_str);
DAP_LOG(log, "({0}) <-- {1}", client_name, json_str);
}
// Read a JSON packet from the "in" stream.
std::string DAP::ReadJSON() {
std::string length_str;
std::string json_str;
int length;
if (!input.read_expected(log, "Content-Length: "))
return json_str;
if (!input.read_line(log, length_str))
return json_str;
if (!llvm::to_integer(length_str, length))
return json_str;
if (!input.read_expected(log, "\r\n"))
return json_str;
if (!input.read_full(log, length, json_str))
return json_str;
DAP_LOG(log, "({0}) --> {1}", client_name, json_str);
return json_str;
// FIXME: Instead of parsing the output message from JSON, pass the `Message`
// as parameter to `SendJSON`.
protocol::Message message;
llvm::json::Path::Root root;
if (!fromJSON(json, message, root)) {
DAP_LOG_ERROR(log, root.getError(), "({1}) encoding failed: {0}",
transport.GetClientName());
return;
}
if (llvm::Error err = transport.Write(message))
DAP_LOG_ERROR(log, std::move(err), "({1}) write failed: {0}",
transport.GetClientName());
}
// "OutputEvent": {
@ -693,29 +662,10 @@ void DAP::SetTarget(const lldb::SBTarget target) {
}
}
PacketStatus DAP::GetNextObject(llvm::json::Object &object) {
std::string json = ReadJSON();
if (json.empty())
return PacketStatus::EndOfFile;
llvm::StringRef json_sref(json);
llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref);
if (!json_value) {
DAP_LOG_ERROR(log, json_value.takeError(),
"({1}) failed to parse JSON: {0}", client_name);
return PacketStatus::JSONMalformed;
}
llvm::json::Object *object_ptr = json_value->getAsObject();
if (!object_ptr) {
DAP_LOG(log, "({0}) error: json packet isn't a object", client_name);
return PacketStatus::JSONNotObject;
}
object = *object_ptr;
return PacketStatus::Success;
}
bool DAP::HandleObject(const llvm::json::Object &object) {
bool DAP::HandleObject(const protocol::Message &M) {
// FIXME: Directly handle `Message` instead of serializing to JSON.
llvm::json::Value v = toJSON(M);
llvm::json::Object object = *v.getAsObject();
const auto packet_type = GetString(object, "type");
if (packet_type == "request") {
const auto command = GetString(object, "command");
@ -726,7 +676,8 @@ bool DAP::HandleObject(const llvm::json::Object &object) {
return true; // Success
}
DAP_LOG(log, "({0}) error: unhandled command '{1}'", client_name, command);
DAP_LOG(log, "({0}) error: unhandled command '{1}'",
transport.GetClientName(), command);
return false; // Fail
}
@ -749,9 +700,8 @@ bool DAP::HandleObject(const llvm::json::Object &object) {
// Result should be given, use null if not.
if (GetBoolean(object, "success").value_or(false)) {
llvm::json::Value Result = nullptr;
if (auto *B = object.get("body")) {
if (auto *B = object.get("body"))
Result = std::move(*B);
}
(*response_handler)(Result);
} else {
llvm::StringRef message = GetString(object, "message");
@ -818,19 +768,15 @@ llvm::Error DAP::Loop() {
StopEventHandlers();
});
while (!disconnecting) {
llvm::json::Object object;
lldb_dap::PacketStatus status = GetNextObject(object);
llvm::Expected<std::optional<protocol::Message>> next = transport.Read();
if (!next)
return next.takeError();
if (status == lldb_dap::PacketStatus::EndOfFile) {
// nullopt on EOF
if (!*next)
break;
}
if (status != lldb_dap::PacketStatus::Success) {
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"failed to send packet");
}
if (!HandleObject(object)) {
if (!HandleObject(**next)) {
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"unhandled packet");
}

View File

@ -14,11 +14,12 @@
#include "FunctionBreakpoint.h"
#include "Handler/RequestHandler.h"
#include "Handler/ResponseHandler.h"
#include "IOStream.h"
#include "InstructionBreakpoint.h"
#include "OutputRedirector.h"
#include "ProgressEvent.h"
#include "Protocol.h"
#include "SourceBreakpoint.h"
#include "Transport.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBDebugger.h"
@ -39,7 +40,6 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Threading.h"
#include <map>
#include <memory>
#include <mutex>
#include <optional>
@ -145,11 +145,9 @@ struct SendEventRequestHandler : public lldb::SBCommandPluginInterface {
};
struct DAP {
llvm::StringRef client_name;
llvm::StringRef debug_adapter_path;
std::ofstream *log;
InputStream input;
OutputStream output;
Transport &transport;
lldb::SBFile in;
OutputRedirector out;
OutputRedirector err;
@ -210,12 +208,30 @@ struct DAP {
// will contain that expression.
std::string last_nonempty_var_expression;
DAP(llvm::StringRef client_name, llvm::StringRef path, std::ofstream *log,
lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode,
std::vector<std::string> pre_init_commands);
/// Creates a new DAP sessions.
///
/// \param[in] path
/// Path to the lldb-dap binary.
/// \param[in] log
/// Log file stream, if configured.
/// \param[in] default_repl_mode
/// Default repl mode behavior, as configured by the binary.
/// \param[in] pre_init_commands
/// LLDB commands to execute as soon as the debugger instance is allocaed.
/// \param[in] transport
/// Transport for this debug session.
DAP(llvm::StringRef path, std::ofstream *log,
const ReplMode default_repl_mode,
std::vector<std::string> pre_init_commands, Transport &transport);
~DAP();
/// DAP is not copyable.
/// @{
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);
@ -233,8 +249,6 @@ struct DAP {
// the "out" stream.
void SendJSON(const llvm::json::Value &json);
std::string ReadJSON();
void SendOutput(OutputType o, const llvm::StringRef output);
void SendProgressEvent(uint64_t progress_id, const char *message,
@ -307,8 +321,7 @@ struct DAP {
/// listeing for its breakpoint events.
void SetTarget(const lldb::SBTarget target);
PacketStatus GetNextObject(llvm::json::Object &object);
bool HandleObject(const llvm::json::Object &object);
bool HandleObject(const protocol::Message &M);
/// Disconnect the DAP session.
lldb::SBError Disconnect();
@ -382,12 +395,6 @@ struct DAP {
InstructionBreakpoint *GetInstructionBreakpoint(const lldb::break_id_t bp_id);
InstructionBreakpoint *GetInstructionBPFromStopReason(lldb::SBThread &thread);
private:
// 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.
void SendJSON(const std::string &json_str);
};
} // namespace lldb_dap

View File

@ -111,7 +111,7 @@ void ProgressEventThreadFunction(DAP &dap) {
// them prevent multiple threads from writing simultaneously so no locking
// is required.
static void EventThreadFunction(DAP &dap) {
llvm::set_thread_name(dap.client_name + ".event_handler");
llvm::set_thread_name(dap.transport.GetClientName() + ".event_handler");
lldb::SBEvent event;
lldb::SBListener listener = dap.debugger.GetListener();
dap.broadcaster.AddListener(listener, eBroadcastBitStopEventThread);

View File

@ -1,73 +0,0 @@
//===-- IOStream.cpp --------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "IOStream.h"
#include "lldb/Utility/IOObject.h"
#include "lldb/Utility/Status.h"
#include <fstream>
#include <string>
using namespace lldb_dap;
bool OutputStream::write_full(llvm::StringRef str) {
if (!descriptor)
return false;
size_t num_bytes = str.size();
auto status = descriptor->Write(str.data(), num_bytes);
return status.Success();
}
bool InputStream::read_full(std::ofstream *log, size_t length,
std::string &text) {
if (!descriptor)
return false;
std::string data;
data.resize(length);
auto status = descriptor->Read(data.data(), length);
if (status.Fail())
return false;
text += data.substr(0, length);
return true;
}
bool InputStream::read_line(std::ofstream *log, std::string &line) {
line.clear();
while (true) {
std::string next;
if (!read_full(log, 1, next))
return false;
// If EOF is encoutnered, '' is returned, break out of this loop.
if (next.empty())
return false;
line += next;
if (llvm::StringRef(line).ends_with("\r\n"))
break;
}
line.erase(line.size() - 2);
return true;
}
bool InputStream::read_expected(std::ofstream *log, llvm::StringRef expected) {
std::string result;
if (!read_full(log, expected.size(), result))
return false;
if (expected != result) {
if (log)
*log << "Warning: Expected '" << expected.str() << "', got '" << result
<< "\n";
return false;
}
return true;
}

View File

@ -1,42 +0,0 @@
//===-- IOStream.h ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_TOOLS_LLDB_DAP_IOSTREAM_H
#define LLDB_TOOLS_LLDB_DAP_IOSTREAM_H
#include "lldb/lldb-forward.h"
#include "llvm/ADT/StringRef.h"
#include <fstream>
#include <string>
namespace lldb_dap {
struct InputStream {
lldb::IOObjectSP descriptor;
explicit InputStream(lldb::IOObjectSP 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);
bool read_expected(std::ofstream *log, llvm::StringRef expected);
};
struct OutputStream {
lldb::IOObjectSP descriptor;
explicit OutputStream(lldb::IOObjectSP descriptor)
: descriptor(std::move(descriptor)) {}
bool write_full(llvm::StringRef str);
};
} // namespace lldb_dap
#endif

View File

@ -0,0 +1,126 @@
//===-- Transport.cpp -----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Transport.h"
#include "DAPLog.h"
#include "Protocol.h"
#include "lldb/Utility/IOObject.h"
#include "lldb/Utility/Status.h"
#include "lldb/lldb-forward.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
#include <utility>
using namespace llvm;
using namespace lldb;
using namespace lldb_private;
using namespace lldb_dap;
using namespace lldb_dap::protocol;
/// ReadFull attempts to read the specified number of bytes. If EOF is
/// encountered, an empty string is returned.
static Expected<std::string> ReadFull(IOObject &descriptor, size_t length) {
std::string data;
data.resize(length);
auto status = descriptor.Read(data.data(), length);
if (status.Fail())
return status.takeError();
// Return the actual number of bytes read.
return data.substr(0, length);
}
static Expected<std::string> ReadUntil(IOObject &descriptor,
StringRef delimiter) {
std::string buffer;
buffer.reserve(delimiter.size() + 1);
while (!llvm::StringRef(buffer).ends_with(delimiter)) {
Expected<std::string> next =
ReadFull(descriptor, buffer.empty() ? delimiter.size() : 1);
if (auto Err = next.takeError())
return std::move(Err);
// Return "" if EOF is encountered.
if (next->empty())
return "";
buffer += *next;
}
return buffer.substr(0, buffer.size() - delimiter.size());
}
/// DAP message format
/// ```
/// Content-Length: (?<length>\d+)\r\n\r\n(?<content>.{\k<length>})
/// ```
static constexpr StringLiteral kHeaderContentLength = "Content-Length: ";
static constexpr StringLiteral kHeaderSeparator = "\r\n\r\n";
namespace lldb_dap {
Transport::Transport(StringRef client_name, std::ofstream *log,
IOObjectSP input, IOObjectSP output)
: m_client_name(client_name), m_log(log), m_input(std::move(input)),
m_output(std::move(output)) {}
Expected<std::optional<Message>> Transport::Read() {
if (!m_input || !m_input->IsValid())
return createStringError("transport output is closed");
IOObject *input = m_input.get();
Expected<std::string> message_header =
ReadFull(*input, kHeaderContentLength.size());
if (!message_header)
return message_header.takeError();
// '' returned on EOF.
if (message_header->empty())
return std::nullopt;
if (*message_header != kHeaderContentLength)
return createStringError(formatv("expected '{0}' and got '{1}'",
kHeaderContentLength, *message_header)
.str());
Expected<std::string> raw_length = ReadUntil(*input, kHeaderSeparator);
if (!raw_length)
return raw_length.takeError();
if (raw_length->empty())
return createStringError("unexpected EOF parsing DAP header");
size_t length;
if (!to_integer(*raw_length, length))
return createStringError(
formatv("invalid content length {0}", *raw_length).str());
Expected<std::string> raw_json = ReadFull(*input, length);
if (!raw_json)
return raw_json.takeError();
// If we got less than the expected number of bytes then we hit EOF.
if (raw_json->length() != length)
return createStringError("unexpected EOF parse DAP message body");
DAP_LOG(m_log, "<-- ({0}) {1}", m_client_name, *raw_json);
return json::parse<Message>(*raw_json);
}
Error Transport::Write(const Message &message) {
if (!m_output || !m_output->IsValid())
return createStringError("transport output is closed");
std::string json = formatv("{0}", toJSON(message)).str();
DAP_LOG(m_log, "--> ({0}) {1}", m_client_name, json);
std::string Output;
raw_string_ostream OS(Output);
OS << kHeaderContentLength << json.length() << kHeaderSeparator << json;
size_t num_bytes = Output.size();
return m_output->Write(Output.data(), num_bytes).takeError();
}
} // end namespace lldb_dap

View File

@ -0,0 +1,61 @@
//===-- Transport.h -------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Debug Adapter Protocol transport layer for encoding and decoding protocol
// messages.
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_TOOLS_LLDB_DAP_TRANSPORT_H
#define LLDB_TOOLS_LLDB_DAP_TRANSPORT_H
#include "Protocol.h"
#include "lldb/lldb-forward.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include <fstream>
#include <optional>
namespace lldb_dap {
/// A transport class that performs the Debug Adapter Protocol communication
/// with the client.
class Transport {
public:
Transport(llvm::StringRef client_name, std::ofstream *log,
lldb::IOObjectSP input, lldb::IOObjectSP output);
~Transport() = default;
/// Transport is not copyable.
/// @{
Transport(const Transport &rhs) = delete;
void operator=(const Transport &rhs) = delete;
/// @}
/// Writes a Debug Adater Protocol message to the output stream.
llvm::Error Write(const protocol::Message &M);
/// Reads the next Debug Adater Protocol message from the input stream.
///
/// \returns Returns the next protocol message or nullopt if EOF is reached.
llvm::Expected<std::optional<protocol::Message>> Read();
/// Returns the name of this transport client, for example `stdin/stdout` or
/// `client_1`.
llvm::StringRef GetClientName() { return m_client_name; }
private:
llvm::StringRef m_client_name;
std::ofstream *m_log;
lldb::IOObjectSP m_input;
lldb::IOObjectSP m_output;
};
} // namespace lldb_dap
#endif

View File

@ -11,6 +11,7 @@
#include "EventHelper.h"
#include "Handler/RequestHandler.h"
#include "RunInTerminal.h"
#include "Transport.h"
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBStream.h"
#include "lldb/Host/Config.h"
@ -325,8 +326,9 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,
std::thread client([=, &dap_sessions_condition, &dap_sessions_mutex,
&dap_sessions]() {
llvm::set_thread_name(client_name + ".runloop");
DAP dap = DAP(client_name, program_path, log, io, io, default_repl_mode,
pre_init_commands);
Transport transport(client_name, log, io, io);
DAP dap(program_path, log, default_repl_mode, pre_init_commands,
transport);
if (auto Err = dap.ConfigureIO()) {
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(),
@ -343,7 +345,8 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,
if (auto Err = dap.Loop()) {
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(),
"DAP session error: ");
"DAP session (" + client_name +
") error: ");
}
DAP_LOG(log, "({0}) client disconnected", client_name);
@ -374,7 +377,7 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,
auto error = dap->Disconnect();
if (error.Fail()) {
client_failed = true;
llvm::errs() << "DAP client " << dap->client_name
llvm::errs() << "DAP client " << dap->transport.GetClientName()
<< " disconnected failed: " << error.GetCString() << "\n";
}
// Close the socket to ensure the DAP::Loop read finishes.
@ -498,9 +501,8 @@ int main(int argc, char *argv[]) {
// Create a memory monitor. This can return nullptr if the host platform is
// not supported.
std::unique_ptr<lldb_private::MemoryMonitor> memory_monitor =
lldb_private::MemoryMonitor::Create([&]() {
if (log)
*log << "memory pressure detected\n";
lldb_private::MemoryMonitor::Create([log = log.get()]() {
DAP_LOG(log, "memory pressure detected");
lldb::SBDebugger::MemoryPressureDetected();
});
@ -565,8 +567,10 @@ int main(int argc, char *argv[]) {
lldb::IOObjectSP output = std::make_shared<NativeFile>(
stdout_fd, File::eOpenOptionWriteOnly, false);
DAP dap = DAP("stdin/stdout", program_path, log.get(), std::move(input),
std::move(output), default_repl_mode, pre_init_commands);
constexpr llvm::StringLiteral client_name = "stdin/stdout";
Transport transport(client_name, log.get(), input, output);
DAP dap(program_path, log.get(), default_repl_mode, pre_init_commands,
transport);
// stdout/stderr redirection to the IDE's console
if (auto Err = dap.ConfigureIO(stdout, stderr)) {
@ -583,7 +587,7 @@ int main(int argc, char *argv[]) {
if (auto Err = dap.Loop()) {
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(),
"DAP session error: ");
"DAP session (" + client_name + ") error: ");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;