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 };
58
59 auto entry = dispatcherTable.find(cmd);
60 if (entry != dispatcherTable.end()) {
61 entry->second();
62 LOGI("DebuggerClient DispatcherCmd cmd: %{public}s", cmd.c_str());
63 return true;
64 }
65
66 LOGI("unknown command: %{public}s", cmd.c_str());
67 return false;
68 }
69
BreakCommand()70 int DebuggerClient::BreakCommand()
71 {
72 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
73 uint32_t id = session->GetMessageId();
74
75 std::unique_ptr<PtJson> request = PtJson::CreateObject();
76 request->Add("id", id);
77 request->Add("method", "Debugger.setBreakpointByUrl");
78
79 std::unique_ptr<PtJson> params = PtJson::CreateObject();
80 params->Add("columnNumber", breakPointInfoList_.back().columnNumber);
81 params->Add("lineNumber", breakPointInfoList_.back().lineNumber);
82 params->Add("url", breakPointInfoList_.back().url.c_str());
83 request->Add("params", params);
84
85 std::string message = request->Stringify();
86 if (session->ClientSendReq(message)) {
87 session->GetDomainManager().SetDomainById(id, "Debugger");
88 }
89 return 0;
90 }
91
BacktrackCommand()92 int DebuggerClient::BacktrackCommand()
93 {
94 return 0;
95 }
96
DeleteCommand()97 int DebuggerClient::DeleteCommand()
98 {
99 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
100 uint32_t id = session->GetMessageId();
101
102 std::unique_ptr<PtJson> request = PtJson::CreateObject();
103 request->Add("id", id);
104 request->Add("method", "Debugger.removeBreakpoint");
105
106 std::unique_ptr<PtJson> params = PtJson::CreateObject();
107 std::string breakpointId = breakPointInfoList_.back().url;
108 params->Add("breakpointId", breakpointId.c_str());
109 request->Add("params", params);
110
111 std::string message = request->Stringify();
112 if (session->ClientSendReq(message)) {
113 session->GetDomainManager().SetDomainById(id, "Debugger");
114 }
115 return 0;
116 }
117
DisableCommand()118 int DebuggerClient::DisableCommand()
119 {
120 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
121 uint32_t id = session->GetMessageId();
122
123 std::unique_ptr<PtJson> request = PtJson::CreateObject();
124 request->Add("id", id);
125 request->Add("method", "Debugger.disable");
126
127 std::unique_ptr<PtJson> params = PtJson::CreateObject();
128 request->Add("params", params);
129
130 std::string message = request->Stringify();
131 if (session->ClientSendReq(message)) {
132 session->GetDomainManager().SetDomainById(id, "Debugger");
133 }
134 return 0;
135 }
136
DisplayCommand()137 int DebuggerClient::DisplayCommand()
138 {
139 return 0;
140 }
141
EnableCommand()142 int DebuggerClient::EnableCommand()
143 {
144 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
145 uint32_t id = session->GetMessageId();
146
147 std::unique_ptr<PtJson> request = PtJson::CreateObject();
148 request->Add("id", id);
149 request->Add("method", "Debugger.enable");
150
151 std::unique_ptr<PtJson> params = PtJson::CreateObject();
152 request->Add("params", params);
153
154 std::string message = request->Stringify();
155 if (session->ClientSendReq(message)) {
156 session->GetDomainManager().SetDomainById(id, "Debugger");
157 }
158 return 0;
159 }
160
FinishCommand()161 int DebuggerClient::FinishCommand()
162 {
163 return 0;
164 }
165
FrameCommand()166 int DebuggerClient::FrameCommand()
167 {
168 return 0;
169 }
170
IgnoreCommand()171 int DebuggerClient::IgnoreCommand()
172 {
173 return 0;
174 }
175
InfobreakpointsCommand()176 int DebuggerClient::InfobreakpointsCommand()
177 {
178 return 0;
179 }
180
InfosourceCommand()181 int DebuggerClient::InfosourceCommand()
182 {
183 return 0;
184 }
185
JumpCommand()186 int DebuggerClient::JumpCommand()
187 {
188 return 0;
189 }
190
NextCommand()191 int DebuggerClient::NextCommand()
192 {
193 return 0;
194 }
195
ListCommand()196 int DebuggerClient::ListCommand()
197 {
198 return 0;
199 }
200
PtypeCommand()201 int DebuggerClient::PtypeCommand()
202 {
203 return 0;
204 }
205
RunCommand()206 int DebuggerClient::RunCommand()
207 {
208 return 0;
209 }
210
SetvarCommand()211 int DebuggerClient::SetvarCommand()
212 {
213 return 0;
214 }
215
StepCommand()216 int DebuggerClient::StepCommand()
217 {
218 return 0;
219 }
220
UndisplayCommand()221 int DebuggerClient::UndisplayCommand()
222 {
223 return 0;
224 }
225
WatchCommand()226 int DebuggerClient::WatchCommand()
227 {
228 return 0;
229 }
230
ResumeCommand()231 int DebuggerClient::ResumeCommand()
232 {
233 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
234 uint32_t id = session->GetMessageId();
235
236 std::unique_ptr<PtJson> request = PtJson::CreateObject();
237 request->Add("id", id);
238 request->Add("method", "Debugger.resume");
239
240 std::unique_ptr<PtJson> params = PtJson::CreateObject();
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
StepIntoCommand()250 int DebuggerClient::StepIntoCommand()
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.stepInto");
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
StepOutCommand()269 int DebuggerClient::StepOutCommand()
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.stepOut");
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
StepOverCommand()288 int DebuggerClient::StepOverCommand()
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.stepOver");
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
AddBreakPointInfo(const std::string& url, const int& lineNumber, const int& columnNumber)307 void DebuggerClient::AddBreakPointInfo(const std::string& url, const int& lineNumber, const int& columnNumber)
308 {
309 BreakPointInfo breakPointInfo;
310 breakPointInfo.url = url;
311 breakPointInfo.lineNumber = lineNumber - 1;
312 breakPointInfo.columnNumber = columnNumber;
313 breakPointInfoList_.emplace_back(breakPointInfo);
314 }
315
RecvReply(std::unique_ptr<PtJson> json)316 void DebuggerClient::RecvReply(std::unique_ptr<PtJson> json)
317 {
318 if (json == nullptr) {
319 LOGE("arkdb: json parse error");
320 return;
321 }
322
323 if (!json->IsObject()) {
324 LOGE("arkdb: json parse format error");
325 json->ReleaseRoot();
326 return;
327 }
328
329 std::string wholeMethod;
330 std::string method;
331 Result ret = json->GetString("method", &wholeMethod);
332 if (ret != Result::SUCCESS) {
333 LOGE("arkdb: find method error");
334 }
335
336 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
337 SourceManager &sourceManager = session->GetSourceManager();
338 WatchManager &watchManager = session->GetWatchManager();
339
340 std::string::size_type length = wholeMethod.length();
341 std::string::size_type indexPoint = 0;
342 indexPoint = wholeMethod.find_first_of('.', 0);
343 method = wholeMethod.substr(indexPoint + 1, length);
344 if (method == "paused") {
345 PausedReply(std::move(json));
346 return;
347 } else if (method == "scriptParsed") {
348 sourceManager.EnableReply(std::move(json));
349 return;
350 } else if (method == "resumed") {
351 watchManager.DebugFalseState();
352 return;
353 } else {
354 LOGI("arkdb: Debugger reply is: %{public}s", json->Stringify().c_str());
355 }
356 handleResponse(std::move(json));
357 }
358
PausedReply(const std::unique_ptr<PtJson> json)359 void DebuggerClient::PausedReply(const std::unique_ptr<PtJson> json)
360 {
361 if (json == nullptr) {
362 LOGE("arkdb: json parse error");
363 return;
364 }
365
366 if (!json->IsObject()) {
367 LOGE("arkdb: json parse format error");
368 json->ReleaseRoot();
369 return;
370 }
371
372 std::unique_ptr<PtJson> params;
373 Result ret = json->GetObject("params", ¶ms);
374 if (ret != Result::SUCCESS) {
375 LOGE("arkdb: find params error");
376 return;
377 }
378
379 std::unique_ptr<PtJson> callFrames;
380 ret = params->GetArray("callFrames", &callFrames);
381 if (ret != Result::SUCCESS) {
382 LOGE("arkdb: find callFrames error");
383 return;
384 }
385
386 std::map<int32_t, std::unique_ptr<CallFrame>> data;
387 for (int32_t i = 0; i < callFrames->GetSize(); i++) {
388 std::unique_ptr<CallFrame> callFrameInfo = CallFrame::Create(*(callFrames->Get(i)));
389 data.emplace(i + 1, std::move(callFrameInfo));
390 }
391
392 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
393 StackManager& stackManager = session->GetStackManager();
394 SourceManager &sourceManager = session->GetSourceManager();
395 WatchManager &watchManager = session->GetWatchManager();
396 stackManager.ClearCallFrame();
397 stackManager.SetCallFrames(std::move(data));
398 sourceManager.GetDebugSources(callFrames->Get(0));
399 watchManager.RequestWatchInfo(callFrames->Get(0));
400 watchManager.DebugTrueState();
401 }
402
handleResponse(std::unique_ptr<PtJson> json)403 void DebuggerClient::handleResponse(std::unique_ptr<PtJson> json)
404 {
405 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
406 SourceManager &sourceManager = session->GetSourceManager();
407 WatchManager &watchManager = session->GetWatchManager();
408 BreakPointManager& breakpoint = session->GetBreakPointManager();
409 std::unique_ptr<PtJson> result;
410 Result ret = json->GetObject("result", &result);
411 if (ret != Result::SUCCESS) {
412 LOGE("arkdb: find result error");
413 return;
414 }
415 int32_t id;
416 ret = json->GetInt("id", &id);
417 if (ret == Result::SUCCESS) {
418 std::string scriptSource;
419 ret = result->GetString("scriptSource", &scriptSource);
420 if (ret == Result::SUCCESS) {
421 sourceManager.SetFileSource(id, scriptSource);
422 return;
423 }
424 }
425 std::string breakpointId;
426 ret = result->GetString("breakpointId", &breakpointId);
427 if (ret == Result::SUCCESS) {
428 breakpoint.Createbreaklocation(std::move(json));
429 return;
430 }
431 if (watchManager.HandleWatchResult(std::move(json), id)) {
432 return;
433 }
434 return;
435 }
436 } // OHOS::ArkCompiler::Toolchain