Skip to content

Commit 66af492

Browse files
authored
[lldb-dap] Refactor reverse request response handlers (NFC) (llvm#128594)
This refactors the response handlers for reverse request to follow the same architecture as the request handlers. With only two implementation that might be overkill, but it reduces code duplication and improves error reporting by storing the sequence ID. This PR also fixes an unchecked Expected in the old callback for unknown sequence IDs.
1 parent ab0e6fc commit 66af492

File tree

6 files changed

+124
-50
lines changed

6 files changed

+124
-50
lines changed

lldb/tools/lldb-dap/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ add_lldb_tool(lldb-dap
3737
SourceBreakpoint.cpp
3838
Watchpoint.cpp
3939

40+
Handler/ResponseHandler.cpp
4041
Handler/AttachRequestHandler.cpp
4142
Handler/BreakpointLocationsHandler.cpp
4243
Handler/CompileUnitsRequestHandler.cpp

lldb/tools/lldb-dap/DAP.cpp

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

99
#include "DAP.h"
10+
#include "Handler/ResponseHandler.h"
1011
#include "JSONUtils.h"
1112
#include "LLDBUtils.h"
1213
#include "OutputRedirector.h"
@@ -34,6 +35,7 @@
3435
#include <cstdarg>
3536
#include <cstdio>
3637
#include <fstream>
38+
#include <memory>
3739
#include <mutex>
3840
#include <utility>
3941

@@ -769,10 +771,8 @@ bool DAP::HandleObject(const llvm::json::Object &object) {
769771

770772
if (packet_type == "response") {
771773
auto id = GetSigned(object, "request_seq", 0);
772-
ResponseCallback response_handler = [](llvm::Expected<llvm::json::Value>) {
773-
llvm::errs() << "Unhandled response\n";
774-
};
775774

775+
std::unique_ptr<ResponseHandler> response_handler;
776776
{
777777
std::lock_guard<std::mutex> locker(call_mutex);
778778
auto inflight = inflight_reverse_requests.find(id);
@@ -782,19 +782,22 @@ bool DAP::HandleObject(const llvm::json::Object &object) {
782782
}
783783
}
784784

785+
if (!response_handler)
786+
response_handler = std::make_unique<UnknownResponseHandler>("", id);
787+
785788
// Result should be given, use null if not.
786789
if (GetBoolean(object, "success", false)) {
787790
llvm::json::Value Result = nullptr;
788791
if (auto *B = object.get("body")) {
789792
Result = std::move(*B);
790793
}
791-
response_handler(Result);
794+
(*response_handler)(Result);
792795
} else {
793796
llvm::StringRef message = GetString(object, "message");
794797
if (message.empty()) {
795798
message = "Unknown error, response failed";
796799
}
797-
response_handler(llvm::createStringError(
800+
(*response_handler)(llvm::createStringError(
798801
std::error_code(-1, std::generic_category()), message));
799802
}
800803

@@ -875,24 +878,6 @@ llvm::Error DAP::Loop() {
875878
return llvm::Error::success();
876879
}
877880

878-
void DAP::SendReverseRequest(llvm::StringRef command,
879-
llvm::json::Value arguments,
880-
ResponseCallback callback) {
881-
int64_t id;
882-
{
883-
std::lock_guard<std::mutex> locker(call_mutex);
884-
id = ++reverse_request_seq;
885-
inflight_reverse_requests.emplace(id, std::move(callback));
886-
}
887-
888-
SendJSON(llvm::json::Object{
889-
{"type", "request"},
890-
{"seq", id},
891-
{"command", command},
892-
{"arguments", std::move(arguments)},
893-
});
894-
}
895-
896881
lldb::SBError DAP::WaitForProcessToStop(uint32_t seconds) {
897882
lldb::SBError error;
898883
lldb::SBProcess process = target.GetProcess();
@@ -1007,17 +992,10 @@ bool StartDebuggingRequestHandler::DoExecute(
1007992
return false;
1008993
}
1009994

1010-
dap.SendReverseRequest(
995+
dap.SendReverseRequest<LogFailureResponseHandler>(
1011996
"startDebugging",
1012997
llvm::json::Object{{"request", request},
1013-
{"configuration", std::move(*configuration)}},
1014-
[](llvm::Expected<llvm::json::Value> value) {
1015-
if (!value) {
1016-
llvm::Error err = value.takeError();
1017-
llvm::errs() << "reverse start debugging request failed: "
1018-
<< llvm::toString(std::move(err)) << "\n";
1019-
}
1020-
});
998+
{"configuration", std::move(*configuration)}});
1021999

10221000
result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
10231001

lldb/tools/lldb-dap/DAP.h

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "ExceptionBreakpoint.h"
1414
#include "FunctionBreakpoint.h"
1515
#include "Handler/RequestHandler.h"
16+
#include "Handler/ResponseHandler.h"
1617
#include "IOStream.h"
1718
#include "InstructionBreakpoint.h"
1819
#include "OutputRedirector.h"
@@ -68,8 +69,6 @@ enum DAPBroadcasterBits {
6869
eBroadcastBitStopProgressThread = 1u << 1
6970
};
7071

71-
typedef void (*ResponseCallback)(llvm::Expected<llvm::json::Value> value);
72-
7372
enum class PacketStatus {
7473
Success = 0,
7574
EndOfFile,
@@ -197,7 +196,7 @@ struct DAP {
197196
llvm::DenseSet<lldb::tid_t> thread_ids;
198197
uint32_t reverse_request_seq;
199198
std::mutex call_mutex;
200-
std::map<int /* request_seq */, ResponseCallback /* reply handler */>
199+
llvm::SmallDenseMap<int64_t, std::unique_ptr<ResponseHandler>>
201200
inflight_reverse_requests;
202201
ReplMode repl_mode;
203202
std::string command_escape_prefix = "`";
@@ -327,12 +326,24 @@ struct DAP {
327326
/// The reverse request command.
328327
///
329328
/// \param[in] arguments
330-
/// The reverse request arguements.
331-
///
332-
/// \param[in] callback
333-
/// A callback to execute when the response arrives.
334-
void SendReverseRequest(llvm::StringRef command, llvm::json::Value arguments,
335-
ResponseCallback callback);
329+
/// The reverse request arguments.
330+
template <typename Handler>
331+
void SendReverseRequest(llvm::StringRef command,
332+
llvm::json::Value arguments) {
333+
int64_t id;
334+
{
335+
std::lock_guard<std::mutex> locker(call_mutex);
336+
id = ++reverse_request_seq;
337+
inflight_reverse_requests[id] = std::make_unique<Handler>(command, id);
338+
}
339+
340+
SendJSON(llvm::json::Object{
341+
{"type", "request"},
342+
{"seq", id},
343+
{"command", command},
344+
{"arguments", std::move(arguments)},
345+
});
346+
}
336347

337348
/// Registers a request handler.
338349
template <typename Handler> void RegisterRequest() {

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

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,8 @@ static llvm::Error RunInTerminal(DAP &dap,
101101
#endif
102102
llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
103103
launch_request, dap.debug_adaptor_path, comm_file.m_path, debugger_pid);
104-
dap.SendReverseRequest("runInTerminal", std::move(reverse_request),
105-
[](llvm::Expected<llvm::json::Value> value) {
106-
if (!value) {
107-
llvm::Error err = value.takeError();
108-
llvm::errs()
109-
<< "runInTerminal request failed: "
110-
<< llvm::toString(std::move(err)) << "\n";
111-
}
112-
});
104+
dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal",
105+
std::move(reverse_request));
113106

114107
if (llvm::Expected<lldb::pid_t> pid = comm_channel.GetLauncherPid())
115108
attach_info.SetProcessID(*pid);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===-- ResponseHandler.cpp -----------------------------------------------===//
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+
#include "ResponseHandler.h"
10+
#include "llvm/ADT/StringRef.h"
11+
#include "llvm/Support/Error.h"
12+
#include "llvm/Support/raw_ostream.h"
13+
14+
namespace lldb_dap {
15+
16+
void UnknownResponseHandler::operator()(
17+
llvm::Expected<llvm::json::Value> value) const {
18+
llvm::errs() << "unexpected response: ";
19+
if (value) {
20+
if (std::optional<llvm::StringRef> str = value->getAsString())
21+
llvm::errs() << *str;
22+
} else {
23+
llvm::errs() << "error: " << llvm::toString(value.takeError());
24+
}
25+
llvm::errs() << '\n';
26+
}
27+
28+
void LogFailureResponseHandler::operator()(
29+
llvm::Expected<llvm::json::Value> value) const {
30+
if (!value)
31+
llvm::errs() << "reverse request \"" << m_command << "\" (" << m_id
32+
<< ") failed: " << llvm::toString(value.takeError()) << '\n';
33+
}
34+
35+
} // namespace lldb_dap
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//===-- ResponseHandler.h -------------------------------------------------===//
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_TOOLS_LLDB_DAP_HANDLER_RESPONSEHANDLER_H
10+
#define LLDB_TOOLS_LLDB_DAP_HANDLER_RESPONSEHANDLER_H
11+
12+
#include "llvm/ADT/StringRef.h"
13+
#include "llvm/Support/JSON.h"
14+
#include <cstdint>
15+
16+
namespace lldb_dap {
17+
struct DAP;
18+
19+
/// Handler for responses to reverse requests.
20+
class ResponseHandler {
21+
public:
22+
ResponseHandler(llvm::StringRef command, int64_t id)
23+
: m_command(command), m_id(id) {}
24+
25+
/// ResponseHandlers are not copyable.
26+
/// @{
27+
ResponseHandler(const ResponseHandler &) = delete;
28+
ResponseHandler &operator=(const ResponseHandler &) = delete;
29+
/// @}
30+
31+
virtual ~ResponseHandler() = default;
32+
33+
virtual void operator()(llvm::Expected<llvm::json::Value> value) const = 0;
34+
35+
protected:
36+
llvm::StringRef m_command;
37+
int64_t m_id;
38+
};
39+
40+
/// Response handler used for unknown responses.
41+
class UnknownResponseHandler : public ResponseHandler {
42+
public:
43+
using ResponseHandler::ResponseHandler;
44+
void operator()(llvm::Expected<llvm::json::Value> value) const override;
45+
};
46+
47+
/// Response handler which logs to stderr in case of a failure.
48+
class LogFailureResponseHandler : public ResponseHandler {
49+
public:
50+
using ResponseHandler::ResponseHandler;
51+
void operator()(llvm::Expected<llvm::json::Value> value) const override;
52+
};
53+
54+
} // namespace lldb_dap
55+
56+
#endif

0 commit comments

Comments
 (0)