• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 PUBLIC_API 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 SetSmartBreakpoint(const JSPtLocation &location);
121     bool RemoveBreakpoint(const JSPtLocation &location) override;
122     void RemoveAllBreakpoints() override;
123     bool RemoveBreakpointsByUrl(const std::string &url) override;
124     void BytecodePcChanged(JSThread *thread, JSHandle<Method> method, uint32_t bcOffset) override;
LoadModule(std::string_view filename,std::string_view entryPoint)125     void LoadModule(std::string_view filename, std::string_view entryPoint) override
126     {
127         if (hooks_ == nullptr) {
128             return;
129         }
130         hooks_->LoadModule(filename, entryPoint);
131     }
VmStart()132     void VmStart() override
133     {
134         if (hooks_ == nullptr) {
135             return;
136         }
137         hooks_->VmStart();
138     }
VmDeath()139     void VmDeath() override
140     {
141         if (hooks_ == nullptr) {
142             return;
143         }
144         hooks_->VmDeath();
145     }
NativeCalling(const void * nativeAddress)146     void NativeCalling(const void *nativeAddress) override
147     {
148         if (hooks_ == nullptr) {
149             return;
150         }
151         hooks_->NativeCalling(nativeAddress);
152     }
NativeReturn(const void * nativeAddress)153     void NativeReturn(const void *nativeAddress) override
154     {
155         if (hooks_ == nullptr) {
156             return;
157         }
158         hooks_->NativeReturn(nativeAddress);
159     }
160     void MethodEntry(JSHandle<Method> method, JSHandle<JSTaggedValue> envHandle) override;
161     void MethodExit(JSHandle<Method> method) override;
162     // used by debugger statement
GetSingleStepStatus()163     bool GetSingleStepStatus() const
164     {
165         return singleStepOnDebuggerStmt_;
166     }
SetSingleStepStatus(bool status)167     void SetSingleStepStatus(bool status)
168     {
169         singleStepOnDebuggerStmt_ = status;
170     }
171     // Used by Launch Accelerate mode
DisableFirstTimeFlag()172     void DisableFirstTimeFlag()
173     {
174         if (hooks_ == nullptr) {
175             return;
176         }
177         hooks_->DisableFirstTimeFlag();
178     }
179 private:
180     std::unique_ptr<PtMethod> FindMethod(const JSPtLocation &location) const;
181     std::optional<JSBreakpoint> FindBreakpoint(JSHandle<Method> method, uint32_t bcOffset) const;
182     std::optional<JSBreakpoint> FindSmartBreakpoint(JSHandle<Method> method, uint32_t bcOffset) const;
183     bool RemoveBreakpoint(const std::unique_ptr<PtMethod> &ptMethod, uint32_t bcOffset);
184     bool RemoveSmartBreakpoint(const std::unique_ptr<PtMethod> &ptMethod, uint32_t bcOffset);
185     void HandleExceptionThrowEvent(const JSThread *thread, JSHandle<Method> method, uint32_t bcOffset);
186     bool HandleStep(JSHandle<Method> method, uint32_t bcOffset);
187     bool HandleNativeOut();
188     bool HandleBreakpoint(JSHandle<Method> method, uint32_t bcOffset);
189     void DumpBreakpoints();
190     bool IsBreakpointCondSatisfied(std::optional<JSBreakpoint> breakpoint) const;
191 
192     const EcmaVM *ecmaVm_;
193     PtHooks *hooks_ {nullptr};
194     NotificationManager *notificationMgr_ {nullptr};
195     bool singleStepOnDebuggerStmt_ {false};
196 
197     CUnorderedSet<JSBreakpoint, HashJSBreakpoint> breakpoints_ {};
198     CUnorderedSet<JSBreakpoint, HashJSBreakpoint> smartBreakpoints_ {};
199 
200     friend class JsDebuggerFriendTest;
201 };
202 }  // namespace panda::ecmascript::tooling
203 
204 #endif  // ECMASCRIPT_DEBUGGER_JS_DEBUGGER_H
205