• 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 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