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", &params);
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