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