• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #ifndef ECMASCRIPT_TOOLING_AGENT_DEBUGGER_IMPL_H
17 #define ECMASCRIPT_TOOLING_AGENT_DEBUGGER_IMPL_H
18 
19 #include "agent/runtime_impl.h"
20 #include "backend/js_pt_hooks.h"
21 #include "base/pt_params.h"
22 #include "backend/js_single_stepper.h"
23 #include "dispatcher.h"
24 
25 #include "ecmascript/debugger/js_debugger_manager.h"
26 #include "ecmascript/debugger/js_pt_method.h"
27 #include "libpandabase/macros.h"
28 
29 namespace panda::ecmascript::tooling {
30 namespace test {
31 class TestHooks;
32 }  // namespace test
33 
34 enum class DebuggerState { DISABLED, ENABLED, PAUSED };
35 class DebuggerImpl final {
36 public:
37     DebuggerImpl(const EcmaVM *vm, ProtocolChannel *channel, RuntimeImpl *runtime);
38     ~DebuggerImpl();
39 
40     // event
41     bool NotifyScriptParsed(ScriptId scriptId, const std::string &fileName,
42                             std::string_view entryPoint = "func_main_0");
43     bool NotifySingleStep(const JSPtLocation &location);
44     void NotifyPaused(std::optional<JSPtLocation> location, PauseReason reason);
45     void NotifyHandleProtocolCommand();
46     void NotifyNativeCalling(const void *nativeAddress);
47     void SetDebuggerState(DebuggerState debuggerState);
48 
49     DispatchResponse Enable(const EnableParams &params, UniqueDebuggerId *id);
50     DispatchResponse Disable();
51     DispatchResponse EvaluateOnCallFrame(const EvaluateOnCallFrameParams &params,
52                                          std::unique_ptr<RemoteObject> *result);
53     DispatchResponse GetPossibleBreakpoints(const GetPossibleBreakpointsParams &params,
54                                             std::vector<std::unique_ptr<BreakLocation>> *outLocations);
55     DispatchResponse GetScriptSource(const GetScriptSourceParams &params, std::string *source);
56     DispatchResponse Pause();
57     DispatchResponse RemoveBreakpoint(const RemoveBreakpointParams &params);
58     DispatchResponse Resume(const ResumeParams &params);
59     DispatchResponse SetAsyncCallStackDepth();
60     DispatchResponse SetBreakpointByUrl(const SetBreakpointByUrlParams &params, std::string *outId,
61                                         std::vector<std::unique_ptr<Location>> *outLocations);
62     DispatchResponse GetPossibleAndSetBreakpointByUrl(const GetPossibleAndSetBreakpointParams &params,
63                                         std::vector<std::unique_ptr<BreakpointReturnInfo>> &outLocations);
64     DispatchResponse SetPauseOnExceptions(const SetPauseOnExceptionsParams &params);
65     DispatchResponse StepInto(const StepIntoParams &params);
66     DispatchResponse StepOut();
67     DispatchResponse StepOver(const StepOverParams &params);
68     DispatchResponse SetBlackboxPatterns();
69     DispatchResponse SetMixedDebugEnabled(const SetMixedDebugParams &params);
70     DispatchResponse ReplyNativeCalling(const ReplyNativeCallingParams &params);
71     DispatchResponse DropFrame(const DropFrameParams &params);
72 
73     /**
74      * @brief: match first script and callback
75      *
76      * @return: true means matched and callback execute success
77      */
78     template<class Callback>
MatchScripts(const Callback & cb,const std::string & matchStr,ScriptMatchType type)79     bool MatchScripts(const Callback &cb, const std::string &matchStr, ScriptMatchType type) const
80     {
81         for (const auto &script : scripts_) {
82             std::string value;
83             switch (type) {
84                 case ScriptMatchType::URL: {
85                     value = script.second->GetUrl();
86                     break;
87                 }
88                 case ScriptMatchType::FILE_NAME: {
89                     value = script.second->GetFileName();
90                     break;
91                 }
92                 case ScriptMatchType::HASH: {
93                     value = script.second->GetHash();
94                     break;
95                 }
96                 default: {
97                     return false;
98                 }
99             }
100             if (matchStr == value) {
101                 return cb(script.second.get());
102             }
103         }
104         return false;
105     }
106     bool GenerateCallFrames(std::vector<std::unique_ptr<CallFrame>> *callFrames);
107 
108     class DispatcherImpl final : public DispatcherBase {
109     public:
DispatcherImpl(ProtocolChannel * channel,std::unique_ptr<DebuggerImpl> debugger)110         DispatcherImpl(ProtocolChannel *channel, std::unique_ptr<DebuggerImpl> debugger)
111             : DispatcherBase(channel), debugger_(std::move(debugger)) {}
112         ~DispatcherImpl() override = default;
113 
114         void Dispatch(const DispatchRequest &request) override;
115         void Enable(const DispatchRequest &request);
116         void Disable(const DispatchRequest &request);
117         void EvaluateOnCallFrame(const DispatchRequest &request);
118         void GetPossibleBreakpoints(const DispatchRequest &request);
119         void GetScriptSource(const DispatchRequest &request);
120         void Pause(const DispatchRequest &request);
121         void RemoveBreakpoint(const DispatchRequest &request);
122         void Resume(const DispatchRequest &request);
123         void SetAsyncCallStackDepth(const DispatchRequest &request);
124         void SetBreakpointByUrl(const DispatchRequest &request);
125         void SetPauseOnExceptions(const DispatchRequest &request);
126         void StepInto(const DispatchRequest &request);
127         void StepOut(const DispatchRequest &request);
128         void StepOver(const DispatchRequest &request);
129         void SetMixedDebugEnabled(const DispatchRequest &request);
130         void SetBlackboxPatterns(const DispatchRequest &request);
131         void ReplyNativeCalling(const DispatchRequest &request);
132         void GetPossibleAndSetBreakpointByUrl(const DispatchRequest &request);
133         void DropFrame(const DispatchRequest &request);
134 
135     private:
136         NO_COPY_SEMANTIC(DispatcherImpl);
137         NO_MOVE_SEMANTIC(DispatcherImpl);
138 
139         using AgentHandler = void (DebuggerImpl::DispatcherImpl::*)(const DispatchRequest &request);
140         std::unique_ptr<DebuggerImpl> debugger_ {};
141     };
142 
143 private:
144     NO_COPY_SEMANTIC(DebuggerImpl);
145     NO_MOVE_SEMANTIC(DebuggerImpl);
146 
147     std::string Trim(const std::string &str);
148     DebugInfoExtractor *GetExtractor(const JSPandaFile *jsPandaFile);
149     DebugInfoExtractor *GetExtractor(const std::string &url);
150     std::optional<std::string> CmptEvaluateValue(CallFrameId callFrameId, const std::string &expression,
151                                              std::unique_ptr<RemoteObject> *result);
152     bool GenerateCallFrame(CallFrame *callFrame, const FrameHandler *frameHandler, CallFrameId frameId);
153     void SaveCallFrameHandler(const FrameHandler *frameHandler);
154     std::unique_ptr<Scope> GetLocalScopeChain(const FrameHandler *frameHandler,
155         std::unique_ptr<RemoteObject> *thisObj);
156     std::unique_ptr<Scope> GetModuleScopeChain();
157     std::unique_ptr<Scope> GetGlobalScopeChain();
158     void GetLocalVariables(const FrameHandler *frameHandler, panda_file::File::EntityId methodId,
159         const JSPandaFile *jsPandaFile, Local<JSValueRef> &thisVal, Local<ObjectRef> &localObj);
160     void GetClosureVariables(const FrameHandler *frameHandler, Local<JSValueRef> &thisVal,
161         Local<ObjectRef> &localObj);
162     void CleanUpOnPaused();
163     void UpdateScopeObject(const FrameHandler *frameHandler, std::string_view varName, Local<JSValueRef> newVal);
164     void ClearSingleStepper();
165     Local<JSValueRef> ConvertToLocal(const std::string &varValue);
166     bool DecodeAndCheckBase64(const std::string &src, std::vector<uint8_t> &dest);
167     bool IsSkipLine(const JSPtLocation &location);
168     bool CheckPauseOnException();
169     bool IsWithinVariableScope(const LocalVariableInfo &localVariableInfo, uint32_t bcOffset);
170     bool ProcessSingleBreakpoint(const BreakpointInfo &breakpoint,
171         std::vector<std::unique_ptr<BreakpointReturnInfo>> &outLocations);
172 
GetRecordName(const std::string & url)173     const std::string &GetRecordName(const std::string &url)
174     {
175         static const std::string recordName = "";
176         auto iter = recordNames_.find(url);
177         if (iter != recordNames_.end()) {
178             return iter->second;
179         }
180         return recordName;
181     }
182 
183     class Frontend {
184     public:
Frontend(ProtocolChannel * channel)185         explicit Frontend(ProtocolChannel *channel) : channel_(channel) {}
186         ~Frontend() = default;
187 
188         void BreakpointResolved(const EcmaVM *vm);
189         void Paused(const EcmaVM *vm, const tooling::Paused &paused);
190         void Resumed(const EcmaVM *vm);
191         void NativeCalling(const EcmaVM *vm, const tooling::NativeCalling &nativeCalling);
192         void ScriptFailedToParse(const EcmaVM *vm);
193         void ScriptParsed(const EcmaVM *vm, const PtScript &script);
194         void WaitForDebugger(const EcmaVM *vm);
195         void RunIfWaitingForDebugger(const EcmaVM *vm);
196 
197     private:
198         bool AllowNotify(const EcmaVM *vm) const;
199 
200         ProtocolChannel *channel_ {nullptr};
201     };
202 
203     const EcmaVM *vm_ {nullptr};
204     Frontend frontend_;
205 
206     RuntimeImpl *runtime_ {nullptr};
207     std::unique_ptr<JSPtHooks> hooks_ {nullptr};
208     JSDebugger *jsDebugger_ {nullptr};
209 
210     std::unordered_map<std::string, std::string> recordNames_ {};
211     std::unordered_map<ScriptId, std::unique_ptr<PtScript>> scripts_ {};
212     PauseOnExceptionsState pauseOnException_ {PauseOnExceptionsState::NONE};
213     DebuggerState debuggerState_ {DebuggerState::ENABLED};
214     bool pauseOnNextByteCode_ {false};
215     std::unique_ptr<SingleStepper> singleStepper_ {nullptr};
216     std::vector<void *>  nativePointer_;
217 
218     std::unordered_map<JSTaggedType *, RemoteObjectId> scopeObjects_ {};
219     std::vector<std::shared_ptr<FrameHandler>> callFrameHandlers_;
220     JsDebuggerManager::ObjectUpdaterFunc updaterFunc_ {nullptr};
221     JsDebuggerManager::SingleStepperFunc stepperFunc_ {nullptr};
222 
223     friend class JSPtHooks;
224     friend class test::TestHooks;
225 };
226 }  // namespace panda::ecmascript::tooling
227 #endif