Skip to content

Commit a29c5c9

Browse files
committed
[lldb-dap] Correct lldb-dap seq handling.
We've been treating the `seq` attribute incorrectly in lldb-dap. Previously, we always had `seq=0` for events and responses. We only filled in the `seq` field on reverse requests. However, looking at the spec and other DAP implementations, we are supposed to fill in the `seq` field for each request we send to the DAP client. I've updated our usage to fill in `seq` in `DAP::Send` so that all events/requests/responses have a properly filled `seq` value.
1 parent d371417 commit a29c5c9

File tree

7 files changed

+80
-67
lines changed

7 files changed

+80
-67
lines changed

lldb/tools/lldb-dap/DAP.cpp

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -266,40 +266,47 @@ void DAP::SendJSON(const llvm::json::Value &json) {
266266
Send(message);
267267
}
268268

269-
void DAP::Send(const Message &message) {
270-
if (const protocol::Event *event = std::get_if<protocol::Event>(&message)) {
271-
if (llvm::Error err = transport.Send(*event))
269+
Id DAP::Send(const Message &message) {
270+
std::lock_guard<std::mutex> guard(call_mutex);
271+
if (const protocol::Event *e = std::get_if<protocol::Event>(&message)) {
272+
protocol::Event event = *e;
273+
event.seq = seq++;
274+
if (llvm::Error err = transport.Send(event))
272275
DAP_LOG_ERROR(log, std::move(err), "({0}) sending event failed",
273276
m_client_name);
274-
return;
277+
return event.seq;
275278
}
276279

277-
if (const Request *req = std::get_if<Request>(&message)) {
278-
if (llvm::Error err = transport.Send(*req))
280+
if (const Request *r = std::get_if<Request>(&message)) {
281+
Request req = *r;
282+
req.seq = seq++;
283+
if (llvm::Error err = transport.Send(req))
279284
DAP_LOG_ERROR(log, std::move(err), "({0}) sending request failed",
280285
m_client_name);
281-
return;
286+
return req.seq;
282287
}
283288

284-
if (const Response *resp = std::get_if<Response>(&message)) {
289+
if (const Response *r = std::get_if<Response>(&message)) {
290+
Response resp = *r;
291+
resp.seq = seq++;
285292
// FIXME: After all the requests have migrated from LegacyRequestHandler >
286293
// RequestHandler<> this should be handled in RequestHandler<>::operator().
287294
// If the debugger was interrupted, convert this response into a
288295
// 'cancelled' response because we might have a partial result.
289-
llvm::Error err =
290-
(debugger.InterruptRequested())
291-
? transport.Send({/*request_seq=*/resp->request_seq,
292-
/*command=*/resp->command,
293-
/*success=*/false,
294-
/*message=*/eResponseMessageCancelled,
295-
/*body=*/std::nullopt})
296-
: transport.Send(*resp);
297-
if (err) {
296+
llvm::Error err = (debugger.InterruptRequested())
297+
? transport.Send({
298+
/*seq=*/resp.seq,
299+
/*request_seq=*/resp.request_seq,
300+
/*command=*/resp.command,
301+
/*success=*/false,
302+
/*message=*/eResponseMessageCancelled,
303+
/*body=*/std::nullopt,
304+
})
305+
: transport.Send(resp);
306+
if (err)
298307
DAP_LOG_ERROR(log, std::move(err), "({0}) sending response failed",
299308
m_client_name);
300-
return;
301-
}
302-
return;
309+
return resp.seq;
303310
}
304311

305312
llvm_unreachable("Unexpected message type");
@@ -1453,17 +1460,20 @@ void DAP::EventThread() {
14531460
if (remove_module && module_exists) {
14541461
modules.erase(module_id);
14551462
Send(protocol::Event{
1456-
"module", ModuleEventBody{std::move(p_module).value(),
1457-
ModuleEventBody::eReasonRemoved}});
1463+
0, "module",
1464+
ModuleEventBody{std::move(p_module).value(),
1465+
ModuleEventBody::eReasonRemoved}});
14581466
} else if (module_exists) {
14591467
Send(protocol::Event{
1460-
"module", ModuleEventBody{std::move(p_module).value(),
1461-
ModuleEventBody::eReasonChanged}});
1468+
0, "module",
1469+
ModuleEventBody{std::move(p_module).value(),
1470+
ModuleEventBody::eReasonChanged}});
14621471
} else if (!remove_module) {
14631472
modules.insert(module_id);
14641473
Send(protocol::Event{
1465-
"module", ModuleEventBody{std::move(p_module).value(),
1466-
ModuleEventBody::eReasonNew}});
1474+
0, "module",
1475+
ModuleEventBody{std::move(p_module).value(),
1476+
ModuleEventBody::eReasonNew}});
14671477
}
14681478
}
14691479
}

lldb/tools/lldb-dap/DAP.h

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ struct DAP final : public DAPTransport::MessageHandler {
136136
/// unless we send a "thread" event to indicate the thread exited.
137137
llvm::DenseSet<lldb::tid_t> thread_ids;
138138

139-
uint32_t reverse_request_seq = 0;
139+
uint32_t seq = 0;
140140
std::mutex call_mutex;
141141
llvm::SmallDenseMap<int64_t, std::unique_ptr<ResponseHandler>>
142142
inflight_reverse_requests;
@@ -220,8 +220,8 @@ struct DAP final : public DAPTransport::MessageHandler {
220220
/// Serialize the JSON value into a string and send the JSON packet to the
221221
/// "out" stream.
222222
void SendJSON(const llvm::json::Value &json);
223-
/// Send the given message to the client
224-
void Send(const protocol::Message &message);
223+
/// Send the given message to the client.
224+
protocol::Id Send(const protocol::Message &message);
225225

226226
void SendOutput(OutputType o, const llvm::StringRef output);
227227

@@ -353,19 +353,14 @@ struct DAP final : public DAPTransport::MessageHandler {
353353
template <typename Handler>
354354
void SendReverseRequest(llvm::StringRef command,
355355
llvm::json::Value arguments) {
356-
int64_t id;
357-
{
358-
std::lock_guard<std::mutex> locker(call_mutex);
359-
id = ++reverse_request_seq;
360-
inflight_reverse_requests[id] = std::make_unique<Handler>(command, id);
361-
}
362-
363-
SendJSON(llvm::json::Object{
364-
{"type", "request"},
365-
{"seq", id},
366-
{"command", command},
367-
{"arguments", std::move(arguments)},
356+
protocol::Id id = Send(protocol::Request{
357+
0,
358+
command.str(),
359+
std::move(arguments),
368360
});
361+
362+
std::lock_guard<std::mutex> locker(call_mutex);
363+
inflight_reverse_requests[id] = std::make_unique<Handler>(command, id);
369364
}
370365

371366
/// The set of capabilities supported by this adapter.

lldb/tools/lldb-dap/EventHelper.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ void SendExtraCapabilities(DAP &dap) {
7070

7171
// Only notify the client if supportedFeatures changed.
7272
if (!body.capabilities.supportedFeatures.empty())
73-
dap.Send(protocol::Event{"capabilities", std::move(body)});
73+
dap.Send(protocol::Event{0, "capabilities", std::move(body)});
7474
}
7575

7676
// "ProcessEvent": {
@@ -281,7 +281,7 @@ void SendInvalidatedEvent(
281281
return;
282282
protocol::InvalidatedEventBody body;
283283
body.areas = areas;
284-
dap.Send(protocol::Event{"invalidated", std::move(body)});
284+
dap.Send(protocol::Event{0, "invalidated", std::move(body)});
285285
}
286286

287287
void SendMemoryEvent(DAP &dap, lldb::SBValue variable) {
@@ -292,7 +292,7 @@ void SendMemoryEvent(DAP &dap, lldb::SBValue variable) {
292292
body.count = variable.GetByteSize();
293293
if (body.memoryReference == LLDB_INVALID_ADDRESS)
294294
return;
295-
dap.Send(protocol::Event{"memory", std::move(body)});
295+
dap.Send(protocol::Event{0, "memory", std::move(body)});
296296
}
297297

298298
} // namespace lldb_dap

lldb/tools/lldb-dap/Handler/RequestHandler.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
157157
void BaseRequestHandler::Run(const Request &request) {
158158
// If this request was cancelled, send a cancelled response.
159159
if (dap.IsCancelled(request)) {
160-
Response cancelled{/*request_seq=*/request.seq,
160+
Response cancelled{/*seq=*/0,
161+
/*request_seq=*/request.seq,
161162
/*command=*/request.command,
162163
/*success=*/false,
163164
/*message=*/eResponseMessageCancelled,

lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ bool operator==(const Request &a, const Request &b) {
104104

105105
json::Value toJSON(const Response &R) {
106106
json::Object Result{{"type", "response"},
107-
{"seq", 0},
107+
{"seq", R.seq},
108108
{"command", R.command},
109109
{"request_seq", R.request_seq},
110110
{"success", R.success}};
@@ -132,8 +132,9 @@ json::Value toJSON(const Response &R) {
132132
return std::move(Result);
133133
}
134134

135-
bool fromJSON(json::Value const &Params,
136-
std::variant<ResponseMessage, std::string> &M, json::Path P) {
135+
static bool fromJSON(json::Value const &Params,
136+
std::variant<ResponseMessage, std::string> &M,
137+
json::Path P) {
137138
auto rawMessage = Params.getAsString();
138139
if (!rawMessage) {
139140
P.report("expected a string");
@@ -157,8 +158,7 @@ bool fromJSON(json::Value const &Params, Response &R, json::Path P) {
157158
return false;
158159

159160
MessageType type;
160-
int64_t seq;
161-
if (!O.map("type", type) || !O.map("seq", seq) ||
161+
if (!O.map("type", type) || !O.map("seq", R.seq) ||
162162
!O.map("command", R.command) || !O.map("request_seq", R.request_seq))
163163
return false;
164164

@@ -168,12 +168,7 @@ bool fromJSON(json::Value const &Params, Response &R, json::Path P) {
168168
}
169169

170170
if (R.command.empty()) {
171-
P.field("command").report("expected to not be ''");
172-
return false;
173-
}
174-
175-
if (R.request_seq == 0) {
176-
P.field("request_seq").report("expected to not be '0'");
171+
P.field("command").report("expected to not be empty");
177172
return false;
178173
}
179174

@@ -219,7 +214,7 @@ bool fromJSON(json::Value const &Params, ErrorMessage &EM, json::Path P) {
219214
json::Value toJSON(const Event &E) {
220215
json::Object Result{
221216
{"type", "event"},
222-
{"seq", 0},
217+
{"seq", E.seq},
223218
{"event", E.event},
224219
};
225220

@@ -235,22 +230,16 @@ bool fromJSON(json::Value const &Params, Event &E, json::Path P) {
235230
return false;
236231

237232
MessageType type;
238-
int64_t seq;
239-
if (!O.map("type", type) || !O.map("seq", seq) || !O.map("event", E.event))
233+
if (!O.map("type", type) || !O.map("seq", E.seq) || !O.map("event", E.event))
240234
return false;
241235

242236
if (type != eMessageTypeEvent) {
243237
P.field("type").report("expected to be 'event'");
244238
return false;
245239
}
246240

247-
if (seq != 0) {
248-
P.field("seq").report("expected to be '0'");
249-
return false;
250-
}
251-
252241
if (E.event.empty()) {
253-
P.field("event").report("expected to not be ''");
242+
P.field("event").report("expected to not be empty");
254243
return false;
255244
}
256245

lldb/tools/lldb-dap/Protocol/ProtocolBase.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ struct Request {
4141
/// associate requests with their corresponding responses. For protocol
4242
/// messages of type `request` the sequence number can be used to cancel the
4343
/// request.
44-
Id seq;
44+
Id seq = 0;
4545

4646
/// The command to execute.
4747
std::string command;
@@ -58,6 +58,15 @@ bool operator==(const Request &, const Request &);
5858

5959
/// A debug adapter initiated event.
6060
struct Event {
61+
/// Sequence number of the message (also known as message ID). The `seq` for
62+
/// the first message sent by a client or debug adapter is 1, and for each
63+
/// subsequent message is 1 greater than the previous message sent by that
64+
/// actor. `seq` can be used to order requests, responses, and events, and to
65+
/// associate requests with their corresponding responses. For protocol
66+
/// messages of type `request` the sequence number can be used to cancel the
67+
/// request.
68+
Id seq = 0;
69+
6170
/// Type of event.
6271
std::string event;
6372

@@ -77,6 +86,15 @@ enum ResponseMessage : unsigned {
7786

7887
/// Response for a request.
7988
struct Response {
89+
/// Sequence number of the message (also known as message ID). The `seq` for
90+
/// the first message sent by a client or debug adapter is 1, and for each
91+
/// subsequent message is 1 greater than the previous message sent by that
92+
/// actor. `seq` can be used to order requests, responses, and events, and to
93+
/// associate requests with their corresponding responses. For protocol
94+
/// messages of type `request` the sequence number can be used to cancel the
95+
/// request.
96+
Id seq = 0;
97+
8098
/// Sequence number of the corresponding request.
8199
Id request_seq;
82100

lldb/unittests/DAP/DAPTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ using namespace testing;
2121
class DAPTest : public TransportBase {};
2222

2323
TEST_F(DAPTest, SendProtocolMessages) {
24-
dap->Send(Event{/*event=*/"my-event", /*body=*/std::nullopt});
24+
dap->Send(Event{0, /*event=*/"my-event", /*body=*/std::nullopt});
2525
EXPECT_CALL(client, Received(IsEvent("my-event")));
2626
Run();
2727
}

0 commit comments

Comments
 (0)