• 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/dynamic/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 enum class DebuggerFeature { LAUNCH_ACCELERATE, UNKNOWN };
36 class DebuggerImpl final {
37 public:
38     DebuggerImpl(const EcmaVM *vm, ProtocolChannel *channel, RuntimeImpl *runtime);
39     ~DebuggerImpl();
40 
41     // event
42     bool NotifyScriptParsed(const std::string &fileName,
43                             std::string_view entryPoint = "func_main_0");
44     bool CheckScriptParsed(const std::string &fileName);
45     bool NotifyScriptParsedBySendable(JSHandle<Method> method);
46     bool MatchUrlAndFileName(const std::string &url, const std::string &fileName);
47     bool NotifySingleStep(const JSPtLocation &location);
48     void NotifyPaused(std::optional<JSPtLocation> location, PauseReason reason);
49     void GeneratePausedInfo(PauseReason reason,
50                            std::vector<std::string> &hitBreakpoints,
51                            const Local<JSValueRef> &exception);
52     bool NotifyNativeOut();
53     void NotifyHandleProtocolCommand();
54     std::vector<void *> GetNativeAddr();
55     void NotifyNativeCalling(const void *nativeAddress);
56     void NotifyNativeReturn(const void *nativeAddress);
57     void NotifyReturnNative();
58     bool IsUserCode(const void *nativeAddress);
59     void SetDebuggerState(DebuggerState debuggerState);
60     void SetNativeOutPause(bool nativeOutPause);
61     void AddBreakpointDetail(const std::string &url, int32_t lineNumber,
62         std::string *outId, std::vector<std::unique_ptr<Location>> *outLocations);
63     bool GenerateAsyncFrames(std::shared_ptr<AsyncStack> asyncStack, bool skipTopFrame);
64     bool GenerateAsyncFrame(StackFrame *stackFrame, const FrameHandler *frameHandler);
65     void SetPauseOnNextByteCode(bool pauseOnNextByteCode);
66 
67     DispatchResponse ContinueToLocation(const ContinueToLocationParams &params);
68     DispatchResponse Enable(const EnableParams &params, UniqueDebuggerId *id);
69     DispatchResponse Disable();
70     DispatchResponse EvaluateOnCallFrame(const EvaluateOnCallFrameParams &params,
71                                          std::unique_ptr<RemoteObject> *result);
72     DispatchResponse GetPossibleBreakpoints(const GetPossibleBreakpointsParams &params,
73                                             std::vector<std::unique_ptr<BreakLocation>> *outLocations);
74     DispatchResponse GetScriptSource(const GetScriptSourceParams &params, std::string *source);
75     DispatchResponse Pause();
76     DispatchResponse RemoveBreakpoint(const RemoveBreakpointParams &params);
77     DispatchResponse RemoveBreakpointsByUrl(const RemoveBreakpointsByUrlParams &params);
78     DispatchResponse Resume(const ResumeParams &params);
79     DispatchResponse SetAsyncCallStackDepth(const SetAsyncCallStackDepthParams &params);
80     DispatchResponse SetBreakpointByUrl(const SetBreakpointByUrlParams &params, std::string *outId,
81                                         std::vector<std::unique_ptr<Location>> *outLocations,
82                                         bool isSmartBreakpoint = false);
83     DispatchResponse SetBreakpointsActive(const SetBreakpointsActiveParams &params);
84     DispatchResponse GetPossibleAndSetBreakpointByUrl(const GetPossibleAndSetBreakpointParams &params,
85         std::vector<std::shared_ptr<BreakpointReturnInfo>> &outLocations);
86     DispatchResponse SetPauseOnExceptions(const SetPauseOnExceptionsParams &params);
87     DispatchResponse SetSkipAllPauses(const SetSkipAllPausesParams &params);
88     DispatchResponse SetNativeRange(const SetNativeRangeParams &params);
89     DispatchResponse ResetSingleStepper(const ResetSingleStepperParams &params);
90     DispatchResponse StepInto(const StepIntoParams &params);
91     DispatchResponse SmartStepInto(const SmartStepIntoParams &params);
92     DispatchResponse StepOut();
93     DispatchResponse StepOver(const StepOverParams &params);
94     DispatchResponse SetBlackboxPatterns();
95     DispatchResponse SetMixedDebugEnabled(const SetMixedDebugParams &params);
96     DispatchResponse ReplyNativeCalling(const ReplyNativeCallingParams &params);
97     DispatchResponse DropFrame(const DropFrameParams &params);
98     DispatchResponse ClientDisconnect();
99     DispatchResponse CallFunctionOn(
100             const CallFunctionOnParams &params,
101             std::unique_ptr<RemoteObject> *outRemoteObject,
102             std::optional<std::unique_ptr<ExceptionDetails>> *outExceptionDetails);
103     DispatchResponse SaveAllPossibleBreakpoints(const SaveAllPossibleBreakpointsParams &params);
104     DispatchResponse SetSymbolicBreakpoints(const SetSymbolicBreakpointsParams &params);
105     DispatchResponse RemoveSymbolicBreakpoints(const RemoveSymbolicBreakpointsParams &params);
106 
107     /**
108      * @brief: match first script and callback
109      *
110      * @return: true means matched and callback execute success
111      */
112     template<class Callback>
MatchScripts(const Callback & cb,const std::string & matchStr,ScriptMatchType type)113     bool MatchScripts(const Callback &cb, const std::string &matchStr, ScriptMatchType type) const
114     {
115         for (const auto &script : scripts_) {
116             std::string value;
117             switch (type) {
118                 case ScriptMatchType::URL: {
119                     value = script.second->GetUrl();
120                     break;
121                 }
122                 case ScriptMatchType::FILE_NAME: {
123                     value = script.second->GetFileName();
124                     break;
125                 }
126                 case ScriptMatchType::HASH: {
127                     value = script.second->GetHash();
128                     break;
129                 }
130                 default: {
131                     return false;
132                 }
133             }
134             if (matchStr == value) {
135                 return cb(script.second.get());
136             }
137         }
138         return false;
139     }
140 
MatchAllScripts(const std::string & url)141     std::vector<PtScript *> MatchAllScripts(const std::string &url) const
142     {
143         std::vector<PtScript *> result;
144         for (const auto &script : scripts_) {
145             if (url == script.second->GetUrl()) {
146                 result.push_back(script.second.get());
147             }
148         }
149         return result;
150     }
151     bool GenerateCallFrames(std::vector<std::unique_ptr<CallFrame>> *callFrames, bool getScope);
152 
153     class DispatcherImpl final : public DispatcherBase {
154     public:
DispatcherImpl(ProtocolChannel * channel,std::unique_ptr<DebuggerImpl> debugger)155         DispatcherImpl(ProtocolChannel *channel, std::unique_ptr<DebuggerImpl> debugger)
156             : DispatcherBase(channel), debugger_(std::move(debugger)) {}
157         ~DispatcherImpl() override = default;
158 
159         void ContinueToLocation(const DispatchRequest &request);
160         std::string GetJsFrames();
161         std::string EvaluateOnCallFrame(const int32_t callId, std::unique_ptr<EvaluateOnCallFrameParams> params);
162         std::string CallFunctionOn(const int32_t callId, std::unique_ptr<CallFunctionOnParams> params);
163         void Dispatch(const DispatchRequest &request) override;
164         void Enable(const DispatchRequest &request);
165         void Disable(const DispatchRequest &request);
166         void EvaluateOnCallFrame(const DispatchRequest &request);
167         void GetPossibleBreakpoints(const DispatchRequest &request);
168         void GetScriptSource(const DispatchRequest &request);
169         void Pause(const DispatchRequest &request);
170         void RemoveBreakpoint(const DispatchRequest &request);
171         void RemoveBreakpointsByUrl(const DispatchRequest &request);
172         void Resume(const DispatchRequest &request);
173         void SetAsyncCallStackDepth(const DispatchRequest &request);
174         void SetBreakpointByUrl(const DispatchRequest &request);
175         void SetBreakpointsActive(const DispatchRequest &request);
176         void SetPauseOnExceptions(const DispatchRequest &request);
177         void SetSkipAllPauses(const DispatchRequest &request);
178         void SetNativeRange(const DispatchRequest &request);
179         void ResetSingleStepper(const DispatchRequest &request);
180         void StepInto(const DispatchRequest &request);
181         void SmartStepInto(const DispatchRequest &request);
182         void StepOut(const DispatchRequest &request);
183         void StepOver(const DispatchRequest &request);
184         void SetMixedDebugEnabled(const DispatchRequest &request);
185         void SetBlackboxPatterns(const DispatchRequest &request);
186         void ReplyNativeCalling(const DispatchRequest &request);
187         void GetPossibleAndSetBreakpointByUrl(const DispatchRequest &request);
188         void DropFrame(const DispatchRequest &request);
189         void ClientDisconnect(const DispatchRequest &request);
190         void CallFunctionOn(const DispatchRequest &request);
191         void SaveAllPossibleBreakpoints(const DispatchRequest &request);
192         void SetSymbolicBreakpoints(const DispatchRequest &request);
193         void RemoveSymbolicBreakpoints(const DispatchRequest &request);
194         std::string SaveAllPossibleBreakpoints(const int32_t callId,
195             std::unique_ptr<SaveAllPossibleBreakpointsParams> params);
196         std::string RemoveBreakpointsByUrl(const int32_t callId,
197             std::unique_ptr<RemoveBreakpointsByUrlParams> params);
198         std::string GetPossibleAndSetBreakpointByUrl(const int32_t callId,
199             std::unique_ptr<GetPossibleAndSetBreakpointParams> params);
200 
201         enum class Method {
202             CONTINUE_TO_LOCATION,
203             ENABLE,
204             DISABLE,
205             EVALUATE_ON_CALL_FRAME,
206             GET_POSSIBLE_BREAKPOINTS,
207             GET_SCRIPT_SOURCE,
208             PAUSE,
209             REMOVE_BREAKPOINT,
210             REMOVE_BREAKPOINTS_BY_URL,
211             RESUME,
212             SET_ASYNC_CALL_STACK_DEPTH,
213             SET_BREAKPOINT_BY_URL,
214             SET_BREAKPOINTS_ACTIVE,
215             SET_PAUSE_ON_EXCEPTIONS,
216             SET_SKIP_ALL_PAUSES,
217             STEP_INTO,
218             SMART_STEP_INTO,
219             STEP_OUT,
220             STEP_OVER,
221             SET_MIXED_DEBUG_ENABLED,
222             SET_BLACKBOX_PATTERNS,
223             REPLY_NATIVE_CALLING,
224             GET_POSSIBLE_AND_SET_BREAKPOINT_BY_URL,
225             DROP_FRAME,
226             SET_NATIVE_RANGE,
227             RESET_SINGLE_STEPPER,
228             CLIENT_DISCONNECT,
229             CALL_FUNCTION_ON,
230             SAVE_ALL_POSSIBLE_BREAKPOINTS,
231             SET_SYMBOLIC_BREAKPOINTS,
232             REMOVE_SYMBOLIC_BREAKPOINTS,
233             UNKNOWN
234         };
235         Method GetMethodEnum(const std::string& method);
236 
237     private:
238         NO_COPY_SEMANTIC(DispatcherImpl);
239         NO_MOVE_SEMANTIC(DispatcherImpl);
240 
241         std::unique_ptr<DebuggerImpl> debugger_ {};
242     };
243 
244 private:
245     NO_COPY_SEMANTIC(DebuggerImpl);
246     NO_MOVE_SEMANTIC(DebuggerImpl);
247 
248     std::string Trim(const std::string &str);
249     DebugInfoExtractor *GetExtractor(const JSPandaFile *jsPandaFile);
250     std::vector<DebugInfoExtractor *> GetExtractors(const std::string &url);
251     std::optional<std::string> CmptEvaluateValue(CallFrameId callFrameId, const std::string &expression,
252         std::unique_ptr<RemoteObject> *result);
253     bool GenerateCallFrame(CallFrame *callFrame, const FrameHandler *frameHandler, CallFrameId frameId, bool getScope);
254     void GenerateScopeChains(bool getScope, const FrameHandler *frameHandler, const JSPandaFile *jsPandaFile,
255         std::vector<std::unique_ptr<Scope>> &scopeChain, std::unique_ptr<RemoteObject> &thisObj);
256     void SaveCallFrameHandler(const FrameHandler *frameHandler);
257     std::unique_ptr<Scope> GetLocalScopeChain(const FrameHandler *frameHandler,
258         std::unique_ptr<RemoteObject> *thisObj);
259     std::unique_ptr<Scope> GetModuleScopeChain(const FrameHandler *frameHandler);
260     std::unique_ptr<Scope> GetGlobalScopeChain(const FrameHandler *frameHandler);
261     std::vector<std::unique_ptr<Scope>> GetClosureScopeChains(const FrameHandler *frameHandler,
262         std::unique_ptr<RemoteObject> *thisObj);
263     void GetLocalVariables(const FrameHandler *frameHandler, panda_file::File::EntityId methodId,
264         const JSPandaFile *jsPandaFile, Local<JSValueRef> &thisVal, Local<ObjectRef> &localObj);
265     void CleanUpOnPaused();
266     void CleanUpRuntimeProperties();
267     void UpdateScopeObject(const FrameHandler *frameHandler, std::string_view varName,
268         Local<JSValueRef> newVal, const std::string& scope);
269     void ClearSingleStepper();
270     Local<JSValueRef> ConvertToLocal(const std::string &varValue);
271     bool DecodeAndCheckBase64(const std::string &src, std::vector<uint8_t> &dest);
272     bool IsSkipLine(const JSPtLocation &location);
273     bool CheckPauseOnException();
274     bool IsWithinVariableScope(const LocalVariableInfo &localVariableInfo, uint32_t bcOffset);
275     bool ProcessSingleBreakpoint(const BreakpointInfo &breakpoint,
276         std::vector<std::shared_ptr<BreakpointReturnInfo>> &outLocations);
277     bool IsVariableSkipped(const std::string &varName);
278     Local<FunctionRef> CheckAndGenerateCondFunc(const std::optional<std::string> &condition);
279     void InitializeExtendedProtocolsList();
280     bool NeedToSetBreakpointsWhenParsingScript(const std::string &url);
281     std::vector<std::shared_ptr<BreakpointReturnInfo>> SetBreakpointsWhenParsingScript(const std::string &url);
282     void SavePendingBreakpoints(const SaveAllPossibleBreakpointsParams &params);
283     bool InsertIntoPendingBreakpoints(const BreakpointInfo &breakpoint);
284     void SaveParsedScriptsAndUrl(const std::string &fileName, const std::string &url,
285         const std::string &recordName, const std::string &source = "");
286     void EnableDebuggerFeatures(const EnableParams &params);
287     DebuggerFeature GetDebuggerFeatureEnum(std::string &option);
288     void EnableFeature(DebuggerFeature feature);
289 
GetRecordName(const std::string & url)290     const std::unordered_set<std::string> &GetRecordName(const std::string &url)
291     {
292         static const std::unordered_set<std::string> recordName;
293         auto iter = recordNames_.find(url);
294         if (iter != recordNames_.end()) {
295             return iter->second;
296         }
297         return recordName;
298     }
EnableLaunchAccelerateMode()299     void EnableLaunchAccelerateMode()
300     {
301         breakOnStartEnable_ = false;
302     }
IsLaunchAccelerateMode()303     bool IsLaunchAccelerateMode() const
304     {
305         return !breakOnStartEnable_;
306     }
307 
GetAllRecordNames()308     const std::unordered_set<std::string> &GetAllRecordNames() const
309     {
310         return recordNameSet_;
311     }
312 
313     class Frontend {
314     public:
Frontend(ProtocolChannel * channel)315         explicit Frontend(ProtocolChannel *channel) : channel_(channel) {}
316         ~Frontend() = default;
317 
318         void BreakpointResolved(const EcmaVM *vm);
319         void Paused(const EcmaVM *vm, const tooling::Paused &paused);
320         void Resumed(const EcmaVM *vm);
321         void NativeCalling(const EcmaVM *vm, const tooling::NativeCalling &nativeCalling);
322         void MixedStack(const EcmaVM *vm, const tooling::MixedStack &mixedStack);
323         void ScriptFailedToParse(const EcmaVM *vm);
324         void ScriptParsed(const EcmaVM *vm, const PtScript &script);
325         void WaitForDebugger(const EcmaVM *vm);
326         void RunIfWaitingForDebugger(const EcmaVM *vm);
327 
328     private:
329         bool AllowNotify(const EcmaVM *vm) const;
330 
331         ProtocolChannel *channel_ {nullptr};
332     };
333 
334     const EcmaVM *vm_ {nullptr};
335     Frontend frontend_;
336 
337     RuntimeImpl *runtime_ {nullptr};
338     std::unique_ptr<JSPtHooks> hooks_ {nullptr};
339     JSDebugger *jsDebugger_ {nullptr};
340 
341     std::unordered_map<std::string, std::unordered_set<std::string>> recordNames_ {};
342     std::unordered_set<std::string> recordNameSet_ {};
343     std::unordered_map<std::string, std::unordered_set<std::string>> urlFileNameMap_ {};
344     std::unordered_map<ScriptId, std::shared_ptr<PtScript>> scripts_ {};
345     PauseOnExceptionsState pauseOnException_ {PauseOnExceptionsState::NONE};
346     DebuggerState debuggerState_ {DebuggerState::ENABLED};
347     bool pauseOnNextByteCode_ {false};
348     bool breakpointsState_ {true};
349     bool skipAllPausess_ {false};
350     bool mixStackEnabled_ {false};
351     int32_t maxAsyncCallChainDepth_ {0};
352     std::unique_ptr<SingleStepper> singleStepper_ {nullptr};
353     Location location_ {};
354 
355     std::unique_ptr<SingleStepper> nativeOut_ {nullptr};
356     std::vector<void *>  nativePointer_;
357 
358     bool nativeOutPause_ {false};
359     std::vector<NativeRange> nativeRanges_ {};
360     std::unordered_map<JSTaggedType *, std::unordered_map<std::string,
361         std::vector<RemoteObjectId>>> scopeObjects_ {};
362     std::vector<std::shared_ptr<FrameHandler>> callFrameHandlers_;
363     JsDebuggerManager::ObjectUpdaterFunc updaterFunc_ {nullptr};
364     JsDebuggerManager::SingleStepperFunc stepperFunc_ {nullptr};
365     JsDebuggerManager::ReturnNativeFunc returnNative_ {nullptr};
366     std::vector<std::string> debuggerExtendedProtocols_ {};
367     // For launch accelerate mode
368     std::unordered_map<std::string, CUnorderedSet<std::shared_ptr<BreakpointInfo>, HashBreakpointInfo>>
369         breakpointPendingMap_ {};
370     bool breakOnStartEnable_ {true};
371 
372     friend class JSPtHooks;
373     friend class test::TestHooks;
374     friend class DebuggerImplFriendTest;
375 };
376 }  // namespace panda::ecmascript::tooling
377 #endif