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/client/domain/debugger_client.h"
17
18 #include "tooling/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 { "resume", std::bind(&DebuggerClient::ResumeCommand, this)},
47 { "step-into", std::bind(&DebuggerClient::StepIntoCommand, this)},
48 { "step-out", std::bind(&DebuggerClient::StepOutCommand, this)},
49 { "step-over", std::bind(&DebuggerClient::StepOverCommand, this)},
50 { "enable-launch-accelerate", std::bind(&DebuggerClient::EnableLaunchAccelerateCommand, this)},
51 { "saveAllPossibleBreakpoints", std::bind(&DebuggerClient::SaveAllPossibleBreakpointsCommand, this)},
52 };
53
54 auto entry = dispatcherTable.find(cmd);
55 if (entry != dispatcherTable.end()) {
56 entry->second();
57 LOGI("DebuggerClient DispatcherCmd cmd: %{public}s", cmd.c_str());
58 return true;
59 }
60
61 LOGI("unknown command: %{public}s", cmd.c_str());
62 return false;
63 }
64
BreakCommand()65 int DebuggerClient::BreakCommand()
66 {
67 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
68 uint32_t id = session->GetMessageId();
69
70 std::unique_ptr<PtJson> request = PtJson::CreateObject();
71 request->Add("id", id);
72 request->Add("method", "Debugger.setBreakpointByUrl");
73
74 std::unique_ptr<PtJson> params = PtJson::CreateObject();
75 params->Add("columnNumber", breakPointInfoList_.back().columnNumber);
76 params->Add("lineNumber", breakPointInfoList_.back().lineNumber);
77 params->Add("url", breakPointInfoList_.back().url.c_str());
78 request->Add("params", params);
79
80 std::string message = request->Stringify();
81 if (session->ClientSendReq(message)) {
82 session->GetDomainManager().SetDomainById(id, "Debugger");
83 }
84 return 0;
85 }
86
BacktrackCommand()87 int DebuggerClient::BacktrackCommand()
88 {
89 return 0;
90 }
91
DeleteCommand()92 int DebuggerClient::DeleteCommand()
93 {
94 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
95 uint32_t id = session->GetMessageId();
96
97 std::unique_ptr<PtJson> request = PtJson::CreateObject();
98 request->Add("id", id);
99 request->Add("method", "Debugger.removeBreakpoint");
100
101 std::unique_ptr<PtJson> params = PtJson::CreateObject();
102 std::string breakpointId = breakPointInfoList_.back().url;
103 params->Add("breakpointId", breakpointId.c_str());
104 request->Add("params", params);
105
106 std::string message = request->Stringify();
107 if (session->ClientSendReq(message)) {
108 session->GetDomainManager().SetDomainById(id, "Debugger");
109 }
110 return 0;
111 }
112
DisableCommand()113 int DebuggerClient::DisableCommand()
114 {
115 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
116 uint32_t id = session->GetMessageId();
117
118 std::unique_ptr<PtJson> request = PtJson::CreateObject();
119 request->Add("id", id);
120 request->Add("method", "Debugger.disable");
121
122 std::unique_ptr<PtJson> params = PtJson::CreateObject();
123 request->Add("params", params);
124
125 std::string message = request->Stringify();
126 if (session->ClientSendReq(message)) {
127 session->GetDomainManager().SetDomainById(id, "Debugger");
128 }
129 return 0;
130 }
131
DisplayCommand()132 int DebuggerClient::DisplayCommand()
133 {
134 return 0;
135 }
136
EnableCommand()137 int DebuggerClient::EnableCommand()
138 {
139 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
140 uint32_t id = session->GetMessageId();
141
142 std::unique_ptr<PtJson> request = PtJson::CreateObject();
143 request->Add("id", id);
144 request->Add("method", "Debugger.enable");
145
146 std::unique_ptr<PtJson> params = PtJson::CreateObject();
147 request->Add("params", params);
148
149 std::string message = request->Stringify();
150 if (session->ClientSendReq(message)) {
151 session->GetDomainManager().SetDomainById(id, "Debugger");
152 }
153 return 0;
154 }
155
FinishCommand()156 int DebuggerClient::FinishCommand()
157 {
158 return 0;
159 }
160
FrameCommand()161 int DebuggerClient::FrameCommand()
162 {
163 return 0;
164 }
165
IgnoreCommand()166 int DebuggerClient::IgnoreCommand()
167 {
168 return 0;
169 }
170
InfobreakpointsCommand()171 int DebuggerClient::InfobreakpointsCommand()
172 {
173 return 0;
174 }
175
InfosourceCommand()176 int DebuggerClient::InfosourceCommand()
177 {
178 return 0;
179 }
180
JumpCommand()181 int DebuggerClient::JumpCommand()
182 {
183 return 0;
184 }
185
NextCommand()186 int DebuggerClient::NextCommand()
187 {
188 return 0;
189 }
190
ListCommand()191 int DebuggerClient::ListCommand()
192 {
193 return 0;
194 }
195
PtypeCommand()196 int DebuggerClient::PtypeCommand()
197 {
198 return 0;
199 }
200
RunCommand()201 int DebuggerClient::RunCommand()
202 {
203 return 0;
204 }
205
SetvarCommand()206 int DebuggerClient::SetvarCommand()
207 {
208 return 0;
209 }
210
StepCommand()211 int DebuggerClient::StepCommand()
212 {
213 return 0;
214 }
215
UndisplayCommand()216 int DebuggerClient::UndisplayCommand()
217 {
218 return 0;
219 }
220
WatchCommand()221 int DebuggerClient::WatchCommand()
222 {
223 return 0;
224 }
225
ResumeCommand()226 int DebuggerClient::ResumeCommand()
227 {
228 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
229 uint32_t id = session->GetMessageId();
230
231 std::unique_ptr<PtJson> request = PtJson::CreateObject();
232 request->Add("id", id);
233 request->Add("method", "Debugger.resume");
234
235 std::unique_ptr<PtJson> params = PtJson::CreateObject();
236 request->Add("params", params);
237
238 std::string message = request->Stringify();
239 if (session->ClientSendReq(message)) {
240 session->GetDomainManager().SetDomainById(id, "Debugger");
241 }
242 return 0;
243 }
244
StepIntoCommand()245 int DebuggerClient::StepIntoCommand()
246 {
247 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
248 uint32_t id = session->GetMessageId();
249
250 std::unique_ptr<PtJson> request = PtJson::CreateObject();
251 request->Add("id", id);
252 request->Add("method", "Debugger.stepInto");
253
254 std::unique_ptr<PtJson> params = PtJson::CreateObject();
255 request->Add("params", params);
256
257 std::string message = request->Stringify();
258 if (session->ClientSendReq(message)) {
259 session->GetDomainManager().SetDomainById(id, "Debugger");
260 }
261 return 0;
262 }
263
StepOutCommand()264 int DebuggerClient::StepOutCommand()
265 {
266 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
267 uint32_t id = session->GetMessageId();
268
269 std::unique_ptr<PtJson> request = PtJson::CreateObject();
270 request->Add("id", id);
271 request->Add("method", "Debugger.stepOut");
272
273 std::unique_ptr<PtJson> params = PtJson::CreateObject();
274 request->Add("params", params);
275
276 std::string message = request->Stringify();
277 if (session->ClientSendReq(message)) {
278 session->GetDomainManager().SetDomainById(id, "Debugger");
279 }
280 return 0;
281 }
282
StepOverCommand()283 int DebuggerClient::StepOverCommand()
284 {
285 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
286 uint32_t id = session->GetMessageId();
287
288 std::unique_ptr<PtJson> request = PtJson::CreateObject();
289 request->Add("id", id);
290 request->Add("method", "Debugger.stepOver");
291
292 std::unique_ptr<PtJson> params = PtJson::CreateObject();
293 request->Add("params", params);
294
295 std::string message = request->Stringify();
296 if (session->ClientSendReq(message)) {
297 session->GetDomainManager().SetDomainById(id, "Debugger");
298 }
299 return 0;
300 }
301
AddBreakPointInfo(const std::string & url,const int & lineNumber,const int & columnNumber)302 void DebuggerClient::AddBreakPointInfo(const std::string& url, const int& lineNumber, const int& columnNumber)
303 {
304 BreakPointInfo breakPointInfo;
305 breakPointInfo.url = url;
306 breakPointInfo.lineNumber = lineNumber - 1;
307 breakPointInfo.columnNumber = columnNumber;
308 breakPointInfoList_.emplace_back(breakPointInfo);
309 }
310
RecvReply(std::unique_ptr<PtJson> json)311 void DebuggerClient::RecvReply(std::unique_ptr<PtJson> json)
312 {
313 if (json == nullptr) {
314 LOGE("arkdb: json parse error");
315 return;
316 }
317
318 if (!json->IsObject()) {
319 LOGE("arkdb: json parse format error");
320 json->ReleaseRoot();
321 return;
322 }
323
324 std::string wholeMethod;
325 std::string method;
326 Result ret = json->GetString("method", &wholeMethod);
327 if (ret != Result::SUCCESS) {
328 LOGE("arkdb: find method error");
329 }
330
331 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
332 SourceManager &sourceManager = session->GetSourceManager();
333 WatchManager &watchManager = session->GetWatchManager();
334
335 std::string::size_type length = wholeMethod.length();
336 std::string::size_type indexPoint = 0;
337 indexPoint = wholeMethod.find_first_of('.', 0);
338 method = wholeMethod.substr(indexPoint + 1, length);
339 if (method == "paused") {
340 PausedReply(std::move(json));
341 return;
342 } else if (method == "scriptParsed") {
343 sourceManager.EnableReply(std::move(json));
344 return;
345 } else if (method == "resumed") {
346 watchManager.DebugFalseState();
347 return;
348 } else {
349 LOGI("arkdb: Debugger reply is: %{public}s", json->Stringify().c_str());
350 }
351 handleResponse(std::move(json));
352 }
353
PausedReply(const std::unique_ptr<PtJson> json)354 void DebuggerClient::PausedReply(const std::unique_ptr<PtJson> json)
355 {
356 if (json == nullptr) {
357 LOGE("arkdb: json parse error");
358 return;
359 }
360
361 if (!json->IsObject()) {
362 LOGE("arkdb: json parse format error");
363 json->ReleaseRoot();
364 return;
365 }
366
367 std::unique_ptr<PtJson> params;
368 Result ret = json->GetObject("params", ¶ms);
369 if (ret != Result::SUCCESS) {
370 LOGE("arkdb: find params error");
371 return;
372 }
373
374 std::unique_ptr<PtJson> callFrames;
375 ret = params->GetArray("callFrames", &callFrames);
376 if (ret != Result::SUCCESS) {
377 LOGE("arkdb: find callFrames error");
378 return;
379 }
380
381 std::map<int32_t, std::unique_ptr<CallFrame>> data;
382 for (int32_t i = 0; i < callFrames->GetSize(); i++) {
383 std::unique_ptr<CallFrame> callFrameInfo = CallFrame::Create(*(callFrames->Get(i)));
384 if (callFrameInfo == nullptr) {
385 LOGE("arkdb: get call frame info error");
386 return;
387 }
388 data.emplace(i + 1, std::move(callFrameInfo));
389 }
390
391 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
392 StackManager& stackManager = session->GetStackManager();
393 SourceManager &sourceManager = session->GetSourceManager();
394 WatchManager &watchManager = session->GetWatchManager();
395 stackManager.ClearCallFrame();
396 stackManager.SetCallFrames(std::move(data));
397 sourceManager.GetDebugSources(callFrames->Get(0));
398 watchManager.RequestWatchInfo(callFrames->Get(0));
399 watchManager.DebugTrueState();
400 }
401
handleResponse(std::unique_ptr<PtJson> json)402 void DebuggerClient::handleResponse(std::unique_ptr<PtJson> json)
403 {
404 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
405 SourceManager &sourceManager = session->GetSourceManager();
406 WatchManager &watchManager = session->GetWatchManager();
407 BreakPointManager& breakpoint = session->GetBreakPointManager();
408 std::unique_ptr<PtJson> result;
409 Result ret = json->GetObject("result", &result);
410 if (ret != Result::SUCCESS) {
411 LOGE("arkdb: find result error");
412 return;
413 }
414 int32_t id;
415 ret = json->GetInt("id", &id);
416 if (ret == Result::SUCCESS) {
417 std::string scriptSource;
418 ret = result->GetString("scriptSource", &scriptSource);
419 if (ret == Result::SUCCESS) {
420 sourceManager.SetFileSource(id, scriptSource);
421 return;
422 }
423 }
424 std::string breakpointId;
425 ret = result->GetString("breakpointId", &breakpointId);
426 if (ret == Result::SUCCESS) {
427 breakpoint.Createbreaklocation(std::move(json));
428 return;
429 }
430 if (watchManager.HandleWatchResult(std::move(json), id)) {
431 return;
432 }
433 return;
434 }
435
SaveAllPossibleBreakpointsCommand()436 int DebuggerClient::SaveAllPossibleBreakpointsCommand()
437 {
438 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
439 uint32_t id = session->GetMessageId();
440
441 std::unique_ptr<PtJson> request = PtJson::CreateObject();
442 request->Add("id", id);
443 request->Add("method", "Debugger.saveAllPossibleBreakpoints");
444
445 std::unique_ptr<PtJson> params = PtJson::CreateObject();
446 std::unique_ptr<PtJson> locations = PtJson::CreateObject();
447 std::unique_ptr<PtJson> vector = PtJson::CreateArray();
448
449 std::unique_ptr<PtJson> bp = PtJson::CreateObject();
450 bp->Add("lineNumber", breakPointInfoList_.back().lineNumber);
451 bp->Add("columnNumber", breakPointInfoList_.back().columnNumber);
452 vector->Push(bp);
453 locations->Add(breakPointInfoList_.back().url.c_str(), vector);
454 params->Add("locations", locations);
455 request->Add("params", params);
456
457 std::string message = request->Stringify();
458 if (session->ClientSendReq(message)) {
459 session->GetDomainManager().SetDomainById(id, "Debugger");
460 }
461
462 return 0;
463 }
464
EnableLaunchAccelerateCommand()465 int DebuggerClient::EnableLaunchAccelerateCommand()
466 {
467 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
468 uint32_t id = session->GetMessageId();
469
470 std::unique_ptr<PtJson> request = PtJson::CreateObject();
471 request->Add("id", id);
472 request->Add("method", "Debugger.enable");
473
474 std::unique_ptr<PtJson> params = PtJson::CreateObject();
475 std::unique_ptr<PtJson> options = PtJson::CreateArray();
476
477 options->Push("enableLaunchAccelerate");
478 params->Add("options", options);
479 request->Add("params", params);
480
481 std::string message = request->Stringify();
482 if (session->ClientSendReq(message)) {
483 session->GetDomainManager().SetDomainById(id, "Debugger");
484 }
485
486 return 0;
487 }
488 } // OHOS::ArkCompiler::Toolchain