1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "tooling/dynamic/client/domain/debugger_client.h"
17
18 #include "tooling/dynamic/client/session/session.h"
19
20 using PtJson = panda::ecmascript::tooling::PtJson;
21 namespace OHOS::ArkCompiler::Toolchain {
DispatcherCmd(const std::string & cmd)22 bool DebuggerClient::DispatcherCmd(const std::string &cmd)
23 {
24 std::map<std::string, std::function<int()>> dispatcherTable {
25 { "break", std::bind(&DebuggerClient::BreakCommand, this)},
26 { "backtrack", std::bind(&DebuggerClient::BacktrackCommand, this)},
27 { "continue", std::bind(&DebuggerClient::ResumeCommand, this)},
28 { "delete", std::bind(&DebuggerClient::DeleteCommand, this)},
29 { "jump", std::bind(&DebuggerClient::JumpCommand, this)},
30 { "disable", std::bind(&DebuggerClient::DisableCommand, this)},
31 { "display", std::bind(&DebuggerClient::DisplayCommand, this)},
32 { "enable", std::bind(&DebuggerClient::EnableCommand, this)},
33 { "finish", std::bind(&DebuggerClient::FinishCommand, this)},
34 { "frame", std::bind(&DebuggerClient::FrameCommand, this)},
35 { "ignore", std::bind(&DebuggerClient::IgnoreCommand, this)},
36 { "infobreakpoints", std::bind(&DebuggerClient::InfobreakpointsCommand, this)},
37 { "infosource", std::bind(&DebuggerClient::InfosourceCommand, this)},
38 { "list", std::bind(&DebuggerClient::ListCommand, this)},
39 { "next", std::bind(&DebuggerClient::NextCommand, this)},
40 { "ptype", std::bind(&DebuggerClient::PtypeCommand, this)},
41 { "run", std::bind(&DebuggerClient::RunCommand, this)},
42 { "setvar", std::bind(&DebuggerClient::SetvarCommand, this)},
43 { "step", std::bind(&DebuggerClient::StepCommand, this)},
44 { "undisplay", std::bind(&DebuggerClient::UndisplayCommand, this)},
45 { "watch", std::bind(&DebuggerClient::WatchCommand, this)},
46 { "setAsyncStackDepth", std::bind(&DebuggerClient::AsyncStackDepthCommand, this)},
47 { "resume", std::bind(&DebuggerClient::ResumeCommand, this)},
48 { "step-into", std::bind(&DebuggerClient::StepIntoCommand, this)},
49 { "step-out", std::bind(&DebuggerClient::StepOutCommand, this)},
50 { "step-over", std::bind(&DebuggerClient::StepOverCommand, this)},
51 { "enable-launch-accelerate", std::bind(&DebuggerClient::EnableLaunchAccelerateCommand, this)},
52 { "saveAllPossibleBreakpoints", std::bind(&DebuggerClient::SaveAllPossibleBreakpointsCommand, this)},
53 { "setSymbolicBreakpoints", std::bind(&DebuggerClient::SetSymbolicBreakpointsCommand, this)},
54 { "removeSymbolicBreakpoints", std::bind(&DebuggerClient::RemoveSymbolicBreakpointsCommand, this)},
55 };
56
57 auto entry = dispatcherTable.find(cmd);
58 if (entry != dispatcherTable.end()) {
59 entry->second();
60 LOGI("DebuggerClient DispatcherCmd cmd: %{public}s", cmd.c_str());
61 return true;
62 }
63
64 LOGI("unknown command: %{public}s", cmd.c_str());
65 return false;
66 }
67
BreakCommand()68 int DebuggerClient::BreakCommand()
69 {
70 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
71 uint32_t id = session->GetMessageId();
72
73 std::unique_ptr<PtJson> request = PtJson::CreateObject();
74 request->Add("id", id);
75 request->Add("method", "Debugger.setBreakpointByUrl");
76
77 std::unique_ptr<PtJson> params = PtJson::CreateObject();
78 params->Add("columnNumber", breakPointInfoList_.back().columnNumber);
79 params->Add("lineNumber", breakPointInfoList_.back().lineNumber);
80 params->Add("url", breakPointInfoList_.back().url.c_str());
81 request->Add("params", params);
82
83 std::string message = request->Stringify();
84 if (session->ClientSendReq(message)) {
85 session->GetDomainManager().SetDomainById(id, "Debugger");
86 }
87 return 0;
88 }
89
BacktrackCommand()90 int DebuggerClient::BacktrackCommand()
91 {
92 return 0;
93 }
94
DeleteCommand()95 int DebuggerClient::DeleteCommand()
96 {
97 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
98 uint32_t id = session->GetMessageId();
99
100 std::unique_ptr<PtJson> request = PtJson::CreateObject();
101 request->Add("id", id);
102 request->Add("method", "Debugger.removeBreakpoint");
103
104 std::unique_ptr<PtJson> params = PtJson::CreateObject();
105 std::string breakpointId = breakPointInfoList_.back().url;
106 params->Add("breakpointId", breakpointId.c_str());
107 request->Add("params", params);
108
109 std::string message = request->Stringify();
110 if (session->ClientSendReq(message)) {
111 session->GetDomainManager().SetDomainById(id, "Debugger");
112 }
113 return 0;
114 }
115
DisableCommand()116 int DebuggerClient::DisableCommand()
117 {
118 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
119 uint32_t id = session->GetMessageId();
120
121 std::unique_ptr<PtJson> request = PtJson::CreateObject();
122 request->Add("id", id);
123 request->Add("method", "Debugger.disable");
124
125 std::unique_ptr<PtJson> params = PtJson::CreateObject();
126 request->Add("params", params);
127
128 std::string message = request->Stringify();
129 if (session->ClientSendReq(message)) {
130 session->GetDomainManager().SetDomainById(id, "Debugger");
131 }
132 return 0;
133 }
134
DisplayCommand()135 int DebuggerClient::DisplayCommand()
136 {
137 return 0;
138 }
139
EnableCommand()140 int DebuggerClient::EnableCommand()
141 {
142 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
143 uint32_t id = session->GetMessageId();
144
145 std::unique_ptr<PtJson> request = PtJson::CreateObject();
146 request->Add("id", id);
147 request->Add("method", "Debugger.enable");
148
149 std::unique_ptr<PtJson> params = PtJson::CreateObject();
150 request->Add("params", params);
151
152 std::string message = request->Stringify();
153 if (session->ClientSendReq(message)) {
154 session->GetDomainManager().SetDomainById(id, "Debugger");
155 }
156 return 0;
157 }
158
FinishCommand()159 int DebuggerClient::FinishCommand()
160 {
161 return 0;
162 }
163
FrameCommand()164 int DebuggerClient::FrameCommand()
165 {
166 return 0;
167 }
168
IgnoreCommand()169 int DebuggerClient::IgnoreCommand()
170 {
171 return 0;
172 }
173
InfobreakpointsCommand()174 int DebuggerClient::InfobreakpointsCommand()
175 {
176 return 0;
177 }
178
InfosourceCommand()179 int DebuggerClient::InfosourceCommand()
180 {
181 return 0;
182 }
183
JumpCommand()184 int DebuggerClient::JumpCommand()
185 {
186 return 0;
187 }
188
NextCommand()189 int DebuggerClient::NextCommand()
190 {
191 return 0;
192 }
193
ListCommand()194 int DebuggerClient::ListCommand()
195 {
196 return 0;
197 }
198
PtypeCommand()199 int DebuggerClient::PtypeCommand()
200 {
201 return 0;
202 }
203
RunCommand()204 int DebuggerClient::RunCommand()
205 {
206 return 0;
207 }
208
SetvarCommand()209 int DebuggerClient::SetvarCommand()
210 {
211 return 0;
212 }
213
StepCommand()214 int DebuggerClient::StepCommand()
215 {
216 return 0;
217 }
218
UndisplayCommand()219 int DebuggerClient::UndisplayCommand()
220 {
221 return 0;
222 }
223
WatchCommand()224 int DebuggerClient::WatchCommand()
225 {
226 return 0;
227 }
228
AsyncStackDepthCommand()229 int DebuggerClient::AsyncStackDepthCommand()
230 {
231 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
232 uint32_t id = session->GetMessageId();
233
234 std::unique_ptr<PtJson> request = PtJson::CreateObject();
235 request->Add("id", id);
236 request->Add("method", "Debugger.setAsyncCallStackDepth");
237
238 std::unique_ptr<PtJson> params = PtJson::CreateObject();
239 // 32 : maxAsyncCallChainDepth
240 params->Add("maxDepth", 32);
241 request->Add("params", params);
242
243 std::string message = request->Stringify();
244 if (session->ClientSendReq(message)) {
245 session->GetDomainManager().SetDomainById(id, "Debugger");
246 }
247 return 0;
248 }
249
ResumeCommand()250 int DebuggerClient::ResumeCommand()
251 {
252 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
253 uint32_t id = session->GetMessageId();
254
255 std::unique_ptr<PtJson> request = PtJson::CreateObject();
256 request->Add("id", id);
257 request->Add("method", "Debugger.resume");
258
259 std::unique_ptr<PtJson> params = PtJson::CreateObject();
260 request->Add("params", params);
261
262 std::string message = request->Stringify();
263 if (session->ClientSendReq(message)) {
264 session->GetDomainManager().SetDomainById(id, "Debugger");
265 }
266 return 0;
267 }
268
StepIntoCommand()269 int DebuggerClient::StepIntoCommand()
270 {
271 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
272 uint32_t id = session->GetMessageId();
273
274 std::unique_ptr<PtJson> request = PtJson::CreateObject();
275 request->Add("id", id);
276 request->Add("method", "Debugger.stepInto");
277
278 std::unique_ptr<PtJson> params = PtJson::CreateObject();
279 request->Add("params", params);
280
281 std::string message = request->Stringify();
282 if (session->ClientSendReq(message)) {
283 session->GetDomainManager().SetDomainById(id, "Debugger");
284 }
285 return 0;
286 }
287
StepOutCommand()288 int DebuggerClient::StepOutCommand()
289 {
290 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
291 uint32_t id = session->GetMessageId();
292
293 std::unique_ptr<PtJson> request = PtJson::CreateObject();
294 request->Add("id", id);
295 request->Add("method", "Debugger.stepOut");
296
297 std::unique_ptr<PtJson> params = PtJson::CreateObject();
298 request->Add("params", params);
299
300 std::string message = request->Stringify();
301 if (session->ClientSendReq(message)) {
302 session->GetDomainManager().SetDomainById(id, "Debugger");
303 }
304 return 0;
305 }
306
StepOverCommand()307 int DebuggerClient::StepOverCommand()
308 {
309 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
310 uint32_t id = session->GetMessageId();
311
312 std::unique_ptr<PtJson> request = PtJson::CreateObject();
313 request->Add("id", id);
314 request->Add("method", "Debugger.stepOver");
315
316 std::unique_ptr<PtJson> params = PtJson::CreateObject();
317 request->Add("params", params);
318
319 std::string message = request->Stringify();
320 if (session->ClientSendReq(message)) {
321 session->GetDomainManager().SetDomainById(id, "Debugger");
322 }
323 return 0;
324 }
325
AddBreakPointInfo(const std::string & url,const int & lineNumber,const int & columnNumber)326 void DebuggerClient::AddBreakPointInfo(const std::string& url, const int& lineNumber, const int& columnNumber)
327 {
328 BreakPointInfo breakPointInfo;
329 breakPointInfo.url = url;
330 breakPointInfo.lineNumber = lineNumber - 1;
331 breakPointInfo.columnNumber = columnNumber;
332 breakPointInfoList_.emplace_back(breakPointInfo);
333 }
334
AddSymbolicBreakpointInfo(const std::string & functionName)335 void DebuggerClient::AddSymbolicBreakpointInfo(const std::string& functionName)
336 {
337 SymbolicBreakpointInfo symbolicBreakpointInfo;
338 symbolicBreakpointInfo.functionName = functionName;
339 symbolicBreakpointInfoList_.emplace_back(symbolicBreakpointInfo);
340 }
341
RecvReply(std::unique_ptr<PtJson> json)342 void DebuggerClient::RecvReply(std::unique_ptr<PtJson> json)
343 {
344 if (json == nullptr) {
345 LOGE("arkdb: json parse error");
346 return;
347 }
348
349 if (!json->IsObject()) {
350 LOGE("arkdb: json parse format error");
351 json->ReleaseRoot();
352 return;
353 }
354
355 std::string wholeMethod;
356 std::string method;
357 Result ret = json->GetString("method", &wholeMethod);
358 if (ret != Result::SUCCESS) {
359 LOGE("arkdb: find method error");
360 }
361
362 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
363 SourceManager &sourceManager = session->GetSourceManager();
364 WatchManager &watchManager = session->GetWatchManager();
365
366 std::string::size_type length = wholeMethod.length();
367 std::string::size_type indexPoint = 0;
368 indexPoint = wholeMethod.find_first_of('.', 0);
369 method = wholeMethod.substr(indexPoint + 1, length);
370 if (method == "paused") {
371 PausedReply(std::move(json));
372 return;
373 } else if (method == "scriptParsed") {
374 sourceManager.EnableReply(std::move(json));
375 return;
376 } else if (method == "resumed") {
377 watchManager.DebugFalseState();
378 return;
379 } else {
380 LOGI("arkdb: Debugger reply is: %{public}s", json->Stringify().c_str());
381 }
382 handleResponse(std::move(json));
383 }
384
PausedReply(const std::unique_ptr<PtJson> json)385 void DebuggerClient::PausedReply(const std::unique_ptr<PtJson> json)
386 {
387 if (json == nullptr) {
388 LOGE("arkdb: json parse error");
389 return;
390 }
391
392 if (!json->IsObject()) {
393 LOGE("arkdb: json parse format error");
394 json->ReleaseRoot();
395 return;
396 }
397
398 std::unique_ptr<PtJson> params;
399 Result ret = json->GetObject("params", ¶ms);
400 if (ret != Result::SUCCESS) {
401 LOGE("arkdb: find params error");
402 return;
403 }
404
405 std::unique_ptr<PtJson> callFrames;
406 ret = params->GetArray("callFrames", &callFrames);
407 if (ret != Result::SUCCESS) {
408 LOGE("arkdb: find callFrames error");
409 return;
410 }
411
412 std::map<int32_t, std::unique_ptr<CallFrame>> data;
413 for (int32_t i = 0; i < callFrames->GetSize(); i++) {
414 std::unique_ptr<CallFrame> callFrameInfo = CallFrame::Create(*(callFrames->Get(i)));
415 if (callFrameInfo == nullptr) {
416 LOGE("arkdb: get call frame info error");
417 return;
418 }
419 data.emplace(i + 1, std::move(callFrameInfo));
420 }
421
422 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
423 StackManager& stackManager = session->GetStackManager();
424 SourceManager &sourceManager = session->GetSourceManager();
425 WatchManager &watchManager = session->GetWatchManager();
426 stackManager.ClearCallFrame();
427 stackManager.SetCallFrames(std::move(data));
428 sourceManager.GetDebugSources(callFrames->Get(0));
429 watchManager.RequestWatchInfo(callFrames->Get(0));
430 watchManager.DebugTrueState();
431 }
432
handleResponse(std::unique_ptr<PtJson> json)433 void DebuggerClient::handleResponse(std::unique_ptr<PtJson> json)
434 {
435 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
436 SourceManager &sourceManager = session->GetSourceManager();
437 WatchManager &watchManager = session->GetWatchManager();
438 BreakPointManager& breakpoint = session->GetBreakPointManager();
439 std::unique_ptr<PtJson> result;
440 Result ret = json->GetObject("result", &result);
441 if (ret != Result::SUCCESS) {
442 LOGE("arkdb: find result error");
443 return;
444 }
445 int32_t id;
446 ret = json->GetInt("id", &id);
447 if (ret == Result::SUCCESS) {
448 std::string scriptSource;
449 ret = result->GetString("scriptSource", &scriptSource);
450 if (ret == Result::SUCCESS) {
451 sourceManager.SetFileSource(id, scriptSource);
452 return;
453 }
454 }
455 std::string breakpointId;
456 ret = result->GetString("breakpointId", &breakpointId);
457 if (ret == Result::SUCCESS) {
458 breakpoint.Createbreaklocation(std::move(json));
459 return;
460 }
461 if (watchManager.HandleWatchResult(std::move(json), id)) {
462 return;
463 }
464 return;
465 }
466
SaveAllPossibleBreakpointsCommand()467 int DebuggerClient::SaveAllPossibleBreakpointsCommand()
468 {
469 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
470 uint32_t id = session->GetMessageId();
471
472 std::unique_ptr<PtJson> request = PtJson::CreateObject();
473 request->Add("id", id);
474 request->Add("method", "Debugger.saveAllPossibleBreakpoints");
475
476 std::unique_ptr<PtJson> params = PtJson::CreateObject();
477 std::unique_ptr<PtJson> locations = PtJson::CreateObject();
478 std::unique_ptr<PtJson> vector = PtJson::CreateArray();
479
480 std::unique_ptr<PtJson> bp = PtJson::CreateObject();
481 bp->Add("lineNumber", breakPointInfoList_.back().lineNumber);
482 bp->Add("columnNumber", breakPointInfoList_.back().columnNumber);
483 vector->Push(bp);
484 locations->Add(breakPointInfoList_.back().url.c_str(), vector);
485 params->Add("locations", locations);
486 request->Add("params", params);
487
488 std::string message = request->Stringify();
489 if (session->ClientSendReq(message)) {
490 session->GetDomainManager().SetDomainById(id, "Debugger");
491 }
492
493 return 0;
494 }
495
SetSymbolicBreakpointsCommand()496 int DebuggerClient::SetSymbolicBreakpointsCommand()
497 {
498 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
499 uint32_t id = session->GetMessageId();
500
501 std::unique_ptr<PtJson> request = PtJson::CreateObject();
502 request->Add("id", id);
503 request->Add("method", "Debugger.setSymbolicBreakpoints");
504
505 std::unique_ptr<PtJson> params = PtJson::CreateObject();
506 std::unique_ptr<PtJson> symbolicBreakpoints = PtJson::CreateArray();
507
508 std::unique_ptr<PtJson> symbolicBreakpoint = PtJson::CreateObject();
509 symbolicBreakpoint->Add("functionName", symbolicBreakpointInfoList_.back().functionName.c_str());
510 symbolicBreakpoints->Push(symbolicBreakpoint);
511 params->Add("symbolicBreakpoints", symbolicBreakpoints);
512 request->Add("params", params);
513
514 std::string message = request->Stringify();
515 if (session->ClientSendReq(message)) {
516 session->GetDomainManager().SetDomainById(id, "Debugger");
517 }
518
519 return 0;
520 }
521
RemoveSymbolicBreakpointsCommand()522 int DebuggerClient::RemoveSymbolicBreakpointsCommand()
523 {
524 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
525 uint32_t id = session->GetMessageId();
526
527 std::unique_ptr<PtJson> request = PtJson::CreateObject();
528 request->Add("id", id);
529 request->Add("method", "Debugger.removeSymbolicBreakpoints");
530
531 std::unique_ptr<PtJson> params = PtJson::CreateObject();
532 std::unique_ptr<PtJson> symbolicBreakpoints = PtJson::CreateArray();
533
534 std::unique_ptr<PtJson> symbolicBreakpoint = PtJson::CreateObject();
535 symbolicBreakpoint->Add("functionName", symbolicBreakpointInfoList_.back().functionName.c_str());
536 symbolicBreakpoints->Push(symbolicBreakpoint);
537 params->Add("symbolicBreakpoints", symbolicBreakpoints);
538 request->Add("params", params);
539
540 std::string message = request->Stringify();
541 if (session->ClientSendReq(message)) {
542 session->GetDomainManager().SetDomainById(id, "Debugger");
543 }
544
545 return 0;
546 }
547
EnableLaunchAccelerateCommand()548 int DebuggerClient::EnableLaunchAccelerateCommand()
549 {
550 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
551 uint32_t id = session->GetMessageId();
552
553 std::unique_ptr<PtJson> request = PtJson::CreateObject();
554 request->Add("id", id);
555 request->Add("method", "Debugger.enable");
556
557 std::unique_ptr<PtJson> params = PtJson::CreateObject();
558 std::unique_ptr<PtJson> options = PtJson::CreateArray();
559
560 options->Push("enableLaunchAccelerate");
561 params->Add("options", options);
562 request->Add("params", params);
563
564 std::string message = request->Stringify();
565 if (session->ClientSendReq(message)) {
566 session->GetDomainManager().SetDomainById(id, "Debugger");
567 }
568
569 return 0;
570 }
571 } // OHOS::ArkCompiler::Toolchain