• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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();
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 
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     }
PendingJobEntry()144     void PendingJobEntry() override
145     {
146         if (hooks_ == nullptr) {
147             return;
148         }
149         hooks_->PendingJobEntry();
150     }
NativeCalling(const void * nativeAddress)151     void NativeCalling(const void *nativeAddress) override
152     {
153         if (hooks_ == nullptr) {
154             return;
155         }
156         hooks_->NativeCalling(nativeAddress);
157     }
158 private:
159     std::unique_ptr<PtMethod> FindMethod(const JSPtLocation &location) const;
160     std::optional<JSBreakpoint> FindBreakpoint(JSHandle<Method> method, uint32_t bcOffset) const;
161     bool RemoveBreakpoint(const std::unique_ptr<PtMethod> &ptMethod, uint32_t bcOffset);
162     void HandleExceptionThrowEvent(const JSThread *thread, JSHandle<Method> method, uint32_t bcOffset);
163     bool HandleStep(JSHandle<Method> method, uint32_t bcOffset);
164     bool HandleBreakpoint(JSHandle<Method> method, uint32_t bcOffset);
165     void DumpBreakpoints();
166 
167     const EcmaVM *ecmaVm_;
168     PtHooks *hooks_ {nullptr};
169     NotificationManager *notificationMgr_ {nullptr};
170 
171     CUnorderedSet<JSBreakpoint, HashJSBreakpoint> breakpoints_ {};
172 };
173 }  // namespace panda::ecmascript::tooling
174 
175 #endif  // ECMASCRIPT_TOOLING_BACKEND_JS_DEBUGGER_H
176