• 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 "tooling/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     bool NotifyNativeOut();
46     void NotifyHandleProtocolCommand();
47     void NotifyNativeCalling(const void *nativeAddress);
48     void NotifyNativeReturn(const void *nativeAddress);
49     void NotifyReturnNative();
50     bool IsUserCode(const void *nativeAddress);
51     void SetDebuggerState(DebuggerState debuggerState);
52 
53     DispatchResponse ContinueToLocation(const ContinueToLocationParams &params);
54     DispatchResponse Enable(const EnableParams &params, UniqueDebuggerId *id);
55     DispatchResponse Disable();
56     DispatchResponse EvaluateOnCallFrame(const EvaluateOnCallFrameParams &params,
57                                          std::unique_ptr<RemoteObject> *result);
58     DispatchResponse GetPossibleBreakpoints(const GetPossibleBreakpointsParams &params,
59                                             std::vector<std::unique_ptr<BreakLocation>> *outLocations);
60     DispatchResponse GetScriptSource(const GetScriptSourceParams &params, std::string *source);
61     DispatchResponse Pause();
62     DispatchResponse RemoveBreakpoint(const RemoveBreakpointParams &params);
63     DispatchResponse Resume(const ResumeParams &params);
64     DispatchResponse SetAsyncCallStackDepth();
65     DispatchResponse SetBreakpointByUrl(const SetBreakpointByUrlParams &params, std::string *outId,
66                                         std::vector<std::unique_ptr<Location>> *outLocations);
67     DispatchResponse SetBreakpointsActive(const SetBreakpointsActiveParams &params);
68     DispatchResponse GetPossibleAndSetBreakpointByUrl(const GetPossibleAndSetBreakpointParams &params,
69         std::vector<std::unique_ptr<BreakpointReturnInfo>> &outLocations);
70     DispatchResponse SetPauseOnExceptions(const SetPauseOnExceptionsParams &params);
71     DispatchResponse SetSkipAllPauses(const SetSkipAllPausesParams &params);
72     DispatchResponse SetNativeRange(const SetNativeRangeParams &params);
73     DispatchResponse ResetSingleStepper(const ResetSingleStepperParams &params);
74     DispatchResponse StepInto(const StepIntoParams &params);
75     DispatchResponse StepOut();
76     DispatchResponse StepOver(const StepOverParams &params);
77     DispatchResponse SetBlackboxPatterns();
78     DispatchResponse SetMixedDebugEnabled(const SetMixedDebugParams &params);
79     DispatchResponse ReplyNativeCalling(const ReplyNativeCallingParams &params);
80     DispatchResponse DropFrame(const DropFrameParams &params);
81     DispatchResponse ClientDisconnect();
82     DispatchResponse CallFunctionOn(
83             const CallFunctionOnParams &params,
84             std::unique_ptr<RemoteObject> *outRemoteObject,
85             std::optional<std::unique_ptr<ExceptionDetails>> *outExceptionDetails);
86 
87     /**
88      * @brief: match first script and callback
89      *
90      * @return: true means matched and callback execute success
91      */
92     template<class Callback>
MatchScripts(const Callback & cb,const std::string & matchStr,ScriptMatchType type)93     bool MatchScripts(const Callback &cb, const std::string &matchStr, ScriptMatchType type) const
94     {
95         for (const auto &script : scripts_) {
96             std::string value;
97             switch (type) {
98                 case ScriptMatchType::URL: {
99                     value = script.second->GetUrl();
100                     break;
101                 }
102                 case ScriptMatchType::FILE_NAME: {
103                     value = script.second->GetFileName();
104                     break;
105                 }
106                 case ScriptMatchType::HASH: {
107                     value = script.second->GetHash();
108                     break;
109                 }
110                 default: {
111                     return false;
112                 }
113             }
114             if (matchStr == value) {
115                 return cb(script.second.get());
116             }
117         }
118         return false;
119     }
120 
MatchUrlAndFileName(const std::string & url,const std::string & fileName)121     bool MatchUrlAndFileName(const std::string &url, const std::string &fileName) const
122     {
123         for (const auto &script : scripts_) {
124             if (url == script.second->GetUrl() && fileName == script.second->GetFileName()) {
125                 return true;
126             }
127         }
128         return false;
129     }
130 
MatchAllScripts(const std::string & url)131     std::vector<PtScript *> MatchAllScripts(const std::string &url) const
132     {
133         std::vector<PtScript *> result;
134         for (const auto &script : scripts_) {
135             if (url == script.second->GetUrl()) {
136                 result.push_back(script.second.get());
137             }
138         }
139         return result;
140     }
141     bool GenerateCallFrames(std::vector<std::unique_ptr<CallFrame>> *callFrames, bool getScope);
142 
143     class DispatcherImpl final : public DispatcherBase {
144     public:
DispatcherImpl(ProtocolChannel * channel,std::unique_ptr<DebuggerImpl> debugger)145         DispatcherImpl(ProtocolChannel *channel, std::unique_ptr<DebuggerImpl> debugger)
146             : DispatcherBase(channel), debugger_(std::move(debugger)) {}
147         ~DispatcherImpl() override = default;
148 
149         void ContinueToLocation(const DispatchRequest &request);
150         void Dispatch(const DispatchRequest &request) override;
151         void Enable(const DispatchRequest &request);
152         void Disable(const DispatchRequest &request);
153         void EvaluateOnCallFrame(const DispatchRequest &request);
154         void GetPossibleBreakpoints(const DispatchRequest &request);
155         void GetScriptSource(const DispatchRequest &request);
156         void Pause(const DispatchRequest &request);
157         void RemoveBreakpoint(const DispatchRequest &request);
158         void Resume(const DispatchRequest &request);
159         void SetAsyncCallStackDepth(const DispatchRequest &request);
160         void SetBreakpointByUrl(const DispatchRequest &request);
161         void SetBreakpointsActive(const DispatchRequest &request);
162         void SetPauseOnExceptions(const DispatchRequest &request);
163         void SetSkipAllPauses(const DispatchRequest &request);
164         void SetNativeRange(const DispatchRequest &request);
165         void ResetSingleStepper(const DispatchRequest &request);
166         void StepInto(const DispatchRequest &request);
167         void StepOut(const DispatchRequest &request);
168         void StepOver(const DispatchRequest &request);
169         void SetMixedDebugEnabled(const DispatchRequest &request);
170         void SetBlackboxPatterns(const DispatchRequest &request);
171         void ReplyNativeCalling(const DispatchRequest &request);
172         void GetPossibleAndSetBreakpointByUrl(const DispatchRequest &request);
173         void DropFrame(const DispatchRequest &request);
174         void ClientDisconnect(const DispatchRequest &request);
175         void CallFunctionOn(const DispatchRequest &request);
176 
177     private:
178         NO_COPY_SEMANTIC(DispatcherImpl);
179         NO_MOVE_SEMANTIC(DispatcherImpl);
180 
181         using AgentHandler = void (DebuggerImpl::DispatcherImpl::*)(const DispatchRequest &request);
182         std::unique_ptr<DebuggerImpl> debugger_ {};
183     };
184 
185 private:
186     NO_COPY_SEMANTIC(DebuggerImpl);
187     NO_MOVE_SEMANTIC(DebuggerImpl);
188 
189     std::string Trim(const std::string &str);
190     DebugInfoExtractor *GetExtractor(const JSPandaFile *jsPandaFile);
191     std::vector<DebugInfoExtractor *> GetExtractors(const std::string &url);
192     std::optional<std::string> CmptEvaluateValue(CallFrameId callFrameId, const std::string &expression,
193         std::unique_ptr<RemoteObject> *result);
194     bool GenerateCallFrame(CallFrame *callFrame, const FrameHandler *frameHandler, CallFrameId frameId, bool getScope);
195     void SaveCallFrameHandler(const FrameHandler *frameHandler);
196     std::unique_ptr<Scope> GetLocalScopeChain(const FrameHandler *frameHandler,
197         std::unique_ptr<RemoteObject> *thisObj);
198     std::unique_ptr<Scope> GetModuleScopeChain();
199     std::unique_ptr<Scope> GetGlobalScopeChain();
200     std::vector<std::unique_ptr<Scope>> GetClosureScopeChains(const FrameHandler *frameHandler,
201         std::unique_ptr<RemoteObject> *thisObj);
202     void GetLocalVariables(const FrameHandler *frameHandler, panda_file::File::EntityId methodId,
203         const JSPandaFile *jsPandaFile, Local<JSValueRef> &thisVal, Local<ObjectRef> &localObj);
204     void CleanUpOnPaused();
205     void CleanUpRuntimeProperties();
206     void UpdateScopeObject(const FrameHandler *frameHandler, std::string_view varName, Local<JSValueRef> newVal);
207     void ClearSingleStepper();
208     Local<JSValueRef> ConvertToLocal(const std::string &varValue);
209     bool DecodeAndCheckBase64(const std::string &src, std::vector<uint8_t> &dest);
210     bool IsSkipLine(const JSPtLocation &location);
211     bool CheckPauseOnException();
212     bool IsWithinVariableScope(const LocalVariableInfo &localVariableInfo, uint32_t bcOffset);
213     bool ProcessSingleBreakpoint(const BreakpointInfo &breakpoint,
214         std::vector<std::unique_ptr<BreakpointReturnInfo>> &outLocations);
215     bool IsVariableSkipped(const std::string &varName);
216     Local<FunctionRef> CheckAndGenerateCondFunc(const std::optional<std::string> &condition);
217 
GetRecordName(const std::string & url)218     const std::unordered_set<std::string> &GetRecordName(const std::string &url)
219     {
220         static const std::unordered_set<std::string> recordName;
221         auto iter = recordNames_.find(url);
222         if (iter != recordNames_.end()) {
223             return iter->second;
224         }
225         return recordName;
226     }
227 
228     class Frontend {
229     public:
Frontend(ProtocolChannel * channel)230         explicit Frontend(ProtocolChannel *channel) : channel_(channel) {}
231         ~Frontend() = default;
232 
233         void BreakpointResolved(const EcmaVM *vm);
234         void Paused(const EcmaVM *vm, const tooling::Paused &paused);
235         void Resumed(const EcmaVM *vm);
236         void NativeCalling(const EcmaVM *vm, const tooling::NativeCalling &nativeCalling);
237         void MixedStack(const EcmaVM *vm, const tooling::MixedStack &mixedStack);
238         void ScriptFailedToParse(const EcmaVM *vm);
239         void ScriptParsed(const EcmaVM *vm, const PtScript &script);
240         void WaitForDebugger(const EcmaVM *vm);
241         void RunIfWaitingForDebugger(const EcmaVM *vm);
242 
243     private:
244         bool AllowNotify(const EcmaVM *vm) const;
245 
246         ProtocolChannel *channel_ {nullptr};
247     };
248 
249     const EcmaVM *vm_ {nullptr};
250     Frontend frontend_;
251 
252     RuntimeImpl *runtime_ {nullptr};
253     std::unique_ptr<JSPtHooks> hooks_ {nullptr};
254     JSDebugger *jsDebugger_ {nullptr};
255 
256     std::unordered_map<std::string, std::unordered_set<std::string>> recordNames_ {};
257     std::unordered_map<ScriptId, std::unique_ptr<PtScript>> scripts_ {};
258     PauseOnExceptionsState pauseOnException_ {PauseOnExceptionsState::NONE};
259     DebuggerState debuggerState_ {DebuggerState::ENABLED};
260     bool pauseOnNextByteCode_ {false};
261     bool breakpointsState_ {true};
262     bool skipAllPausess_ {false};
263     bool mixStackEnabled_ {false};
264     std::unique_ptr<SingleStepper> singleStepper_ {nullptr};
265     Location location_ {};
266 
267     std::unique_ptr<SingleStepper> nativeOut_ {nullptr};
268     std::vector<void *>  nativePointer_;
269 
270     bool nativeOutPause_ {false};
271     std::vector<NativeRange> nativeRanges_ {};
272     std::unordered_map<JSTaggedType *, RemoteObjectId> scopeObjects_ {};
273     std::vector<std::shared_ptr<FrameHandler>> callFrameHandlers_;
274     JsDebuggerManager::ObjectUpdaterFunc updaterFunc_ {nullptr};
275     JsDebuggerManager::SingleStepperFunc stepperFunc_ {nullptr};
276     JsDebuggerManager::ReturnNativeFunc returnNative_ {nullptr};
277 
278     friend class JSPtHooks;
279     friend class test::TestHooks;
280 };
281 }  // namespace panda::ecmascript::tooling
282 #endif