Skip to content

Commit 397c479

Browse files
committed
[lldb-dap] Creating a dedicated Transport mechnaism for handling protocol communication.
This removes the previous 'OutputStream' and 'InputStream' objects and the new 'Transport' class takes on the responsibility of seriliaizing and encoding messages. The new Protocol.h file has a dedicated namespace for POD style structures to represent the Debug Adapter Protocol messages.
1 parent 26ac742 commit 397c479

File tree

12 files changed

+667
-228
lines changed

12 files changed

+667
-228
lines changed

lldb/tools/lldb-dap/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,20 @@ add_lldb_tool(lldb-dap
2323
Breakpoint.cpp
2424
BreakpointBase.cpp
2525
DAP.cpp
26+
DAPLog.cpp
2627
EventHelper.cpp
2728
ExceptionBreakpoint.cpp
2829
FifoFiles.cpp
2930
FunctionBreakpoint.cpp
3031
InstructionBreakpoint.cpp
31-
IOStream.cpp
3232
JSONUtils.cpp
3333
LLDBUtils.cpp
3434
OutputRedirector.cpp
3535
ProgressEvent.cpp
3636
RunInTerminal.cpp
3737
SourceBreakpoint.cpp
38+
Transport.cpp
39+
Protocol.cpp
3840
Watchpoint.cpp
3941

4042
Handler/ResponseHandler.cpp

lldb/tools/lldb-dap/DAP.cpp

Lines changed: 32 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "DAP.h"
10+
#include "DAPLog.h"
1011
#include "Handler/ResponseHandler.h"
1112
#include "JSONUtils.h"
1213
#include "LLDBUtils.h"
1314
#include "OutputRedirector.h"
15+
#include "Protocol.h"
1416
#include "lldb/API/SBBreakpoint.h"
1517
#include "lldb/API/SBCommandInterpreter.h"
1618
#include "lldb/API/SBCommandReturnObject.h"
@@ -29,6 +31,7 @@
2931
#include "llvm/Support/Error.h"
3032
#include "llvm/Support/ErrorHandling.h"
3133
#include "llvm/Support/FormatVariadic.h"
34+
#include "llvm/Support/JSON.h"
3235
#include "llvm/Support/raw_ostream.h"
3336
#include <algorithm>
3437
#include <cassert>
@@ -50,6 +53,7 @@
5053
#endif
5154

5255
using namespace lldb_dap;
56+
using namespace lldb_private;
5357

5458
namespace {
5559
#ifdef _WIN32
@@ -61,11 +65,11 @@ const char DEV_NULL[] = "/dev/null";
6165

6266
namespace lldb_dap {
6367

64-
DAP::DAP(std::string name, llvm::StringRef path, std::ofstream *log,
68+
DAP::DAP(llvm::StringRef name, llvm::StringRef path, std::ofstream *log,
6569
lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode,
6670
std::vector<std::string> pre_init_commands)
67-
: name(std::move(name)), debug_adaptor_path(path), log(log),
68-
input(std::move(input)), output(std::move(output)),
71+
: name(name), debug_adaptor_path(path), log(log),
72+
transport(name, std::move(input), std::move(output)),
6973
broadcaster("lldb-dap"), exception_breakpoints(),
7074
pre_init_commands(std::move(pre_init_commands)),
7175
focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false),
@@ -237,65 +241,22 @@ void DAP::StopEventHandlers() {
237241
}
238242
}
239243

240-
// Send the JSON in "json_str" to the "out" stream. Correctly send the
241-
// "Content-Length:" field followed by the length, followed by the raw
242-
// JSON bytes.
243-
void DAP::SendJSON(const std::string &json_str) {
244-
output.write_full("Content-Length: ");
245-
output.write_full(llvm::utostr(json_str.size()));
246-
output.write_full("\r\n\r\n");
247-
output.write_full(json_str);
248-
}
249-
250244
// Serialize the JSON value into a string and send the JSON packet to
251245
// the "out" stream.
252246
void DAP::SendJSON(const llvm::json::Value &json) {
253-
std::string json_str;
254-
llvm::raw_string_ostream strm(json_str);
255-
strm << json;
256-
static std::mutex mutex;
257-
std::lock_guard<std::mutex> locker(mutex);
258-
SendJSON(json_str);
259-
260-
if (log) {
261-
auto now = std::chrono::duration<double>(
262-
std::chrono::system_clock::now().time_since_epoch());
263-
*log << llvm::formatv("{0:f9} {1} <-- ", now.count(), name).str()
264-
<< std::endl
265-
<< "Content-Length: " << json_str.size() << "\r\n\r\n"
266-
<< llvm::formatv("{0:2}", json).str() << std::endl;
267-
}
268-
}
269-
270-
// Read a JSON packet from the "in" stream.
271-
std::string DAP::ReadJSON() {
272-
std::string length_str;
273-
std::string json_str;
274-
int length;
275-
276-
if (!input.read_expected(log, "Content-Length: "))
277-
return json_str;
278-
279-
if (!input.read_line(log, length_str))
280-
return json_str;
281-
282-
if (!llvm::to_integer(length_str, length))
283-
return json_str;
284-
285-
if (!input.read_expected(log, "\r\n"))
286-
return json_str;
287-
288-
if (!input.read_full(log, length, json_str))
289-
return json_str;
290-
291-
if (log) {
292-
auto now = std::chrono::duration<double>(
293-
std::chrono::system_clock::now().time_since_epoch());
294-
*log << llvm::formatv("{0:f9} {1} --> ", now.count(), name).str()
295-
<< std::endl
296-
<< "Content-Length: " << length << "\r\n\r\n";
247+
protocol::ProtocolMessage M;
248+
llvm::json::Path::Root root;
249+
if (!protocol::fromJSON(json, M, root)) {
250+
if (log) {
251+
std::string error;
252+
llvm::raw_string_ostream OS(error);
253+
root.printErrorContext(json, OS);
254+
*log << "encoding failure: " << error << "\n";
255+
}
297256
}
298-
return json_str;
257+
auto status = transport.Write(M);
258+
if (status.Fail() && log)
259+
*log << "transport failure: " << status.AsCString() << "\n";
299260
}
300261

301262
// "OutputEvent": {
@@ -720,40 +681,13 @@ void DAP::SetTarget(const lldb::SBTarget target) {
720681
}
721682
}
722683

723-
PacketStatus DAP::GetNextObject(llvm::json::Object &object) {
724-
std::string json = ReadJSON();
725-
if (json.empty())
726-
return PacketStatus::EndOfFile;
727-
728-
llvm::StringRef json_sref(json);
729-
llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref);
730-
if (!json_value) {
731-
auto error = json_value.takeError();
732-
if (log) {
733-
std::string error_str;
734-
llvm::raw_string_ostream strm(error_str);
735-
strm << error;
736-
*log << "error: failed to parse JSON: " << error_str << std::endl
737-
<< json << std::endl;
738-
}
739-
return PacketStatus::JSONMalformed;
740-
}
741-
742-
if (log) {
743-
*log << llvm::formatv("{0:2}", *json_value).str() << std::endl;
744-
}
745-
746-
llvm::json::Object *object_ptr = json_value->getAsObject();
747-
if (!object_ptr) {
748-
if (log)
749-
*log << "error: json packet isn't a object" << std::endl;
750-
return PacketStatus::JSONNotObject;
751-
}
752-
object = *object_ptr;
753-
return PacketStatus::Success;
684+
llvm::Expected<protocol::ProtocolMessage> DAP::GetNextObject() {
685+
return transport.Read();
754686
}
755687

756-
bool DAP::HandleObject(const llvm::json::Object &object) {
688+
bool DAP::HandleObject(const protocol::ProtocolMessage &M) {
689+
llvm::json::Value v = toJSON(M);
690+
llvm::json::Object object = *v.getAsObject();
757691
const auto packet_type = GetString(object, "type");
758692
if (packet_type == "request") {
759693
const auto command = GetString(object, "command");
@@ -764,9 +698,8 @@ bool DAP::HandleObject(const llvm::json::Object &object) {
764698
return true; // Success
765699
}
766700

767-
if (log)
768-
*log << "error: unhandled command \"" << command.data() << "\""
769-
<< std::endl;
701+
LLDB_LOG(GetLog(DAPLog::Protocol), "Unhandled command {0}", command);
702+
770703
return false; // Fail
771704
}
772705

@@ -805,6 +738,8 @@ bool DAP::HandleObject(const llvm::json::Object &object) {
805738
return true;
806739
}
807740

741+
LLDB_LOG(GetLog(DAPLog::Protocol), "Unsupported protocol message");
742+
808743
return false;
809744
}
810745

@@ -858,19 +793,13 @@ lldb::SBError DAP::Disconnect(bool terminateDebuggee) {
858793
llvm::Error DAP::Loop() {
859794
auto cleanup = llvm::make_scope_exit([this]() { StopEventHandlers(); });
860795
while (!disconnecting) {
861-
llvm::json::Object object;
862-
lldb_dap::PacketStatus status = GetNextObject(object);
863-
864-
if (status == lldb_dap::PacketStatus::EndOfFile) {
865-
break;
866-
}
796+
auto next = GetNextObject();
867797

868-
if (status != lldb_dap::PacketStatus::Success) {
869-
return llvm::createStringError(llvm::inconvertibleErrorCode(),
870-
"failed to send packet");
798+
if (!next) {
799+
return next.takeError();
871800
}
872801

873-
if (!HandleObject(object)) {
802+
if (!HandleObject(*next)) {
874803
return llvm::createStringError(llvm::inconvertibleErrorCode(),
875804
"unhandled packet");
876805
}

lldb/tools/lldb-dap/DAP.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414
#include "FunctionBreakpoint.h"
1515
#include "Handler/RequestHandler.h"
1616
#include "Handler/ResponseHandler.h"
17-
#include "IOStream.h"
1817
#include "InstructionBreakpoint.h"
1918
#include "OutputRedirector.h"
2019
#include "ProgressEvent.h"
20+
#include "Protocol.h"
2121
#include "SourceBreakpoint.h"
22+
#include "Transport.h"
2223
#include "lldb/API/SBBroadcaster.h"
2324
#include "lldb/API/SBCommandInterpreter.h"
2425
#include "lldb/API/SBDebugger.h"
@@ -39,6 +40,7 @@
3940
#include "llvm/Support/Error.h"
4041
#include "llvm/Support/JSON.h"
4142
#include "llvm/Support/Threading.h"
43+
#include <fstream>
4244
#include <map>
4345
#include <memory>
4446
#include <mutex>
@@ -145,11 +147,10 @@ struct SendEventRequestHandler : public lldb::SBCommandPluginInterface {
145147
};
146148

147149
struct DAP {
148-
std::string name;
150+
llvm::StringRef name;
149151
llvm::StringRef debug_adaptor_path;
150152
std::ofstream *log;
151-
InputStream input;
152-
OutputStream output;
153+
Transport transport;
153154
lldb::SBFile in;
154155
OutputRedirector out;
155156
OutputRedirector err;
@@ -210,7 +211,7 @@ struct DAP {
210211
// will contain that expression.
211212
std::string last_nonempty_var_expression;
212213

213-
DAP(std::string name, llvm::StringRef path, std::ofstream *log,
214+
DAP(llvm::StringRef name, llvm::StringRef path, std::ofstream *log,
214215
lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode,
215216
std::vector<std::string> pre_init_commands);
216217
~DAP();
@@ -233,8 +234,6 @@ struct DAP {
233234
// the "out" stream.
234235
void SendJSON(const llvm::json::Value &json);
235236

236-
std::string ReadJSON();
237-
238237
void SendOutput(OutputType o, const llvm::StringRef output);
239238

240239
void SendProgressEvent(uint64_t progress_id, const char *message,
@@ -307,8 +306,8 @@ struct DAP {
307306
/// listeing for its breakpoint events.
308307
void SetTarget(const lldb::SBTarget target);
309308

310-
PacketStatus GetNextObject(llvm::json::Object &object);
311-
bool HandleObject(const llvm::json::Object &object);
309+
llvm::Expected<protocol::ProtocolMessage> GetNextObject();
310+
bool HandleObject(const protocol::ProtocolMessage &);
312311

313312
/// Disconnect the DAP session.
314313
lldb::SBError Disconnect();

lldb/tools/lldb-dap/DAPLog.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include "DAPLog.h"
2+
3+
using namespace lldb_private;
4+
using namespace lldb_dap;
5+
6+
static constexpr Log::Category g_categories[] = {
7+
{{"transport"}, {"log DAP transport"}, DAPLog::Transport},
8+
{{"protocol"}, {"log protocol handling"}, DAPLog::Protocol},
9+
};
10+
11+
static Log::Channel g_log_channel(g_categories,
12+
DAPLog::Transport | DAPLog::Protocol);
13+
14+
template <> Log::Channel &lldb_private::LogChannelFor<DAPLog>() {
15+
return g_log_channel;
16+
}
17+
18+
void lldb_dap::InitializeDAPChannel() {
19+
Log::Register("lldb-dap", g_log_channel);
20+
}

lldb/tools/lldb-dap/DAPLog.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===-- DAPLog.h ------------------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_UTILITY_LLDBLOG_H
10+
#define LLDB_UTILITY_LLDBLOG_H
11+
12+
#include "lldb/Utility/Log.h"
13+
#include "llvm/ADT/BitmaskEnum.h"
14+
15+
namespace lldb_dap {
16+
17+
enum class DAPLog : lldb_private::Log::MaskType {
18+
Transport = lldb_private::Log::ChannelFlag<0>,
19+
Protocol = lldb_private::Log::ChannelFlag<1>,
20+
LLVM_MARK_AS_BITMASK_ENUM(Protocol),
21+
};
22+
23+
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
24+
25+
void InitializeDAPChannel();
26+
27+
} // end namespace lldb_dap
28+
29+
namespace lldb_private {
30+
template <> lldb_private::Log::Channel &LogChannelFor<lldb_dap::DAPLog>();
31+
} // namespace lldb_private
32+
33+
#endif

0 commit comments

Comments
 (0)