1 /* 2 * Copyright (c) 2021-2022 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_BACKEND_JS_DEBUGGER_H 17 #define ECMASCRIPT_TOOLING_BACKEND_JS_DEBUGGER_H 18 19 #include "ecmascript/ecma_vm.h" 20 #include "ecmascript/js_method.h" 21 #include "ecmascript/tooling/backend/debugger_api.h" 22 #include "ecmascript/tooling/interface/notification_manager.h" 23 #include "ecmascript/tooling/interface/js_debugger_manager.h" 24 25 namespace panda::ecmascript::tooling { 26 class JSBreakpoint { 27 public: 28 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) JSBreakpoint(JSMethod * method,uint32_t bcOffset,const Global<FunctionRef> & condFuncRef)29 JSBreakpoint(JSMethod *method, uint32_t bcOffset, const Global<FunctionRef> &condFuncRef) 30 : method_(method), bcOffset_(bcOffset), condFuncRef_(condFuncRef) {} 31 ~JSBreakpoint() = default; 32 GetMethod()33 JSMethod *GetMethod() const 34 { 35 return method_; 36 } 37 GetBytecodeOffset()38 uint32_t GetBytecodeOffset() const 39 { 40 return bcOffset_; 41 } 42 43 bool operator==(const JSBreakpoint &bpoint) const 44 { 45 return GetMethod() == bpoint.GetMethod() && GetBytecodeOffset() == bpoint.GetBytecodeOffset(); 46 } 47 GetConditionFunction()48 const Global<FunctionRef> &GetConditionFunction() 49 { 50 return condFuncRef_; 51 } 52 53 DEFAULT_COPY_SEMANTIC(JSBreakpoint); 54 DEFAULT_MOVE_SEMANTIC(JSBreakpoint); 55 56 private: 57 JSMethod *method_; 58 uint32_t bcOffset_; 59 Global<FunctionRef> condFuncRef_; 60 }; 61 62 class HashJSBreakpoint { 63 public: operator()64 size_t operator()(const JSBreakpoint &bpoint) const 65 { 66 return (std::hash<JSMethod *>()(bpoint.GetMethod())) ^ (std::hash<uint32_t>()(bpoint.GetBytecodeOffset())); 67 } 68 }; 69 70 class JSDebugger : public JSDebugInterface, RuntimeListener { 71 public: JSDebugger(const EcmaVM * vm)72 explicit JSDebugger(const EcmaVM *vm) : ecmaVm_(vm) 73 { 74 notificationMgr_ = ecmaVm_->GetJsDebuggerManager()->GetNotificationManager(); 75 notificationMgr_->AddListener(this); 76 } ~JSDebugger()77 ~JSDebugger() override 78 { 79 notificationMgr_->RemoveListener(); 80 } 81 RegisterHooks(PtHooks * hooks)82 void RegisterHooks(PtHooks *hooks) override 83 { 84 hooks_ = hooks; 85 // send vm start event after add hooks 86 notificationMgr_->VmStartEvent(); 87 } UnregisterHooks()88 void UnregisterHooks() override 89 { 90 // send vm death event before delete hooks 91 notificationMgr_->VmDeathEvent(); 92 hooks_ = nullptr; 93 } 94 95 bool SetBreakpoint(const JSPtLocation &location, Local<FunctionRef> condFuncRef) override; 96 bool RemoveBreakpoint(const JSPtLocation &location) override; 97 void BytecodePcChanged(JSThread *thread, JSMethod *method, uint32_t bcOffset) override; LoadModule(std::string_view filename)98 void LoadModule(std::string_view filename) override 99 { 100 if (hooks_ == nullptr) { 101 return; 102 } 103 hooks_->LoadModule(filename); 104 } VmStart()105 void VmStart() override 106 { 107 if (hooks_ == nullptr) { 108 return; 109 } 110 hooks_->VmStart(); 111 } VmDeath()112 void VmDeath() override 113 { 114 if (hooks_ == nullptr) { 115 return; 116 } 117 hooks_->VmDeath(); 118 } PendingJobEntry()119 void PendingJobEntry() override 120 { 121 if (hooks_ == nullptr) { 122 return; 123 } 124 hooks_->PendingJobEntry(); 125 } 126 127 private: 128 JSMethod *FindMethod(const JSPtLocation &location) const; 129 std::optional<JSBreakpoint> FindBreakpoint(const JSMethod *method, uint32_t bcOffset) const; 130 bool RemoveBreakpoint(const JSMethod *method, uint32_t bcOffset); 131 void HandleExceptionThrowEvent(const JSThread *thread, const JSMethod *method, uint32_t bcOffset); 132 bool HandleStep(const JSMethod *method, uint32_t bcOffset); 133 bool HandleBreakpoint(const JSMethod *method, uint32_t bcOffset); 134 135 const EcmaVM *ecmaVm_; 136 PtHooks *hooks_ {nullptr}; 137 NotificationManager *notificationMgr_ {nullptr}; 138 139 CUnorderedSet<JSBreakpoint, HashJSBreakpoint> breakpoints_ {}; 140 }; 141 } // namespace panda::ecmascript::tooling 142 143 #endif // ECMASCRIPT_TOOLING_BACKEND_JS_DEBUGGER_H 144