1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "rawdebugsession.h"
6#include "dap/session.h"
7#include "dap/protocol.h"
8#include "objects.hpp"
9
10#include <QDebug>
11
12namespace dap {
13
14/**
15 * @brief rawDebugSession implimented by original dap
16 * protocol.TODO(mozart):Decide whether to use synchronous
17 * or asynchronous.
18 * @param parent
19 */
20RawDebugSession::RawDebugSession(std::shared_ptr<Session> &_session, QObject *parent)
21 : QObject(parent)
22 , session(_session)
23{
24 initialize();
25}
26
27bool RawDebugSession::initialize()
28{
29 errHandler = [&](const std::string& err){
30 onError(err);
31 };
32 return true;
33}
34
35Promise<InitializeRequest> RawDebugSession::initialize(const InitializeRequest &args)
36{
37 auto response = send(args);
38 auto capabilities = response.get().response;
39 mergeCapabilities(capabilities);
40 return response;
41}
42
43bool RawDebugSession::disconnect(const DisconnectRequest &args)
44{
45 optional<boolean> terminateDebuggee;
46 if (capabilities().supportTerminateDebuggee)
47 terminateDebuggee = args.terminateDebuggee;
48 return shutdown(terminateDebuggee, args.restart);
49}
50
51void RawDebugSession::mergeCapabilities(const InitializeResponse &capabilities)
52{
53 _capabilities = objects::mixin(_capabilities, capabilities);
54}
55
56void RawDebugSession::onError(const std::string& error)
57{
58 qInfo() << "Error :" << error.data();
59}
60
61void RawDebugSession::start()
62{
63 // All the handlers we care about have now been registered.
64 // We now bind the session to stdin and stdout to connect to the client.
65 // After the call to bind() we should start receiving requests, starting with
66 // the Initialize request.
67// std::shared_ptr<dap::Reader> in = dap::file(stdin, false);
68// std::shared_ptr<dap::Writer> out = dap::file(stdout, false);
69
70// // connect to server.
71// session->connect(in, out);
72}
73
74Promise<LaunchRequest> RawDebugSession::launch(const LaunchRequest &request)
75{
76 auto response = send(request);
77 return response;
78}
79
80Promise<AttachRequest> RawDebugSession::attach(const AttachRequest &request)
81{
82 auto response = send(request);
83 return response;
84}
85
86bool RawDebugSession::terminate(bool restart)
87{
88 Q_UNUSED(restart)
89 if (capabilities().supportsTerminateRequest) {
90 TerminateRequest request;
91 auto response = send(request);
92 response.wait();
93 return true;
94 }
95 qInfo() << "terminated not supported";
96 return false;
97}
98
99bool RawDebugSession::restart(const RestartRequest &request)
100{
101 if (_capabilities.supportsRestartRequest) {
102 send(request);
103 return true;
104 }
105 qInfo() << "restart not supported";
106 return false;
107}
108
109Promise<NextRequest> RawDebugSession::next(const NextRequest &request)
110{
111 auto response = send(request);
112 response.wait();
113 // fire notify event.
114 return response;
115}
116
117Promise<StepInRequest> RawDebugSession::stepIn(const StepInRequest &request)
118{
119 auto response = send(request);
120 response.wait();
121 // fire notify event.
122 return response;
123}
124
125Promise<StepOutRequest> RawDebugSession::stepOut(const StepOutRequest &request)
126{
127 auto response = send(request);
128 response.wait();
129 // fire notify event.
130 return response;
131}
132
133Promise<ContinueRequest> RawDebugSession::continueDbg(const ContinueRequest &request)
134{
135 auto response = send(request);
136 response.wait();
137 auto responseBody = response.get().response;
138 if (responseBody.allThreadsContinued.has_value()) {
139 allThreadsContinued = responseBody.allThreadsContinued.value();
140 }
141 // fire event.
142
143 return response;
144}
145
146Promise<PauseRequest> RawDebugSession::pause(const PauseRequest &request)
147{
148 auto response = send(request);
149 return response;
150}
151
152Promise<TerminateThreadsRequest> RawDebugSession::terminateThreads(const TerminateThreadsRequest &request)
153{
154 if (_capabilities.supportsTerminateThreadsRequest) {
155 return send(request);
156 }
157 qInfo() << "terminateThreads not supported";
158 return {};
159}
160
161Promise<SetVariableRequest> RawDebugSession::setVariable(const SetVariableRequest &request)
162{
163 if (_capabilities.supportsSetVariable) {
164 return send(request);
165 }
166 qInfo() << "supportsSetVariable not supported";
167 return {};
168}
169
170Promise<SetExpressionRequest> RawDebugSession::setExpression(const SetExpressionRequest &request)
171{
172 if (_capabilities.supportsSetExpression) {
173 return send(request);
174 }
175 qInfo() << "supportsSetExpression not supported";
176 return {};
177}
178
179Promise<RestartFrameRequest> RawDebugSession::restartFrame(const RestartFrameRequest &request)
180{
181 if (_capabilities.supportsRestartFrame) {
182 auto response = send(request);
183 response.wait();
184 return response;
185 }
186 qInfo() << "supportsRestartFrame not supported";
187 return {};
188}
189
190Promise<StepInTargetsRequest> RawDebugSession::stepInTargets(const StepInTargetsRequest &request)
191{
192 if (_capabilities.supportsStepInTargetsRequest) {
193 return send(request);
194 }
195 qInfo() << "supportsStepInTargetsRequest not supported";
196 return {};
197}
198
199Promise<CompletionsRequest> RawDebugSession::completions(const CompletionsRequest &request)
200{
201 if (_capabilities.supportsCompletionsRequest) {
202 return send(request);
203 }
204 qInfo() << "supportsCompletionsRequest not supported";
205 return {};
206}
207
208Promise<SetBreakpointsRequest> RawDebugSession::setBreakpoints(const SetBreakpointsRequest &request)
209{
210 return send(request);
211}
212
213Promise<SetFunctionBreakpointsRequest> RawDebugSession::setFunctionBreakpoints(
214 const SetFunctionBreakpointsRequest &request)
215{
216 if (_capabilities.supportsFunctionBreakpoints) {
217 return send(request);
218 }
219 qInfo() << "supportsFunctionBreakpoints not supported";
220 return {};
221}
222
223Promise<DataBreakpointInfoRequest> RawDebugSession::dataBreakpointInfo(const DataBreakpointInfoRequest &request)
224{
225 if (_capabilities.supportsDataBreakpoints) {
226 return send(request);
227 }
228 qInfo() << "supportsDataBreakpoints not supported";
229 return {};
230}
231
232Promise<SetDataBreakpointsRequest> RawDebugSession::setDataBreakpoints(const SetDataBreakpointsRequest &request)
233{
234 if (_capabilities.supportsDataBreakpoints) {
235 return send(request);
236 }
237 qInfo() << "supportsDataBreakpoints not supported";
238 return {};
239}
240
241Promise<SetExceptionBreakpointsRequest> RawDebugSession::setExceptionBreakpoints(
242 const SetExceptionBreakpointsRequest &request)
243{
244 return send(request);
245}
246
247Promise<BreakpointLocationsRequest> RawDebugSession::breakpointLocations(const BreakpointLocationsRequest &request)
248{
249 if (_capabilities.supportsBreakpointLocationsRequest) {
250 return send(request);
251 }
252 qInfo() << "supportsBreakpointLocationsRequest not supported";
253 return {};
254}
255
256Promise<ConfigurationDoneRequest> RawDebugSession::configurationDone()
257{
258 if (_capabilities.supportsConfigurationDoneRequest)
259 return send(ConfigurationDoneRequest());
260 qInfo() << "supportsConfigurationDoneRequest not supported";
261 return {};
262}
263
264Promise<StackTraceRequest> RawDebugSession::stackTrace(const StackTraceRequest &request)
265{
266 return send(request);
267}
268
269Promise<ExceptionInfoRequest> RawDebugSession::exceptionInfo(const ExceptionInfoRequest &request)
270{
271 if (_capabilities.supportsExceptionInfoRequest) {
272 return send(request);
273 }
274 qInfo() << "supportsExceptionInfoRequest not supported";
275 return {};
276}
277
278Promise<ScopesRequest> RawDebugSession::scopes(const ScopesRequest &request)
279{
280 return send(request);
281}
282
283Promise<VariablesRequest> RawDebugSession::variables(const VariablesRequest &request)
284{
285 return send(request);
286}
287
288Promise<SourceRequest> RawDebugSession::source(const SourceRequest &request)
289{
290 return send(request);
291}
292
293Promise<LoadedSourcesRequest> RawDebugSession::loadedSources(const LoadedSourcesRequest &request)
294{
295 if (_capabilities.supportsLoadedSourcesRequest) {
296 return send(request);
297 }
298 qInfo() << "supportsLoadedSourcesRequest not supported";
299 return {};
300}
301
302Promise<ThreadsRequest> RawDebugSession::threads()
303{
304 ThreadsRequest request;
305 return send(request);
306}
307
308Promise<EvaluateRequest> RawDebugSession::evaluate(const EvaluateRequest &request)
309{
310 return send(request);
311}
312
313Promise<StepBackRequest> RawDebugSession::stepBack(const StepBackRequest &request)
314{
315 if (_capabilities.supportsStepBack) {
316 auto response = send(request);
317 response.wait();
318 // fire event.
319 return response;
320 }
321 qInfo() << "supportsStepBack not supported";
322 return {};
323}
324
325Promise<ReverseContinueRequest> RawDebugSession::reverseContinue(const ReverseContinueRequest &request)
326{
327 if (_capabilities.supportsStepBack) {
328 auto response = send(request);
329 response.wait();
330 // fire event.
331 return response;
332 }
333 qInfo() << "supportsStepBack not supported";
334 return {};
335}
336
337Promise<GotoTargetsRequest> RawDebugSession::gotoTargets(const GotoTargetsRequest &request)
338{
339 if (_capabilities.supportsGotoTargetsRequest) {
340 return send(request);
341 }
342 qInfo() << "supportsGotoTargetsRequest not supported";
343 return {};
344}
345
346Promise<GotoRequest> RawDebugSession::goto_(const GotoRequest &request)
347{
348 if (_capabilities.supportsGotoTargetsRequest) {
349 auto response = send(request);
350 response.wait();
351 // fire event.
352 return response;
353 }
354 qInfo() << "supportsGotoTargetsRequest not supported";
355 return {};
356}
357
358Promise<SetInstructionBreakpointsRequest> RawDebugSession::setInstructionBreakpoints(const SetInstructionBreakpointsRequest &request)
359{
360 if (_capabilities.supportsInstructionBreakpoints) {
361 auto response = send(request);
362 response.wait();
363 // fire event.
364 return response;
365 }
366 qInfo() << "supportsInstructionBreakpoints not supported";
367 return {};
368}
369
370Promise<DisassembleRequest> RawDebugSession::disassemble(const DisassembleRequest &request)
371{
372 if (_capabilities.supportsDisassembleRequest) {
373 auto response = send(request);
374 response.wait();
375 // fire event.
376 return response;
377 }
378 qInfo() << "supportsDisassembleRequest not supported";
379 return {};
380}
381
382Promise<CancelRequest> RawDebugSession::cancel(const CancelRequest &request)
383{
384 return send(request);
385}
386
387const Capabilities &RawDebugSession::capabilities() const
388{
389 return _capabilities;
390}
391
392bool RawDebugSession::shutdown(optional<boolean> terminateDebuggee, optional<boolean> restart)
393{
394 if (!inShutdown) {
395 inShutdown = true;
396 DisconnectRequest request;
397 request.restart = restart;
398 request.terminateDebuggee = terminateDebuggee;
399 syncSend(request);
400 }
401 return true;
402}
403
404bool RawDebugSession::readyForBreakpoints() const
405{
406 return _readyForBreakpoints;
407}
408
409void RawDebugSession::setReadyForBreakpoints(bool bReady)
410{
411 _readyForBreakpoints = bReady;
412}
413
414void RawDebugSession::registerHandlers()
415{
416 /*
417 * Register events.
418 */
419
420 // The event indicates that one or more capabilities have changed.
421 session->registerHandler([&](const CapabilitiesEvent &event){
422 _capabilities = objects::mixin(_capabilities, event.capabilities);
423 qInfo() << "\n--> recv : " << "CapabilitiesEvent";
424 });
425
426 // The event indicates that the execution of the debuggee has continued.
427 session->registerHandler([&](const ContinuedEvent &event){
428 allThreadsContinued = event.allThreadsContinued.value();
429 Q_UNUSED(event)
430 qInfo() << "\n--> recv : " << "ContinuedEvent";
431 });
432}
433
434template<typename REQUEST, typename RESPONSE>
435bool RawDebugSession::send(const REQUEST &request, RESPONSE *res)
436{
437 auto r = session->send(request).get();
438 if (r.error) {
439 errHandler(r.error.message);
440 return false;
441 }
442 *res = r.response;
443 return true;
444}
445
446template<typename REQUEST>
447bool RawDebugSession::syncSend(const REQUEST &request)
448{
449 using RESPONSE = typename REQUEST::Response;
450 RESPONSE response;
451 return send(request, &response);
452}
453
454template<typename REQUEST>
455Promise<REQUEST> RawDebugSession::send(const REQUEST &request)
456{
457 return session->send(request);
458}
459} // end namespace.
460