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