1 /* 2 * Copyright (c) 2021-2023 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_DEBUGGER_JS_DEBUGGER_H 17 #define ECMASCRIPT_DEBUGGER_JS_DEBUGGER_H 18 19 #include "ecmascript/debugger/debugger_api.h" 20 #include "ecmascript/debugger/js_debugger_manager.h" 21 #include "ecmascript/debugger/js_pt_method.h" 22 #include "ecmascript/ecma_vm.h" 23 #include "ecmascript/jspandafile/method_literal.h" 24 25 namespace panda::ecmascript::tooling { 26 class JSBreakpoint { 27 public: 28 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) JSBreakpoint(const std::string & sourceFile,PtMethod * ptMethod,uint32_t bcOffset,const Global<FunctionRef> & condFuncRef)29 JSBreakpoint(const std::string &sourceFile, PtMethod *ptMethod, uint32_t bcOffset, 30 const Global<FunctionRef> &condFuncRef) : sourceFile_(sourceFile), ptMethod_(ptMethod), 31 bcOffset_(bcOffset), condFuncRef_(condFuncRef) {} 32 ~JSBreakpoint() = default; 33 GetSourceFile()34 const std::string &GetSourceFile() const 35 { 36 return sourceFile_; 37 } 38 GetPtMethod()39 PtMethod *GetPtMethod() const 40 { 41 return ptMethod_; 42 } 43 GetBytecodeOffset()44 uint32_t GetBytecodeOffset() const 45 { 46 return bcOffset_; 47 } 48 49 bool operator==(const JSBreakpoint &bpoint) const 50 { 51 return bcOffset_ == bpoint.GetBytecodeOffset() && 52 ptMethod_->GetMethodId() == bpoint.GetPtMethod()->GetMethodId() && 53 sourceFile_ == bpoint.GetSourceFile() && 54 ptMethod_->GetJSPandaFile() == bpoint.GetPtMethod()->GetJSPandaFile(); 55 } 56 ToString()57 std::string ToString() const 58 { 59 std::stringstream breakpoint; 60 breakpoint << "["; 61 breakpoint << "methodId:" << ptMethod_->GetMethodId() << ", "; 62 breakpoint << "bytecodeOffset:" << bcOffset_ << ", "; 63 breakpoint << "sourceFile:" << "\""<< sourceFile_ << "\""<< ", "; 64 breakpoint << "jsPandaFile:" << "\"" << ptMethod_->GetJSPandaFile()->GetJSPandaFileDesc() << "\""; 65 breakpoint << "]"; 66 return breakpoint.str(); 67 } 68 GetConditionFunction()69 const Global<FunctionRef> &GetConditionFunction() 70 { 71 return condFuncRef_; 72 } 73 74 DEFAULT_COPY_SEMANTIC(JSBreakpoint); 75 DEFAULT_MOVE_SEMANTIC(JSBreakpoint); 76 77 private: 78 std::string sourceFile_; 79 PtMethod *ptMethod_ {nullptr}; 80 uint32_t bcOffset_; 81 Global<FunctionRef> condFuncRef_; 82 }; 83 84 class HashJSBreakpoint { 85 public: operator()86 size_t operator()(const JSBreakpoint &bpoint) const 87 { 88 return (std::hash<std::string>()(bpoint.GetSourceFile())) ^ 89 (std::hash<uint32_t>()(bpoint.GetPtMethod()->GetMethodId().GetOffset())) ^ 90 (std::hash<uint32_t>()(bpoint.GetBytecodeOffset())); 91 } 92 }; 93 94 class JSDebugger : public JSDebugInterface, RuntimeListener { 95 public: JSDebugger(const EcmaVM * vm)96 explicit JSDebugger(const EcmaVM *vm) : ecmaVm_(vm) 97 { 98 notificationMgr_ = ecmaVm_->GetJsDebuggerManager()->GetNotificationManager(); 99 notificationMgr_->AddListener(this); 100 } ~JSDebugger()101 ~JSDebugger() override 102 { 103 notificationMgr_->RemoveListener(this); 104 } 105 RegisterHooks(PtHooks * hooks)106 void RegisterHooks(PtHooks *hooks) override 107 { 108 hooks_ = hooks; 109 // send vm start event after add hooks 110 notificationMgr_->VmStartEvent(); 111 } UnregisterHooks()112 void UnregisterHooks() override 113 { 114 // send vm death event before delete hooks 115 notificationMgr_->VmDeathEvent(); 116 hooks_ = nullptr; 117 } 118 bool HandleDebuggerStmt(JSHandle<Method> method, uint32_t bcOffset) override; 119 bool SetBreakpoint(const JSPtLocation &location, Local<FunctionRef> condFuncRef) override; 120 bool RemoveBreakpoint(const JSPtLocation &location) override; 121 void RemoveAllBreakpoints() override; 122 void BytecodePcChanged(JSThread *thread, JSHandle<Method> method, uint32_t bcOffset) override; LoadModule(std::string_view filename,std::string_view entryPoint)123 void LoadModule(std::string_view filename, std::string_view entryPoint) override 124 { 125 if (hooks_ == nullptr) { 126 return; 127 } 128 hooks_->LoadModule(filename, entryPoint); 129 } VmStart()130 void VmStart() override 131 { 132 if (hooks_ == nullptr) { 133 return; 134 } 135 hooks_->VmStart(); 136 } VmDeath()137 void VmDeath() override 138 { 139 if (hooks_ == nullptr) { 140 return; 141 } 142 hooks_->VmDeath(); 143 } NativeCalling(const void * nativeAddress)144 void NativeCalling(const void *nativeAddress) override 145 { 146 if (hooks_ == nullptr) { 147 return; 148 } 149 hooks_->NativeCalling(nativeAddress); 150 } NativeReturn(const void * nativeAddress)151 void NativeReturn(const void *nativeAddress) override 152 { 153 if (hooks_ == nullptr) { 154 return; 155 } 156 hooks_->NativeReturn(nativeAddress); 157 } 158 void MethodEntry(JSHandle<Method> method, JSHandle<JSTaggedValue> envHandle) override; 159 void MethodExit(JSHandle<Method> method) override; 160 // used by debugger statement GetSingleStepStatus()161 bool GetSingleStepStatus() const 162 { 163 return singleStepOnDebuggerStmt_; 164 } SetSingleStepStatus(bool status)165 void SetSingleStepStatus(bool status) 166 { 167 singleStepOnDebuggerStmt_ = status; 168 } 169 private: 170 std::unique_ptr<PtMethod> FindMethod(const JSPtLocation &location) const; 171 std::optional<JSBreakpoint> FindBreakpoint(JSHandle<Method> method, uint32_t bcOffset) const; 172 bool RemoveBreakpoint(const std::unique_ptr<PtMethod> &ptMethod, uint32_t bcOffset); 173 void HandleExceptionThrowEvent(const JSThread *thread, JSHandle<Method> method, uint32_t bcOffset); 174 bool HandleStep(JSHandle<Method> method, uint32_t bcOffset); 175 bool HandleNativeOut(); 176 bool HandleBreakpoint(JSHandle<Method> method, uint32_t bcOffset); 177 void DumpBreakpoints(); 178 bool IsBreakpointCondSatisfied(std::optional<JSBreakpoint> breakpoint) const; 179 180 const EcmaVM *ecmaVm_; 181 PtHooks *hooks_ {nullptr}; 182 NotificationManager *notificationMgr_ {nullptr}; 183 bool singleStepOnDebuggerStmt_ {false}; 184 185 CUnorderedSet<JSBreakpoint, HashJSBreakpoint> breakpoints_ {}; 186 }; 187 } // namespace panda::ecmascript::tooling 188 189 #endif // ECMASCRIPT_DEBUGGER_JS_DEBUGGER_H 190