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 "libpandabase/macros.h" 20 #include "ecmascript/tooling/agent/runtime_impl.h" 21 #include "ecmascript/tooling/backend/js_pt_hooks.h" 22 #include "ecmascript/tooling/base/pt_params.h" 23 #include "ecmascript/tooling/backend/js_pt_extractor.h" 24 #include "ecmascript/tooling/dispatcher.h" 25 #include "ecmascript/tooling/interface/js_debugger_manager.h" 26 27 namespace panda::ecmascript::tooling { 28 namespace test { 29 class TestHooks; 30 } // namespace test 31 class DebuggerImpl final { 32 public: 33 DebuggerImpl(const EcmaVM *vm, ProtocolChannel *channel, RuntimeImpl *runtime); 34 ~DebuggerImpl(); 35 36 // event 37 bool NotifyScriptParsed(ScriptId scriptId, const std::string &fileName); 38 bool NotifySingleStep(const JSPtLocation &location); 39 void NotifyPaused(std::optional<JSPtLocation> location, PauseReason reason); 40 void NotifyPendingJobEntry(); 41 void NotifyHandleProtocolCommand(); 42 43 DispatchResponse Enable(const EnableParams ¶ms, UniqueDebuggerId *id); 44 DispatchResponse Disable(); 45 DispatchResponse EvaluateOnCallFrame(const EvaluateOnCallFrameParams ¶ms, 46 std::unique_ptr<RemoteObject> *result); 47 DispatchResponse GetPossibleBreakpoints(const GetPossibleBreakpointsParams ¶ms, 48 std::vector<std::unique_ptr<BreakLocation>> *outLocations); 49 DispatchResponse GetScriptSource(const GetScriptSourceParams ¶ms, std::string *source); 50 DispatchResponse Pause(); 51 DispatchResponse RemoveBreakpoint(const RemoveBreakpointParams ¶ms); 52 DispatchResponse Resume(const ResumeParams ¶ms); 53 DispatchResponse SetAsyncCallStackDepth(); 54 DispatchResponse SetBreakpointByUrl(const SetBreakpointByUrlParams ¶ms, std::string *outId, 55 std::vector<std::unique_ptr<Location>> *outLocations); 56 DispatchResponse SetPauseOnExceptions(const SetPauseOnExceptionsParams ¶ms); 57 DispatchResponse StepInto(const StepIntoParams ¶ms); 58 DispatchResponse StepOut(); 59 DispatchResponse StepOver(const StepOverParams ¶ms); 60 DispatchResponse SetBlackboxPatterns(); 61 62 /** 63 * @brief: match first script and callback 64 * 65 * @return: true means matched and callback execute success 66 */ 67 template<class Callback> MatchScripts(const Callback & cb,const std::string & matchStr,ScriptMatchType type)68 bool MatchScripts(const Callback &cb, const std::string &matchStr, ScriptMatchType type) const 69 { 70 for (const auto &script : scripts_) { 71 std::string value; 72 switch (type) { 73 case ScriptMatchType::URL: { 74 value = script.second->GetUrl(); 75 break; 76 } 77 case ScriptMatchType::FILE_NAME: { 78 value = script.second->GetFileName(); 79 break; 80 } 81 case ScriptMatchType::HASH: { 82 value = script.second->GetHash(); 83 break; 84 } 85 default: { 86 return false; 87 } 88 } 89 if (matchStr == value) { 90 return cb(script.second.get()); 91 } 92 } 93 return false; 94 } 95 bool GenerateCallFrames(std::vector<std::unique_ptr<CallFrame>> *callFrames); 96 97 class DispatcherImpl final : public DispatcherBase { 98 public: DispatcherImpl(ProtocolChannel * channel,std::unique_ptr<DebuggerImpl> debugger)99 DispatcherImpl(ProtocolChannel *channel, std::unique_ptr<DebuggerImpl> debugger) 100 : DispatcherBase(channel), debugger_(std::move(debugger)) {} 101 ~DispatcherImpl() override = default; 102 103 void Dispatch(const DispatchRequest &request) override; 104 void Enable(const DispatchRequest &request); 105 void Disable(const DispatchRequest &request); 106 void EvaluateOnCallFrame(const DispatchRequest &request); 107 void GetPossibleBreakpoints(const DispatchRequest &request); 108 void GetScriptSource(const DispatchRequest &request); 109 void Pause(const DispatchRequest &request); 110 void RemoveBreakpoint(const DispatchRequest &request); 111 void Resume(const DispatchRequest &request); 112 void SetAsyncCallStackDepth(const DispatchRequest &request); 113 void SetBreakpointByUrl(const DispatchRequest &request); 114 void SetPauseOnExceptions(const DispatchRequest &request); 115 void StepInto(const DispatchRequest &request); 116 void StepOut(const DispatchRequest &request); 117 void StepOver(const DispatchRequest &request); 118 void SetBlackboxPatterns(const DispatchRequest &request); 119 120 private: 121 NO_COPY_SEMANTIC(DispatcherImpl); 122 NO_MOVE_SEMANTIC(DispatcherImpl); 123 124 using AgentHandler = void (DebuggerImpl::DispatcherImpl::*)(const DispatchRequest &request); 125 std::unique_ptr<DebuggerImpl> debugger_ {}; 126 }; 127 128 private: 129 NO_COPY_SEMANTIC(DebuggerImpl); 130 NO_MOVE_SEMANTIC(DebuggerImpl); 131 132 std::string Trim(const std::string &str); 133 JSPtExtractor *GetExtractor(const JSPandaFile *jsPandaFile); 134 JSPtExtractor *GetExtractor(const std::string &url); 135 std::optional<std::string> CmptEvaluateValue(CallFrameId callFrameId, const std::string &expression, 136 std::unique_ptr<RemoteObject> *result); 137 bool GenerateCallFrame(CallFrame *callFrame, const InterpretedFrameHandler *frameHandler, CallFrameId frameId); 138 void SaveCallFrameHandler(const InterpretedFrameHandler *frameHandler); 139 std::unique_ptr<Scope> GetLocalScopeChain(const InterpretedFrameHandler *frameHandler, 140 std::unique_ptr<RemoteObject> *thisObj); 141 std::unique_ptr<Scope> GetGlobalScopeChain(); 142 void GetLocalVariables(const InterpretedFrameHandler *frameHandler, const JSMethod *method, 143 Local<JSValueRef> &thisVal, Local<ObjectRef> &localObj); 144 void CleanUpOnPaused(); 145 void UpdateScopeObject(const InterpretedFrameHandler *frameHandler, 146 std::string_view varName, Local<JSValueRef> newVal); 147 Local<JSValueRef> ConvertToLocal(const std::string &varValue); 148 bool DecodeAndCheckBase64(const std::string &src, std::string &dest); 149 bool IsSkipLine(const JSPtLocation &location); 150 151 class Frontend { 152 public: Frontend(ProtocolChannel * channel)153 explicit Frontend(ProtocolChannel *channel) : channel_(channel) {} 154 155 void BreakpointResolved(const EcmaVM *vm); 156 void Paused(const EcmaVM *vm, const tooling::Paused &paused); 157 void Resumed(const EcmaVM *vm); 158 void ScriptFailedToParse(const EcmaVM *vm); 159 void ScriptParsed(const EcmaVM *vm, const PtScript &script); 160 void WaitForDebugger(const EcmaVM *vm); 161 162 private: 163 bool AllowNotify(const EcmaVM *vm) const; 164 165 ProtocolChannel *channel_ {nullptr}; 166 }; 167 168 const EcmaVM *vm_ {nullptr}; 169 Frontend frontend_; 170 171 RuntimeImpl *runtime_ {nullptr}; 172 std::unique_ptr<JSPtHooks> hooks_ {nullptr}; 173 JSDebugger *jsDebugger_ {nullptr}; 174 175 std::unordered_map<std::string, JSPtExtractor *> extractors_ {}; 176 std::unordered_map<ScriptId, std::unique_ptr<PtScript>> scripts_ {}; 177 bool pauseOnException_ {false}; 178 bool pauseOnNextByteCode_ {false}; 179 std::unique_ptr<JSPtExtractor::SingleStepper> singleStepper_ {nullptr}; 180 181 std::unordered_map<JSTaggedType *, RemoteObjectId> scopeObjects_ {}; 182 std::vector<std::shared_ptr<InterpretedFrameHandler>> callFrameHandlers_; 183 JsDebuggerManager::ObjectUpdaterFunc updaterFunc_ {nullptr}; 184 185 friend class JSPtHooks; 186 friend class test::TestHooks; 187 }; 188 } // namespace panda::ecmascript::tooling 189 #endif