14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021-2023 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_DEBUGGER_JS_DEBUGGER_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_DEBUGGER_JS_DEBUGGER_H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include "ecmascript/debugger/debugger_api.h" 204514f5e3Sopenharmony_ci#include "ecmascript/debugger/js_debugger_manager.h" 214514f5e3Sopenharmony_ci#include "ecmascript/debugger/js_pt_method.h" 224514f5e3Sopenharmony_ci#include "ecmascript/ecma_vm.h" 234514f5e3Sopenharmony_ci#include "ecmascript/jspandafile/method_literal.h" 244514f5e3Sopenharmony_ci 254514f5e3Sopenharmony_cinamespace panda::ecmascript::tooling { 264514f5e3Sopenharmony_ciclass JSBreakpoint { 274514f5e3Sopenharmony_cipublic: 284514f5e3Sopenharmony_ci // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) 294514f5e3Sopenharmony_ci JSBreakpoint(const std::string &sourceFile, PtMethod *ptMethod, uint32_t bcOffset, 304514f5e3Sopenharmony_ci const Global<FunctionRef> &condFuncRef) : sourceFile_(sourceFile), ptMethod_(ptMethod), 314514f5e3Sopenharmony_ci bcOffset_(bcOffset), condFuncRef_(condFuncRef) {} 324514f5e3Sopenharmony_ci ~JSBreakpoint() = default; 334514f5e3Sopenharmony_ci 344514f5e3Sopenharmony_ci const std::string &GetSourceFile() const 354514f5e3Sopenharmony_ci { 364514f5e3Sopenharmony_ci return sourceFile_; 374514f5e3Sopenharmony_ci } 384514f5e3Sopenharmony_ci 394514f5e3Sopenharmony_ci PtMethod *GetPtMethod() const 404514f5e3Sopenharmony_ci { 414514f5e3Sopenharmony_ci return ptMethod_; 424514f5e3Sopenharmony_ci } 434514f5e3Sopenharmony_ci 444514f5e3Sopenharmony_ci uint32_t GetBytecodeOffset() const 454514f5e3Sopenharmony_ci { 464514f5e3Sopenharmony_ci return bcOffset_; 474514f5e3Sopenharmony_ci } 484514f5e3Sopenharmony_ci 494514f5e3Sopenharmony_ci bool operator==(const JSBreakpoint &bpoint) const 504514f5e3Sopenharmony_ci { 514514f5e3Sopenharmony_ci return bcOffset_ == bpoint.GetBytecodeOffset() && 524514f5e3Sopenharmony_ci ptMethod_->GetMethodId() == bpoint.GetPtMethod()->GetMethodId() && 534514f5e3Sopenharmony_ci sourceFile_ == bpoint.GetSourceFile() && 544514f5e3Sopenharmony_ci ptMethod_->GetJSPandaFile() == bpoint.GetPtMethod()->GetJSPandaFile(); 554514f5e3Sopenharmony_ci } 564514f5e3Sopenharmony_ci 574514f5e3Sopenharmony_ci std::string ToString() const 584514f5e3Sopenharmony_ci { 594514f5e3Sopenharmony_ci std::stringstream breakpoint; 604514f5e3Sopenharmony_ci breakpoint << "["; 614514f5e3Sopenharmony_ci breakpoint << "methodId:" << ptMethod_->GetMethodId() << ", "; 624514f5e3Sopenharmony_ci breakpoint << "bytecodeOffset:" << bcOffset_ << ", "; 634514f5e3Sopenharmony_ci breakpoint << "sourceFile:" << "\""<< sourceFile_ << "\""<< ", "; 644514f5e3Sopenharmony_ci breakpoint << "jsPandaFile:" << "\"" << ptMethod_->GetJSPandaFile()->GetJSPandaFileDesc() << "\""; 654514f5e3Sopenharmony_ci breakpoint << "]"; 664514f5e3Sopenharmony_ci return breakpoint.str(); 674514f5e3Sopenharmony_ci } 684514f5e3Sopenharmony_ci 694514f5e3Sopenharmony_ci const Global<FunctionRef> &GetConditionFunction() 704514f5e3Sopenharmony_ci { 714514f5e3Sopenharmony_ci return condFuncRef_; 724514f5e3Sopenharmony_ci } 734514f5e3Sopenharmony_ci 744514f5e3Sopenharmony_ci DEFAULT_COPY_SEMANTIC(JSBreakpoint); 754514f5e3Sopenharmony_ci DEFAULT_MOVE_SEMANTIC(JSBreakpoint); 764514f5e3Sopenharmony_ci 774514f5e3Sopenharmony_ciprivate: 784514f5e3Sopenharmony_ci std::string sourceFile_; 794514f5e3Sopenharmony_ci PtMethod *ptMethod_ {nullptr}; 804514f5e3Sopenharmony_ci uint32_t bcOffset_; 814514f5e3Sopenharmony_ci Global<FunctionRef> condFuncRef_; 824514f5e3Sopenharmony_ci}; 834514f5e3Sopenharmony_ci 844514f5e3Sopenharmony_ciclass HashJSBreakpoint { 854514f5e3Sopenharmony_cipublic: 864514f5e3Sopenharmony_ci size_t operator()(const JSBreakpoint &bpoint) const 874514f5e3Sopenharmony_ci { 884514f5e3Sopenharmony_ci return (std::hash<std::string>()(bpoint.GetSourceFile())) ^ 894514f5e3Sopenharmony_ci (std::hash<uint32_t>()(bpoint.GetPtMethod()->GetMethodId().GetOffset())) ^ 904514f5e3Sopenharmony_ci (std::hash<uint32_t>()(bpoint.GetBytecodeOffset())); 914514f5e3Sopenharmony_ci } 924514f5e3Sopenharmony_ci}; 934514f5e3Sopenharmony_ci 944514f5e3Sopenharmony_ciclass JSDebugger : public JSDebugInterface, RuntimeListener { 954514f5e3Sopenharmony_cipublic: 964514f5e3Sopenharmony_ci explicit JSDebugger(const EcmaVM *vm) : ecmaVm_(vm) 974514f5e3Sopenharmony_ci { 984514f5e3Sopenharmony_ci notificationMgr_ = ecmaVm_->GetJsDebuggerManager()->GetNotificationManager(); 994514f5e3Sopenharmony_ci notificationMgr_->AddListener(this); 1004514f5e3Sopenharmony_ci } 1014514f5e3Sopenharmony_ci ~JSDebugger() override 1024514f5e3Sopenharmony_ci { 1034514f5e3Sopenharmony_ci notificationMgr_->RemoveListener(this); 1044514f5e3Sopenharmony_ci } 1054514f5e3Sopenharmony_ci 1064514f5e3Sopenharmony_ci void RegisterHooks(PtHooks *hooks) override 1074514f5e3Sopenharmony_ci { 1084514f5e3Sopenharmony_ci hooks_ = hooks; 1094514f5e3Sopenharmony_ci // send vm start event after add hooks 1104514f5e3Sopenharmony_ci notificationMgr_->VmStartEvent(); 1114514f5e3Sopenharmony_ci } 1124514f5e3Sopenharmony_ci void UnregisterHooks() override 1134514f5e3Sopenharmony_ci { 1144514f5e3Sopenharmony_ci // send vm death event before delete hooks 1154514f5e3Sopenharmony_ci notificationMgr_->VmDeathEvent(); 1164514f5e3Sopenharmony_ci hooks_ = nullptr; 1174514f5e3Sopenharmony_ci } 1184514f5e3Sopenharmony_ci bool HandleDebuggerStmt(JSHandle<Method> method, uint32_t bcOffset) override; 1194514f5e3Sopenharmony_ci bool SetBreakpoint(const JSPtLocation &location, Local<FunctionRef> condFuncRef) override; 1204514f5e3Sopenharmony_ci bool SetSmartBreakpoint(const JSPtLocation &location); 1214514f5e3Sopenharmony_ci bool RemoveBreakpoint(const JSPtLocation &location) override; 1224514f5e3Sopenharmony_ci void RemoveAllBreakpoints() override; 1234514f5e3Sopenharmony_ci bool RemoveBreakpointsByUrl(const std::string &url) override; 1244514f5e3Sopenharmony_ci void BytecodePcChanged(JSThread *thread, JSHandle<Method> method, uint32_t bcOffset) override; 1254514f5e3Sopenharmony_ci void LoadModule(std::string_view filename, std::string_view entryPoint) override 1264514f5e3Sopenharmony_ci { 1274514f5e3Sopenharmony_ci if (hooks_ == nullptr) { 1284514f5e3Sopenharmony_ci return; 1294514f5e3Sopenharmony_ci } 1304514f5e3Sopenharmony_ci hooks_->LoadModule(filename, entryPoint); 1314514f5e3Sopenharmony_ci } 1324514f5e3Sopenharmony_ci void VmStart() override 1334514f5e3Sopenharmony_ci { 1344514f5e3Sopenharmony_ci if (hooks_ == nullptr) { 1354514f5e3Sopenharmony_ci return; 1364514f5e3Sopenharmony_ci } 1374514f5e3Sopenharmony_ci hooks_->VmStart(); 1384514f5e3Sopenharmony_ci } 1394514f5e3Sopenharmony_ci void VmDeath() override 1404514f5e3Sopenharmony_ci { 1414514f5e3Sopenharmony_ci if (hooks_ == nullptr) { 1424514f5e3Sopenharmony_ci return; 1434514f5e3Sopenharmony_ci } 1444514f5e3Sopenharmony_ci hooks_->VmDeath(); 1454514f5e3Sopenharmony_ci } 1464514f5e3Sopenharmony_ci void NativeCalling(const void *nativeAddress) override 1474514f5e3Sopenharmony_ci { 1484514f5e3Sopenharmony_ci if (hooks_ == nullptr) { 1494514f5e3Sopenharmony_ci return; 1504514f5e3Sopenharmony_ci } 1514514f5e3Sopenharmony_ci hooks_->NativeCalling(nativeAddress); 1524514f5e3Sopenharmony_ci } 1534514f5e3Sopenharmony_ci void NativeReturn(const void *nativeAddress) override 1544514f5e3Sopenharmony_ci { 1554514f5e3Sopenharmony_ci if (hooks_ == nullptr) { 1564514f5e3Sopenharmony_ci return; 1574514f5e3Sopenharmony_ci } 1584514f5e3Sopenharmony_ci hooks_->NativeReturn(nativeAddress); 1594514f5e3Sopenharmony_ci } 1604514f5e3Sopenharmony_ci void MethodEntry(JSHandle<Method> method, JSHandle<JSTaggedValue> envHandle) override; 1614514f5e3Sopenharmony_ci void MethodExit(JSHandle<Method> method) override; 1624514f5e3Sopenharmony_ci // used by debugger statement 1634514f5e3Sopenharmony_ci bool GetSingleStepStatus() const 1644514f5e3Sopenharmony_ci { 1654514f5e3Sopenharmony_ci return singleStepOnDebuggerStmt_; 1664514f5e3Sopenharmony_ci } 1674514f5e3Sopenharmony_ci void SetSingleStepStatus(bool status) 1684514f5e3Sopenharmony_ci { 1694514f5e3Sopenharmony_ci singleStepOnDebuggerStmt_ = status; 1704514f5e3Sopenharmony_ci } 1714514f5e3Sopenharmony_ciprivate: 1724514f5e3Sopenharmony_ci std::unique_ptr<PtMethod> FindMethod(const JSPtLocation &location) const; 1734514f5e3Sopenharmony_ci std::optional<JSBreakpoint> FindBreakpoint(JSHandle<Method> method, uint32_t bcOffset) const; 1744514f5e3Sopenharmony_ci std::optional<JSBreakpoint> FindSmartBreakpoint(JSHandle<Method> method, uint32_t bcOffset) const; 1754514f5e3Sopenharmony_ci bool RemoveBreakpoint(const std::unique_ptr<PtMethod> &ptMethod, uint32_t bcOffset); 1764514f5e3Sopenharmony_ci bool RemoveSmartBreakpoint(const std::unique_ptr<PtMethod> &ptMethod, uint32_t bcOffset); 1774514f5e3Sopenharmony_ci void HandleExceptionThrowEvent(const JSThread *thread, JSHandle<Method> method, uint32_t bcOffset); 1784514f5e3Sopenharmony_ci bool HandleStep(JSHandle<Method> method, uint32_t bcOffset); 1794514f5e3Sopenharmony_ci bool HandleNativeOut(); 1804514f5e3Sopenharmony_ci bool HandleBreakpoint(JSHandle<Method> method, uint32_t bcOffset); 1814514f5e3Sopenharmony_ci void DumpBreakpoints(); 1824514f5e3Sopenharmony_ci bool IsBreakpointCondSatisfied(std::optional<JSBreakpoint> breakpoint) const; 1834514f5e3Sopenharmony_ci 1844514f5e3Sopenharmony_ci const EcmaVM *ecmaVm_; 1854514f5e3Sopenharmony_ci PtHooks *hooks_ {nullptr}; 1864514f5e3Sopenharmony_ci NotificationManager *notificationMgr_ {nullptr}; 1874514f5e3Sopenharmony_ci bool singleStepOnDebuggerStmt_ {false}; 1884514f5e3Sopenharmony_ci 1894514f5e3Sopenharmony_ci CUnorderedSet<JSBreakpoint, HashJSBreakpoint> breakpoints_ {}; 1904514f5e3Sopenharmony_ci CUnorderedSet<JSBreakpoint, HashJSBreakpoint> smartBreakpoints_ {}; 1914514f5e3Sopenharmony_ci 1924514f5e3Sopenharmony_ci friend class JsDebuggerFriendTest; 1934514f5e3Sopenharmony_ci}; 1944514f5e3Sopenharmony_ci} // namespace panda::ecmascript::tooling 1954514f5e3Sopenharmony_ci 1964514f5e3Sopenharmony_ci#endif // ECMASCRIPT_DEBUGGER_JS_DEBUGGER_H 197